It’s Been a While, RISE and 2-Way (Client Authenticated) SSL

It’s been a while since we were back at the blog.  I wish we had a better excuse but to be honest we’ve been packed with client work.  Everything from leading a few large identity and access projects to building some custom mobile applications.  More on the latter in a few weeks.

We’ve been busy hiring new team members and will be starting one of our RISE (Rapid Identity Solutions and Engineering) programs shortly.  For most of our careers there has been a shortage in talented young identity and access management engineers.  Most of the people we run into are mid or late in their careers and we feel that the industry needs some hungry young blood.  One of our clients is sponsoring a 6 month “bootcamp” of sorts where we are taking 5 team members 0-2 years out of college, pairing them up with 2 of our senior engineers for 6 months and developing some new solutions.

One of the first lessons we teach the new team members is about client authenticated SSL.  Many of them don’t even know Apache and mod_ssl yet, let alone client authentication.  So we’re going to put up a tutorial here on generating a Certificate Authority, Server Certificate, and Client Certificate and installing it on a RHEL 6.2 machine.  If you’re interested in joining the RISE program, or know anyone who might be send us an email (careers@uberether.com) there are a few more positions open.

On to the show:

From a base CentOS 5.5 install you need to set your hostname.  To do so execute the following:
> sudo hostname apache.uberether.com
> sudo vi /etc/sysconfig/network
set the hostname to hostname=apache.uberether.com
> :wq

Then lay down Apache and Mod_SSL on the box:
sudo yum install httpd mod_ssl
OpenSSL is installed on RHEL boxes by default, so now we can go and create our own Certificate Authority (CA).  Personally we like to use an openssl.cnf file for generating our CA and certs.  It just makes life easier. Take this block and create a file on your OS called openssl.cnf:
[ ca ]
default_ca       = CA_default

[ CA_default ]
dir              = .
serial           = $dir/serial
database         = $dir/certindex.txt
certs            = $dir/certs
new_certs_dir    = $dir/newcerts
crl_dir          = $dir/crl
crl              = $dir/crl.pem
certificate      = $dir/ca.crt
private_key      = $dir/private/ca.key
serial           = $dir/serial
RANDFILE         = $dir/private/.rand
default_days     = 365
default_crl_days = 30
default_md       = sha1
preserve         = no
email_in_dn      = no
name_opt         = ca_default
cert_opt         = ca_default
policy           = policy_match

