Setup: Server with X.509 Certificates

The most-used form of server authentication uses X.509 certificates, also known as PKIX certificates. This section explains how to set them up for the TLS Pool.

They bind a public key with an algorithm such as RSA or ECDSA to an identity, which includes the web server name. The binding is confirmed by a trusted third party, or certificate authority. This may be a paid party, or one providing certificates for free, such as Let’s Encrypt or CAcert.

Generally, a certificate authority will explain the hoops that you must jump through:

  1. Generate a private key of a certain algorithm and size, for example 2048 bits RSA or 256 bits ECDSA. As a side-effect, a public key is usually derived from the private key as well.
  2. Using that, generate a certificate request, which incorporates the public key and your intended identity, notably CN=www.example.com and perhaps one or more DNS names also explicitly mentioned. A special form is a wildcard certificate, such as CN=*.example.com, which would cover any name under the domain name.
  3. Then you upload only the certificate request. The certificate authority is likely to scrutinise your request, strip parts that it won’t allow and perhaps provide alternative forms of a name, such as the domain name without the www prefix label.
  4. The certificate authority should now do some hard work to validate that you are the owner of the website. In practice, a flimsy test such as the ability to receive email is considered sufficient to grant you a certificate for 1 up to 3 years. Sarcasm intended.
  5. You now receive the certificate over email, or can download it somewhere. Used together with the private key that you kept to yourself, you can now instruct your server to secure its connections with TLS. The way to do that is completely dependent on the server program, but often comes down to mentioning the paths of the two files somewhere in a configuration file.

This path is still the same with the TLS Pool, except that we use PKCS #11 and so our private keys are better protected — at least that is possible, but it depends on the precise PKCS #11 implementation chosen. But even the basic SoftHSMv2 that we advise to newcomers already encrypts the certificate with a PIN, thereby improving over what most servers do. Also, the design of the TLS Pool as a separate process means that access to this file is not required from the same server that may be running scripts of mediocre quality and often dubious maintenance status.

To create a private key with the TLS Pool, we need to run a tool that is versed in PKCS #11. Instead of openssl rsa that quickly becomes cryptic when handling PKCS #11, we recommend using the tools that come with GnuTLS:

P11LIB=`tlspool-configvar -c /etc/tlspool.conf pkcs11_path`
P11URI=`tlspool-configvar -c /etc/tlspool.conf pkcs11_token`
p11tool --provider "$P11LIB" --login --generate-rsa --bits 2048 --label=Label --id=30303031 --outfile=/dev/null "$P11URI"
OBJURI="$P11URI;id=%30%30%30%31;label=Label;type=private"
echo "PKCS #11 Object URI: $OBJURI"

The --id=30303031 form is a bit awkward; it represents the identity, which often is a binary identity, in hexadecimal form, so the identity given here would be 0001 when interpreted as ASCII. The main use of the identity is matches private keys to public keys and perhaps certificates. The --label on the other hand, is intended for human consumption.

Neither the --id nor the --label needs to be unique — other than for practical purposes of finding back the one object that you are looking for, of course. Assuming that at least their combination is unique, the printed pkcs11: URI should help to locate the generated private key in the future; note how the hexadecimal content is percent-escaped in the URI form.

For the upcoming request, we should write a template file holding the details of how we would like our certificate to look. We will assume below that the template is saved in request.template. An example can be found in the certtool(1) manual page, but a short form that should work mostly is

organization = "Snake Oil, Ltd"
state = "Bliss"
country = US
cn = "www.example.com"
dns_name = "www.example.com"
dns_name = "example.com"

We now create a certificate request using the concealed private key. For this, we use another tool from GnuTLS:

certtool --provider "$P11LIB" --generate-request --outfile request.pem --template=request.template

The result in request.pem is what you should ship to your certificate authority.

We now twiddle our thumbs until our certificate authority has done its work. This may involves jumping through some hoops, such as clicking on a link in an email sent to your domain administrator’s address.

Upon arrival, save the certificate to a file named new.pem — or at least, that will be the name assumed below. We shall also assume that you got the textual form, as that is common. We however, need the binary form so we need to transform it from PEM to DER notation:

certtool --infile new.pem --outfile new.der --outder

We now hold a file named new.der that we can use to import into the TLS Pool. And remember the pkcs11: URI for the object? We saved it in $OBJURI when generating the private key, as well as printed it on the output. We will need that too, because now we bring the signed certificate and the private key together.

To import the certificate and private key as a pair into the TLS Pool, we run the following command:

set_localid /etc/tlspool.conf www.example.com X.509,server "$OBJURI" new.der

The arguments on this line are:

  • A reference to the configuration file for the TLS Pool; this is used to find the database environment and the localid.db locations. If the database and/or its environment have not been created yet, this tool will do it for us.
  • The name for which the newly imported credential can be used. You may additionally want to import it without the www prefix label. If you hold a wildcard certificate, please understand that the TLS Pool does not search its localid.db in that way; you should import each covered name separately.
  • The flags indicate that the type of this entry is an X.509 certificate, meant to be used in a server.
  • The pkcs11: URI and the filename of the DER file with the certificate are all that’s left.

Variations exist. For instance, you might have added anything but the root certificate to new.der, in the order of escalating the hierarchy. In that case, you should add the chained flag as well. This is how non-standard certificate authorities (those that are not in trust.db or another certificate authority list on the remote end) can be supported; CAcert is probably the best-known example of that.

After this, your done. If you ever need to remove the certificate, for example because its due date has passed, you can either overwrite it with a new one (using the same flags) or you can rerun the command but leave out the pkcs11: URI and DER file name.

You do not need to restart the TLS Pool after having modified the database; it should pickup automatically. This is the main reason for using databases to configure these things.