Exploring Key Stores and Public Certificates — JKS

Seralahthan
12 min readFeb 12, 2022

In this post let’s explore the fundamentals of a Java Key Store (JKS) and a Public Key Certificate.

!!! Caution: Long Post !!!

This post is going to be a bit elaborate and lengthy, so, if you are looking for a quick cheat sheet of commands… Here you go…

The key store is a storage facility to store cryptographic keys and certificates used for SSL communications.

There are different types of key stores available in Java depending on the type of entries the keystore can store and how the keystore can store the entries. Java Key Store (JKS) is one of the widely used key store types available in Java.

Each key store can hold a unique set of keys depending on the type.
In General, A key store contains the following types of keys,

  • Private Key Entry/Entries
    (With a certificate chain for the corresponding Public Key Entry/Entries).
  • Trusted Certificates
    (Third-party Public keys + Certificate Chains)
  • Secret Key Entry/Entries

Private Key (PrivateKeyEntry)

It is the key used for asymmetric encryption and signing a digital signature. The private key entry is password protected.

Generally, a JKS type of key store can have only one private key entry in a key store file. Some key store types, allow having multiple private key entries in a single key store.

Along with the private key entry, a certificate chain for the corresponding public key entry also will be there.

Trusted Certificates (TrustedCertificateEntry)

It holds the third-party public keys used for asymmetric encryption and digital signature validation along with the Trusted Certificate Chains.

A key store can hold any number of Trusted Certificates.

Secret Key (SecretKeyEntry)

It is the key used for symmetric encryption.
Generally, a JKS doesn’t have SecretKey entries.

There are different types of Java key stores depending on the entries a key store can store and how these entries are stored in the key store. Some of the popular Java key stores are JKS, JCEKS, PKCS12, DKS, and BKS.

Let’s explore some of these Java key store types and their differences.

Java Key Store (JKS)

Is a repository of security certificates — either authorisation certificates or public key certificates — plus corresponding private keys, used for instance in SSL encryption.

Implementation can be found at java.security.KeyStore
This key store is Java-specific and usually has an extension of .jks
(eg: wso2carbon.jks)

According to the Java specification, JKS key store manages different types of entries. Each type of entry implements the KeyStore.Entry interface.
Three basic KeyStore.Entry implementations are provided:

  • KeyStore.PrivateKeyEntry
  • KeyStore.SecretKeyEntry
  • KeyStore.TrustedCertificateEntry

Refer to the Java documentation for further details.

Features of JKS

  • Since this is a Java-specific key store cannot be used with other programming languages.
  • It doesn’t support storing Secret Key entries.
  • Only a single Private Key entry can be stored in a key store file, multiple Private Key entries are not allowed.
  • Private Key entries stored in the JKS key store can’t be extracted.

Now let’s see how we can implement a key store using Java.
Java provides few options to work with key stores :

  • Writing a Java code
  • Using the inbuilt tool named “keytool which comes along with the JDK.

Keytool is a command-line tool that is shipped along with the JDK.
It can be used to create keystore, generate keys, import and export certificates, etc.

Note that keytool is only available with Java JDK installations and not with Java JRE runtimes.

Create a JKS with Private & Public key pairs using Keytool

keytool -genkeypair -v -alias sample -keyalg RSA -keysize 2048 \
-validity 365 -keystore sample_keystore.jks

This is achieved by using the keytool ‘-genkeypair’ option, in earlier version of keytool ‘-genkey’ option was used which is still supported for backward compatibility.

The above command will create a JKS key store named sample_keystore.jks which contains, a 2048 bit Private/Public key pair aliased “sample” created using the RSA cryptographic algorithm and a self-signed certificate (SHA256withRSA) with a validity period of 365 days.

Above command,

  1. Generates a RSA 2048 bit Public and Private key pair,
  2. Wraps the public key into an X.509 v3 self-signed certificate signed by SHA256withRSA with a validity period of 365 days,
  3. Self-signed certificate is then stored as a single-element certificate chain.
  4. Certificate chain and the Private Key are stored in a new keystore ‘sample_keystore.jks’ entry identified by alias ‘sample’.

While executing the above command to generate the key store, you will be prompted for the “CN”, “key store password” and “key password” as below,

