Howto verify Java TLS (with Server Name Indication) and the error 'PKIX path building failed'
When Java programs generate the error 'PKIX path building failed' it can be unclear whether this is due to:
- CA certificate not being present (i.e. a broken chain of trust)
- an updated/new CA
- a self-signed certificate not being in the 'cacerts' keystore
- the CA from a privately signed certificate not being in the 'cacerts' keystore
The Atlassian people have a SSLPoke utility class that is very useful for testing the Java stack. e.g. (output)
$ java -Djavax.net.debug=ssl SSLPoke teamcity.lucidsolutions.co.nz 443
Before testing/verifying the java stack use the openssl s_client command to verify the certificate being presented. e.g. [Note: the openssl used here supports TLS SNI and the '-servername' option]
$ openssl s_client -connect teamcity.lucidsolutions.co.nz:443 -servername teamcity.lucidsolutions.co.nz
Conclusions
- The StartCOM CA certificate in OpenJDK is no consistent with the one I have for class 1 server certificate and needs to be added to the 'cacerts' file.
- The OpenJDK trust manager accepts a valid certificate, even though the common name is not the same as that specified. This double brokenness gets over the TLS SNI issues.
JDK 6
The Sun JDK/JRE and OpenJDK do not support TLS Server Name Indication (SNI).JDK 7
It appears that JDK/JRE 7 will support client TLS SNI. At the time of writing this feature has been added and beta versions are available.
The boolean property 'jsse.enableSNIExtension' controls whether TLS SNI extensions are supported in the client. The default is for this to be 'true' (enabled). The JSSE reference guide reads:
|
* jsse.enableSNIExtension
system property. Server Name Indication (SNI) is a TLS extension,
defined in RFC
4366. It enables TLS connections to virtual servers, in which
multiple servers for different network names are hosted at a single
underlying network address. Some very old SSL/TLS vendors may not be able handle SSL/TLS extensions. In this case, set this property to false
to disable the SNI extension. |
The support seems to be added in this changeset. This bug reports it fixed in 'Java 7 b118'
Links
- JSSE 7 Reference Guide
- Unable to connect to SSL Services due to PKIX Path building failed
- Connecting to SSL services
Appendices
SSLPoke Failure
$ java SSLPoke teamcity.lucidsolutions.co.nz 443 sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224) at sun.security.validator.Validator.validate(Validator.java:235) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1144) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:610) at sun.security.ssl.Handshaker.process_record(Handshaker.java:546) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:913) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158) at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:652) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:92) at SSLPoke.main(SSLPoke.java:31) Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319) ... 15 more
Add StartCOM StartSSL ca certificate
# wget http://www.startssl.com/certs/ca.crt # keytool -importcert -alias startssl-manual -keystore /usr/lib/jvm/jre-openjdk/lib/security/cacerts -file ca.crt
Java version
$ java -version java version "1.6.0_20" OpenJDK Runtime Environment (IcedTea6 1.9.8) (rhel-1.22.1.9.8.el5_6-x86_64) OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)