I am trying to trouble shoot a two way SSL handshake mechanism. I get an error
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
This indicates that one of my keystore or my truststore files does not have the appropriate entries. I know the way to trouble shoot this is to go to the server's truststore do the keytool list check the signing authorities and come to the client's key/truststore and verify this.
Can someone list these steps clearly (with the appropriate commands) please? Googling is not leading me anywhere. I just need a list of steps of "How can I confirm that Client X can talk to Server Y with two way SSL using Cert Z"?
The SunCertPathBuilderException exception is thrown whenever there the certificate validator fails to establish a chain between the certificate and a root certificate.
The easiest way to confirm that the certificate validates is to use a graphical tool like
Keyman, or
KeyTool IUI
The above tools are recommended since the exception is usually thrown in the absence of a root certificate.
If you want to examine what certificates are getting exchanged, it is better to switch on the ssl debug flag on the JVM node where the validation is failing.
Another option is to use a network traffic capture utility like Ethereal or Microsoft Netmon to obtain a dump of the traffic containing the certificate exchanges.
PS: Are you using the right keystore in the first place? I remember doing the same mistake many moons ago...
Related
I have two apps, one is written in nodejs (which in this case is simple mock-server) and spring app (core app). I want to create a SSL connection between this two. Firstly I generated pair of key and cert, then simply setup a nodejs to work over SSL (I used this example: setting SSL - nodeJs).
I have checked that when I wrote in browser https://localhost:3000 it gives me a "secure" connection (with open padlock - so it's ok).
Next I was making a configuration on spring app using setting SSL - Spring. I took a cert from previous step generation and set it in keystore into .p12 file. In spring application I changed the url to node app to https.
When I try to connect from spring app and get some mock data from node I'm getting this stacktrace:
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I found something in stack but when I set this cert in specific directory and then restart my app, result is same.
Have anyone maybe a clue what could be wrong in this configuration and some suggestion how to fix it?
I found the solution of this problem. I don't know why, but when I created a keystore with cert inside and then use it in my spring app it cannot find this keystore with cert globally. I was looking for documentation about openJDK11 (because I used it) and find a link to Enabling Unlimited Strength Jurisdiction Policy and check file for which I have version of openJDK11.
In my case the line from crypto.policy was commented, don't know why. When I uncommented it and set unlimited it gives me one more error, but then I find one another solution. I found that, that I need to add my sign-self certificate to cacerts file (how to add my self-signed cert to cacerts). After this two operation it works as charm.
I am accessing a web service. When I go to the web service's URL in my browser, the certificate is signed and automatically is accepted.
What I don't understand is that when I use Java to access the web service I get something along the lines of:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I would imagine this means that the certificate is not signed, but it is.
Doesn't com.sun.net.ssl.internal.ssl go to the certificate authority automatically and check if the certificate is signed? If not, is there something I need to set up in addition in order to do this?
There is more checking than just the signature. The certificate authority that produced the signature must be validated, among other things. Java's list of trusted certificate authorities is different than your browser's. You may need to download the CA cert with your browser and install it with Java's keytool.
It seems that the web server or the URL you are connecting to does not have a valid certificate from an authorized CA.To solve see this alternative solution.
I'm trying to authenticate with a server over HTTPS. I'm having problems with the handshake. I think this is due to the fact that when I go to the URL in my browser, a popup box appears. If I cancel that, I can then go to a form which will allow me to login again. The server security is TAM.
Its actually at the start where I'm having problems. When I try to run this code:
HttpResponse response = httpclient.execute(httpget);
I get an IOException error stating that javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated. The sample code I'm using is from Apache HTTPClient docs. I've tried to also use the built in java authentication methods, but I get other problems with the handshake, saying the certificate isn't trusted.
Anyway, I'm pretty stuck at the moment, which is frustrating because I thought this type of stuff should be basic enough.
So, could someone be so kind as to direct me to some sample code for authentication over HTTPS?
Thanks.
EDIT:
Just to add another error I get when using the built in java http auth, relating to the certificate:
javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.g: PKIX path building failed:
java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is:
java.security.cert.CertPathValidatorException: The certificate issued by CN=XXX Internal Root CA, O=XXX Corporation, C=US is not trusted; internal cause is:
java.security.cert.CertPathValidatorException: Certificate chaining error
It seems you are missing server SSL certificates in jvm keystore, you need to import certificates using keytool. Here is one link on how to do. Here is another link (even though it is for Gmail, you may find steps useful)
The problem here is Windows. Or more specifically the WinInet API, apparently.
I can create a custom TrustManager that accepts all certs, and it can connect fine. Also, if I try my code without the hack on linux, then it works fine. So whatever way Windows handle the keystore is giving me problems.
I'm trying to print a URL (without having a browser involved at all) but the URL is currently throwing the following:
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
I'm calling the URL using a JEditorPane's setPage method, which just takes a URL as a parameter. Assuming I can't change anything server side and I still need to get to this resource, how would I go about ignoring the certificate error (or something else that gets me to my goal)?
Accessing this URL via a browser tells me the site is untrusted and asks me if I want to proceed.
Extend JEditorPane to override the getStream() method.
Inside that method, you can open a URLConnection. Test whether it is an HttpsURLConnection. If it is, initialize your own SSLContext with a custom X509TrustManager that doesn't perform any checks. Get the context's SSLSocketFactory and set it as the socket factory for the connection. Then return the InputStream from the connection.
This will defeat any attempts by the runtime to protect the user from a spoof site serving up malware. If that's really what you want…
This is possibly because your certificate in your keystore for accessing target HTTPS URL does not match the certificate from server.
You need to import the certificate in to your JVM's keystore.
Obtain keystore certificatesto access this URL and then importit into the main keystore with
keytool -importkeystore -srckeystore /path/to/custom/keystore -destkeystore $JAVA_HOME/jre/lib/security/cacerts
Assuming you are using Java from $JAVA_HOME
I would use erickson solution.
Another way is to add server's certificate (probably self signed) to your trusted certificates KeyStore (I would do it just in your test enviroment).
Use:
java InstallCert YourHost
to create a jssecacerts file
then copy it to the following folder:
$JAVA_HOME/jre/lib/security
If it is the same server that you will be contacting each time, it might be okay to simply trust this one certificate by adding it to the trust store. I wouldn't add this to the default cacerts file, but you can make your own keystore and specify it through the javax.net.ssl.trustStore system property.
Lastly, if you want to disable PKIX checking completely (which you should only do if you understand that this will compromise security quite a lot) the only way is to implement your own SSL context and trust manager as erickson has suggested.
On a related note: my mutual certifcate authentication with a WCF .net Web Service was causing issues in my test environment. I added these two lines to my code to fix the problem and allow me to work through the issue:
//Uncomment this in case server demands some unsafe operations
System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
//this command allowed me to see the detailed debugger log for detecting the
//issue with my certs.
System.setProperty("javax.net.debug","all");
Here is a nice reference for dealing with SSL negotiation and certifcates in a Java/Windows/Unix world: Transport Layer Security (TLS) Renegotiation Issue Readme
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
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.
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
http://groups.google.com/group/google-checkout-developers-forum/web/google-checkout-and-ssl-certificates?version=49
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
http://groups.google.com/group/google-checkout-api-troubleshooting/browse_thread/thread/99862c11d37d3127