HOWTO: Creating SSL certificates with CAcert.org and OpenSSL

20060406T0140


This is a detailed explanation of creating some SSL certificates with OpenSSL, getting them signed by CAcert.org, and then deploying them in a real system.

This HOWTO assumes some background knowledge in the fields of SSL and PKI (public key infrastructure) cryptography, but it's not really essential.

Introduction

SSL (secure sockets layer) allows you to encrypt communications. It also allows you to perform authentication. When submitting data over an SSL-established connection, you can be reasonably sure that it won't be intercepted along the way.

However, SSL is often viewed as synonymous with trusted — and this is simply not the case. When visiting a website with an h ttps:// URL, this simply means that the owner of the website payed Verisign or someone a large chunk of money. That's it. Unfortunat ely, the general public aren't aware of this fact, and web browsers don't make them aware of it. Even for advanced users who are aware of t his, there are no real tools to assign levels of trust. Instead, there is a binary authenticated or not authenticated.

SSL works by way of certificates. A CA (certificate authority) has a private key which they can then use to sign other certificates. If a self-signed certificate from the CA is made available to somebody who wishes to check any given certificate, that client can use the self -signed certificate to validate the signature on any other certificate signed by the CA.

This is hierarchical; so as long as the root certificate is made available, an arbitrary chain of certificates rooted with the CA can be verified.

CAcert.org is one such root CA. Unfortunately, their root certificate is not included by default in most applications, but it's usually pretty simple to add. Once added, any certificates they have signed will automatically be verified.

Getting some Certificates

Setting up a CAcert.org account

The first thing you'll need to do is head over to CAcert and hit the Join link. Th is is a typical signup process where they email you a link which then activates your account.

If you're really security-conscious, you can do what I did and base-64 encode a bit of data from /dev/random and use that a s your passphrase. Of course, this isn't memorable, so you should store it in some form of AES-encrypted file (I use kwallet).

Server Certificates

Assuming that you've bought a domain, say mydomain.dom, you now want to generate a server certificate for it, and for subdo mains like www.mydomain.dom.

The first step is to prove that you own the domain. Choose Domains -> Add and enter the domain name. CAcert.org seem to do some DNS checks and offer the email addresses of the registered admins; but you can also choose root@, hostmaster@, postmaster@, web master@ or admin@ domain. Once you've chosen the address, you'll receive an email with an activation link; following this will then prove t hat you own the domain.

Now you'll need to generate a private key and a certificate signing request. This requires the openssl commandline cli ent. First, generate the private key with:

# unencrypted, 4096-bit key
openssl genrsa -out privkey.pem 4096

# alternatively, encrypted
openssl genrsa -des3 -out privkey.pem 4096

The key length recommended by the OpenSSL key HOWTO is at least 2048 bits; I'm usi ng 4096 bits. If you choose to encrypt the key (which is probably wise), you'll have to enter the passphrase for it every time you start a server that uses it. This might not be possible; so you might have to opt for an unencrypted key and hope your disk is safe.

Now that you've got a key, you'll need to generate the certificate signing request:

# generate certificate signing request
openssl req -new -key privkey.pem -out cert.csr
# will ask some questions
# CommonName is domain name!

# display contents
cat cert.csr

The openssl client will ask you some questions about the certificate. Most of this information is ignored by CAcert.org (see their document ation) but the CommonName is extremely important: this is where you entered the fully-qualified domain name of the server you want a certif icate for (e.g. www.mydomain.dom).

To get a signed certificate from CAcert.org, simply choose Server certificates -> New and paste in the contents of t he cert.csr file. You can then copy the signed server certificate from their website.

Depending on your application, you probably want to store that signed certificate along with the private key: simply edit the priv key.pem file in your favourite text editor and paste the signed certificate (including the delimiter lines) after the existing priva te key. You can then generally point your application at this file and it will be happy.

Client Certificates

A less-well-known but nevertheless useful feature of SSL is that it can be used to authenticate clients to a server, as well as simply p roviding an encrypted communication channel. Unfortunately, CAcert.org's client certificates can only contain your email address, which can lead to limitations.

To generate a client certificate, you have to add your email address to the CAcert.org site (and of course follow the activation link in the test email). Once this is done, you can simply use the web interface to generate a certificate directly in your browser.

I found that Konqueror (3.5.2) failed to work here. It brought up the client certificate generation dialog etc. but for some reason the process failed. However, Firefox allowed me to generate the client certificate and then export it (they call it "backup") as a PKCS#12 file . I could then import it into Konqueror and it works fine. You can then tell Konqueror to present the client certificate to a specific webs erver.

The PKCS#12 certificate can also be used for e.g. subversion clients etc. although this is where the email address becomes a limiting fa ctor.

Setting up Specific Applications

Apache 2 Server

Although full configuration of Apache's mod_ssl is beyond this page (see the Apache docs, since they're pretty helpful), some tips are i n order.

In your vhost configuration (or wherever you put the directive SSLEngine On), add the server certificate with the line:

SSLCertificateFile /path/to/cert.pem

This assumes that you've got both the private key and the certificate in the same file. It's also a very good idea to make sure that this f ile is not world-readable. Under Gentoo, the bit of apache that reads the key file runs as root, so I've made it read-only to root with no group or world permissions (0400). If you've encrypted the private key, then apache will pop up with its passphrase dialog; if the key is u nencrypted, this will just work.

Apache 2 Client Authentication

You can also configure Apache 2 to verify clients based on their certificates. Again, consult the Apache docs for full details, but an e xample would be:

SSLVerifyClient require

SSLCACertificateFile /usr/share/ca-certificates/cacert.org/cacert.org.crt
SSLOptions +FakeBasicAuth
AuthName "Tourmaline Server Control"
AuthType basic

AuthUserFile /var/www/www.lwithers.me.uk/access/site
Require valid-user

This tells Apache to accept client certificates signed by the root CA (in the specified file), and to use the certificate's subject as the username. An example of the access file /var/www/www.lwithers.me.uk/access/site might be:

/CN=CAcert WoT User/emailAddress=l@lwithers.me.uk:...

which you would add with the command:

htpasswd2 /passwd/file "/CN=...me.uk"

The password should be set to "password". You can mess around with the directives a little but there's no easy way to convert the horrible mess of a subject into a nice username that something like Subversion could appreciate. What's really needed is an Apache module but nobody has written one.

Courier MTA

This is pretty simple; again, you prepare the private key and client certificate in a .pem file (should be owned by e.g. mail:root and mode 0400). Put this somewhere sensible. Then simply edit your configuration files to point at this:

TLS_CERTFILE="/path/to/cert.pem"

You can potentially use different keys for the different server components; this is useful if you access the servers on different hostnames (remember: the common name must match the fully-qualified hostname).