CN should generally match the hostname of the server.
Generally is good to use the same password for the keystore password and the key password (for the alias “sample”).

Some servers like Tomcat Catalina Server by default use the “key store password” as the “key password” for the connectors if not explicitly mentioned.

Not all the parameters are required to be passed in the above keytool command, following are the optional defaults for the keystore creation command,

-alias: mykey
-keyalg: DSA
-keysize: 2048 bit (for both RSA and DSA)
-validity: 90 days
-storetype: JKS (property value fetched from 'java.security.keystore.type' from Java jdk/jre)

Refer to the keytool documentation for further details.

Configuring Tomcat Catalina Server with the JKS

If you are using a Tomcat Catalina Server and using separate “key password” and “key store password”, you need to explicitly configure it in the server.xml file of the Tomcat Server found in the <TOMCAT_HOME>/conf/ directory.

<!-- Define an SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="${path_to_keystore}/sample_keystore.jks"
keystorePass="keystore_password"
keyPass="key_password"
clientAuth="false" sslProtocol="TLS"/>

Note that keystorePass is used to specify the “key store password” while keyPass is used to specify the “key password”.

Refer to the Tomcat documentation for further details.

List entries of JKS

Now let’s list the key store entries of the “sample_keystore.jks

keytool -list -v -keystore sample_keystore.jks

The entries will look like below with a PrivateKeyEntry and a Certificate chain

Converting a JKS to PKCS12 keystore

As you would have noticed when we created a JKS key store using the key tool, there was this following Warning message,

Warning:
The JKS keystore uses a proprietary format.
It is recommended to migrate to PKCS12 which is an industry standard format.

JKS and JCEKS key stores are in Java proprietary format, and it is recommended to use PKCS12 format key store as it is the standard industry format. Later in this post, we will discover more on JCEKS and PKCS12 key store formats.

Let’s convert the “sample_keystore.jks” to a PKCS12 key store with .pfx extension.

keytool -importkeystore -srckeystore sample_keystore.jks \
-destkeystore sample_keystore.pfx -deststoretype pkcs12

A successful conversion will result in the following outcome

Export public certificate from JKS in DER format (binary-encoded format)

Now, let’s try to export the Public key certificate from the “sample_keystore.jks” with alias “sample to “sample.crt” Public certificate file.

keytool -exportcert -alias sample -file sample.crt \
-keystore sample_keystore.jks

Results will look like below,

If you try to view the content of the “sample.crt” file it would be in a
non-human readable format. This is because the Public certificate generated is in a binary encoded certificate.

Public certificates can have content with the following two encodings:

  • Binary DER-encoded certificates (non-human readable)
  • ASCII (Base64) PEM-encoded certificates (human-readable)

DER: Distinguished Encoding Rules (Subset of Basic Encoding Rules of ASN.1)
PEM: Privacy-Enhanced Mail

Note:
Encoding is a process of transforming the data into a different format using a publicly available schema. It can easily be reversed. The purpose of encoding is not to keep the information secure rather it is to transform the data into a format safe to be consumed by different systems.

Public certificate can have the following common file extensions:

  • “.crt” extension: Certificate may be encoded as binary DER Or ASCII PEM.
  • “.der extension: Certificate encoded with binary DER.
  • “.pem” extension: Certificate encoded with ASCII (Base64).

So, to get the Public certificate in a human-readable format we can export it either using PEM encoded .crt extension Or PEM encoded .pem extension.

keytool -exportcert -alias sample -file sample.pem \
-keystore sample_keystore.jks

Exporting the Public certificate with .pem extension as above will still result in a binary encoded Public key certificate.

This is because, regardless of the -file format provided, keytool’s -exportcert command will by default always create the Public key certificate as a binary encoded certificate.

Export public certificate from JKS in PEM format
(ASCII Base64 human-readble format)

In order to export the Public certificate from the JKS key store in a PEM format, we need to pass an additional -rfc argument while using the
-exportcert command.

keytool -exportcert -alias sample -file sample.pem \
-keystore sample_keystore.jks -rfc

Content of the “sample.pem Public certificate will look like below,

As you can see from above PEM format Public certificate has the
— — -BEGIN CERTIFICATE — — — and — — -END CERTIFICATE — — — tags.

Import third-party public certificates to the JKS

