Tuesday, March 17, 2015

Self-Served Certificate Authority

Creating and running your own certificate authority (CA) is how you can issue your own SSL certificates. This is not for everyone but can save a lot of hassle and money in the right circumstances. Herein I've documented the steps I successfully took to get set up with a CA on Ubuntu Linux using OpenSSL.

[UPDATED Friday, April 9, 2015 (2015/04/09)]


Much of this requires superuser permissions. I find it easier to just temporarily sign in as root rather than prefacing everything with "sudo", but don't forget to "exit" afterwards.
sudo su

First set up a place to keep your public key infrastructure (PKI).
mkdir /etc/keys
mkdir /etc/keys/ca
mkdir /etc/keys/ca/conf
mkdir /etc/keys/ca/certs
cd /etc/keys/ca

All PKI begins with a private key. Create a new private key for yourself as a certificate authority (CA).
openssl genrsa -out ca_root.key 8192
= Use the openssl software to generate a new, private, RSA cryptographic key, 8192 bits in length, saved as "ca_root.key".

The private key can optionally be encrypted and secured with a passphrase by adding an (singular / just one) encryption option to the private key creation command [genrsa].
If you do not know which you want to use, then I recommend AES256. [1]

You then need to create a certificate signing request (CSR). A CSR provides identifying information (e.g. your name) and is signed by a private key.
openssl req -verbose -new -sha256 -extensions v3_ca -days 3650 -key ca_root.key -out ca_root.csr -utf8
= Use the openssl software to generate a CSR using the SHA256 algorithm and version 3 extensions for a CA, good for 10 years after creation (365 days per year * 10 years), signed with the private key "ca_root.key", and saved as "ca_root.csr" in UTF-8.
  • If the PK is getting encrypted by default and you do not want that, then use the option "-nodes" (as in [no DES]).

This CSR then needs to be self-signed with the private key to be a root CA X.509 certificate. By self-signing, the CA is certifying that it is itself. The signed certificate is the public key portion of PKI. Self-sign the CSR.
openssl x509 -req -in ca_root.csr -signkey ca_root.key -days 3650 -out ca_root.pem
= Use the openssl software to generate an X.509 certificate from the CSR "ca_root.csr", self-signed by the private key "ca_root.key", good for 10 years after creation (365 days per year * 10 years), and saved as "ca_root.pem".

You can check out / read / look at your key, request, and certificate, if you are interested:
cat ca_root.key
openssl rsa -in ca_root.key -noout -text
cat ca_root.csr
openssl req -in ca_root.csr -noout -text
cat ca_root.pem
openssl x509 -in ca_root.pem -noout -text
= Simply calling cat ("concatenate") will show you the encrypted contents. Calling openssl with rsa or x509, respectively, will decrypt the key and certificate showing you their human-readable contents.
  • To the best of my searching, the CA root certificate serial number is irrelevant.

Copy the public certificate and change the extension from .pem to .crt for use/installation on Microsoft Windows.
cp ca_root.pem ca_root.crt

The root CA certificate needs to be added to the certificate management store wherever it needs to be trusted. e.g. Internet Explorer (Chrome uses the same store) and Firefox.
- Internet Explorer > Menu or Tools > Internet Options > Content tab > Certificates > Trusted Root Certification Authorities tab > Import
  • The default "Certificate intended purposes" should be sufficient, but if they might not be then you can change them by selecting the certificate and clicking the "Advanced" button.
- Firefox > Menu or Tools > Options > Advanced section > Certificates tab > View Certificates > Authorities tab > Import > choose what the certificate is supposed to identify (e.g your website, your email address).
[3] , [4] , [5]

Using the CA to sign CSRs will require a flat-file text database, a serial number file, and a configuration file. Store these in the configuration directory.
touch conf/index.txt
echo "01" > conf/ca_root.srl
nano conf/openssl.ca.conf

[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]
dir            = /etc/keys/ca           # top dir
database       = $dir/conf/index.txt    # index file.
new_certs_dir  = $dir/certs             # new certs dir

certificate    = $dir/ca_root.pem       # The CA cert
serial         = $dir/conf/ca_root.srl  # serial no file
private_key    = $dir/ca_root.key       # CA private key

