Friday, July 4, 2008

Creating your own Certificate Authority using OpenSSL

It took me a long time to put all this together, but now it seems extremely simple. I hope it comes in handy to others who are trying to setup a private CA.

There are three parts:
a) Creating a Certificate Authority
b) Setting up the Server(Tomcat)
c) Setting up the client

This article does not cover certificate revocation.

a) Creating a Certificate Authority

There are two ways to do this
- Using scripts provided by OpenSSL
- Using OpenSSL commands and creating your own directory structure

We will use the second method. So lets get started. Make sure you have downloaded and installed OpenSSL

1) Create a new Directory structure

MyCompanyCA\private

2) Goto the MyCompanyCA directory, create an RSA keypair for the CA using OpenSSL:

% openssl genrsa -des3 -out private/CA_key.pem 2048

Note down password you entered above for CA PASSWORD here _________________

3) Next, create, from the private key, the public-key certificate for your CA. To generate this self-signed certificate, use the following command:

% openssl req -new -key private/CA_key.pem -x509 -days 365 -out CA_cert.cer

This creates a public-key certificate from the private key you generated earlier. The -x509 switch indicates that we wish to generate this X.509 certificate, and the -days switch gives our generated certificate an expiration date. Since we are generating this public-key certificate for the first time, the command asks a number of questions, intended to populate the necessary X.500 information:

% openssl req -new -key private/CA_key.pem -x509 -days 365 -out CA_cert.cer
Enter pass phrase for private/CA_key.pem:
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]:CA
State or Province Name (full name) [Some-State]:Ontario
Locality Name (eg, city) []:Toronto
Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyCompany Info Inc.
Organizational Unit Name (eg, section) []:SECURITY Team
Common Name (eg, YOUR name) []: Certificate Authority Created by Ash Srivastava
Email Address []: asrivastava@MyCompanyinfo.com

Note: the public-key certificate should be the only file from the two that you just generated that you should share with anyone.
That’s all you need, your CA is now setup.

b) Setting up the Server(Tomcat)

1) Goto your local tomcat directory(Ex: Tomcat 5.5)
2) Generate a private key and CSR(Certificate Signing request) using the Java keytool application. To generate an RSA keypair using keytool, use the following command:

% keytool -genkey -v -alias tomcat -keyalg RSA -keysize 2048 -keystore my_keystore.jks

This command generates an RSA keypair of size 2,048 bits, following the OpenSSL example above. However, keytool will, at the same time, also generate a Java keystore (JKS) format keystore file in which the keypair, along with a self-signed public-key certificate, is placed, giving it a shorter alias of "tomcat." Since keytool creates the X.509 certificate in this step, it asks the user for the necessary X.500 information:

% keytool -genkey -v -alias tomcat -keyalg RSA -keysize 2048 -keystore my_keystore.jks
Enter keystore password: password
What is your first and last name?
[Unknown]: localhost
What is the name of your organizational unit?
[Unknown]: SECURITY team
What is the name of your organization?
[Unknown]: MyCompany Info Inc.
What is the name of your City or Locality?
[Unknown]: Toronto
What is the name of your State or Province?
[Unknown]: Ontario
What is the two-letter country code for this unit?
[Unknown]: CA
Is CN=localhost, OU=SECURITY team, O= MyCompany Info Inc., L=Toronto, ST=Ontario, C=CA correct?
[no]: yes
Generating 2,048 bit RSA key pair and self-signed certificate (MD5WithRSA)
for: CN=localhost, OU=SECURITY team, O= MyCompany Info Inc., L=Toronto, ST=Ontario, C=CA
Enter key password for
(RETURN if same as keystore password):
[Saving my_keystore.jks]

The CN should exactly be the name of the host which this certificate will identify i.e in my case localhost. Note down password you entered above for server keystore PASSWORD here _________________

3) To generate the CSR from our new keypair using keytool, you can use the following command:

