Part 1: Creating your own SSL certificates for a custom Java client-server application

By 01

Wednesday, August 27, 2008
This is the first of a two part series that will demonstrate how to build a Java client-server application that uses a Mutually Authenticated SSL connection to securely communicate. The first part of this series will walk through the creation of certificates that will be stored in JKS certificate databases.  The second article will cover the Java code needed to create the client and server.

By Mutually Authenticated SSL (or two-way SSL), I mean an SSL connection where both the client and server must present a trusted certificate during the SSL handshake(see [5],[6],[7]).

Two tools are needed to create the JKS certificate databases and certificates: openssl & keytool.  "The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well as a full-strength general purpose cryptography library."[2]  The www.openssl.org website contains detailed information about the openssl tool.  The Java keytool is a tool distributed with JDK/JREs that "manages keystores and certificates."[3]  JKS (Java KeyStore) is the default certificate database format for Java.  Java makes a distinction between certificate databases that contain private keys and personal certificates, Keystores, and certificate databases which contain CA, Certificate Authority, certificates, Truststores.  For the remainder of this article, the terms Keystore and Truststore will be used to describe these ideas and draw a distinction between which type of JKS certificate database we are discussing.

The following steps were performed using Java v1.5.0_15 for Windows and OpenSSL  v0.9.8e for Windows (distributed with Cygwin 1.5.24). The following should be valid with just about any version of Java and OpenSSL from the past five years.

Our goal is to create a Truststore and Keystore for Mutually Authenticated SSL client program and a Truststore and Keystore for the Mutually Authenticated SSL server program--keeping with the Java standard of separating CA certs and private certs.  There are probably many variations of how one can achieve this, but below is how I decided to do it.  Each Keystore will contain a private key and certificate that is signed by a Certificate Authority.  Since the certificates will be signed by a CA, a CA must be created and the CA certificate must be put into the Keystore and Truststore for both client and server.  The CA's certificate is added to the Truststore so that a trust chain can be established during the SSL handshake; it is added to the Keystores because this is a requirement of the keytool--to load a signed certificate into a JKS file, the CA certificate that signed the personal certificate must be loaded. 

We will be acting as our own Certificate Authority.  So, the first step is to create our own CA private key and certificate.

1. Create a serial number file.

echo "01" > serial

2. Create a CA Text database file.  Note, this is a dummy file.

cp /dev/null index.txt

3. An openssl.cfg configuration file is need to fulfil some pieces of this process.  You can grab the default configuration file from the openssl installation directory (/usr/ssl on a Cygwin installation).  From inside the directory where you are performing this procedure, do the following 

cp /usr/ssl/openssl.cnf .

4. Change the working directory parameter in this file from './demoCA' to '.'.  Save the change.

5. Create CA private key and certificate with openssl that will be valid for ten years.

openssl req -new -x509 -keyout cakey.pem -out cacert.pem -days 3650

You will see the following output.  Answer questions in a similar fashion to what I have done below

$ openssl req -new -x509 -keyout cakey.pem -out cacert.pem -days 3650
Generating a 1024 bit RSA private key
.................++++++
................................................++++++
writing new private key to 'cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:Unknown
Locality Name (eg, city) []:Unknown
Organization Name (eg, company) [Internet Widgits Pty Ltd]:www.thinkmiddleware.com
Organizational Unit Name (eg, section) []:Unknown
Common Name (eg, YOUR name) []:01
Email Address []:01@thinkmiddleware.com


This command results in a PEM format CA key being written to the file cakey.pem and a PEM format CA certificate being written to cacert.pem.  These files represent your very own CA; protect your private key.  If anyone gets your CA private key, they can sign certificates that supposedly came through you.  Also, note, I am using 'changeit' as the password; I advise using something more original.  We are now going to use this CA to sign certificates for our client and server programs.


The first step is to generate a new private key for use with the server program.  This also results in a new Keystore being generated.


For the server keystore, do the following:

keytool -genkey -keystore server-keystore.jks -alias server-cert -validity 3650

You will see the following output.  Answer questions in a similar fashion to what I have done below.


Enter keystore password:  changeit
What is your first and last name?
  [Unknown]:  01
What is the name of your organizational unit?
  [Unknown]:
What is the name of your organization?
  [Unknown]:  www.thinkmiddleware.com
