I’m about to deploy a small sideproject I’ve been coding the past 2 weeks and I want to make sure that the site is served over https. Since I’ll likely put it on a subdomain to my own company and I don’t want to go get another signature from a public authority I thought I would try to roll my own mini-CA chain which I can use for these types of situations.
My basic idea is to set it up using a root certificate, an intermediate certificate and a project specific certificate. The root certificate signs the intermediate certificate which will sign the project certificate. So we have a very simple chain that way. I will store the root certificate offline on a usb device and have a accessible certificate revocation list hosted in a static directory on my company’s website.
Note that it’s important to keep the signed certificates somewhere safe too. If we don’t have access to the cert then we can’t revoke it!
First I will generate the root and intermediate certificates. I’ll put a password on the root cert
-des3 flag. The root cert will also be self-signed.
openssl genrsa -des3 -out blacknode.root.pem 4096
openssl genrsa -out blacknode.dev.pem 4096
openssl req -new -x509 -days 3650 -key blacknode.root.pem -out blacknode.root.crt
Since I want to use the
openssl ca tool I need to set up the directory a certain way.
echo "01" > ca/serial
cp blacknode.root.crt ca/
cp blacknode.root.pem ca/private
Finally create a file
openssl.cnf describing the structure further. Please note
the defaultmd and defaultdays values. Defaultmd must be a hash algorithm good enough
to pass for firefox. The default MD5 which I copied from the openssl example was NOT.
Having a low defaultdays value might cause headaches in the future when you have
to renew the certs.
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = ./ca # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/blacknode.root.crt # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/blacknode.root.pem# CA private key
RANDFILE = $dir/private/.rand # random number file
default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha256 # md to use
policy = policy_any # default policy
email_in_dn = no # Don't add the email into cert DN
name_opt = ca_default # Subject name display option
cert_opt = ca_default # Certificate display option
copy_extensions = none # Don't copy extensions from request
[ policy_any ]
countryName = supplied
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ v3_req ]
basicConstraints = critical,CA:false
keyUsage = nonRepudiation
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_ca ]
subjectKeyIdentifier = hash
extendedKeyUsage = critical,serverAuth, clientAuth
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign, digitalSignature, nonRepudiation,keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign
Then sign the blacknode.dev certificate using the root cert.
openssl ca -config openssl-root.cnf -extensions v3_ca -out blacknode.dev.signed.crt -infiles blacknode.dev.csr
The output should look something like the following. Note the basicConstraints and key usage sections. These allow the signing certificate to sign new certs too.
Serial Number: 1 (0x1)
Not Before: Feb 24 15:03:47 2015 GMT
Not After : Feb 24 15:03:47 2016 GMT
countryName = SE
stateOrProvinceName = Stockholm
organizationName = Blacknode
organizationalUnitName = Development
commonName = dev.blacknode.se
X509v3 Subject Key Identifier:
X509v3 Extended Key Usage: critical
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints:
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement, Certificate Sign, CRL Sign
Phew, halfway there.
So now I have my root ca which I put on a usb stick. I copy the needed public certs
and create another ca directory in my home directory by repeating the procedure in the previous section, except this time
blacknode.dev.pem key instead. Basically a lot of this is the same as before. We also create a similar openssl.cnf file here, but with the right paths to the dev cert instead.
Since I trust myself, I’ll create the key for my https service here directly.
openssl genrsa -out faktura.pem 2048
openssl req -new -days 1095 -key faktura.pem -out faktura.csr
openssl ca -config openssl.cnf -in faktura.csr -out faktura.signed.crt
Finally, create a chained certificate and verify.
cat blacknode.dev.signed.crt blacknode.root.crt > blacknode.chained.crt
[tethik@asimov dev-ca]$ openssl verify -CAfile blacknode.chained.crt faktura.signed.crt
Now I can copy the keys and cert to the server. I intend to write a shorter post about setting up https on apache in the future.
Also left to do is setting up a certificate revocation list for each signing certificate and publishing them somewhere. Probably on my main company website.
For a linux system, installing the certs is easy. Just copy the
root public certificate (in my case blacknode.root.crt) to the
For accessing your https-enabled websites etc in your browser you may have to add the cert
to the browsers trusted certificate too. In Firefox, you can do this by going to
‘Preferences’, then under the ‘Advanced’ tab open the ‘View certificates’ window.
Then under Authorities import the root certificate.
Of course, this implies a great trust in that certificate. So be careful. I only intend to use this cert for projects which are not supposed to be used by the public.