Stjepan Groš

Certificate handling

Like it or not good system administration assumes that you are acquainted with certificates and how they work. For the time being I won't explain here what certificates are and how they work, but I'll describe tools to handle certificates and some regular tasks you'll have to do with the certificates in a daily system administration work. This text is specific to Fedora 10, but it should be generally applicable to any other modern distribution.

There are multiple tools to manage certificates in Fedora 10. The first one is ubiquitous openssl tool that exists not only on many Linux distributions but many other Unixes. This tool was the first opensource tool that appeared and also it is licensed under BSD license what makes it attractive for vendors that want to add their own extensions without being forced to give those extensions back to open source community. Then, there is a certtool from gnutls package. The gnutls package is also open source but under GNU license. Finally, there is a tool called keytool that is part of Java SE package, and thus also available in many environments, including Windows operating systems.

In the following text we'll concentrate on the following task that make up certificate management process:

All the tasks will be described for each tool that was mentioned in the previous paragraph, i.e. for openssl, certtool and keytool.

Some basics about certificates

Certificate formats

Certificates can be stored in PEM, DER or pkcs12 format. When the certificate is stored in the PEM format then it's an ASCII file that starts with the following string:

-----BEGIN CERTIFICATE-----

then there is certificate in base64 encoding, and finally, the certificate ends with the sequence:

-----END CERTIFICATE-----

Unlike PEM or DER, PKCS#12 is a keystore format meaning that it stores certificates and keys. It is used by many programs, but most importantly, if you wish to import certificate into M$ Outlook or M$IE you'll have to use this format, i.e. you'll have to send your user the certificate using this format.

There is also obsoleted NET (Netscape Server) format rarely used today.

openssl tool

The openssl tool is a very powerful utility. But the for our purpose the use of this tool directly can be cumbersome. Fortunately, there is excellent add-on written in Perl and called CA.pl. On Fedora systems this tool is packaged into openssl-perl package. So, install this package if you didn't already.

Before we describe how to implement steps mentioned in the introduction section, we'll describe step how to configure CA.pl for your use:

  1. Create directory where you'll store all the data about you certificate infrastructure. I'll reference this directory as $CAHOME from now on.
  2. Copy the file CA.pl to your $CAHOME directory. Open the file and make in it the following changes:

    1. The line that defines variable SSLEAY_CONFIG change so that it's value is -config ./openssl.cnf. This means you'll always have to start CA.pl utility from the $CAHOME directory. Otherwise, things won't work.
    2. Change the value of the variable CADAYS to some large value, e.g. 3650 (10 years). I believe you don't wont a fuss caused by changing all the certificates you installed.
    3. The value of the variable CATOP set to $CAHOME.

  3. Find an example of OpenSSL configuration file, named openssl.cnf. On Fedora 10 there is one version of this file in /etc/pki/tls directory. Make a copy of this file in the $CAHOME directory.
  4. The openssl.cnf file consists of sections in a style of regular Window ini files, i.e. each section starts with a header inside square brackets (e.g. [ ca ]). Open the copy with your favorite editor and change the following parameters:

    1. In the section CA_default set dir to the value of your $CAHOME variable.
    2. In case you haven't province name in your country, or don't wont to use it, look for variable stateOrProvinceName under section policy_match. You have to set it to optional if it isn't already.
    3. Under section req_distinguished_name change the value of variables countryName_default, stateOrProvinceName_default, localityName_default, 0.organizationName_default. This will save you some typing.

Ok, we are now set to create CA and start to manage certificates.

Creating CA

This is a one time process with which you create you own certificate authority, something in a level of VeriSign and similarly but not exactly, as we'll see. To create CA, go to the $CAHOME directory and issue CA.pl command in the following way:

