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
Related
I have a local environment with WebLogic 10.3.4 and and .ear app deployed on it. This app must communicate with external services via REST APIs. These external services are exposed in https and use wildcard certificates.
I receive the following exceptions when I try to connect to to one of these services.
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://dds-service.domain.com" General SSLEngine problem; nested exception is javax.net.ssl.SSLHandshakeException: General SSLEngine problem [...]
[...] Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target [...]
[...] Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
So what I tried in first instance was to open the same url the app tries to connect to in my browser, download its wildcard certificate (.cer Base64 encoded) and with key tool import it into the jvm's trust store that WebLogic loads and looks up when trying to validate a cert. I am sure is the correct one because i imported other certificates that caused the same error and also because of this log
<Loading trusted certificates from the jks keystore file C:\WEBLOG~1\wls\JROCKI~1.1-3\jre\lib\security\cacerts.>
At this point, I suppose the problem is related to the way I import the wildcard certificate in WebLogic. I tried to look for different ways to do it but, like this one, require a .pfx file that is not currently available to me at the moment.
Do I need a .pfx to solve this or is there another way?
If someone will ever have the same problem, here is the solution i found: it appears that WLS 10.3.x has issues in trusting certificates wth keys longer than 128 bits, this is what caused the problem in first instance. That said, 2 actions solved my problem
-DUseSunHttpHandler=true added as a VM argument in the setDomainEnv script
Enable JSSE SSL via WLS adminn console (Environment > Servers > server name > Configuration > SSL > Advanced > check the JSSE SSL box)
Click Save, and restart WLS server.
I am getting this error in Tomcat on Linux when making an HTTPS request to another server. On Windows, SSL requests work fine. Could you please help me to resolve this.
I have loaded a keystore inside my app, so no configuration is needed.
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(keyStore,
new TrustSelfSignedStrategy()).build(),
verifier);
Error :
SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path
Hard to tell from just the code snippet you've provided.
It could be many things but here is some thoughts:
Your certificate does not exist in the keystore you have included in the app
Your keystore does not have the indended ceritifcate.
You are loading a keystore that is not the one you think you are trying to load, thus it does not have the certificate.
The certificate in the keystore is not right.
When running it on Windows, you might have set a flag like: -Dcom.sun.net.ssl.checkRevocation=false which disables the checking.
Maybe you have some VM flag that is diverting the correct path for the keystore, like: -Djavax.net.ssl.trustStore=
Run with the VM flag: -Djavax.net.debug=all to potentially see additional data about your keystore.
I have a Rest web service developed in java, glassfish, running on a centos server.
We recently opted to use the https protocol and started testing through the test certificate provided by glassfish itself at deployment time (port 8181).
Using Postman for testing I just needed to disable one option in the configuration: "SSL certificate verification".
However the modules that consumed my service, service destop, in java, started to throw exceptions.
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
In test environment, windows, the lines below corrected the problem, already in production, hundreds, could not solve.
String certificatesTrustStorePath = "/etc/alternatives/jre_1.8.0/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath); System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
The error in centos is the one presented in the post below, already read about the various reasons but could not solve.
Error - trustAnchors parameter must be non-empty
If you know how to solve in linux I appreciate it,but the question is not this ...
Do these lines I have published specify where the cacerts file is (and within my platform certificate)?
But it seems to me wrong ... I've already consumed third party https rest services and never had to specify the certificate path ... this would require me to know structurally some details of a third party server. Am I wrong?
So, I imagine there must be another way to do it ... could anyone help?
Yes, your code specifies a custom path for truststore where the ssl cert is present.
This is the public key shared corresponding to the https protocol for the handshake(either self-signed or signed by a whitelisted CA).
Default path where these get stored is
$JAVA_HOME/jre/lib/security/cacerts
Though above can be overridden.
So in your code, you have overridden the path, to point it where the public key(cert) is already present. Thus it's working for you.
Truststore is just a collection of public keys.
Alternatively, you can import the public key in the default truststore as well to make it work.
In that case, you don't have to explicitly set a different truststore.
There is many ways to do it.
copy your file to $java_home\jre\lib\security\cacerts\ than you don't have to set property manually.
you can also mention path at runtime using
-Djavax.net.ssl.trustStore=/home/user/SSL/mycacerts
-Djavax.net.ssl.keyStore=/home/user/SSL/serverkeystore.jks
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 have PKCS#12 keystore that I've sucessfully imported in my browser for accessing a server that needs 2-way SSL authentication. Works perfectly reaching any https URL there.
However, I'm unable to access an URL in the same server, and from the same host when using Axis 1.4. The given Axis faultString is:
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
My javax.net.ssl.{keyStore,keyStorePassword,keyStoreType} properties seem to be set up fine.
How can I resolve this?
I came across a simpler answer if all you want is for your client to be able to call the SSL web service and ignore SSL certificate errors. (Of course you would NOT do this in production!, but it sure is handy for testing.)
Just put this statement before you invoke any web services:
System.setProperty("axis.socketSecureFactory",
"org.apache.axis.components.net.SunFakeTrustSocketFactory");
I found this at the Axis wiki.
Finally, importing the certificates into my own truststore, using Andreas Sterbenz's InstallCert, and setting the trustStore properties as indicated here did the trick!