% keytool -certreq -v -alias tomcat -keystore my_keystore.jks -file tomcat_request.csr
You can now submit the resulting file to the CA for certificate issuance.

4) Using the private key/public-key certificate you generated earlier for the CA, you can sign the certificate contained in the CSR using OpenSSL. Copy tomcat_request.csr to MyCompanyCA directory, the goto MyCompanyCA directory and type the following:

% openssl x509 -req -days 365 -in tomcat_request.csr -CA CA_cert.cer -CAkey private/CA_key.pem -CAcreateserial -out tomcat.cer

This command issues a new certificate, signed by your CA, with a validity period of one year. The use of the -CAcreateserial switch enables the unique assignment of serial numbers to our issued certificates. Since this is the first certificate issued by your CA, a new file is created (demoCA/CA_cert.srl) containing the number "02," which is the next serial number to be used when the next certificate is issued (serial number "01" was used by the first certificate). Thus, when issuing subsequent certificates, you would use the following command:

% openssl x509 -req -days 365 -in new_request.csr -CA demoCA/CA_cert.cer -CAkey demoCA/private/CA_key.pem -CAserial demoDA/CA_cert.srl -out new_certificate.cer

Once your CA has issued the certificate, you can send it back to the requester for use. It's also important to keep a copy of the certificate around, just in case you need to revoke it later.

5) Send tomcat.cer and CA_cert.cer to the server and paste tomcat.cer to the server directory. (Ex: Tomcat 5.5).

Rename my_keystore.jks to keystore.key

Now add CA_cert.cer to the truststore and tomcat.cer to the keystore.

The keystoreFile is a collection of X.509 certificates one of which Tomcat will use to identify itself to Browsers. This certificate contains the DNS name of the server on which Tomcat is running which the HTTP client will have used as the servername part of the URL. It is possible to use a file that contains multiple certificates (in which case Tomcat will use the certificate stored under the alias "Tomcat" or, if that is not found, will use the first certificate it finds that also has an associated private key). However, to assure that no mistakes are made it is sensible practice to use a file that has only the one host certificate, plus of course its private key and chain of parent Certificate Authorities.

The truststoreFile is a collection of X.509 certificates representing Certificate Authorities from which Tomcat is willing to accept User certificates. Since the keystoreFile contains the CA that issued the certificate identifying the server, the truststoreFile and keystoreFile could be the same in a CAS configuration where the URL (actually the port) that uses X.509 authentication is not the well know widely recognized URL for interactive (userid/password form) login, and therefore the only CA that it trusts is the institutional internal CA.
The JKS (Java Key Store) file format is maintained by a tool provided by Sun in the /bin subdirectory of the Java Development Kit (JDK) distribution of your current version of Java. It is documented in http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/keytool.html.

Add CA_cert.cer to the truststore
% keytool --import -alias CA -keystore trustStore.jks -file CA_cert.cer
Enter keystore password: tomcat
Owner: EMAILADDRESS=asrivastava@MyCompanyinfo.com, CN=Certificate Authority Created by Ash Srivastava, OU=SECURITY Team, O=MyCompany Info Inc., L=Toronto, ST=Ontario, C=CA
Issuer: EMAILADDRESS=asrivastava@MyCompanyinfo.com, CN=Certificate Authority Created by Ash Srivastava, OU=SECURITY Team, O=MyCompany Info Inc., L=Toronto, ST=Ontario, C=CA
Serial number: 0
Valid from: Wed Jul 02 16:10:50 EDT 2008 until: Thu Jul 02 16:10:50 EDT 2009
Certificate fingerprints:
MD5: 22:15:FB:7D:3D:22:40:3E:BC:EE:FD:33:92:BF:E6:8F
SHA1: 8A:EC:45:37:8D:1F:F0:E7:B4:20:69:B9:DC:93:AC:C6:46:04:7E:7E
Trust this certificate? [no]: yes
Certificate was added to keystore

Note down password you entered above for server truststore PASSWORD here___________

