Getting a X509 certificate
By default, most servers use two certificates:
- One for the HTTPS (web) server
- One for the IMAPS (mail) server
For private servers, these are often two self-signed certificates. This is typical installation if you run a Linux distribution and turn on HTTPS (apache) and IMAPS (courier-ssl) with the default settings.
An alternative is:
- Use the same certificate certificate for both HTTPS and IMAPS.
The advantage is that your users only need to store one certificate on their machine. Most applications allow users to simply click a button to "store this certificate permanently".
Or even slightly better:
- Use one root certificate for your organisation (or use another trusted root), the "root certification authority" (CA). Typically valid for a very long time.
- Use a certificate for IMAPS and HTTPS signed by the root certificate authority (CA). Typically valid for a year.
Or perhaps best:
- Use a well-known certificate authority to sign your certificates.
This could be a commercial service like VeriSign, DigiSigTrust, Entrust, Internet publishing Services, GlobalSign, RSA security, Trust Center, Thawte, etc. However, I recommend to use CAcert.ort, which is a free and trustworthy service. Your certificates will not be recognized by browsers by default, but it more likely people will trust the CAcert.org root certificate than your private root certificate.
The advantage of a special (long-lived) root certificate is that your users only need to store the certificate once, and never have to change trust settings, even not if you change the HTTPS or IMAPS certificate. The disadvantage is that users must explicitly download the root certificate; simply clicking the "store this certificate permanently" only stores the application certificate, which will be renewed every year (the same behaviour users are custom to).
Contents
Company CA's
OpenSSL tool
openssl is a tool which is very useful to manipulate certificates, like signing other certificates, and
Requesting a certificate
You can request a certificate, by first creating a (private) keypair and then a (public) certificate request:
% openssl genrsa -out key.pem 2048 % openssl req -new -key key.pem -out request.pem
Then you send this to the CA, which checks the identity and you get a cert.pem file. The (secret) key.pem and (public) cert.pem can be used for HTTPS, IMAPS, Globus, etc.
However, you need to fill in all kinds of options, like your name or the server name, and typically use a config file with openssl req. See man req for details.
DutchGrid
To make it even easier, go to: http://certificate.nikhef.nl/request/
Fill in this form. You get two results: A PDF file with details, and a shell script, called makerequest.sh. If you run the makerequest.sh script, it will call openssl as listed above, and mail the userkey.pem to ca@nikhef.nl. Now you need to print the PDF file, fill it in, and take it to the CA.
The resulting usercert.pem and userkey.pem can be used as the certificate. Note that these files are called "usercert" and "userkey" even if it concerns a server certificate.
Registration Authority
A registration authority (RA) is a person at an institute who is delegated by the CA to verify the identity. For example, DutchGrid has a RA at the UvA. Someone who wants a certificate then goes to the RA (who is often in the same building) with his or her passport. The delegate verifies the identity, and informs the CA, who then signs the certificate request.
Certificate requests
openssl smime -sign -in newrequest.mail.unsigned -out newrequest.mail.mime.out -signer usercert.pem -inkey userkey.pem openssl smime -verify -in newrequest.mail.mime.out -signer usercert.pem -CAfile 16da7552.0
Match Key File to Certificate File
Check if key file and certificate file match using the modulus:
For the certificate:
openssl x509 -modulus -noout -in <certfile.pem>
For the private key:
openssl rsa -modulus -noout -in <userkey.pem>
Renewing
- correct signature
- not expired
- not in the CRL
Certificate Revokation Lists
Obtaining Webbased CA's
openssl s_client
Examine webbased certificates:
echo "" | openssl s_client -connect mickey.macfreek.nl:443 | openssl x509 -noout -text
Root Certificate
To create your own root certificate (and thus start your own certificate authority), find one of the many how to's available. The following script creates a root certificate.
See for example http://www.cs.ru.nl/~jeroenbr/CA%20HOWTO.html
CAcert.org signed server certificates
For private servers, using a CAcert.org-signed certificate is a very good option, it is free, does not require you to self-sign your certificates, and is more likely to be trusted by others than whatever self-signed certificate you come up with yourself.
Obtaining a new certificate
The steps are:
- Join CAcert
- Add the domain you control to your account
- Generate a Certificate Signing Request (CSR)
- Submit the contents from the CSR file to CAcert
- CAcert then sends you an email with a signed copy of your certificate, which you should install for HTTPS or IMAPS.
- Follow the procedure of installing the server certificate.
Renewing a certificate
- Go to View server certificates, and renew the certificate.
- Follow the procedure of installing the server certificate.
CACert Certificate Details
Note that the CACert server certificates uses subjectAltnames, so you can use it in combination with virtual hosting.
Issuer: O=Root CA, OU=http://www.cacert.org, CN=CA Cert Signing Authority/ emailAddress=support@cacert.org Validity Not Before: Nov 19 13:34:32 2007 GMT Not After : May 17 13:34:32 2008 GMT Subject: CN=mickey.macfreek.nl [...] X509v3 Subject Alternative Name: DNS:mickey.macfreek.nl, othername:<unsupported>, DNS:webmail.macfreek.nl, othername:<unsupported>, DNS:webcam.macfreek.nl, othername:<unsupported>
The "othername" entries in the subjectAltName intrigued me.
After short examination, the othername appeared to have type 1.3.6.1.5.5.7.8.5, which turned out to be an OID for xmppAddr, as defined in section 5.1.1 of RFC 3920.
KeyChain Access displayed the otherName as "A0 14 0C 12 6D 69 63 6B 65 79 2E 6D 61 63 66 72 65 65 6B 2E 6E 6C", which turns out to be 3 control chars ("A1 14 0C"), a length byte ("12"), and and UTF-8 representation of "mickey.macfreek.nl" ("6D 69 63 6B 65 79 2E 6D 61 63 66 72 65 65 6B 2E 6E 6C"). Similar for the other entries. Apparently XMPP needs this for encrypted chat, and the contents seems genuine, so I haven't looked further.
The validity is shorter than requested. That value is also ignored, and a validity length based on your credibility is issued. For credibility, assurance points are used by CAcert.
Create a certification request
I used the following command to generate my Certificate Signing Request (CSR):
openssl req -new -config server.cnf -nodes -keyout serverkey.pem -out serverreq.pem
Or, if you already have a private/public key pair, and don't want to change it:
openssl req -new -config server.cnf -key serverkey.pem -out serverreq.csr
With server.cnf as follows:
[ req ] default_bits = 2048 default_days = 400 default_keyfile = serverkey.pem default_md = sha1 encrypt_key = yes prompt = no distinguished_name = server_distinguished_name req_extensions = server_cert_extensions # x509_extensions does not work here [ server_distinguished_name ] countryName = NL #stateOrProvinceName = Utrecht localityName = Utrecht organizationName = Freek Dijkstra organizationalUnitName = MacFreek commonName = mickey.macfreek.nl emailAddress = hostmaster@macfreek.nl [ server_cert_extensions ] nsCertType = server subjectAltName = DNS:mickey.macfreek.nl,DNS:webmail.macfreek.nl,DNS:webcam.macfreek.nl
Note that CAcert does remove everything except commonName (CN) and subjectAltName (SAN). Also, it automatically prepends the CN to the list of subjectAltNames, even if it already present. This is a known bug. However, do add it manually, even for CA cert (since CAcert has another bug and does not add the CN after renewals).
You can examine the certificate request and server public/private key pair with:
openssl req -noout -text -in serverreq.pem openssl rsa -noout -text -in serverkey.pem
As soon as you submitted the certificate request, you should store the result. You can examine it with:
openssl x509 -noout -text -in servercert.pem
Create a self-signed Certificate
First, create a /etc/ssl/server.cnf config file, as you would do for CAcert.
The following script creates a public/private key pair, creates one certificate for both HTTPS and IMAPS based on this key pair and a configuration file.
#! /bin/sh # # mkcert, based on mkimpadcert and apache2-ssl-certificate # # Generates one self-signed certificate for both apache and imapd to use # # mkimapdcert is Copyright 2000 Double Precision, Inc., and is distributed # under the GPL version 2, with provisioning that it is allowed to link # against OpenSSL. # # This is a short script to quickly generate a self-signed X.509 key for # IMAP over SSL. Normally this script would get called by an automatic # package installation routine. prefix="/etc/ssl" config=$prefix/server.cnf openssl=/usr/bin/openssl randfile=$prefix/serverdh.rand certfile=$prefix/servercert.pem keyfile=$prefix/serverkey.pem dhfile=$prefix/serverdh.pem apachefile=/etc/apache2/ssl/apache.pem imapfile=/etc/courier/imapd.pem # Verifies if OpenSSL is installed if [ ! -x $openssl ]; then echo "openssl not installed" exit 0 fi # Verifies if apache and imap certificates don't already exist if [ -e $apachefile ]; then echo "(Old) Apache certificate file $apachefile already exists. (re)move it and continue" exit 0 fi if [ -e $imapfile ]; then echo "(Old) Imap certificate file $imapfile already exists. (re)move it and continue" exit 0 fi # generate random data (used for Diffie-Hellman + cert) dd if=/dev/urandom of=$randfile count=1 2>/dev/null # generate RSA keys and self-signed certificate $openssl req -new -x509 -nodes -config $config -out $certfile -keyout $keyfile # generate Diffie-Hellman parameters $openssl dhparam -rand $randfile 512 >> $dhfile rm -f $randfile # print base certificate information $openssl x509 -subject -dates -fingerprint -noout -in $certfile
Install Certificate for Apache and IMAP
We assume that you have:
- /etc/ssl/serverkey.pem
- The private/public key pair.
- /etc/ssl/servercert.pem
- A signed certificate, matching the key pair, and signed by some authority (either self-assigned, signed by CAcert, or by a commercial CA).
The Debian installations of Apache and Courier expected a combined certificate/key file. You can simply generate these yourself by concatenating the above files:
For Apache:
cd /etc/ssl/ cat servercert.pem serverkey.pem > /etc/apache2/ssl/apache.pem chmod 600 /etc/apache2/ssl/apache.pem # create hash symlink cd /etc/apache2/ssl/ ln -sf apache.pem `openssl x509 -hash -noout -in apache.pem`.0
For IMAP (courier)
cd /etc/ssl/ cat servercert.pem serverkey.pem > /etc/courier/imapd.pem chmod 600 /etc/courier/imapd.pem
The owner of these files should be the same as the user who starts Apache and Courier. That is typically root.
You must restart apache and courier after this change.
sudo /etc/init.d/apache2 reload sudo /etc/init.d/courier-imap-ssl reload
Verify Installed Certificate
You can download and examine an installed certificate using openssl:
echo "" | openssl s_client -connect myserver.example.org:993 > myserver-imaps.pem openssl x509 -noout -text -in myserver-imaps.pem
For HTTPS replace port 993 with port 443:
echo "" | openssl s_client -connect mickey.macfreek.nl:443 | openssl x509 -noout -text
See also: Add Root Certificates to KeyChain
HTTPS Virtual Hosts
Finally, if your servers listens to multiple hostnames (e.g. both www.example.org and mail.example.org), you should consider adding the additional names to the "SubjectAltNames" tag in the X509 certificate.
Take for example a server listing to both www.example.org, webmail.example.org and example.org. The server certificate can only have one name in the "CN" (Common Name) field. If that's www.example.org, a browser will display an error if you access webmail.example.org. In addition it's not possible to serve a different X509 certificate based on the (virtual) Host field in the HTTP field, since that field is only sent after the certificate was sent.
The solution is to use the SubjectAltNames, rather then the CN field. Here is how:
[ req ] default_bits = 2048 default_days = 365 default_keyfile = privkey.pem prompt = no encrypt_key = yes distinguished_name = req_distinguished_name x509_extensions = req_x509v3_extensions # or req_extensions [ req_distinguished_name ] countryName = NL # stateOrProvinceName = Noord-Holland localityName = Utrecht organizationName = MyHosting Company organizationalUnitName = Certificate Authority Department 0.commonName = www.example.org 1.commonName = webmail.example.org 2.commonName = example.org # emailAddress = hostmaster@example.org [ req_x509v3_extensions ] nsCertType = server subjectAltName = DNS:www.example.org,DNS:webmail.example.org,DNS:example.org
Note that you should put all alternative names in the SubjectAltName, including the primary name. You should also specify the primary name in the commonName field for backward compatibility. Finally, you should precede each entry in the subjectAltName with "DNS:", and separate each entry with a comma.
If you like, you can also wildcards. E.g. DNS:*.example.org. However, be cautious for security implications here. Are you sure that your certificate is valid for all subdomains?
Sources: http://www.es.net/pub/esnet-doc/SubjectAltName.pdf and http://wiki.cacert.org/wiki/VhostTaskForce
The disadvantage of subjectAltName is that it does not scale well: you have to replace your certificate each time you add a new virtual host. A more recent alternative is to negotiate the certificate to use during the SSL handshake phase. While this is not possible with SSl, it is possible with TLS, and is called Server Name Indication (SNI). For an overview of the different methods, see for example Name-based SSL virtual hosts: how to tackle the problem by Kaspar Brand of the Swiss national research network Switch.