I'm using the ClientRequest library to perform a 'GET' request however I'm running into a certificate error:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397) [jsse.jar:1.7.0_40]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor.execute(ApacheHttpClient4Executor.java:182) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
Since this is just a test environment, I want to be able to ignore or accept all certificates over https. (I know this defeats the purpose of ssl.) Any pointers in the right direction is much appreciated!
ClientRequest request = new ClientRequest(someURL.toString());
ClientResponse<SomeClass> response = null;
response = request.get(SomeClass.class);
response.getEntity();
Since you're using Apache HTTP Client, with a certificate that's not trusted by default, this exception has the same cause as "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed" in most other uses of SSLSocket (see this answer for details): essentially, it's an indication that your certificate isn't trusted.
Instead of ignoring the error (by adding specific code to bypass any certificate validation, code you may forget about when you get closer to the release deadline), import your custom certificate in your truststore. For example, create a local copy of the cacerts file bundled with your JRE, use keytool to import your custom certificate, and point the javax.net.ssl.trustStore system property (and related properties) to that file when you start your JVM.
Related
I have an Issue with the verification of a ssl certificate.
What I am trying to do, is sending some data from a java program to a server, which then stores that data.
The issue is, that the ssl certificate validation fails with the following exception:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed [...] unable to find valid certification path to...
I am able to resolve this issue, by adding the "end-user" certificate of the server to the truststore I am using.
The chain looks something like this:
Root Certificate 1
Intermediate Cert 11
Intermediate Certificate x
End-User Certificate
Something to note about this whole chain / process:
The communication is using the companies proxy, which replaces all the certificates, and creates its own chain.
So back to the issue:
By adding the end-user certificate everything runs fine. But only for a little while, before that certificate gets refreshed and the one I added is no longer valid. I have tried adding just the root certificate, just each intermediate certificate, adding all 3 certificates and also adding the certificate which would be used if the proxy does not replace the chain. But somehow the certificate cannot be validated.
Is there something I might be overlooking? Do I have to add something else to be able to validate the certificate?
Edit:
Maybe something to note:
I checked the chain, by using the browser and navigating to said server, and then checking the ssl certificates.
I see SSL exception while invoking a rest api using Jersey API client library.
This used to work fine till few days ago. Based on the exception, I understand it is certificate expiry related. However I am not sure if the client machine needs to have the certificate (if any) upgraded or the API implementation server needs to upgrade. Code I use to call the API is mentioned below. I verified the ssl certs on my machine using How to determine SSL cert expiration date from a PEM encoded certificate? and I could not find any expired certificates.
com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: timestamp check failed
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:151)
Client client = Client.create(JerseyJacksonConfigFactory.getConfig());
this.resource = client.resource(baseUrl);
resource.path("foo").entity(barEntity).type(MediaType.APPLICATION_JSON_TYPE).accept(MediaType.APPLICATION_JSON).put();
I have configured my Tomcat instance to use SSL on port 8443. I've verified it's working by hitting the main tomcat page thru https:8443 on my browser.
Now I'm trying to understand what I need to do to get a Java program to read from an HTTPS URL on that tomcat server. I followed the instructions here:
Java SSL Tutorial
I just copied the .keystore file down to my client that I generated with Java's keytool on my web server. It is self signed, just for dev work. This seemed a little weird to me since that also has the private key, right? I thought I would do something to export the public key and put that on my client, but I can't find a good guide on what steps I need to for that.
Anyway, when I tried using the .keystore generated on my server in my client, I get this error:
***
%% Invalidated: [Session-1, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: 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
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
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
I've set my client up to run with these JVM args:
-Djavax.net.ssl.keyStore=.keystore -Djavax.net.ssl.keyStorePassword=changeit -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl
It does print out a bunch of stuff in that .keystore, so I'm sure it is reading it. But the server doesn't seem to like it when it tries to handshake.
What do I need to do to get that SSL Java client reading data from my webserver?
------- edit
Oops, I just noticed I was using the wrong JVM args for client. I changed to this and now it seems get further.
-Djavax.net.ssl.trustStore=.keystore -Djavax.net.ssl.trustStorePassword=changeit
I still haven't gotten it to read URL data yet. And I'm still wondering how to just give the client the public key so it can do its decryption instead of the entire server keystore.
---------- edit #2
Finally got it working. Had a couple of roadblocks along the way:
For some reason I had to make my URLs like this in Eclipse:
URL myurl = new URL("https", host, port, "/docs/setup.html", new sun.net.www.protocol.https.Handler());
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
Otherwise I'd get a class cast exception on the second line.
And, I had to regenerate my server .keystore file and copy to my client with an alternate name like this:
keytool -genkey -alias tomcat -keyalg RSA -ext san=ip:<my server ip>
I'd still like to gain a better understanding of what's needed on the client rather than the whole keystore, but at least I can play around with it now.
Java "keystore" files are used to serve two conceptually different purposes. One purpose is to serve as a key store, which is where one stores key pairs used to prove the machine's own identity. The other purpose is to serve as a trust store, which is used to store information used to identify other machines that one trusts.
You shouldn't copy the server's keystore file onto a client, since as you say it contains the private key of the server, which it contains because the file is a key store for the server. Rather, you want to create your own keystore file that serves as a trust store for the client, in which you want to import the server's certificate so your client will know to trust the server. To do that, you export a certificate from the server's keystore, and then import that certificate into the client's keystore file.
Some more detailed information appears in my related answer to this question:
Secret Key SSL Socket connections in Java
I want to get the content of a url with the https protocol. The problem is that when this code is executed from a tomcat server, I get a HandshakeException.
url = new URL("https://donneespubliques.meteofrance.fr/donnees_libres/Txt/Nivo/nivo.20140309.csv");
Scanner s = new Scanner(url.openStream());
I tried to look into other stackoverflow questions (How can I use different certificates on specific connections? or SSL Socket connection) and it seems I need to define a KeyStore.
I have no idea of how to do this.
The full error in the tomcat server is
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
What is the best way to acheve this?
The default java truststore ($JAVA_HOME/lib/security/cacerts) contains the CA cert for donneespubliques.meteofrance.fr. Most likely tomcat is using a different one.
You should be able to force it by updating the tomcat startup script to include the castore location. Something like this:
-Djavax.net.ssl.trustStore="C:\Program Files\Java\jre7\lib\security\cacerts"
-Djavax.net.ssl.trustStorePassword=changeit
I need to be able to point JMeter at a test server which has an expired SSL certificate (it will be some time before we are able to renew it). JMeter is quite rightly throwing an exception when it tries to connect:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:284)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:62)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1075)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1064)
at org.apache.jmeter.threads.JMeterThread.process_sampler(JMeterThread.java:426)
at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:255)
at java.lang.Thread.run(Unknown Source)
Does anybody know of any way that I can import said certificate into the keystore and in the process change the expiry date (and would this even help or would the fact that the server certificate has expired still cause this exception to be thrown)?
I've tried to set the validity as part of the import but this is ignored:
keytool -import ... -validity 100
P.S - I know I could implement my own TrustManager which ignores these checks but my fingers won't allow me to write such evil code and I'd much rather get to a solution that I can install on the server without having to modify JMeter!
Thanks for your time.
JMeter does not validate certificate so this is not the cause of your issue.
Which implementation do you use, java, HC3 or HC4 ?
Your issue could come from error in Socket version negotation.
Try setting this in user.properties:
https.socket.protocols=SSLv2Hello SSLv3 TLSv1
You may have to play with them depending on your server configuration, for example only set this:
https.socket.protocols=SSLv3