[DutchGrid CA site] CA gymnastics, an account of some testing

In order to be prepared for future requests on the NIKHEF/DutchGrid CA, I did some `CA gymnastics'. Topics of interest were:

All test were performed using OpenSSL 0.9.5a, released on April 1, 2000.

An invaluable resource was the CA manual published by the German research networking centre DFN as DFN bericht nr. 89: Aufbau und Betrieb einer Zertifizierungsinstanz.

Singing a cert with the CA key with arbitrary serial

This command emulates the entire functionality of the compound openssl ca command. Provided we have a "ca.cnf" file that contains a proper series of extensions for the user cert, we can do:

echo "intended_cert_serial_no" > newserial

openssl x509 \
	-req \
	-days 9663  \
	-extfile ca.cnf -extensions ext_user \
	-CA data/cacert.pem -CAkey data/private/cakey.pem \
	-CAserial newserial \
	-in original_request.pem \
	-out newercert.pem
Adding attributes to an existing CA key

If you have an existing CA cert that already signed some user certs but you need to modify or add extenstions (or change the validity of the CA cert), you can reuse the old key pair. In this case, the issued user certs remain valid when checked against the new CA cert. Note that you should never change the DN (you cant anyways) and you should can keep the same serial in this case (at least as long as your users will accept such a change!). Exactly this change may be forthcoming for the Globus CA cert starting with the new release in the summer of 2001. The new GlobusCA cert is already in CVS (see the Globus java mailing list, message 00067).

First, update the ca.cnf file to include the new extensions. Note that you will have to repeat all extensions you want! By converting the CA cert to a request.pem file, you loose all current extensions! We will use the -days argument to extend the CA certs life time.

vi ca.cnf
mv data/cacert.pem data/original-cacert.pem
openssl x509 \
	-x509toreq \
	-in data/original-cacert.pem \
	-signkey data/private/cakey.pem \
	-out carequest.pem
openssl x509 \
	-req \
	-days 1826 \
	-extfile ca.cnf -extensions ext_ca \
	-signkey data/private/cakey.pem \
	-in carequest.pem \
	-out data/cacert.pem
The last command will generate a self-signed cert with the default serial number 0 and a life time of 5 years. If we now verify an existing cert signed by this ca, if should verify OK:
openssl verify -CAfile data/cacert.pem data/newcerts/01.pem
Adding attributes to an existing user cert

If you only have an existing cert you're out of luck. You will need the original certificate request and the CA private key. Then, make (or midify) a configuration file with the full required set of extensions. In this example, the ca.cnf file has a section ext_user that also requires two environment variables set (EMAIL and TAG).

The default version of the OpenSSL "ca" tool does not allow renewal of a certificate while the old one is still valid. In order to counter this side effect, we have to forcibly expire the cert. We should not revoke it, since in that case the old cert will be refused by complying relying parties, where we want a smooth transition period. Therefore, look for the DN in the index.txt file for the user's DN and put the marker (first character on the line) to "E". You can subsequently sign the request again with a new expiry date.

Note that a new serial number will be assigned to this cert (this is the proper thing to do, since there might be a need to revoke the old as well as the new cert during the transition period!). You can also modify the X.509v3 extensions as this point.

Certificate chaining, re-signing self-signed certs and cross-certification

If you want to cross-certify an existing CA, you will need that CA's public certificate and your own CA's private key. Use the following command:

EMAIL="your_ca_operator@email.address" \
TAG="crosscert X-20010601-113522" \
openssl ca \
	-config ca.cnf \
	-policy policy_anything \
	-preserveDN \
	-extensions ext_ca \
	-ss_cert cacert-nikhef-ms.pem \
	-out crosscertified_cert.pem
Note well: you need to use X.509v3 extensions that are appropriate for CA's (i.e., "basicConstraints = critical, CA:true")!

Subordinate CA's

Creating subordinate CA's is somewhat different. First, we drastically extend our ca.cnf file, now called subord.cnf. This config file has two ca's, called "niktest1" and "subord". You can select one of them on the commandline of the openssl ca using the -name argument.
After updating the subord.cnf file, we recreate the usual directory structure (see the ca.sh script for details) and generate a request (so not a self-signed X.509 cert as is usual for a ca cert!):

openssl req \
	-new \
	-config subord.cnf \
	-keyout subord/private/cakey.pem \
	-out subord/careq.pem
Now, we sign the request with the "niktest1" CA:
openssl ca \
	-config subord.cnf -name niktest1 \
	-policy policy_anything -preserveDN \
	-extensions ext_subord_ca \
	-days 1095 \
	-in subord/careq.pem \
	-out subord/cacert.pem
Now the new cacert.pem can successfully be used as a CA. For verification, you'll need both the subord CA cert and the root CA cert (niktest1). But first, generate a request from a test user like this:
openssl req \
	-new \
	-config subord.cnf \
	-keyout testuser/key.pem \
	-out testuser/req.pem 
and sign it:
EMAIL="testuser@nikhef.nl" \
TAG="subord-20010601-111623" \
openssl ca \
	-config subord.cnf -name subord \
	-preserveDN \
	-extensions ext_user \
	-in testuser/req.pem \
	-out testuser/cert.pem


First, we move all the CA certs (niktest1 and subord) to a directory "dir/" using the "hash" convention. All the CA certs should have a file with extension ".0" so do not take the certs serial as the extension.
openssl verify -CApath ./dir testuser/cert.pem
will return OK. IF we remove the niktest1 CA cert from this direcory, it will fail, just like the equivalent command:
openssl verify -CAfile subord/cacert.pem testuser/cert.pem
telling you:
testuser/cert.pem: /C=NL/O=NIKHEF/CN=Subordinate CA below niktest1
error 2 at 1 depth lookup:unable to get issuer certificate

Example certs

As a reference and maybe as a guideline for extensions in certs, I collected some different certs from the 'Net:

Comment to David Groep