How to Fix 'SSLPeerUnverifiedException: peer not authenticated' Exception in Java / Groovy
When developing with web services in Java you may come across the need to connect to a HTTPS URL, for example when creating a REST client. In some cases there will be an issue with the type of certificate the web server is using, resulting in a SSLPeerUnverifiedException.
To solve this you could previously export the servers SSL certificate via firefox / chrome and load this directly into the cacerts keystore (jvm's default trusted keystore). In recent versions of firefox / chrome this feature seems to have disappeared. In this post we will show you how to grab the certificate using command line tools and then load it into the cacerts keystore. Finally we give an example of connecting to a HTTPS URL with Groovy using RESTClient.
Please note this guide is for Linux / Mac users. Windows users may be able to follow along using cygwin, but we have not tested this. If you are using an alternative trusted keystore in your application, use this instead of cacerts in the examples.
Prerequisites: Before loading any key into your cacerts keystore, please verify you are happy with the certificate and its authenticity, and issuer. You can do this by using a tool like this one.
Disclaimer: Follow this guide at your own risk, we can not be held liable / accountable for any damage or issues caused to you or your systems.
Step 1: Download and Store the Certificate
To download and store the certificate run the following command, changing $ADDRESS for the sites address. For example https://www.facebook.com would become facebook.com:
echo -n | openssl s_client -connect $ADDRESS:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/$ADDRESS.cert
To check the certificate was grabbed, you can run:
cat /tmp/$ADDRESS.cert
This will output the certificate and you should see something like:
-----BEGIN CERTIFICATE-----
*DATA*
-----END CERTIFICATE-----
Step 2: Load this into the default keystore for the JVM CACERTS
First of all you need to locate the cacerts keystore for the JRE you are using. To find out the version of java run the following command:
java -version
This should give you something similar to:
java version "1.6.0_11"
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b16, mixed mode)
Next take the Java version number from the previous output, in this case 1.6.0_11 and use locate to find the cacerts keystore for this Java install:
locate cacerts | grep "1.6.0_11"
The output should give you something similar to:
/usr/lib/jvm/jre1.6.0_11/lib/security/cacerts
Now you have enough information to import the key into the keystore. Run the following command, replacing the $ADDRESS with the address variable you used earlier, the $ALIAS with a name for the certificate i.e. facebook. Replace the $PATH variable with the path to the cacert (the output from the locate command we just ran). Also we have added the -storepass argument, passing the default password for the cacerts keystore. You will want to change this, if you have not already, and should be prompted to do so.
sudo keytool -importcert -alias "$ALIAS" -file /tmp/$ADDRESS.cert -keystore $PATH/cacerts -storepass changeit
Once you run this you will be shown the certificate and prompted to confirm you want to import the certificate:
Trust this certificate? [no]: yes
Certificate was added to keystore
Now you should have the certificate ready for use in your application, providing it is configured to use the default keystore and runs on the JVM we configured the certificate for!
Step 3: Test It!
Here is some example Groovy code using RESTClient: