Monday, 18 March 2013

Become Your Own SSL Certificate Authority

I have recently started signing my own SSL certificates for internal use at my company. I had several reasons to do this:

  • I was fed up of getting SSL warnings for every new system I deployed because of its self generated SSL certificates
  • I wanted to improve security and stop training myself and others to click "proceed to site" which for some was becoming an automatic reflex
  • I wanted to investigate the options for adding SSL certificates to things like VPN connections and direct access via IPv6
  • I was also interested in learning more about securing emails with SSL for identity verification etc although I'm currently more than happy with GPG it is not for everyone.
  • It sounded like a fun challenge
Please also note that I'm using the term "SSL" throughout this guide. SSL (Secure Sockets Layer) has now been depreciated and replaced with TLS (Transport Layer Security) however everyone still refers to TLS as SSL so that is what I'm doing in this guide. Certificates generated using OpenSSL as in this guide are TLS certificates and fully trustworthy which you can check by viewing the connection properties when you have applied a certificate to a server. See Wikipedia for more details on this.

In order for this to work I would need to create my own certificate authority and import that into all computers as trusted. Importing into computers can be done manually however since I have a windows domain it is easier to distribute the authority to all computers via GPO. Then I could start creating CSR's (Certificate Signing Requests) and signing SSL certs for the various systems around the company. First things first though I needed to create a Certificate Authority.

Choosing a Live Linux Distro

Conventional wisdom with Certificate Authorities is that it needs to be a dedicated machine that is not connected to any network. You can generate the keys as required on this machine and then copy them to a blank USB key which never returns to the dedicated box. In theory therefore the CA's key is only stored on a single machine that is not possible to hack into over the network and if it is compromised is not able to communicate anything confidential. In practice I have a few problems with this idea. Firstly it means you need to have a dedicated machine sitting somewhere taking up space. This machine needs to highly reliable since it will be important and probably left unused for long periods of time. You also need so make sure this machine is secure which adds overhead in the setup - decent password policy, physically securing it to make sure nobody gets near it, ensure that nobody decides to use it as a test machine for something because "it has not been touched in ages so can't be needed any more" etc. Finally you need to backup the ultra secret CA private key somewhere else anyway which leads to my solution.

I boot from a live Linux CD on a machine not connected to the network (in my case an old laptop with no hard drive). I have a pair of USB memory sticks that are only ever connected to this system (one live and one backup) for storing the private CA key and other required files and then use another blank memory stick to copy the signed SSL certificates to the relevant host. Effectively therefore my whole CA infrastructure is a simple USB memory stick which is easy to physically secure. Any time I need to use it I can get any suitable live Linux distro and boot on any isolated system. No need to worry about securing the machine I use since secret stuff is only stored in memory while the machine is on.

That said the first challenge was finding a live distro to use which already had an up to date OpenSSL installed and in a suitable working condition for running a CA since I did not really want to connect to the internet do download additional packages since that would probably weaken the overall security. Finding a list of packages included on live CD's proved easier than expected using the search at Distrowatch.  Distrowatch has a search page that lets you find distro's with a specific version of a package and also lists the package versions for each distro at the bottom of its page. Not ideal as for some it has an updated package in the current distro but the live image is much older.
  • Debian live 6.0.7 LXDE (openssl version 0.9.8o from June 2010 - typical of Debian's legendary release cycles)
  • Ubuntu 12.10 desktop (openssl version 1.0.1c)
  • Mageia 2 (openssl version 1.0.0j)
  • Fedora (openssl version 1.0.1c)
Since most live distro's seem to include Openssl the choice largely comes down to personal preference. I went with Ubuntu since it was one of the more up to date and I am most at home in Debian based systems but any of the above should work. Obviously you might hit some problems if you follow this guide exactly but use a different system as config files etc might be subtly different. Once you have decided on which distro to use you then need to get started on generating the root CA key and certificate. Watch out for keyboard layouts though - most live distro's default to US english layout which can cause chaos down the line with your password...

Creating a Certificate Authority

First you need to setup your working directories and Openssl config file:
$ mkdir CA
$ cd CA
$ mkdir certs crl newcerts private csr
$ touch index.txt
$ echo 1000 > serial
$ cp /usr/lib/ssl/openssl.cnf .
Now edit the openssl.cnf file and make the following change in the CA_default section: change "dir = ./demoCA" to "dir = . ". You can also change the defaults for country, company name etc if they will always be the same (search for countryName_default to jump to the right area of the config file).

By default certificates are created with permission to do everything EXCEPT code signing. Since all you probably want to do is connect via https securely it is also worth un-commenting this line in the [ usr_cert ] section:
nsCertType = server
Next generate the private RSA key for the CA with 4096 bits (should be enough for now, increase to match your levels of paranoia) Enter a strong password when prompted as this private key will be encrypted with tripple Des (-des3 switch)
$ openssl genrsa -des3 -out private/cakey.pem 4096
And then use this key to create the CA x509 certificate with a 10 year lifetime (or whatever you wish - since this cert should never leave the key generation system it is reasonably safe to give it a long lifetime). Enter the password you used for the key generation and then enter details for the certificate as prompted. This stuff will be visible in the final certs so don't put dummy data in there.
$ openssl req -new -x509 -extensions v3_ca -key private/cakey.pem -out cacert.pem -days 3650

Generate SSL certificates for servers

The CA is now setup and ready to go. Time to create a key and csr for a test server, this time only valid for 365 days as it will be more exposed to loss being on a server that is hosting a website. Again fill in the details with real data for the server you want the ssl cert for. Do not enter a challenge password here unless you want the server to prompt for an ssl certificate password on every reboot. This step can be completed on the server that needs the certificate rather than the CA system if preferred - you just need to copy the csr file (NOT the .key file) to the CA system in order to create the certificate. Note that if you do not do this on the CA server you probably want to omit the "-config openssl.cnf" bit from this command.
$ openssl req -config openssl.cnf -new -nodes -newkey rsa:2048 -keyout private/testserver1.key -out csr/testserver1.csr -days 365
Now you just need to sign the csr with the CA's private key (this step will need to be done on the CA system)
$ openssl ca -config openssl.cnf -out certs/testserver1.crt -infiles csr/testserver1.csr
You will now have the signed ssl certificate for the server in certs/testserver1.crt, the serial file will have been incremented by 1 and the index.txt file will have an entry for the certificate you just created.

Import the root CA certificate into your computers manually

This is nice and easy on windows - copy the cacert.pem file to your computer, rename it to cacert.crt and then double click on it. A wizard will step you through adding to the default certificate store and it will then be accessible by your web browsers (at least in Chrome and Internet Explorer - Firefox uses its own certificate store so you will need to import manually for that to work).

Import certificate into domain

I did this on my Server 2003 domain so it might be slightly different on newer server OS's. You can either re use an existing group policy or create a new one and apply it as required. In "Group Policy  Object Editor" browse to Computer Configuration --> Windows Settings --> Security Settings --> Public Key Policies --> Trusted Root Certification Authorities. Right click and choose "import" and you will get a very similar wizard to importing directly on a computer. Once done you can either wait for the group policy to propagate or on a computer run "gpupdate /force" to pull in the updated GPO with certificate immediately  Your computers will now show any relevant SSL certificates as trusted.

Tidy Up

After creating any new certificates you will need to ensure your CA folder is backed up to at least two separate highly secure memory sticks since if you lose these files you have just lost the ability to create new certificates with this Authority. Keep the certificates you generate safe as if somebody gets hold of one they will be able to impersonate that server - ideally they should only be stored on the server that hosts the SSL site and maybe on the secure memory sticks.


  • TXT_DB Error number 2 when generating certificates - By default Openssl will only generate a single certificate for each server and if you try to generate another one then it gives this cryptic error. Either you need to revoke the previous certificate or edit the openssl.cnf file and uncomment the "#unique_subject = no" line. To revoke the previous certificate find the serial number of the certificate from the index.txt file. Then issue the command "openssl ca -config openssl.cnf -revoke newcerts/<NUMBER OF CERT>.pem"

No comments:

Post a Comment