Search code examples
javasecuritytomcat7keytool

java.security.SignatureException: Signature does not match


  1. I created a java keystore with name cloudsslkeystore.jks

     keytool -genkeypair -validity 730 -alias cloudsslkey -keystore cloudsslkeystore.jks -dname "cn=localhost" -keypass password -storepass password
    
  2. I exported it as certificate with name cloudcertificate.cer

     keytool -export -rfc -keystore cloudsslkeystore.jks -alias cloudsslkey -file cloudcertificate.cer 
     Enter keystore password:password
     Certificate stored in file <cloudcertificate.cer>
    
  3. I added the certificate cloudcertificate.cer to my local java security folder

    C:\Program Files\Java\jre7\lib\security>keytool -keystore cacerts -importcert -noprompt -trustcacerts -alias cloudsslkey -file cloudcertificate.cer
    Enter keystore password:changeit
    Certificate was added to keystore
    

    Now I used the same java keystore cloudsslkeystore.jks in tomcat server of a different machine by modifying server.xml

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
                   maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
                   clientAuth="false" sslProtocol="TLS" keystoreFile="c:\keytool\cloudsslkeystore.jks" keystorePass="password" />
    

When I try to hit a webservice thru a java client, I get this exception.

Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Problem writing SAAJ model to stream: sun.security.validator.ValidatorException: PKIX
 path validation failed: java.security.cert.CertPathValidatorException: signature check failed
        at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:159)
        at com.sun.proxy.$Proxy39.getAllRecommendations(Unknown Source)
        at client.WSClient.main(WSClient.java:73)
Caused by: com.ctc.wstx.exc.WstxIOException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValida
torException: signature check failed
        at com.ctc.wstx.sw.BaseStreamWriter.writeCharacters(BaseStreamWriter.java:458)
        at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:749)
        at org.apache.cxf.staxutils.StaxUtils.copy(StaxUtils.java:696)
        at org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor$SAAJOutEndingInterceptor.handleMessage(SAAJOutInterceptor.java:214)
        at org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor$SAAJOutEndingInterceptor.handleMessage(SAAJOutInterceptor.java:174)
        at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
        at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:326)
        at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:279)
        at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
        at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:137)
        ... 2 more
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathVal
idatorException: signature check failed
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
        at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.setupWrappedStream(URLConnectionHTTPConduit.java:17
4)
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1302)
        at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1258)
        at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.onFirstWrite(URLConnectionHTTPConduit.java:201)
        at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47)
        at org.apache.cxf.io.AbstractThresholdOutputStream.unBuffer(AbstractThresholdOutputStream.java:89)
        at org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:63)
        at org.apache.cxf.io.CacheAndWriteOutputStream.write(CacheAndWriteOutputStream.java:80)
        at org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:51)
        at com.ctc.wstx.io.UTF8Writer.write(UTF8Writer.java:143)
        at com.ctc.wstx.sw.BufferingXmlWriter.writeRaw(BufferingXmlWriter.java:285)
        at com.ctc.wstx.sw.BufferingXmlWriter.writeCharacters(BufferingXmlWriter.java:603)
        at com.ctc.wstx.sw.BaseStreamWriter.writeCharacters(BaseStreamWriter.java:456)
        ... 13 more
Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: signature check fail
ed
        at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:350)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:260)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
        ... 37 more
Caused by: java.security.cert.CertPathValidatorException: signature check failed
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:159)
        at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:351)
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:191)
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:279)
        at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:345)
        ... 43 more
Caused by: java.security.SignatureException: Signature does not match.
        at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:451)
        at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:160)
        at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:139)
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:133)
        ... 47 more

Solution

  • The Signature does not match error is the symptom that the server identity is unknown to the client, ie the client truststore does not have the server certificate.

    Create the server certificate and add it to a keystore:

    keytool -genkey -noprompt -alias "$alias" -dname "CN=$dname_cn, OU=$dname_ou, O=$dname_o, L=$dname_l, S=$dname_s, C=$dname_c" -keystore "$keystore" -storepass "$storepass" -keypass "$keypass"

    and export it for the client into a truststore:

    keytool -export -alias "$alias" -storepass "$storepass" -file "$alias".cer -keystore "$keystore"

    If you want 2-way SSL then you have to repeat this twice, inverting, they both must know each other.

    Now the tricky part is to build an SSLContext correctly and configure your client and server with it.

    In Grizzly I do:

    SSLContextConfigurator sslContextConfigurator = new SSLContextConfigurator();
    
    // set up security context
    sslContextConfigurator.setKeyStoreFile(configuration.getKeystore()); // contains the server keypair
    sslContextConfigurator.setKeyStorePass(configuration.getKeystorePassword());
    sslContextConfigurator.setKeyStoreType(configuration.getKeystoreType());
    sslContextConfigurator.setKeyPass(configuration.getKeystoreKeypass());
    sslContextConfigurator.setTrustStoreFile(configuration.getTruststore()); // contains the list of trusted certificates
    sslContextConfigurator.setTrustStorePass(configuration.getTruststorePassword());
    sslContextConfigurator.setTrustStoreType(configuration.getTruststoreType());
    if (!sslContextConfigurator.validateConfiguration(true))
        throw new Exception("Invalid SSL configuration");
    

    For advanced debugging do not forget System.setProperty("javax.net.debug", "all");