SSL CA and certificate basics

Note: this page needs updated for current practices, including CAA and TLSA records in DNS and conventions regarding what goes in the common name for various certificate types vs. what goes in Subject Alternative Names. Name-based constraints also need covered, they're needed to constrain what domains a root/issuing certificate can sign certificates for.

If you're not familiar with SSL certificates at all, read the SSL certificate basics page for background information. If you don't understand SSL certificates in general, none of the rest will make sense. The commands on this page assume that you're either working on a modern Unix machine or a Windows machine with the Cygwin environment installed, and have a current version of OpenSSL installed. I don't provide instructions for native Windows since the tools there tend to be proprietary, GUI-based and too difficult to provide written instructions for.

Creating a CA using RSA-based certificates

SSL certificates are too useful a thing to not be able to get them on demand. At the same time, for development you don't want to be spending money on them when they'll only be used internally. You can kludge things together by doing plain self-signed certificates, but that means importing every individual certificate into every piece of software that needs it. A better way is to create your own CA with a root certificate, then you can import that CA certificate into your software and issue any number of certificates as needed and have them accepted. Note that this won't be useful for public-facing servers, but it's handy for development systems where it'll just be you accessing them or for internal systems like e-mail servers where you know what machines should be accessing them and can install the CA certificate as needed without too much trouble. There's several pieces of software that'll help with that, but they gloss over what's happening and don't always work the way you'd like. I ended up working up the commands to do the job directly, it turns out they aren't that complicated, and I decided to document things here. This assumes you've got OpenSSL installed.

First, you'll need to decide where you're going to locate your CA. The ideal place is under a regular user account on a machine not routinely used for browsing the Web or connecting to outside sites. For real security you can put the entire CA on a flash drive and simply remove it from the machine when not in use. Wherever you decide, make sure that directory exists. We'll call it ${DIR} for convenience. Then create the following directories under it: private, certs, newcerts, crl. Set the permissions on private, newcerts and crl to "u=rwx,go=" (no access for anyone but the owner). The commands would be:

mkdir ${DIR}
cd ${DIR}
mkdir private
mkdir certs
mkdir newcerts
mkdir crl
chmod a=rwx,go= private newcerts crl

Then create the housekeeping files that'll be needed later:

echo 01 >crlnumber
echo 1000 >serial
touch index.txt

Now, locate your openssl.cnf file. Common locations for it are /etc/ssl, /usr/lib/ssl or /usr/ssl. You'll need to modify it slightly to reflect your soon-to-be CA. Find the "[ CA_default ]" section, and the first thing in it should be a "dir" setting. Change it's value to ${DIR}, so it's now pointing at the root of your CA directory tree. Down lower there should be a "default_days" entry. It's initially set to 365 (1 year). I prefer to set it to 730 (2 years) to avoid having to issue new certificates quite as often. Resist the temptation to set it to be much longer than 5 years. Issuing new server certificates is a lot less hassle when you've got your own CA root certificate and having certificates expire in a reasonable amount of time means you don't have to worry about compromised certificates forever. Further down in the "[ req ]" section you'll find a "default_bits" entry. I bump this up to 4096, because anything shorter is becoming too easy to brute-force with modern hardware.

Below this is the "[ req_distinguished_name ]" section. You may want to modify some of the "*_default" entries here to reflect the common values you'll be using. You don't need to, since you can enter non-default values for them when creating certificates, but if you're always going to be in one city it saves typing to have that city as the default value. The most common ones you'll want to do this for are "countryName", "stateOrPrivinceName" and "organizationName".