What is the name of your City or Locality?
  [Unknown]:
What is the name of your State or Province?
  [Unknown]:
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=01, OU=Unknown, O=www.thinkmiddleware.com, L=Unknown, ST=Unknown, C=US correct? [no]:  yes


Enter key password for <server-cert>
        (RETURN if same as keystore password):  changeit

If you want the certificate to correctly reference a hostname such as www.thinkmiddleware.com, instead of adding your first and last name, you would want to add www.thinkmiddleware.com.

At this point, you should have a Keystore for your server program called server-keystore.jks; this certificate database now contains the private key for your server program.

For the client keystore, do the following:

keytool -genkey -keystore client-keystore.jks -alias client-cert -validity 3650

Answer question in a similar fashion to responses given above for the server cert.  For the name referenced by the certificate, a good client certificate naming convention would be advisable.  If you intend to use something like J2EE Security CLIENT_CERT authentication, a reasonable naming convention that maps certificate DNs to userids the container knows.

At this point, you should have a Keystore for your client program called client-keystore.jks; this certificate database now contains the private key for your client program.

Next, a certificate request needs to be generated for each certificate that we want to generate (there is one certificate for each private key).  To generate a certificate for the server private key, run the following command:

$ keytool -certreq -alias server-cert -file server-cert.csr -keystore server-keystore.jks

The output from this command will look like something similar to the following:

Enter keystore password:  changeit


Enter whatever password you chose for the server keystore. 

This sill create a file called server-cert.csr.  This file contains your certificate request that is needed by the CA (yourself in this case) to generate a signed certificate.

To generate a certificate request for the client private key, run the following command:


$ keytool -certreq -alias client-cert -file client-cert.csr -keystore client-keystore.jks

The output will be the same as for the server keystore--enter whatever password you chose for this keystore.  Next, the CA certificate & private key that was previously generated with the openssl command and the certificate requests we just created with keytool will be used to create signed certificates for client and server programs.

To create the server certificate, run the following command:

openssl ca -out server-cert.crt -days 3650 -keyfile cakey.pem -in server-cert.csr -cert cacert.pem -outdir . -config openssl.cnf

The output will look similar to the following:

$ openssl ca -out server-cert.crt -days 3650 -keyfile cakey.pem -in server-cert
.csr -cert cacert.pem -outdir . -config openssl.cnf
Using configuration from openssl.cnf
Enter pass phrase for cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 3 (0x3)
        Validity
            Not Before: Aug 28 01:11:58 2008 GMT
            Not After : Aug 26 01:11:58 2018 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = Unknown
            organizationName          = www.thinkmiddleware.com
            organizationalUnitName    = Unknown
            commonName                = 01
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                C0:42:C9:BD:DB:F5:56:E6:5D:F2:71:C9:C4:2F:43:65:80:F7:B0:B6
            X509v3 Authority Key Identifier:
                keyid:1C:E3:F8:07:6C:16:EE:D3:51:32:12:0B:64:62:B3:A6:87:C9:1C:1D

Certificate is to be certified until Aug 26 01:11:58 2018 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated


This command should result in a certificate being created in a file called server-cert.crt.  Next, generate the client certificate by running the following command:


openssl ca -out client-cert.crt -days 3650 -keyfile cakey.pem -in client-cert.csr -cert cacert.pem -outdir . -config openssl.cnf


This command should result in a certificate being created in a file called client--cert.crt.  Before we can load these newly created certificates into our keystores, the CA certificate must be loaded into each keystore as a Trusted Certificate.  If the CA certificates needed to establish a trust chain with the new certificates is not in the keystore, keytool will not allow you to add the new certificates to the keystore.

Add the CA certificate to the server keystore with the following command:

$ keytool -import -alias ca -file cacert.pem -keystore server-keystore.jks -trustcacerts


The output from this command will look something like the following:

