It looks like a standard question, but I couldn't find clear directions anywhere.
I have java code trying to connect to a server with probably self-signed (or expired) certificate. The code reports the following error :
[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught when processing request: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
As I understand it, I have to use keytool and tell java that it's OK to allow this connection.
All instructions to fix this problem assume I'm fully proficient with keytool, such as
generate private key for server and import it into keystore
Is there anybody who could post detailed instructions?
I'm running unix, so bash script would be best.
Not sure if it's important, but code executed in jboss.
Navigate to the site with the cert you want to trust, and click through the usual warnings for untrusted certificates. In the address bar, right click on the red warning triangle and "Not secure" message and, from the resulting menu, select "Certificate" to show the certificate.
Copy the file JAVA_HOME\lib\security\cacerts to another folder. Click OK for the warning about the trust path. Click OK when it displays the details about the certificate. Click Yes to accept the certificate as trusted.
You have basically two options here: add the self-signed certificate to your JVM truststore or configure your client to
Export the certificate from your browser and import it in your JVM truststore (to establish a chain of trust):
<JAVA_HOME>\bin\keytool -import -v -trustcacerts -alias server-alias -file server.cer -keystore cacerts.jks -keypass changeit -storepass changeit
Disable Certificate Validation:
// Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (GeneralSecurityException e) { } // Now you can access an https URL without having the certificate in the truststore try { URL url = new URL("https://hostname/index.html"); } catch (MalformedURLException e) { }
Note that I do not recommend the Option #2 at all. Disabling the trust manager defeats some parts of SSL and makes you vulnerable to man in the middle attacks. Prefer Option #1 or, even better, have the server use a "real" certificate signed by a well known CA.
There's a better alternative to trusting all certificates: Create a TrustStore
that specifically trusts a given certificate and use this to create a SSLContext
from which to get the SSLSocketFactory
to set on the HttpsURLConnection
. Here's the complete code:
File crtFile = new File("server.crt"); Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile)); // Or if the crt-file is packaged into a jar file: // CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt")); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry("server", certificate); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); connection.setSSLSocketFactory(sslContext.getSocketFactory());
You can alternatively load the KeyStore
directly from a file or retrieve the X.509 Certificate from any trusted source.
Note that with this code, the certificates in cacerts
will not be used. This particular HttpsURLConnection
will only trust this specific certificate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With