A little more than two years ago, I set up a PKI and did a post on it. The main goal was to get a certificate on my EdgeOS router to get proper HTTPS support without the annoying red X. When I did it, however, I didn’t do it quite right, and so I decided to redo it all. Some of the major problems:
- The cert for my router expired after two years. Hence, I as of today I need a new cert anyway.
- The intermediate cert also expired after two years. Lame!
- To trust the chain, I had to import the intermediate cert into Windows, not the root cert. I should just need the root cert.
So I decided to do it right, and do it all over again for posterity, again largely following this post from Didier Stevens and again having the same old issues. Details below.
I started basically from scratch, keeping only the root CA key. From this key, I created a root cert that expires after 30 years. I did this because I noticed that most of the root certs out there have pretty lengthy expiration periods. So I ran this command to create a new CA certificate:
openssl req -new -sha256 -x509 -days 10957 -key ca.key -out ca.crt
Next was creating the intermediate certificate. Remember when I had the problems with creating an intermediate certificate that was allowed to sign things last time? Yup, did it again this time. Eventually, though, I figured it out and ran the following commands, starting with my old IA key:
openssl req -new -sha256 -key ia.key -out ia.csr
openssl x509 -sha256 -req -days 5478 -in ia.csr -CA ca.crt -CAkey ca.key -extfile ./v3.ext -set_serial 2 -out ia.crt
Fortunately, I found my old ext file from the last time I did it, which provided the intermediate certificate with the proper signing rights. My v3.ext file is as so:
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:TRUE
keyUsage=critical, digitalSignature, nonRepudiation, keyCertSign
The intermediate certificate is good for 15 years, so I can sign multiple iterations of the server keys with it. I set the serial number as 2 because hey, it’s my second intermediate cert!
Finally, I created the cert for my EdgeOS router:
openssl req -new -sha256 -key erl1.key -out erl1.csr
openssl x509 -sha256 -req -days 1096 -in erl1.csr -CA ia.crt -CAkey ia.key -set_serial 3 -out erl1.crt
To get the right format for the router, I had to cat private key and the certificate together:
cat erl1.crt erl1.key > server.pem
I then copied both the intermediate certificate and the server.pem file to the router. Why the intermediate certificate as well? So it could send the chain properly. After doing some research into lighttpd, I found that in order to get proper validation, you have to send not only the server certificate, but the intermediate certificate as well. To do this, I modified the /etc/lighttpd/conf-enabled/10-ssl.conf file to contain the following section:
$SERVER[“socket”] == “0.0.0.0:443” {
ssl.engine = “enable”
ssl.use-sslv3 = “disable”
ssl.ca-file = “/etc/lighttpd/intermediate.crt”
ssl.pemfile = “/etc/lighttpd/server.pem”
ssl.cipher-list = “aRSA+HIGH !3DES +kEDH +kRSA !kSRP !kPSK !NULL !RC4”
Although the ssl.pemfile variable was already correctly set, I had to add the ssl.ca-file variable to point at the intermediate certificate.
But wait! There is this ominous warning at the top of the /etc/lighttpd/conf-enabled/10-ssl.conf file:
# Do not edit, auto generated by ubnt-gen-lighty-conf.sh
So it would appear that upon reconfig the ssl.ca-file setting would not be preserved. So the solution is to edit the ubnt-gen-lighty-conf.sh file so that the 10-ssl.conf file is recreated properly.
Finally, I exported the root CA into a format that I could import into Windows, so that anything signed by my root CA would be trusted.
When all of this was said and done, I got the happy green lock in Chrome!
The end result was exactly what I wanted: a certificate for my router with a three-year lifespan, signed by the intermediate cert, which is signed by my trusted root certificate.
At least now when this certificate expires in three years, I’ll be able to replace it no problem and keep the trust chain intact.