default_days   = 730                    # 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 distinguished name (DN)

name_opt       = ca_default             # Subject name display option
cert_opt       = ca_default             # Certificate display option
copy_extensions = copy                  # Don't copy extensions from request

[ policy_any ]
countryName            = supplied
stateOrProvinceName    = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional
  • The serial number in ca_root.srl will be automatically incremented by OpenSSL each time the CA is used to sign new certificates.

Each end entity certificate you wish to create and sign (e.g. for your website, email) will need its own private key. Create a new private key.
openssl genrsa -out certs/entity.key 4096
  • The bit length used here (4096) is smaller than that used for the original CA root key, but it doesn't have to be.

Create a CSR for the end entity using the new private key.
openssl req -verbose -new -sha256 -days 1825 -key certs/entity.key -out certs/entity.csr -utf8
  • We are no longer using "-extensions v3_ca" because we aren't signing a CA root certificate.
  • A wildcard certificate can be created by putting *.domain.tld as the common name (using your domain and tld; also potentially a subdomain as wildcards can only cover a single level of subdomain matching; a wildcard name will *NOT* match the naked domain [*.domain.tld will not work with domain.tld]).
  • Additional names can be included/supported using an openssl configuration file and the subjectAltName extension.

Sign the CSR using the CA.
openssl ca -verbose -config conf/openssl.ca.conf -in certs/entity.csr -out certs/entity.crt -days 1825 -utf8
= Use the openssl software to sign the CSR "entity.csr" with the CA and options specified in the configuration file "openssl.ca.conf", saving the resulting certificate as "entity.crt".
  • The CA cannot sign a certificate with the same common name as an active (un-revoked) certificate.

Creating a wildcard certificate with the naked domain name included as a SubjectAltName requires the use of a configuration file.
nano certs/entity.conf

[ req ]
default_bits = 4096
default_keyfile = entity.key
encrypt_key = no
default_md = sha256
prompt = no
utf8 = yes
distinguished_name = my_req_distinguished_name
req_extensions = my_extensions

[ my_req_distinguished_name ]
C = US
ST = Michigan
L = .
O  = LogSine
CN = *.logsine.com

[ my_extensions ]
basicConstraints = CA:false
subjectAltName = @my_subject_alt_names
subjectKeyIdentifier = hash

[ my_subject_alt_names ]
DNS.1 = *.logsine.com
DNS.2 = logsine.com
  • You create a CSR using this config using:
    openssl req -verbose -new -sha256 -days 1825 -key certs/entity.key -out certs/entity.csr -config certs/entity.conf

If you accidentally sign a certificate, for a given/particular common name, that isn't set up how you want it, then you will have to revoke the incorrect/old certificate before OpenSSL will let you sign a new one for the same common name. Revoking a certificate issued by your CA is very easy - just use the same CA configuration file and the -revoke option:
openssl ca -verbose -config conf/openssl.ca.conf -revoke certs/entity.crt
  • Getting anything else to recognize revoked certificates involves certificate revocation lists (CSLs).

Are you willing to try a third-party tool if it might be easier?


● The bit-length of a private key defines how many possible combinations it could be, and thus determines the difficulty of "breaking" its security by trying to guess it. However, making it longer also increases the amount of processing time it takes to create, transfer, etc. Also, many applications may have limits on the length of SSL certificate accepted. For the tutorial below, I simply picked a longer bit-length than was recommended at the time I was learning about it but was also what I guessed was not too large to be accepted by modern applications.

● Although creating your own certificate authority is currently the only way to freely obtain a bunch of otherwise obscenely [extortionately?] expensive SSL certificates, Let's Encrypt (sponsored by the likes of Mozilla and the Electronic Frontier Foundation (EFF)) may be a viable, free option in the future.

● SHA1 began to be phased out in September, 2014. SHA256 (a.k.a. SHA2) is its replacement. Although OpenSSL supports algorithms other than SHA256, I wouldn't use them.

Learn More

  • Learn about OpenSSL configuration files.
  • Read up on and try using an Intermediate Certificate Authority certificate.
  • Learn about the authorityInfoAccess certificate extension and Online Certificate Status Protocol (OCSP).



Services, Tools, and Resources

Relevant Documentation


No comments:

Post a Comment