Tutorial - Java KeyStores (JKS) With Let's Encrypt

Hi All

Been a while since I wrote one of these.

JKS have been causing people a few headaches so I thought I would write a guide on this

A) Talk about JKS, keytool and KeyStore Explorer
B) Create a JKS - letsencrypt.jks with a RSA 2048 key (simple-cert)
C) Add a second RSA 4096 key - (san-cert)
D) Create a CSR for simple-cert and a CSR for san-cert
E) Complete Challenges with Certbot
F) Add certificates to KeyStore and Verify
G) Add To Tomacat 8.x and Verifying Certificate and JKS Functioning
H) Converting Standard certbot artifacts to a JKS (thanks to @sahsanu)
I) Creating JKS files with Bash and OpenSSL
J) Using pyjks for creating JKS files with Hooks
K) Dealing with Intermediates and Roots - options and ground work

Hope this helps out and clarifies some things out.

Andrei

7 Likes

Talk about JKS, keytool and KeyStore Explorer

JKS is tricky as a format as keys can’t exist without certificates. This can be confusing but it’s fairly simple to deal with.

A JKS can also have multiple keys and certificates and these are known as keypairs.

keytool is a java command line utility for working with JKS and is available with the Java Development Kit (JDK) or Java Runtime Environment (JRE). First order of business is to confirm the keytool is available.

A useful reference for keytool:

https://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html

KeyStore Explorer is another tool that is great for working with Key Stores. It can be downloaded here: http://keystore-explorer.org/

Create a JKS - letsencrypt.jks with a RSA 2048 key

Creating a JKS from scratch adds several advantages when generating certificates as it can simplify things for us.

As mentioned previously a key must have a certificate associated with it so we are going to have to provide a domain name with the generation of the key.

We are going to create JKS with the following parameters

Key Store Name: letsencrypt.jks
Key Store Password: test12345
Key Name (alias): simple-cert
Domain Name: jks-simple-cert.firecube.xyz
Web Private Key: RSA 2048

Command to Run:

keytool -genkeypair -alias simple-cert -keyalg RSA -keysize 2048 -keystore letsencrypt.jks -dname "CN=jks-simple-cert.firecube.xyz" -storepass test12345

Lets Have a Visual (KeyStore Explorer) Representation of the JKS we have just created:

Add a second RSA 4096 key - (san-cert)

We are now going to add a second key to the JKS.

Note: this is not a required step for most installs however to understand JKS functionality fully and the purpose of aliases it's good to have two keys (and refer to them in the tomcat config)

Command:

keytool -genkeypair -alias san-cert -keyalg RSA -keysize 4096 -keystore letsencrypt.jks -dname "CN=jks-san-cert.firecube.xyz" -storepass test12345

Create a CSR for simple-cert and a CSR for san-cert

Like most processes (e.g. OpenSSL) we generate a CSR from a Private key.

In the case of JKS we are going to use the existing keys in the JKS to create two CSRs.

having a look at the tool help we can see the various options

One option that is not covered is the -ext option which allows us to have X509 V3 extensions (specifically SANs)

CSRS:

The first CSR we will create will have the following parameters

Domain Name: jks-simple-cert.firecube.xyz
SAN Name: jks-simple-cert.firecube.xyz
Key Name (alias): simple-cert

Command:

keytool -certreq -alias simple-cert -keystore letsencrypt.jks -file jks-simple-cert_firecube_xyz.csr -storepass test12345 -ext san=dns:jks-simple-cert.firecube.xyz

The Second CSR we will create will have the following parameters

Domain Name: jks-san-cert.firecube.xyz
SAN Name: jks-san-cert.firecube.xyz, jks-san-cert1.firecube.xyz, jks-san-cert2.firecube.xyz
Key Name (alias): san-cert

Command:

Note: Quote Marks are needed for windows may not be needed for linux

keytool -certreq -alias san-cert -keystore letsencrypt.jks -file jks-san-cert_firecube_xyz.csr -storepass test12345 -ext "san=dns:jks-san-cert.firecube.xyz,dns:jks-san-cert1.firecube.xyz,dns:jks-san-cert2.firecube.xyz"

Complete Challenges with Certbot

We are going to use the manual plugin with DNS challenges and CSRs we created above

I am using a virtual environment (Certbot-Production for this)

