EXPEDIA GROUP TECHNOLOGY — SOFTWARE

How to Import Public Certificates into Java’s Truststore from a Browser

Troubleshooting troublesome certificates

Avinash Reddy Penugonda
Expedia Group Technology

--

Brand new padlock holding an old gate closed
  • Were you ever able to connect to an HTTPS service endpoint from your browser but not from a Java application?
  • Do you know where to fetch certificates?
  • Has your server’s HTTPS SSL certificate changed?
  • Is your version of Java unable to recognize a Root CA?

If you have faced any of these issues, this article might help.

Recently, while I started an application on my local system that connects to an HTTP service endpoint over SSL, I got an error (shown below) as the application was not able to recognize the Root Certificate Authority(CA) of the endpoint.

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

The error message indicates that the application could not establish a secured connection over SSL (you may see this issue if you are using a certificate that is issued by an internal Certificate Authority or Self-Signed certificate). The trust is handled by having root and intermediate (may not be required if using the default JVM security setting) certificates of your SSL certificate on a trusted keystore which I was missing. I didn’t know where to look for the right certificate so I did a bit of digging.

Since I could connect to the endpoint in the browser over SSL, I extracted the Root CA certificate from the browser and inserted it into my Java truststore. Viola, I could successfully access the HTTPS endpoint from my application!

decorative separator

Steps to follow

Find your current Java version

  • If you have multiple Java versions, you need to decide which version of Java to use with the certificate.
java -version

Get the Root CA SHA-1 fingerprint of the service from your browser

  • Go to the HTTPS service endpoint in your browser
  • Click on the lock button on the address bar
  • Go to Certificate
  • Select the Root Certificate Authority(top-level parent)
  • Get the SHA-1 fingerprint of the Root CA. This example is from the screenshot below:
A8 98 5D 3A 65 E5 E5 C4 B2 D7 D6 6D 40 C6 DD 2F B1 9C 54 36 
Screen shot of a web browser’s certificate viewer showing the Root CA for expedia.com with the highlighted SHA-1 fingerprint
Root CA for expedia.com with the highlighted SHA-1 fingerprint
  • Replace spaces in the fingerprint with colons
A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36

List all the trusted public Root CAs in your Java truststore

  • Navigate to the $JAVA_HOME/jre/lib/security folder for the cacerts file
  • cacerts is the default Java truststore. A truststore authenticates peers. A keystore authenticates yourself. cacerts is where Java stores public certificates of trusted Root CAs
  • Use the following command (on Unix, a similar command is available in other OSes) to list the existing certs in the truststore:
keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -listThe default password for the truststore: changeit
  • This truststore contains 95 entries with the name of the Root CA along with trusted SHA-1 certificate fingerprints as shown below:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 95 entriesverisignclass2g2ca [jdk], Jun 12, 2018, trustedCertEntry,
Certificate fingerprint (SHA1): B3:EA:C4:47:76:C9:C8:1C:EA:F2:9D:95:B6:CC:A0:08:1B:67:EC:9D
digicertassuredidg3 [jdk], Nov 30, 2017, trustedCertEntry,
Certificate fingerprint (SHA1): F5:17:A2:4F:9A:48:C6:C9:F8:A2:00:26:9F:DC:0F:48:2C:AB:30:89
digicertglobalrootca [jdk], Nov 30, 2017, trustedCertEntry,
Certificate fingerprint (SHA1): A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36

Check if the certificate from your browser already exists in the truststore

  • From the above list of trusted entries in the truststore, search for the SHA-1 fingerprint from the browser
  • If the SHA-1 fingerprint from the browser doesn’t exist in your truststore, proceed to the steps below

Export the certificate(.cer file) from the browser

  • I’ll be exporting the certificate for an HTTPS endpoint from Chrome on Mac
  • Go to chrome://settings/privacy in the address bar
  • Click on Manage certificates to open the Keychain Access tool on Mac
  • On the left side of Keychain Access tool, select System under Keychains and My Certificates under Category
  • Select the certificate you want to export, then File > Export Items > Select .cer file format > Save
Screenshot of macOS’s Keychain Assistant with `Export Items` selected
Keychain Access tool to export a certificate
  • While exporting to .cer file, you might be asked to protect it with a password. You will use that password when importing the file.
Screen shot of `save file` modal dialog.
Export the certificate to .cer file format

Import the certificate(.cer file) into Java’s truststore:

  • Be careful to only import the certificates to the truststore that you trust
  • After you export the certificate from the browser into .cer file, you need to import it into the truststore as follows:
sudo keytool -import -alias testCert -keystore $JAVA_HOME/jre/lib/security/cacerts -file example.ceralias - alias for the certificate so have a meaningful name
file - exported .cer certificate from the browser
The default password for the truststore: changeit
  • After you have successfully imported the certificate, you can check if it exists in the truststore based on the alias and the fingerprints of the Root CA
  • Restart your JVM and your application should now be able to recognize the Root CA and connect to the endpoint over SSL

Important to remember

  • If you need to delete a certificate from the truststore that was inserted by accident:
# Recommended to make a copy of keystore before you do this
# List all the certificates
keytool -keystore $JAVA_HOME/jre/lib/security/cacerts -list -v
# Delete a certificate
keytool -delete -alias aliasToRemove -keystore $JAVA_HOME/jre/lib/security/cacerts
  • Instead of adding the certificate to the default Java truststore, you can also create a custom truststore and add it as a JVM parameter while starting the application:
-Djavax.net.ssl.trustStore=/app/security/truststore.jks
-Djavax.net.ssl.trustStorePassword=myTrustStorePassword
  • cacerts files correspond to a version of Java. If you have multiple versions be mindful that you might have to insert the certificate in the right version of Java
decorative separator

References

Please reach out to me if you have any questions/ suggestions or if you think anything is not accurate.

Thanks for reading! Happy coding!

Photo by Markus Winkler on Unsplash

Learn more about technology at Expedia Group™️

--

--