Creating digital certificates with our root certificate
Preparing for certificate creation
When we're going to create certificates, we're going to use the openssl command twice:
- once to create a "certificate signing request", in which we define all information to be included in the certificate, and actually generate the public and private key parts of the key pair, and
- once to instruct the OpenSSL package to sign the certificate with our CA root certificate.
The first step thus creates the actual keypair, and the second step signs the public key.
However, we're going to need to input a lot of parameters on the openssl command line. We can make things a bit easier for us by specifying these in the openssl.cnf file, just as we have added some values when creating the CA itself. To be precise, we're going to add X.509 V3 extensions
By default OpenSSL generates V1 certificates, but if we're not extremely worried about offending certain ancient web browsers, we can add V3 extensions, and even make openssl do that by default. To do this, we find in /etc/ssl/openssl.cnf the following line in the section [ req ], which is likely present but commented out:
req_extensions = v3_req # The extensions to add to a certificate request
Simply remove the # sign in front of it, so that it appears as given above. This by default enables V3 extensions.
Furthermore, check the section [ v3_req ]. It should look like this:
[ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectKeyIdentifier = hash
What is added is the last line, with subjectKeyIdentifier; this line specifies how to identify the public key being certified, so that distinct keys used by the same subject can be differentiated (e.g. as key updating occurs, for example). Four values are possible, but the IETF Public Key Infrastructure (PKIX) working group recommends the setting subjectKeyIdentifier=hash
Creating an SSL certificate
Now we can create an SSL certificate for a web server. For the Common Name of the certificate, we need the exact name of the web server that'll offer the SSL connections. However, some servers run different websites as Virtual Hosts, so they could be running, for example, www.saruman.biz, as well as shop.saruman.biz. That might present a problem, because if the certificate is issued for www.saruman.biz, then each visitor of shop.saruman.biz will get a warning along the lines of "Warning: The website you're trying to visit is shop.saruman.biz, but the certificate offered is for www.saruman.biz". To prevent that, we could use the wildcard character in the name of the certificate, so as to generate a certificate for *.saruman.biz.
CA.sh - certificate creation made easy
Since we have the openssl.cnf set up just right, and the CA.sh script primed, generating an SSL certificate is not very hard. From any old directory, run as root
This will create the signing request. The questions it'll ask, are
- a PEM passphrase, with which to protect the private key of the key pair. Note: you cannot generate a signing request without passphrase, so the private key you'll generate will always have a passphrase. If this is not what you want, do not despair: you can easily remove the passphrase from the private key after it's been generated (see further down). So just use a passphrase, even if you don't need one.
- Country/State/Locality/Organization/Organizational Unit; just as with the CA root certificate creation, these have your preprogrammed defaults that you may or may not change.
- Common Name; here we MUST give the DNS name of the host that is going to use the certificate, e.g. shop.saruman.biz, or *.saruman.biz.
- Challenge password; leave it blank, it's just to protect your signing request while en-route to the CA - but that's you anyway :-)
- Optional company name; leave that blank too, it's also extra information for the CA.
Now your private key and your certificate signing request (CSR) are ready; they're called newkey.pem and newreq.pem by default, and are located in your working directory. Time to do some signing! From that same working directory, run
The script will show that it's using the config file /usr/lib/ssl/openssl.cnf (as we indeed wish), and then ask for the super-duper-secret passphrase to the CA private key (provided you've left that in directory /etc/ssl/ca/private). Feed the script the passphrase, and it'll get to work. It'll check the request, then show you the details of the certificate you're about to sign. An example would be
Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Oct 27 09:34:00 2008 GMT Not After : Nov 1 09:34:00 2009 GMT Subject: countryName = NL stateOrProvinceName = Utrecht organizationName = Saruman.biz organizationalUnitName = Internet Dept. commonName = shop.saruman.biz emailAddress = firstname.lastname@example.org X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 30:F2:61:80:AA:CF:1B:F0:3E:44:41:D6:38:CC:31:F0:94:28:BD:2B X509v3 Authority Key Identifier: keyid:80:41:F8:A5:1F:C2:27:6E:CF:A9:28:8E:8A:EF:83:E7:FD:8A:D5:26 Certificate is to be certified until Nov 1 09:34:00 2009 GMT (370 days) Sign the certificate? [y/n]:
After doing your CA duty and diligently checking all the data, just press y. The script certifies the request, and asks if it is to commit the request. This means it'll update it's own database, by saving a copy of the signed certificate in /etc/ssl/ca/newcerts named after its serial number (01.pem for this example). Furthermore the script will record the serial and ID's of the generated certificate so that the next certificate will have a new serial number. And now: hey presto! We have a newcert.pem in our working directory!
For good measure:
- delete newreq.pem
- rename the generated private key newkey.pem to shop.saruman.biz.seckey.pem
- rename the generated public certificate newcert.pem to shop.saruman.biz.pem
To remove the passphrase from the private key, use a command like this:
openssl rsa -in shop.saruman.biz.seckey.pem -out shop.saruman.biz.nokey.pem
This will make openssl ask for your passphrase, and then create the unsecured shop.saruman.biz.nokey.pem key file. Best practice: ALWAYS use a passphrase-protected key, unless the application cannot support it (e.g. Postfix).
Save the secure private key and its PEM passphrase in a safe place (e.g. Keepass database). And if you removed the passphrase from the private key, then store it in an even safer place!
Now you can deploy your certificate. (more on that in another section).
openssl - the hard way to certificate creation
We don't actually need to use the CA.sh script, because we can do manually what the CA.sh script does. That gives us more control, but also more work. Let's see what we've got to do.
We will now perform the first step in our "manual" certificate generation: we create a signing request with all the information that we want in our SSL certificate. We run the magic incantation - note how we already
openssl req -new -nodes -keyout webmail.saruman.biz.key.pem -out webmail.saruman.biz.req.pem
This generates a new private key (named webmail.saruman.biz.key.pem), and a new, non-encrypted (because of -nodes), key signing request named webmail.saruman.biz.req.pem. We can leave out terms like -newkey rsa:2048 and -days 370 since we've put that in the configuration file. And naturally you're free to choose your own names for the keys.
FIXME - need the full process here
Validating the generated certificates
Again, we can use the openssl command to validate the keys we've generated. For instance, the CA.sh generated certificate, after renaming, is verified with
openssl x509 -in shop.saruman.biz.pem -noout -purpose Certificate purposes: SSL client : Yes SSL client CA : No SSL server : Yes SSL server CA : No Netscape SSL server : Yes Netscape SSL server CA : No S/MIME signing : Yes S/MIME signing CA : No S/MIME encryption : Yes S/MIME encryption CA : No CRL signing : Yes CRL signing CA : No Any Purpose : Yes Any Purpose CA : Yes OCSP helper : Yes OCSP helper CA : No
Notice that the certificate is valid for everything except CA tasks.
Likewise, using -dates instead of -purpose lets you see the validity time period, and -text gives the whole text of the certificate. Note the line marked "issuer", and see how your own CA is referenced there.