3 Dec 2015

Create Java Keystore Using OpenSSL and Keytool for JBOSS

Last week, I encountered an irritating issue getting JBoss to accept my Java Keystore. The .csr was OpenSSL-generated and the certs were derived from VeriSign. The error I would receive on start:

JBWEB003043: Error initializing endpoint: java.io.IOException: 
JBWEB002000: Alias name 1 does not identify a key entry

The steps below eventually got me up and running. Some parts may look counter-intuitive because instead of converting the keystores to a jks-supported format (doing so kept throwing the above error), I took the certs, put them in an OpenSSL keystore,  and then fed that keystore into the conversion.

In this process, I noticed that creating an empty JKS (JKS = Java KeyStore) would automatically create a key in the new .jks. Though I had my key as alias 1, JBoss would tell me it couldn't find what it was looking for.

If you're running into any of what I'm saying, try the below. If you're here to learn, a keystore is your bag and you want to put your certs in the bag. But there are two types of bags, there is the OpenSSL bag and there is the Java KeyStore bag. They are the two coworkers you have that pretend to like each other, one makes more of an effort to get along with the other,  and deep down, everyone in the office finds dealing with them a little touchy.

Let's start fresh:
1. Concatenate both intermediate and root certs (make sure all your certs are in text format). If you can open all your certs in a text editor and see ASCII characters, you're set. If you cannot, perform the below command on each cert.

# Convert certs from data to text (pem) replacing the values below. Keep track of their names. You need to know which cert is which:

openssl x509 -in <NonTextCert.crt> -inform der -outform pem -out <OutputTextCert.pem>

2. You may not have two intermediate certs. In most cases, you'll have one intermediate (your issuer) and the root certificate (known as the CA - Certificate Authority). In this example, there are two intermediates and a root that we will combine into one file called chain.crt:

cat Primary-Intermediate.pem Secondary-Intermediate.pem VeriSign-Root.pem > chain.crt

To ensure there are no Windows carriage returns in the file, use dos2unix to clean it up:


# Ubuntu:
sudo apt-get install dos2unix

# RedHat:
sudo yum install dos2unix

# Clean up:
dos2unix chain.crt
Here is where the fun begins!

3. Use keytool to generate a Java Keystore. Of course, you'll need the JDK to use the Java keytool. When you create the .jks, a key will be generated inside - a key that we don't want since we have existing keys we want to use. Each command is one line, but I broke the command up at whitespaces to make it easier to read. Change the values to yours.


# Use keytool to generate a jks:

./keytool -genkey -alias tempalias -keyalg RSA -keysize 2048 \
   -dname "CN=johnghawi.com, OU=IT, O=Company, L=Toronto, ST=Ontario, C=CA" \
   -keypass changeit \
   -keystore mykeystore.jks \
   -storepass changeit

4. Remove the unwanted key from mykeystore.jks.

./keytool -delete -alias tempalias -keystore mykeystore.jks -storepass changeit

5. Use 'openssl' to generate a .p12 keystore (the OpenSSL equivalent of a JKS) with all the certs that we will want in the java keystore from above. server.p12 will be the name of the OpenSSL keystore.

openssl pkcs12 -export \
   -out server.p12 \
   -inkey johnghawi-private.key \
   -in johnghawi-public.pem \
   -certfile chain.crt

6. Use keytool to import the .p12 keystore into the java keystore.

# keytool will take the srckeystore server.p12, convert its contents and store it in the 
# original .jks we created in Step 3. By default, the pkcs12 (.p12) keystore entry will be created under alias 1. Instead of supplying the below command with -alias, we will be more precise and explicitly specify the source and dest aliases, should you wish to change it in the destination keystore.

./keytool -importkeystore \
   -deststorepass changeit \
   -destkeypass changeit \
   -destkeystore mykeystore.jks \
   -srckeystore server.p12 \
   -srcstoretype PKCS12 \
   -srcstorepass changeit \
   -srcalias 1
   -destalias 1

At this point, the .jks is ready to use. Copy it to the location you want, secure those permissions and ownership if needed, and specify the keystore in the JBoss config.
 
# Add the new keystore into the config. Your path may differ.
vi $JBOSS_HOME/<instance>/configuration/standalone-full-ha.xml
Find the subsystem tag that contains 'connector name="https" - this will be the tag that will use the jks for web communications. Your alias in the config below needs to match the keystore alias used during the import as well as password:


<connector name="https" protocol="HTTPS/1.1" scheme="https" socket-binding="https" enable-lookups="false" secure="true" max-connections="900">

   <ssl name="ssl" key-alias="1" password="changeit" certificate-key-file="/app/certs/mykeystore.jks" protocol="TLSv1" verify-client="false"/>

</connector>

Notice that the config has the keystore passwords stored in plaintext. Usually, this is not a good idea. Encrypted passwords are a topic of their own and out of scope for this tutorial. Anyone with access - legitimate or not - can read the config and password; compromising your keystore. The Vault Tool can be used to encrypt the keystore password that JBoss will use to access the keystore. Take a look at this article in the JBoss documentation: JBossAS7SecuringPasswords