# ./CA.pl -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 1024 bit RSA private key
......++++++
................................++++++
writing new private key to '/root/CA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [HR]:
State or Province Name (full name) []:
Locality Name (eg, city) [Zagreb]:
Organization Name (eg, company) [Example d.o.o.]:
Organizational Unit Name (eg, section) []:IT department
Common Name (eg, your name or your server's hostname) []:CA
Email Address []:ca@example.hr

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /root/CA/openssl.cnf
Enter pass phrase for /root/CA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            c6:1d:cf:5c:a8:d1:f1:a1
        Validity
            Not Before: Dec 30 23:03:08 2008 GMT
            Not After : Dec 30 23:03:08 2011 GMT
        Subject:
            countryName               = HR
            organizationName          = Example d.o.o.
            organizationalUnitName    = IT Department
            commonName                = CA
            emailAddress              = ca@example.hr
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                12:A9:E4:A2:7B:65:2B:81:EF:E1:23:63:3E:22:29:CD:34:BF:9B:D1
            X509v3 Authority Key Identifier: 
                keyid:12:A9:E4:A2:7B:65:2B:81:EF:E1:23:63:3E:22:29:CD:34:BF:9B:D1
                DirName:/C=HR/O=Example d.o.o./OU=IT Department/CN=CA/emailAddress=ca@example.hr
                serial:C6:1D:CF:5C:A8:D1:F1:A1

            X509v3 Basic Constraints: 
                CA:TRUE
Certificate is to be certified until Dec 30 23:03:08 2011 GMT (1095 days)

Write out database with 1 new entries
Data Base Updated

When asked for CA certificate filename just hit enter and the default one will be created. Then next question you'll be asked is pass phrase. I strongly recommend that you enter something that's hard to guess. If anyone compromises your CA all your certificates are compromised and you might have serious problems despite this not begin real CA.

Next, you are asked for general data about CA, i.e. country, locality name and similar. I recommend that you enter your company name under Organization Name and something like IT Department under organizational unit name. Furthermore, under Common name also enter Certificate Authority. Organization name and unit might vary depending on your company organization. Under Email Address enter unique email address for certificate authority, e.g. something like ca@yourdomain. Maybe it would be also good idea to create this mail address.

If anything goes wrong while you create your CA, simply remove all the files except CA.pl and openssl.cnf and start over again.

One file that is important after this step is finished is cacert.pem. This is your CA certificate. If you wish that all your clients treat your CA equally to well known CAs (e.g. Verisign) you have to import this file into you clients, e.g. Web browsers. Actually, this is advisable to do as it increases your security and causes less annoyance for your users. You can also publish your CA somewhere on the Web.

Even though CA.pl is written in such way to keep a copy of all the signed certificates in the directory newcerts I suggest that you create additional directory hierarchy in the $CAHOME (do not create directories that are inside < and > characters, you'll create them later):

$CAHOME ----- issued --+-- servers --+-- <hostname1> --+-- <service11>
                       |             |                       |
                       |             |                       +-- <service12>
                       |             |                       
                       |             +-- <hostname2> ----- <service21>
                       |
                       +-- users --+-- <name.surname1>
                                   |
                                   +-- <name.surname2>
                                   |
                                   +-- <name.surname3>

Issuing certificates

After you created your own CA from now on you'll create certificates for your users and services. The procedure to issue new certificate is same regardless for whom it is created, the difference is in the data you enter. Still, there is one small difference. When you issue certificate for a service maybe it's better not to protect private key, otherwise, you'll have to be present when the service restarts in order to enter pass phrase. This obviously can cause problems if the restart is somewhere in the middle of the night when there is no one present to enter pass phrase.

Issuing certificate is a two step process. First, you generate request, and then, you sign this request with CA's private key. Let's discuss each of those steps in more detail.

To generate request you have to issue the following command:

./CA.pl -newreq

This will create new request with protected private key with a pass phrase. To avoid pass phrase, issue the command in the following way:

./CA.pl -newreq-nodes

If you are issuing certificate for your users I recommend that you enter appropriate organizational unit name to which the users belongs. Under common name enter user's name and surname. Finally, under email address enter user's mail address.

When issuing certifiate for a service, enter ...

After the command finishes, you'll have new request in you $CAHOME directory. newkey.pem is a private key and you don't give this to anyone except to the user. newreq.pem is a certificate sign request. In case you entered some incorrect information, or simply want to start over, just delete those two files and start over again.

The next step is to sign certificate request. Signing is done with the following command, which also has to be run in $CAHOME directory:

./CA.pl -sign

Note that you don't specify signing request file name because it's assumed that the file is named newreq.pem. You'll be first requested to enter pass phrase of the CA's private key! Then, you'll be presented with a data from the certificate request and asked if you wish to sign it. Answer y (for yes) and then you'll be again asked if you wish to commit this certificate. This is the last chance to change your mind, but in our case that's it, so answer y (for yes). You'll be left with a certificate in a file named newcert.pem. You can now remove the file newreq.pem as it is not necessary any more.

Finally, create appropriate directories in the $CAHOME/issued hierarchy and move key and certificate there. Then, give to the user it's private key and certificate, or, in case it's for some service, install key and certificate in the appropriate configuration files.

Revoking certificates

To revoke a certificate is a simple, but you have to use openssl tool directly as CA.pl doesn't support CRL handling. The following command line, executed inside $CAHOME directory will revoke certificate stored in the file newcert.pem:

$ openssl ca -config openssl.cnf -revoke newcert.pem 
Using configuration from openssl.cnf
Enter pass phrase for /root/CA/private/cakey.pem:
Revoking Certificate 87C1311C37E71F14.
Data Base Updated
$

But that's not all. You have to publish your CRL somewhere so that people can retrieve and use it. It's best to publish it on your Web pages. So, generate CRL list by issuing the following command:

$ openssl ca -config openssl.cnf -gencrl -out crl.pem
Using configuration from openssl.cnf
Enter pass phrase for /root/CA/private/cakey.pem:
$

You have to provide pass phrase for you private key because CRL is signed with it in order to guarantee that it's valid. When the previous command finishes, you'll have file named crl.pem that contains revoked certificates. To list the contents of this file, use the following command:

$ openssl crl -in crl.pem -noout -text

Generating certificate request to be signed by public CAs

To generate signing request use the following command:

openssl req -new -keyout myserver.key -out server.csr

After this command finishes you'll have private key stored in the file myserver.key and certificate signing request stored in the file server.csr. To have you certificate signed, mail CSR file to certificate authority. Note that your private key will be protected with passphrase, and this is recommended. In case you don't want this, you can add -nodes option to the previous line.

You can run the previous line as many times as you wish in case you want to change some data in CSR/certificate with no harm. BUT, the moment you send CSR file to CA, the game is over!

It is recommended that you check that passphrase that you typed realy works! If you forget passphrase and CA signs you certificate, you'll have to do all over again! The command to display private key, and check passphrase, is:

openssl rsa -in myserver.key -noout -text

Some frequently used operations on certificates

certtool tool

certtool is a low level tool and thus requires more work in order to handle certificate tasks.

Creating CA

To generate self signed Certificate Authority, first, you have to generate private key. This is done using the following command:

certtool --generate-privkey --outfile key.pem

By default the key of 2048 bits will be generated. There is an option (--bits) that allows you to change that, but because we are generating key for certificate authority maybe it's good to have larger keys.

The next step is to generate self signed certificate. Use the following command to do that:

certtool -s --load-privkey key.pem

You'll be asked a series of questions...

Issuing certificates

Revoking certificates

Generating certificate request to be signed by public CAs

Some frequently used operations on certificates

keytool tool

Java has it's special keystore format, usually with an extension .jks. Prior to JavaSE 6 keytool could not import certificates and keys into a keystore so you had to use some workarounds. Starting with JavaSE 6 the interface and functionality of keytool changed and now it's also very good tool.

Creating CA

Issuing certificates

Revoking certificates

Generating certificate request to be signed by public CAs

Importing certificate and key into key store

Often it will happen that you have a key and certificate obtained via some external methods to keystore and keytool. In that case it's a bit tricky to import both into Java key store, but nevertheless it's doable. I'll suppose that you are starting with certificate and key files, both in PEM format named cert.pem and key.pem, respectively. The idea is the following one: store both files into PKCS#12 keystore format and then, using keytool, import that file into Java key store. Note that probably you'll need Java 6, at least that's the version I worked with.

Step one, using openssl tool store certificate and key into PKCS#12 format keystore:

$ openssl pkcs12 -export -inkey key.pem -in cert.pem -nodes -out keystore.p12 -name some_short_name
Enter Export Password:
Verifying - Enter Export Password:

During this process you'll be asked for the store password. I tried to use -nodes option in order to avoid this but it didn't work. Anyway, when asked for a password enter something, and don't forget what you typed in!

Step two, import PKCS#12 keystore into destination Java key store by issuing the following command:

$ keytool  -importkeystore \
	-srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass password_you_entered_in_previous_step \
	-destkeystore keystore.jks -deststoretype JKS 
Enter destination keystore password:  
Re-enter new password: 
Entry for alias some_short_name successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Note that you are asked for destination keystore password, while the source keystore password is given in the command line!

Some frequently used operations on certificates