Let’s try to import a third-party’s Public certificate as a Trusted CA Certificate.

I have extracted the “wso2carbon.pem file from the “wso2carbon.jks” (default key store shipped with WSO2 Products).

Let’s try to import “wso2carbon.pem” Public certificate to the “sample_keystore.jks”

keytool -import -trustcacerts -alias wso2carbon -file wso2carbon.pem -keystore sample_keystore.jks

Results will look like below,

Export private key entry from JKS

By default, the JKS key store type doesn’t support exporting the Private key entry using the key tool. But it can be achieved by converting the JKS key store to a PKCS12 key store.

Let’s explore how we can export the Private key entry from the “sample_keystore.jks”,

  • Convert the JKS “sample_keystore.jks” key store to a PKCS12 key store “sample_keystore.pfx”. We have already done it.
  • Export the Private key entry from the PKCS12 key store using the openssl into “sample_keystore_private_key.pem” file using PEM encoding
openssl pkcs12 -in sample_keystore.pfx -nodes -nocerts \
-out sample_keystore_private_key.pem

pkcs12 => Key store format we are using.
-nodes => No DES format so the Private key won’t be encrypted.
-nocerts => No certificates at all will be output.

Exported Private key entry will look like the below,

We need to provide the “sample_keystore.pfx” key store password as the Import Password.

As you can see the Private key entry is with the PEM encoding contains
— — -BEGIN PRIVATE KEY — — — and — — -END PRIVATE KEY — — — tags. The Private key is not encrypted.

Convert the private key entry from ‘PEM’ encoding to ‘DER’ encoding

By default, OpenSSL command saves the Private key entry (encrypted/unencrypted) to the file using the PEM encoding.

We can convert the PEM format to DER format using the below command,

openssl pkey -in sample_keystore_private_key.pem -inform pem \
-out sample_keystore_private_key.der -outform der

Exported Unencrypted Private key in DER format will look like below,

As you can see from above “sample_keystore_private_key.der” contains the unencrypted private key entry encoded in binary DER format.

Export the Triple-DES encrypted private key entry from the JKS

By default, if we don’t specify the encryption algorithm Or pass -nodes command, OpenSSL will encrypt the Private key entry using a 3DES encryption algorithm.

Following exports the PEM encoded 3DES encrypted private key entry,

openssl pkcs12 -in sample_keystore.pfx -nocerts \
-out sample_keystore_private_key_default_enc.pem

As you can see from the above “sample_keystore_private_key_default_enc.pem” contains the Triple-DES encrypted (3DES) private key entry.

Please refer to the link for further details on Triple-DES encryption.

Note the tags with — — -BEGIN ENCRYPTED PRIVATE KEY — — — and
— — -END ENCRYPTED PRIVATE KEY — — — which shows us the Private key entry is encrypted.

Apart from using the default 3DES algorithm, we can export the encrypted Private key entry by specifying one of the following encryption algorithms.

  • AES (aes128, aes192, and aes256) => -aes128, -aes192, -aes256
  • DES => -des
  • 3DES => -des3

The default is triple DES.

Export the ‘AES256’ encrypted private key entry from the JKS

Let’s now export the AES256 encrypted Private key entry by, passing the encryption algorithm as below,

Convert the JKS key store to the PKCS12 key store and then execute the following command,

openssl pkcs12 -in sample_keystore.pfx -aes256 -nocerts \
-out sample_keystore_private_key_aes256.pem

Note that we are passing an additional -aes256 argument.

Exported AES256 encrypted private key will look like below,

Export the ‘RSAPrivateKey’ from the JKS

Convert the JKS key store to the PKCS12 key store.

As you may have noticed that the Private key entry contains Bag Attributes and Key Attributes apart from the Encrypted/Un-encrypted Private key entry.

This is because the private key entry we extracted has a PrivateKeyInfo ASN.1 structure as defined in the PKCS#8 (RFC 5208). PrivateKeyInfo structure allows the Private key entry to contain:

  • A Private key
  • An OID that identifies the key type

Newer versions of OpenSSL generate Private key with PKCS#8 format which has — BEGIN PRIVATE KEY —and —END PRIVATE KEY — tags.

At the start of this blog, we created the “sample_keystore.jks” with an RSA 2048 Private and Public key pair. So we need to export the RSA Private key from the key store. Also, we need to use the RSA Private key for SSL communication.