[ policy_match ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
default_bits       = 2048               # Size of keys
default_keyfile    = privkey.pem        # name of generated keys
default_md         = sha1               # message digest algorithm
string_mask        = nombstr            # permitted characters
distinguished_name = req_distinguished_name
req_extensions     = v3_req

[ req_distinguished_name ]
# Variable name                         Prompt string
#-------------------------        ----------------------------------
countryName             = Country Name (2 letter code)
countryName_min         = 2
countryName_max         = 2
stateOrProvinceName     = State or Province Name (full name)
localityName            = Locality Name (city, district, province)
0.organizationName      = Organization Name (company)
organizationalUnitName  = Organizational Unit Name (department, division)
commonName              = Common Name (hostname, IP, or your name)
commonName_max          = 64
emailAddress            = Email Address
emailAddress_max        = 64

# Default values for the above, for consistency and less typing.
# Variable name                         Value
#------------------------         ------------------------------
0.organizationName_default      = UberEther
localityName_default            = Ashburn
stateOrProvinceName_default     = VA
countryName_default             = US

[ v3_ca ]
basicConstraints        = critical, CA:true, pathlen:0
nsCertType              = sslCA
keyUsage                = cRLSign, keyCertSign
extendedKeyUsage        = serverAuth, clientAuth
nsComment               = "OpenSSL CA Certificate"

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage         = nonRepudiation, digitalSignature, keyEncipherment

[ usr_cert ]
basicConstraints      = CA:FALSE
crlDistributionPoints = @crl

[ server ]
basicConstraints      = CA:FALSE
keyUsage              = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage      = serverAuth
nsCertType            = server
nsComment             = "OpenSSL Certificate for SSL Web Server"
crlDistributionPoints = @crl

[ client ]
basicConstraints      = CA:FALSE
keyUsage              = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage      = clientAuth
nsCertType            = client
nsComment             = "OpenSSL Certificate for SSL Client"
crlDistributionPoints = @crl

[ crl_ext ]
basicConstraints        = CA:FALSE
keyUsage                = digitalSignature, keyEncipherment
nsComment               = "OpenSSL generated CRL"

[ crl ]
URI = http://old.uberether.com/ca.crl

OK, now that we’ve made out own lives easier.  Time to start cutting the certs. Execute the following command and when prompted for Organizational Unit Name put in ‘RISE’, when you’re prompted for Common Name put in uberether.com, and for email address put in your email.
openssl req -config ./openssl.cnf -newkey rsa:2048 -nodes -keyform PEM -keyout ca.key -x509 -days 3650 -outform PEM -out ca.cer
Now we create our private SSL key for the server with the command:
openssl genrsa -out server.key 2048
Now we create the csr for the server with the following command, under the common name put apache2.uberether.com:
openssl req -config ./openssl.cnf -new -key server.key -out server.req
Now we actually issue the certificate with our self signed CA:
openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 8888 -extfile openssl.cnf -extensions server -days 365 -outform PEM -out server.cer
Similarly, we now generate our client key:
openssl genrsa -out client.key 2048
Now we generate the CSR for the client certificate, except this time we put in <your name> in the Name field and <your email> in the Email field:
openssl req -config ./openssl.cnf -new -key client.key -out client.req
Now we sign the client certificate:
openssl x509 -req -in client.req -CA ca.cer -CAkey ca.key -set_serial 8889 -extfile openssl.cnf -extensions client -days 365 -outform PEM -out client.cer
And generate the combined private key and certificate p12 file, make sure you remember the password or you will be doing this step again:
openssl pkcs12 -export -inkey client.key -in client.cer -out client.p12
OK, now that we are done with all the certificates it’s time to setup Apache.  The first thing we need to do is configure the SSL module.  We like to put all our certificates in one place.
sudo mkdir /etc/httpd/ssl
sudo cp server.cer server.key ca.cer /etc/httpd/ssl

Since we installed mod_ssl via the yum command above, the server already is listening on 443, the module is loaded and the virtual host is configured.  If you want to check out what was done look in the httpd.con and ssl.conf files.  In the ssl.conf file we want to set the certificates to our own.  Edit the ssl.conf file with the following settings:
SSLCertificateFile /etc/httpd/ssl/server.cer
SSLCertificateKeyFile /etc/httpd/ssl/server.key

Save the file and restart Apache with the following command:
sudo /etc/init.d/httpd restart
At this point go to https://apache2.uberether.com in your browser.  You should be prompted with a message asking you to accept an untrusted certificate.  Do you trust what you do? If so continue through the prompts.  Once complete you should see the Apache home page.

If the page has returned then it’s time to enable client authentication.  Edit the /etc/httpd/conf.d/ssl.conf file again and put in the following information:
SSLVerifyClient require
SSLVerifyDepth 10
SSLCACertificateFile /etc/apache2/ssl/ca.cer

Now go ahead and restart Apache:
sudo /etc/init.d/httpd restart
At this point copy your client.p12 file off of your RHEL machine and load it into your favorite browser.  Hopefully you remember the password you put on the file previously.  Now load up your browser and go to https://apache2.uberether.com.  You should now be prompted for your client certificate.  You should only have one certificate in the drop down list.  Go ahead and select it.  Again you should see the Apache installation page.  If you have any problems retrace your steps.

Looking forward to teaching more to the team soon.  Should be a great group of people to introduce to the identity world.  We promise not to leave such a gap between blog posts next time.

You might also enjoy