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


Keywords:java 


Question: 

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


3 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: helped to point me in the right direction.

 

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

pathLenConstraint

see (Note about certificate chains) in

google says it may be problem with certificate chain order, I have just found that my cert is not in order, not fixed yet, working on it. I will update this later.


old post:

Have almost the same problem.

Adding certificate manualy to keystore helps, but I'd prefer to do it more automatically, with my client.

So my solution:

I will use keystore just for this one app, and one host 1. keystore does not exist - create with some generated password 2. save password in config file 3. ask user (or dont) whether he wants to accept this certificate 4. if so - save it to keystore, and use it when needed

Is this a good solution? Any comments?

 

The problem was with certificate chain order. It was: A->C->B, but should be A->B->C, once we fixed chain order the application started to work.


I havent personally fixed the certs. but this post was helpful