Tuesday, July 26, 2011

How Root Certificate Authorities Work (more or less)

‹prev | My Chain | next›

Up tonight I do something that I should have done a long time ago: set myself up as an SSL Certificate Authority (CA). Since SPDY is run over SSL, it makes sense to simulate as closely as possible real SSL. For the most part in SPDY Book I can get close enough with localhost certificates. Every now and then, I need more.

I could certainly buy a legitimate certificate, but I would worry that I would miss something and need to buy more and more to cover cases that I had not thought of in the first place. If I set myself up as a CA and tell my browser that I trust myself as a CA, then I can make myself legitimate testing certificates any time I need them.

This primarily involves the use of openssl's ca command. The openssl ca command is a bit ugly and hard to use. I am not making this up, it says so in its own documentation:
The ca command is quirky and at times downright unfriendly.
It was originally intended for reporting with limited ability to perform CA-like functions. As people have "mis-used" it for CA work, features got added. The result is, unfriendly.

I am more or less following along with Marcus Redivo's HOWTO. I think that guide will just work for normal installs, but I am using my locally installed ($HOME/local) openssl with NPN support. In many ways, that makes like easier for me because I can edit $HOME/local/ssl/openssl.cnf without fear of messing up my entire system (Marcus edits local configs and forces ca to use them via command line switches).

In my $HOME/local/ssl/openssl.cnf config file, I change the location were my CA work is going to take place:
#dir  = ./demoCA  # Where everything is kept
dir = ./CA
I am not going to be a demo CA, I am a real one, dammit!

Real CAs, at least those that use openssl ca need to do a little ground work before issuing commands wily-nily. The openssl ca command requires a flat file database to exist and a pointer to the next ID of the next certificate blessed by my awesome CA. The openssl.cnf configurations specifies these two pieces of information with:
database = $dir/index.txt # database index file.
#...
serial = $dir/serial # The current serial number
Remember how ca confessed to being really unfriendly? This is one of the ways: both of those files needs to be created before ca will work. No, ca cannot create them itself. The database file needs to simply exist. The serial pointer file needs to contain the ID of the first certificate that we will create. I will do all of this work in my home directory, so I create the CA directory that makes me a real CA:
mkdir CA
And then I initialize the flat file database and record index:
touch CA/index.txt
echo '01' > CA/serial
The last bit of setup involves organization. I need a couple of subdirectories to hold certificates that I, as a CA, sign, and a place to store my super-secret private keys:
mkdir CA/newcerts CA/private
NOTE: Were I a real boy, er... CA, I would need to guard that private directory with my life.

Before moving on, I make my life a bit easier by setting some useful defaults in openssl.cnf:
#countryName_default  = AU
countryName_default = US
#stateOrProvinceName_default = Some-State
stateOrProvinceName_default = Maryland
#0.organizationName_default = Internet Widgits Pty Ltd
0.organizationName_default = EEE Computes, LLC
With that, I can create my CA certificate:
openssl req -new -x509 \
-extensions v3_ca \
-keyout CA/private/cakey.pem \
-out CA/cacert.pem \
-days 3650
The keyout and out options store the private key and my CA certificate in the locations specified in the config file:
certificate = $dir/cacert.pem  # The CA certificate
private_key = $dir/private/cakey.pem# The private key
The openssl req writes the private key, and then requests some CA info:
Generating a 1024 bit RSA private key
........................++++++
....................................................++++++
writing new private key to 'CA/private/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) [US]:
State or Province Name (full name) [Maryland]:
Locality Name (eg, city) []:
Organization Name (eg, company) [EEE Computes, LLC]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:EEE Computes Root CA
Email Address []:ca@eeecomputes.com
Most of that comes from the default values I put in the config. The common name is the name that will identify the CA certificate when it is installed on the browser.

To install the new root CA in Chrome, I go to Preferences // Under the Hood. There I Manage Certificates:



On the Root Certificates tab, I import my new, public cacert.pem:



And now I am official!



I am a real live CA now, but my CA still needs to issue a certificate.

My first customer generates a key and a certificate request to send my way:
openssl genrsa -out jaynestown.key 1024
openssl req -new -key jaynestown.key -out jaynestown.csr
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) [US]:
State or Province Name (full name) [Maryland]:
Locality Name (eg, city) []:
Organization Name (eg, company) [EEE Computes, LLC]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:jaynestown.local
Email Address []:chris@eeecomputes.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
My customer, who wants a certificate for the jaynestown.local server, sends me the jaynestown.csr certificate request. Once I have verified that the check has not bounced, I am ready to sign the jaynestown certificate. Naturally, I use the ugly ca command to do this:
openssl ca -out ./CA/newcerts/jaynestown.crt -in jaynestown.csr
Using configuration from /home/cstrom/local/ssl/openssl.cnf
Enter pass phrase for ./CA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Jul 27 01:32:00 2011 GMT
Not After : Jul 26 01:32:00 2012 GMT
Subject:
countryName = US
stateOrProvinceName = Maryland
organizationName = EEE Computes, LLC
commonName = jaynestown.local
emailAddress = chris@eeecomputes.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
1C:21:62:29:B2:BB:84:26:4B:69:93:5D:E8:A2:82:A5:0C:EA:0C:00
X509v3 Authority Key Identifier:
keyid:3D:1B:A2:E4:94:D4:0C:D0:3B:D5:BC:78:B9:F7:97:40:73:C8:59:A2

Certificate is to be certified until Jul 26 01:32:00 2012 GMT (365 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
I send the signed jaynestown.crt certificate back to my first customer, who might install it (and the private key) under Apache thusly:
        SSLCertificateFile    /etc/ssl/certs/jaynestown.crt
SSLCertificateKeyFile /etc/ssl/private/jaynestown.key
And, with that, my first customer has a legit certificate:



And the certificate is signed by me:



Nice! I have the feeling my new CA is going to have more than a few certificates to sign in the next couple of days.


Day #84

No comments:

Post a Comment