At this point you've got the basic files and OpenSSL set up. The first thing you want to do is create the key and certificate for your CA's root certificate. A note here about keys: it's recommended that you use 4096-bit RSA keys. Shorter keys are subject to being broken by modern massively-parallel hardware-based attacks using multiple graphics cards as processors. 2048-bit keys are acceptable in low-security situations, but anything shorter than that is too vulnerable. The minimum is expected to increase with time, and modern browsers are beginning to refuse to accept certificates based on keys with too few bits to be secure. In addition the standard MD-5 and SHA-1 digest algorithms are deprecated and browsers are or soon will be rejecting certificates that use them. The recommendation is to use either 256-bit or 512-bit SHA-2, otherwise known as SHA256 and SHA512. SHA256 is considered the current standard and is accepted by most browsers. We'll start with an RSA key:

cd ${DIR}
openssl req -newkey rsa:4096 -x509 -days 7305 -extensions v3_ca -sha256 -keyout private/cakey.pem -out cacert.pem
chmod go= private/cakey.pem

The filenames here are mandatory, they're what openssl.cnf is set up to expect. You want to set the permissions on the key to make doubly sure nobody but you can read it. You'll be prompted to enter a number of bits of information. Most important is the passphrase. The key's encrypted to keep it secure if someone happens to gain physical access to the key file. Pick a strong password, don't be afraid of having it be hard to type, you'll only be using it when you generate new certificates. Resist the urge to not have one, you really want the master key locked down. The country, state and locality should be your country, state and city. Organization name should be your company or organization. For the CA I use the domain name as the organizational unit, but it's not truly required. For the common name I use something like the organization name followed by "CA RSA root key" to tell me exactly what kind of key this is. The e-mail address should be one that goes to whoever's going to be responsible for certificates. Note that this certificate'll be valid for 20 years. That's not a mistake. Issuing new root certificates is a pain so you don't want to issue them often, and the key (the vulnerable part) never needs to leave it's isolated little environment so it's easy to keep secure.

Don't worry too much about getting it completely right the first time. You can always delete the cacert.pem and private/cakey.pem files and do it again. That's the joy of having your own little sandbox, mistakes are relatively cost-free (or at least low-cost).

Once you've got your CA key, it's time to create your first server certificate. For these, organizational unit is good to have filled in reasonably. Fill it in with the department or purpose of the certificate, eg. "Postfix SMTP server certificate". The domain name's also good for Web server certificates. The common name's the important one. Client software typically checks the CN of the server's certificate against the hostname it was trying to contact, and rejects the server if the two don't match. This protects against someone trying to impersonate your server or redirect traffic to their own server. It does mean that you can't create a certificate with a CN of "abc.example.com" and expect it to work for "www.example.com". The CN in the certificate has to match the DNS name clients are going to try to connect to. The exception is wildcard certificates: "*.example.com" will be accepted for any hostname in example.com. As a general rule for things like mail servers you'll want to use an exact hostname matching the expected server name. Web servers are the ones where you'll need wildcard certificates the most, to accomodate name-based virtual hosts. Try to avoid wildcard certificates if you can, only use them when you truly need SSL on a single host answering to multiple names. And note that it only works within a single domain. You can't create one certificate that'll work for "abc.example.com" and "xyz.example.org". And while you could create one for "*.com" to answer to multiple .com domains, this is a bad idea because it'll only work internally. Due to security and interception concerns, you'll have a hard time finding a legitimate CA that'll issue you that kind of wildcard certificate when you want to go public. If you've built your system to depend on it, you'll be left with no options.

OK, enough with the lecture. We'll use ${name} to stand in for the name of the certificate file. Usually I use the server name (or the domain name for wildcard certificates), or a one-word name like "dovecot" or "postfix" for certificates intended for the Dovecot IMAP server or Postfix SMTP server software. Commands:

cd ${DIR}
openssl req -newkey rsa:4096 -nodes -days 730 -sha256 -keyout private/${name}-key.pem -out newreq.pem
openssl ca -in newreq.pem -out certs/${name}.pem -notext
rm newreq.pem
chmod go= private/${name}-key.pem