Enter keystore password:  changeit
Owner: EMAILADDRESS=01@thinkmiddleware.com, CN=01, O=www.thinkmiddleware.com, ST=Unknown, C=US
Issuer: EMAILADDRESS=01@thinkmiddleware.com, CN=01, O=www.thinkmiddleware.com, ST=Unknown, C=US
Serial number: 941a74cce787e979
Valid from: Wed Aug 27 20:11:46 CDT 2008 until: Sat Aug 25 20:11:46 CDT 2018
Certificate fingerprints:
         MD5:  94:B6:2A:CF:C2:C5:7A:8A:50:A3:29:7C:DD:20:32:E6
         SHA1: 62:FD:F8:7B:BC:08:E7:B7:05:40:42:C5:14:66:E8:F6:74:49:CF:CB
Trust this certificate? [no]:  yes
Certificate was added to keystore


Add the CA certificate to the client keystore with the following command:

keytool -import -alias ca -file cacert.pem -keystore client-keystore.jks -trustcacerts

The output for this command will look the same as for the server keystore.  The client and server truststores need to be created.  We also need to add the CA certificate to each truststore.  Both tasks can be accomplished with one command for each truststore.  To create the server truststore and load the CA certificate into it, run the following command:

keytool -import -alias ca -file cacert.pem -keystore server-truststore.jks -trustcacerts

The output to this command will look the same as for the server keystore.  To create client truststore and load teh CA certificate into it, run the following command:


keytool -import -alias ca -file cacert.pem -keystore client-truststore.jks -trustcacerts


Now that the CA certificates are in the keystores, the certificates must be loaded into the respective keystores that we created earlier.  To load the server certificate into the server keystore, run the following command:

$  keytool -import -alias server-cert -keystore server-keystore.jks -file server-cert.crt


The output to this command will look something like the following:

Enter keystore password:  changeit
Certificate reply was installed in keystore


Use whichever password you chose earlier.  The client certificate needs to be imported into the client keystore.  Do this with the following command:

$  keytool -import -alias client-cert -keystore client-keystore.jks -file client-cert.crt


The output to this command will look something like the output given above.  At this point, we are done, we have constructed a keystore and truststore to be used with our client program and our server program.  But, to be on the safe side, let's check our work.  To check that the server keystore has our server certificate and the CA certificate present, run the following command:

$ keytool -list -keystore server-keystore.jks
Enter keystore password:  changeit

Keystore type: jks
Keystore provider: SUN

Your keystore contains 2 entries

ca, Aug 25, 2008, trustedCertEntry,
Certificate fingerprint (MD5): D7:46:96:DD:CD:73:1D:80:87:5A:36:46:1E:C6:5C:3D
server-cert, Aug 25, 2008, keyEntry,
Certificate fingerprint (MD5): BF:D2:5F:CD:A6:76:30:32:9E:61:90:8C:C9:80:F5:9B


You should see a list of certificates aliases similar to what is listed here.  There should be two certificate aliases listed: ca & server-cert.  This is what we expect to find.  To verify the contents of the server truststore, run the following command:

$ keytool -list -keystore server-truststore.jks

Enter keystore password:  changeit

Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

ca, Aug 25, 2008, trustedCertEntry,
Certificate fingerprint (MD5): D7:46:96:DD:CD:73:1D:80:87:5A:36:46:1E:C6:5C:3D


You should see a single certificate alias listed called 'ca'.   The client keystore and truststore can be verified in the same manner.  It is left as an exercise for the reader to do this.

We now have certificates keystores and truststores that can be used with our client and server Java programs.

In the next article, I will explain how to use these keystores and truststores to create a custom Java client-server application that can communicate using Mutually Authenticated SSL connections.

References:

[1]http://www.openssl.org/docs/HOWTO/certificates.txt
[2]http://www.openssl.org
[3]http://java.sun.com/j2se/1.5.0/docs/tooldocs/index.html#security
[4]http://java.sun.com
[5]http://www.freesoft.org/CIE/Topics/ssl-draft/3-SPEC.HTM
[6]http://en.wikipedia.org/wiki/Secure_Sockets_Layer
[7]http://www.ietf.org/html.charters/tls-charter.html
[8]http://en.wikipedia.org/wiki/Certificate_Authority

 

©2008 www.thinkmiddleware.com

All copyrights & trademarks belong to their respective owners.

The comments and opinions herein are that of the author.

Please direct all comments to 01.

While the information presented on this web site is believed to be correct, the author is not responsible for any damage, loss of data, or other issues that may arise from using the information posted here.

Made with CityDesk
Last Modified: Sunday, 09-Nov-2008 10:48:29 MST