Note: you should use --staging flag for learning and practice. Once you can issue certificates reliably from the staging authority and remove --staging and obtain production certificates.

CSR for jks-simple-cert.firecube.xyz

Command:

certbot certonly --manual --csr D:\LETSENCRYPT\JAVA-KEY-TOOL\jks-simple-cert_firecube_xyz.csr --preferred-challenges "dns"

CSR for jks-simple-cert.firecube.xyz

Command:

certbot certonly --manual --csr D:\LETSENCRYPT\JAVA-KEY-TOOL\jks-san-cert_firecube_xyz.csr --preferred-challenges "dns"

I renamed the certs along the lines of what they are (certs only and certs with intermediates)

Add certificates to KeyStore and Verify

The key to adding the certs is associating them with the keys

Commands:

keytool -importcert -alias simple-cert -keystore letsencrypt.jks -storepass test12345 -file .\jks-simple-cert-with-chain.cer
keytool -importcert -alias san-cert -keystore letsencrypt.jks -storepass test12345 -file .\jks-san-cert-with-chain.cer

You may get a message like this

You can say yes to force the keytool to accept the certificate however there is a different ways of also dealing with this error

We can download the Let's Encrypt X3 Intermediate and add it to the store using the following command

keytool -import -trustcacerts -alias LE_INTERMEDIATE -file .\LE_INTERMEDIATE_X3_IDENT.cer -keystore .\letsencrypt.jks -storepass test12345

If we run the commands again we will not get warnings as the intermediate is in the keystore.

Note: even though the intermediates are in the certificate files they are not trusted by the keystore until the intermediate certificate is in the store.

Lets have a look at the JKS using the KeyStore Explorer

simple-cert

san-cert

As we can see the certificates are associated with the private keys.

Add To Tomacat 8.x and Verify

Below is a sample configuration of two ports using the same JKS and then different aliases to ports (8443 and 8444). This is one of the nicer aspects of JKS files.

You can also store historic certificates within the JKS.

<Connector port=“8443” protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads=“150” SSLEnabled=“true” scheme=“https” secure=“true” URIEncoding="UTF-8"
keystoreFile="C:\Program Files\Apache Software Foundation\Tomcat 8.5\conf\certs\letsencrypt.jks"
keystorePass=“test12345” keyAlias="simple-cert"
clientAuth=“false” sslProtocol=“TLS” />

<Connector port=“8444” protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads=“150” SSLEnabled=“true” scheme=“https” secure=“true” URIEncoding="UTF-8"
keystoreFile="C:\Program Files\Apache Software Foundation\Tomcat 8.5\conf\certs\letsencrypt.jks"
keystorePass=“test12345” keyAlias="san-cert"
clientAuth=“false” sslProtocol=“TLS” />

Confirmations:

Web Browsers:

OpenSSL:

1 Like

Nicely done, worth pinning.

3 Likes

Converting Standard certbot artifacts to a JKS

Once you have identified the right cert, you need to recreate the keystore with the new key and cert.

0.- Create a dir to store your keystore, I’m using /etc/tomcat8/keystore/ for this example, you should use the path that you want.

mkdir -p /etc/tomcat8/keystore/

1.- Create a pkcs12 store (change HERETHEPASSWORD with the password you want):

openssl pkcs12 -export -in /etc/letsencrypt/live/gpsowl.com/fullchain.pem -inkey /etc/letsencrypt/live/gpsowl.com/privkey.pem -out /etc/tomcat8/keystore/gpsowl.com.p12 -password pass:HERETHEPASSWORD

2.- Import pkcs12 store into a keystore (change HERETHEPASSWORD with the password used in previous command):

keytool -importkeystore -srckeystore /etc/tomcat8/keystore/gpsowl.com.p12 -srcstoretype pkcs12 -srcstorepass HERETHEPASSWORD -destkeystore /etc/tomcat8/keystore/gpsowl.com.keystore -deststoretype jks -deststorepass HERETHEPASSWORD

3.- Configure your tomcat to use the right keystore and pass:

4.- Restart or reload your tomcat.

1 Like

Creating JKS files with Bash and OpenSSL

Thanks to @DarkSupremo and @oppium for the scripts and the work in this post:

Another Script:

Andrei

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.