Today I was notified our notification email mail server was changing hosts. So I made a list of the services that use the notify email address (e.g. firstname.lastname@example.org) – this email address is responsible for sending info to our network users which include updates for everything from issue tracking to password recovery (and then some). With security in mind all emails should be sent over SSL (the mail server supports SSLv3), but the problem is that the installed cert is self-signed; now I know it is a good cert – I generated it, we just don’t wanna fork over the $$ to have a root cert provider put their stamp of approval on it and it’s used for internal purposes only.
Now, if you generated a self-signed SSL cert and want to import that, just skip the “Download the SSL Certificate” section.
There’s Always Something to Mess Your Day Up
Normally this isn’t a big deal: just update the SMTPS credentials and be on your way. However, most of our service applications are Java-based. You’re thinking, “no biggy, just turn on the flag to trust all certs.” Not that easy; the options within our apps don’t have this fancy little checkbox. So I guess I have to do it the hard way: download the cert from the mail server and add it to the Java keystore, restart the service (bah, I have down time), and cross my fingers that it works.
Download the SSL Certificate
This one is pretty easy, and really straight forward (with the help of Didier Stevens’ quickpost)
[user@host ~]$ openssl s_client -connect host.domain.tld:465 > host.domain.tld.dump
verify error:num=18:self signed certificate
[user@host ~]$ cat host.domain.tld.dump
....................BUNCH OF STUFF..............................
No client certificate CA names sent
SSL handshake has read XXXX bytes and written XXX bytes
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Protocol : TLSv1
Cipher : AES256-SHA
Key-Arg : None
Krb5 Principal: None
Start Time: 1332275776
Timeout : 300 (sec)
Verify return code: 18 (self signed certificate)
220-message from host
Obviously the above dump isn’t exactly what you’ll get, but you get the idea… Also, notice the Ctrl+C up there, this is important, the openssl command hangs and you don’t need all the extra stuff, so just wait for the initial dump and cancel the script.
Next, copy the base64 encoded certificate to a .pem file. Don’t forget to include “—–BEGIN CERTIFICATE—–” and “—–END CERTIFICATE—–“. Just save it to something like host.domain.tld.pem. Really, just copy and paste from the terminal. For the idiots: in PuTTY just select it all with the left mouse button, and click on it with the left mouse button. This will copy it to your clipboard. Issue the command “nano host.domain.tld.pem” and right click in nano to paste. Ctrl^O to write out (write the file) and Ctrl^X to exit nano. Done.
Lastly, to figure out the host the certificate belongs to, run the following (this will also confirm if you’ve copied the PEM base64 over correctly):
[user@host ~]$ openssl x509 -in host.domain.tld.pem -text | grep CN
This will show the lines which include “CN” (e.g. “…/CN=host.domain.tld/emailAddress…”). The CN parameter is the host/domain name that the certificate is registered under. This will be required information when importing with keytool.
Install the SSL Certificate with Java’s keytool into the keystore
There are a few things to accomplish in this section: find and locate the JRE you want to use, find the keytool script, find the trusted certificates file (cacerts), and execute a single-line command.
If there are several JRE’s on the system, figure out which one the application uses. For example, the standalone app I have installed has its own jre folder which contains ./bin/keytool, however, I also have a a system-wide Java installation. To expose all the keytools on your system use find / -name “keytool” …don’t use whereis, only registered applications appear with this command.
My setup looks something like this:
[user@host ~]$ find / -name "keytool"
Since I need the service app to have the certificate trusted, I’ll use its own embedded jre keytool, “/opt/thirdpartyapp/jre/bin/keytool”.
Also, the cert needs to be installed into the trusted certs file, so within the particular java/jre installation there should also be a ./lib/security directory with a cacerts file.
TL;DR Working with keytool
Now with the previously retrieved information, here’s the bread’n’butter:
/opt/thirdpartyapp/jre/bin/keytool -import -alias host.domain.tld -keystore /opt/thirdpartyapp/jre/lib/security/cacerts -file ~/host.domain.tld.pem
- The import switch tells keytool we want to import the pem into the trusted certs file (cacerts).
- The alias switch’s value should be the CN you found in the previous section (after running openssl x509…), this is the domain for which the cert was created for
- The keystore switch is the path to the Java keystore file, usually cacerts, which stores trusted certificates
- The file switch’s value is the path to the pem that we created in the previous section.
keytool will now attempt to import the cert. First it’ll prompt for a password, unless you know otherwise try “changeit” or “changeme” – these are widely used defaults. Once you provide the correct password it’ll dump out a bunch of information about the certificate it is importing and lastly ask you if you want to “Trust this certificate” – type “yes” and hit return: “Certificate was added to keystore” is presented.
Now restart the Java application (however it is you do that) and it’ll recognize the SMTPS connection (or what ever else you’re working towards, e.g. HTTPS, SFTP, POP3S etc.)
Piece of cake, after you do it a few times. (Just realized I think i change tenses and POV a couple times in this write up… oh well.)
…like at the bottom of each chapter in your school text books, don’t worry kids, there isn’t a chapter review or quiz.