Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to authenticate to SSL site in java: "pathLenConstraint violated - this cert must be the last cert in the certification path"

Tags:

java

http

ssl

I'm trying to read from a secure (i.e. SSL) web page, in Java code. I'm trying to use both URLConnection (java.net) and Apache's HTTPClient. In both cases, when I make the request, I get this exception:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: basic constraints check failed: pathLenConstraint violated - this cert must be the last cert in the certification path at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1518) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:848) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:818) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1030) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1057) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1041) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:402) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:934) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234) at com.sap.river.coghead.rest.Main.testJavaHTTPConnection(Main.java:45) at com.sap.river.coghead.rest.Main.main(Main.java:32) Caused by: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: basic constraints check failed: pathLenConstraint violated - this cert must be the last cert in the certification path at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:187) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:139) at sun.security.validator.Validator.validate(Validator.java:203) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:172) at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(SSLContextImpl.java:320) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:841) ... 13 more Caused by: java.security.cert.CertPathValidatorException: basic constraints check failed: pathLenConstraint violated - this cert must be the last cert in the certification path at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:139) at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:316) at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:178) at java.security.cert.CertPathValidator.validate(CertPathValidator.java:206) at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:182) ... 18 more

Note that I've succeeded in establishing a non-ssl connection, to a different host though. I'm also able to view this page using the browser - the certificates are validated correctly there.

Do you I need to somehow change the order of certificates as they are retrieved from the server? Is there some configuration I'm missing?

Thanks in advance,

Lior

like image 642
Lior Avatar asked May 06 '09 13:05

Lior


1 Answers

I dug in further and the answer lies in the fact that I needed to import the necessary certificates into the keystore used by the JVM to authenticate SSL. The key store is the 'cacerts' file under the jre/lib/security folder in the jre that is used to run the program.

I manually exported the site's certificates - all of them.
Then I imported it into my default keystore using the 'keytool' utility provided by Sun. Note that you have to import them in the correct order.
I then put the new keystore instead of the JRE's one - and it worked.

I guess it would've been better to import the certificates directly to the JRE's keystore, but the tool asked me for a password which i didn't know.

I believe there's also a way to program around this more easily, just haven't found it yet. I'll be happy to get some pointers (TrustManager class in JSSE?).

Finally, some credit. This post here: http://javaishdiscoveries.blogspot.com/2009/02/battle-with-cacerts-and-https.html helped to point me in the right direction.

like image 146
Lior Avatar answered Nov 10 '22 06:11

Lior