The -nodes option says to not put a password on the key. This isn't secure, there's no protection between someone with access to the key file and the key itself, but server software can't prompt for the password upon startup so you have to leave the password off. The -days option says to make the certificate valid for 2 years. That should be long enough to not swamp you with reissuing certificates constantly. The newreq.pem file is an intermediate step: the "openssl req" command generates the key and a certificate signing request, then the "openssl ca" command signs the certificate using the root CA certificate you generated earlier and puts the signed certificate in the certs directory. newreq.pem isn't needed once the certificate's been signed, so it gets deleted and we make sure to secure the permissions on the key file.

You'll notice that OpenSSL also added a copy of the certificate in the "newcerts" directory with a name based on the serial number from the "serial" file. I let it do that to keep a record of every certificate I've issued. I let "openssl ca" maintain the index database, the "serial" file and the "newcerts" directory, I don't mess with them.

If you want the certificate information in human-readable form, add this command:

openssl x509 -in certs/${name}.pem -out certs/${name}.txt -text

That'll create a .txt file companion to the .pem file with the certificate's information in human-readable form followed by the actual certificate data. SSL software doesn't care about the human-readable text, so generally I leave the .pem file with just the certificate data and never bother with the .txt file. If I need to see it I can always run that command to generate the text.

Installing server certificates depends on the software involved. If you aren't familiar with the software's documentation and where to find out how to configure SSL, start reading. You'll need to know it to get SSL working correctly.

We're missing two steps yet. The first is to put your CA certificate into OpenSSL on your machine so it's usable. Wherever your openssl.cnf file was, there'll be a "certs" directory there. If it's a normal OpenSSL installation, there'll be a lot of root certificates already in there. Pick a name for your certificate file, for example "BudsToolsCACert", and copy "certs/cacert.pem" over to that OpenSSL certs directory as "BudsToolsCACert.pem". Make sure it's readable by everyone. Then run the "c_rehash" command to regenerate the housekeeping information to include your new certificate. That's it. Now OpenSSL on your machine knows about your CA and can verify certificates you've issued with it.

The last step is to import your CA certificate into client software like your Web browser or e-mail client. Some software uses the system OpenSSL certificate store, so once you've installed your CA certificate there that software will work automatically. Other software, eg. most Web browsers or the Thunderbird e-mail client, maintain their own certificate stores. The process varies. For current Firefox, for instance, go into Options, Advanced, the Encryption tab, and hit the View Certificates button. In that dialog go to the Authorities tab, hit the Import button, browser to the cacert.pem file, select it and hit OK. That'll import your certificate and the Firefox will be able to accept any certificates issued by you without any complaining. The process for Thunderbird, Internet Explorer and other software should be similar.

Other algorithms

SSL supports other algorithms besides RSA:

  • DSA, Digital Signature Algorithm. This one's faster at verifying signatures, but slower at generating them and isn't often used because of weaknesses.
  • ECDSA/ECDH, algorithms for signatures and Diffie-Hellman key exchange based on the mathematics of elliptic curves. The standard implementations of these are based on a curve called P-256, defined by the NIST. In 2013 it was revealed that the NSA had covertly compromised the random number generator and the selection of the curve to introduce cryptographic weaknesses in the algorithms that allow them to be more easily broken. Uncertainty over how severe the weaknesses are and whether all of the NIST specifications based on P-256 were compromised or not led to the recommendation that the NIST ECDSA specifications not be used.
  • Ed25519, a version of the elliptic-curve algorithms based on Twisted Edwards curves and in particular Curve25519 instead of P-256. This algorithm is known not to suffer from the weaknesses introduced into the NIST ECDSA algorithms. It's also faster than algorithms based on P-256 and is not vulnerable to side-channel cache timing attacks that would allow other software on the same physical machine (including software running in other VMs hosted on the same physical machine) to recover the keys. It's unfortunately not widely included in SSL implementations yet so it can't be used for certificates for public use.

That means that in practice RSA will be the algorithm of choice combined with SHA256 message digests.