Image with a symbol for a SSL certificate

How to get the SSL certificate from a SMTP server and add it to the Java TrustStore

Introduction

A few days ago we set up a Jenkins installation for a new coworker of our company. Without going into too much detail (as this post is not intended to be a Jenkins course), Jenkins is a continuous integration software which for example helps to automate and document the build process in software development. For example it can listen to a Git repository, performs automated software tests once a developer pushes a new commit to it and then releases the update on the live server if all tests were completed successfully. In this workflow Jenkins offers a simple Email functionality which informs the user whenever a task is completed, failed or some other interesting stuff happens. To enable Jenkins to send these mails, you have to insert the information of your Email-SMTP-Server in the Jenkins settings.

So far, so good. Nowadays it is standard that SMTP uses SSL to encrypt messages. As Jenkins is a Java program, it uses the Java TrustStore for determining which SSL certificates it trusts. So if the certificate of your SMTP server is not part of the Java TrustStore, you will get an error when trying to send mails. The corresponding error message in Jenkins looked something like the following. You might get a similar error message with every other software that applies the Java TrustStore while trying to use a not trusted SSL certficate.

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

	at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)

	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)

	at java.security.cert.CertPathBuilder.build(Unknown Source)

Caused: sun.security.validator.ValidatorException: PKIX path building failed

	at sun.security.validator.PKIXValidator.doBuild(Unknown Source)

	at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)

	at sun.security.validator.Validator.validate(Unknown Source)

	at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)

	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)

	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
...

Get SSL certificate from SMTP server with OpenSSL

To avoid the above mentioned error, we need to get the SSL certificate from our SMTP server and add it to the Java TrustStore. For this we will use OpenSSL that you can download from the official page and install it on your system. As we are working on Windows computers, the following description will be for the Windows operating system, but should be quite similar for Linux and Mac. After OpenSSL is applicable on your system, start the command line. You should now be able to perform the command openssl version to see the installed version of OpenSSL.

Now that we are sure that OpenSSL is working, we can get the SSL certificate from our server. For that we perform the following command in the command line:

openssl s_client -servername <server-address> -connect <server-address>:465 | openssl x509 –text

In this command it is assumed that our SMTP server is reachable on port 465. Let our SMTP server be example.com, then the above command would look like:

openssl s_client -servername example.com -connect example.com:465 | openssl x509 –text

This should print the certificate information to the console. The interesting part can be found between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----.
Image showing an example SSL certificate in the Windows command line
We now simply create a new file for example with our favorite text editor and copy the above shown certificate information (including the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----) into this file. Then we save the file as a certificate with the extension .crt, for example as example.crt.

Add the certificate to the Java TrustStore

This certificate now should be copied into the Security-Folder under your Java Development Kit. In general the path for this location looks something like C:\Program Files\Java\jdk1.8.0_131\jre\lib\security, for sure depending on the JDK version you are using. Now we navigate into this directory with our command line and add this certificate to our trusted certificates. To do so we execute the following command in the command line:

keytool -import -alias <alias> -file <cert-file> -keystore cacerts -storepass changeit

In there you have to specify an alias for your certificate, which is completely up to you. Furthermore you have to specify the name of the certificate that we had created before. In our example the certificate name is example.com and we will use example-cert as the alias:

keytool -import -alias example-cert -file example.crt -keystore cacerts -storepass changeit

After that the certificate should be added to our Java TrustStore. To check if everything worked correctly, we can list all certifcates in the TrustStore with:

keytool -keystore cacerts -storepass changeit -list

In this list you should find the certificate with the above created alias name. If the list of certificates is too long so that the command line will cut the output, you also can write it to a file with the following command:

keytool -keystore cacerts -storepass changeit -list > "C:\Users\<your-username>\Desktop\output.txt" 2>&1

This will create a file output.txt on the desktop with a list of all certificates in the TrustStore, for sure you have to set your user name appropriately. The SSL certificate of your SMTP server is now added to the Java TrustStore and you should get no more error while trying to send Emails.

Some addition for Jenkins

Because we self spent some time on figuring this out, I want to mention some more thing in the special case of Jenkins. With the above described procedure we have added the SSL certificate to the TrustStore of the default Java Runtime Environment (respectively to be more precise, to the JRE you performed the keytool-Operations on). Jenkins by default uses an other JRE that is located in the jre-Folder inside the Jenkins installation directory. Because of that, the above described operations will not prevent you from the certificate error inside Jenkins. For this you have to perform the keytool-Operations on the JRE inside the Jenkins installation directory again or you simply copy and replace the cacerts-File from the default JRE (for example C:\Program Files\Java\jdk1.8.0_131\jre\lib\security) to the Jenkins-JRE (for example C:\Program Files (x86)\Jenkins\jre\lib\security). After that you may need to restart Jenkins in order to get the changes work.

Leave a Reply

Your email address will not be published. Required fields are marked *