Add tomcat.cer to the keystore
% keytool -import -trustcacerts -alias tomcat -file tomcat.cer -keystore keystore.key
You will be asked to provide the server keystore password here

6) Go in server.xml for tomcat and enable SSL by commenting out the 8080 connector and enabling the SSL connector and add the keystore and truststore location

server.xml's SSL section should look like the following:

connector port="8443" maxhttpheadersize="8192" maxthreads="150" minsparethreads="25" maxsparethreads="75" enablelookups="false" disableuploadtimeout="true" acceptcount="100" scheme="https" secure="true" clientauth="true" sslprotocol="TLS" keystorefile="keystore.key" keystorepass="tomcat" truststorefile="trustStore.jks" truststorepass="tomcat"

The clientAuth="want" tells Tomcat to request that the Browser provide a User certificate if one is available. If you want to force the use of User certificates, replace "want" with "true". If you specify "want" and the browser does not have a certificate, then the Webflow configuration described below will forward the request to the userid/password form.

Congratulations your server is setup now.

c) Setting up the client

1) Add CA_cert.cer to your browsers Trust Store
In Firefox, Tools->Options->View Certificates->Authorities Tab->Import
In IE, Tools->Internet options->Content tab->Certificates Button->Trusted root Certification Authorities tab -> Import

2) The client should install openSSL and should generate their private key and a CSR. Create a folder caller ClientCertificate on client computer. Go in that folder and first, you need to generate an RSA private key for the new server:

% openssl genrsa -des3 -out ash.pem 2048

Note down password you entered above for client private key PASSWORD here_________
Just as in the CA example above, this command generates a new RSA private key protected by a DES3 password.

Since you want your CA to issue the public-key certificate, enabling distributed trust by other members of the PKI, you now need to generate a certificate signing request (CSR) from your private key. Using OpenSSL, you can do so with the following command:

% openssl req -new -key ash.pem -out ash_request.csr
It is this CSR file that you can now submit to the CA for public-key certificate issuance.

3) Send ash_rquest.csr to your CA and run the following command in your CA_cert.cer directory

% openssl x509 -req -days 365 -in ash_request.csr -CA CA_cert.cer -CAkey private/CA_key.pem -CAcreateserial -out ash.cer

You will required to enter the CA private key password. Send ash.cer and CA_cer back to the client

4) Now you have ash.pem, ash.cer and CA_cert.cer in your ClientCertificate Directory
To add the client certificate to the browser it has to be in .p12 format. The following command creates a single PKCS#12 file from client certificate, its key and issuer's (CA's) certificate. -name and -caname specify PKCS#12 friendly names for client's cert and CA's cert respectively.

> openssl pkcs12 -export -in ash.cer -inkey ash.pem -certfile CA_cert.cer -out ash.p12 -name "Ash Client Cert 001" -caname "MyCompany CA"

So you have created ash.p12 file which you can go and add to you browser to identify yourself to the server.

In Firefox, Tools->Options->View Certificates->Your Certificate Tab->Import
In IE, Tools->Internet options->Content tab->Certificates Button-> Personal Tab -> Import
Now go to the server and the browser will present you with the certificate you will like to use to represent yourself to the server.

d) Extracting X509 variables from the certificate and using it in a web app.

In the servlet doPost method add the following,

java.security.cert.X509Certificate[] certs = (java.security.cert.X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
HTMLWriter.writeSSLInfo(response,certs);

Simply extract and dispay it on the page

public static void writeSSLInfo(HttpServletResponse response,
X509Certificate[] certs) throws IOException {

response.setContentType("text/html");
PrintWriter writer = response.getWriter();

writeCommonHead(writer, "Authenticate");
for (int i=0; i < style="font-weight: bold;">References
1. http://www.linux.com/feature/38315
2. http://www.ja-sig.org/wiki/display/CASUM/X.509+Certificates
3. http://www.digicert.com/ssl-certificate-installation-tomcat.htm
4. http://www.orenosv.com/orenosp/certmemo_en.txt