I had all sorts of fun today trying to get Subject Alternative Names working with my OpenSSL Apache server. Got there in the end though!
I have been using OpenSSL on my CentOS servers for quite a few years, with certificates for Apache generated in OpenSSL, and then signed by a server that is a CA on my network. I distribute the CA certificate to users’ devices, and install that as a trusted certificate. I can then update, add, etc., as I need to.
With all of the recent attention on OpenSSL (thanks Heartbleed), I decided on tightening up a few things as part of maintenance. One of the things I wanted to do was move away from using wildcard certificates (i.e. *.simonandkate.net to cover blog, mail, etc) and use Subject Alternative Names (SANs) on a certificate for my web hosts, so one certificate that worked for blog.simonandkate.net, and mail.simonandkate.net, etc.
There are plenty of guides online to using self-signed certificates with SANs, but I couldn’t find anything that directly worked with CA-signed certs. They all fell over at one point or another with trying to get from the signing request to the signed certificate whilst retaining the extensions (the SANs).
My old process was to generate a certificate with OpenSSL, use openssl x509toreq to generate a Certificate Signing Request, and then create a signed certificate using the CA. I can’t remember where I got that from, but it’s been working for years with the wild cards. But it didn’t work once I tried to use SANs, thanks to a small bug that is noted on the OpenSSL website (see this page http://www.openssl.org/docs/apps/x509.html right at the bottom: “Extensions in certificates are not transferred to certificate requests and vice versa.”).
I could successfully generate a self-signed certificate using “openssl x509”, with the SANs. But as soon as I used x509toreq to create a signing request, the SANs would drop off.
Note this post assumes that you have openssl installed, have a configured and working CA under that install, and can generate and sign certificates, etc., without any help. This is all done on CentOS 6.5 btw, with a Heartbleed-patched version of openssl 1.0.1-e.
The focus was getting a certificate signing request with SANs in it that I could then sign. Openssl uses a configuration file, usually openssl.cnf. This page here http://www.xinotes.net/notes/note/1094/ had the needed information on tweaking that file, in section 1. The important things are the following lines that need adding if not there:
[req] req_extensions = v3_req [v3_req] subjectAltName = @alt_names [alt_names] DNS.1 = www.foo.com DNS.2 = www.bar.org IP.1 = 192.168.1.1
I also read somewhere that you need to uncomment:
copy_extensions = copy
But I am not 100% certain on that bit… 🙂
EDIT (thanks to Ben, see comments):
To answer the unknown regarding whether or not it is necessary to include and un-comment “copy_extensions = copy”, the answer is affirmative. I was required to un-comment this line. Until I did so, the SANs were not included in the resultant certificate.
Once that is done, a call to “openssl req” specifying the edited file with the -config parameter grabs the SAN extensions info, and will include the SANs in the subsequently created request. So I have created a .cnf file that has the SANs I need in it for each time I need to regenerate certificates.
openssl genrsa -out private.key 2048
creates a private key file.
openssl req -new -out request.csr -key private.key -config openssl.cnf
generates a Certificate Signing Request (CSR), with the new private key, and using the config that you baked into openssl.cnf.
openssl req -text -noout -in request.csr
should show you the CSR, with your SANs in it. If they are not in there, then something has gone wrong…
openssl ca -config openssl.cnf -policy policy_anything -out newcert.pem -in request.csr
Will then sign the certificate from your CA.
From there a:
openssl x509 -in newcert.pem -noout -text
Will show you the CA-signed certificate with the SANs nicely baked in place. You will be left with
private.key newcert.pem request.csr
as the key, certificate, and request files.
Install using normal processes to insert into Apache.