RSAPrivateKey ASN.1 structure defined in PKCS#1 (RFC 3447) allows the Private key entry to only contain the Private key eliminating the
“Bag Attributes” and “Key Attributes”.

Older versions of OpenSSL generate Private key entry in PKCS#1 format with
—BEGIN RSA PRIVATE KEY — and —END RSA PRIVATE KEY —tags.

Since we are using the newer version of OpenSSL to extract the Private key entry, we got the Private key entry in PKCS#8 format with OID.

In order to generate the Private key entry with “RSAPrivateKey” let’s use the below command,

openssl pkcs12 -in sample_keystore.pfx -nodes -nocerts | \
openssl rsa -out sample_keystore_private_key_rsa.pem

RSA Private key entry will look like below,

As you can see from the above the Private key entry only contains the private key without other attributes.

Note the tags with —BEGIN RSA PRIVATE KEY — and
—END RSA PRIVATE KEY — which shows us the Private key entry is an RSAPrivateKey. The RSA private key is not encrypted.

Extracting ‘RSAPrivateKey’ from the ‘PKCS#8’ private key entry

Now let’s consider we already have a Private key entry in PKCS#8 format and we need to extract the RSA Private key from it.

Let’s use “sample_keystore_private_key.pem”, unencrypted PKCS#8 format private key entry and convert it to RSA Private key.

Let’s use the below command,

openssl rsa -in sample_keystore_private_key.pem \
-out sample_keystore_private_key_rsa_converted.pem

The converted “sample_keystore_private_key_rsa_converted.pem” will look like below,

Extracting Triple DES encrypted ‘RSAPrivateKey’ from the ‘PKCS#8’ private key entry

The RSA Private Key we exported Or converted is not encrypted and poses a security threat. Let’s see how we can encrypt the RSA private key while converting.

openssl rsa -in sample_keystore_private_key.pem -des3 \
-out sample_keystore_private_key_rsa_des3.pem

As you can see from the above, the RSA Private key is encrypted.

Note the Proc-Type: 4,ENCRYPTED attribute which shows us the RSA private key entry is encrypted.

Import a private key entry to JKS

We can’t directly import Private key entry to a JKS type key store.
We can import the Private key to a PKCS12 key store and convert it to a JKS key store.

Following command exports the private key, public certificate and certificate chain as a ‘PKCS12’ keystore,

openssl pkcs12 -export -in <public_cert>.crt \
-inkey <private_key>.key -chain -CAfile <ca_cert>.crt \
-name "sample.com" -out sample_keystore_pkcs12.p12

Be sure to set an export password to avoid NullPointerException

Following command converts the ‘PKCS12’ key store to a JKS,

keytool -importkeystore -srckeystore sample_keystore_pkcs12.p12 \
-srcstoretype PKCS12 \
-destkeystore sample_keystore_with_imported_private_key.jks \
-deststoretype JKS -deststorepass abcd@1234

Generating JKS with ‘Secret Key’ entry

According to the JKS key store specification, we can’t store non-PrivateKeys in a “JKS” type key store.

Let’s verify the above statement by trying to generate a JKS key store with a Secret key as below,

keytool -genseckey -alias secretKey -keypass secretKey \
-keyalg AES -keysize 256 -keystore secretKey.jks \
-storepass secretKey -storetype JKS -v

-genseckey option is used to generate the Secret key.
-keyalg argument is used to pass the Secret key algorithm.
Common secret key algorithms include DES, 3DES, and AES.

The above command will result in a key tool error like below,

As you can see even though the 256-bit AES secret key is generated it cannot be stored in the JKS type key store.

Similarly, we can’t import a Secret key entry to a JKS key store.

References:

[1] https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/security/KeyStore.html
[2] https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html#keytool_option_genkeypair
[3] https://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Prepare_the_Certificate_Keystore
[4] https://en.wikipedia.org/wiki/Triple_DES

We have explored different aspects of the JKS key store in this blog.
We will continue to explore the other types of key stores in future blogs.

Thank you for reading.
Cheers!!!

--

--

Seralahthan

Consultant - Integration & CIAM | ATL@WSO2 | BScEng(Hons) in Computer Engineering | Interested in BigData, ML & AI