Creating the Root CA
Directories and Files
The certificate authority uses a specific directory structure to save keys, signed certificates, signing requests and revocation lists. The directory structure is defined within the OpenSSL configuration file.
root-ca/
|
|----certreqs/
|
|----certs/
|
|----crl/
|
|----newcerts/
|
|----private/
# paranoid umask because we are creating private keys
$ umask 077
$ cd /media/$USER/safe_storage
$ mkdir -p example.net.ca/root-ca/{certreqs,certs,crl,newcerts,private}
$ cd example.net.ca/root-ca
Some data files are needed to keep track of issued certificates, their serial numbers and revocations.
$ touch root-ca.index
$ echo 00 > root-ca.crlnum
Create the serial file, to store next incremental serial number.
Using random instead of incremental serial numbers is a recommended security practice.
$ openssl rand -hex 16 > root-ca.serial
OpenSSL configuration
The OpenSSL configuration for the root certificate authority is in the file
root-ca/root-ca.cnf
.
The complete configuration is available for download as
root-ca.cnf
.
1#
2# OpenSSL configuration for the Root Certification Authority.
3#
4
5#
6# This definition doesn't work if HOME isn't defined.
7CA_HOME = .
8RANDFILE = $ENV::CA_HOME/private/.rnd
9
10#
11# Default Certification Authority
12[ ca ]
13default_ca = root_ca
14
15#
16# Root Certification Authority
17[ root_ca ]
18dir = $ENV::CA_HOME
19certs = $dir/certs
20serial = $dir/root-ca.serial
21database = $dir/root-ca.index
22new_certs_dir = $dir/newcerts
23certificate = $dir/root-ca.cert.pem
24private_key = $dir/private/root-ca.key.pem
25default_days = 1826 # 5 years
26crl = $dir/root-ca.crl
27crl_dir = $dir/crl
28crlnumber = $dir/root-ca.crlnum
29name_opt = multiline, align
30cert_opt = no_pubkey
31copy_extensions = copy
32crl_extensions = crl_ext
33default_crl_days = 180
34default_md = sha384
35preserve = no
36email_in_dn = no
37policy = policy
38unique_subject = no
39
40#
41# Distinguished Name Policy for CAs
42[ policy ]
43countryName = optional
44stateOrProvinceName = optional
45localityName = optional
46organizationName = supplied
47organizationalUnitName = optional
48commonName = supplied
49
50#
51# Root CA Request Options
52[ req ]
53default_bits = 4096
54default_keyfile = private/root-ca.key.pem
55encrypt_key = yes
56default_md = sha384
57string_mask = utf8only
58utf8 = yes
59prompt = no
60req_extensions = root-ca_req_ext
61distinguished_name = distinguished_name
62subjectAltName = @subject_alt_name
63
64#
65# Root CA Request Extensions
66[ root-ca_req_ext ]
67subjectKeyIdentifier = hash
68subjectAltName = @subject_alt_name
69
70#
71# Distinguished Name (DN)
72[ distinguished_name ]
73organizationName = example.net
74commonName = example.net Root Certification Authority
75
76#
77# Root CA Certificate Extensions
78[ root-ca_ext ]
79basicConstraints = critical, CA:true
80keyUsage = critical, keyCertSign, cRLSign
81nameConstraints = critical, @name_constraints
82subjectKeyIdentifier = hash
83subjectAltName = @subject_alt_name
84authorityKeyIdentifier = keyid:always
85issuerAltName = issuer:copy
86
87#
88# Intermediate CA Certificate Extensions
89[ intermed-ca_ext ]
90basicConstraints = critical, CA:true, pathlen:0
91keyUsage = critical, keyCertSign, cRLSign
92subjectKeyIdentifier = hash
93subjectAltName = @subject_alt_name
94authorityKeyIdentifier = keyid:always
95issuerAltName = issuer:copy
96authorityInfoAccess = @auth_info_access
97crlDistributionPoints = crl_dist
98
99#
100# CRL Certificate Extensions
101[ crl_ext ]
102authorityKeyIdentifier = keyid:always
103issuerAltName = issuer:copy
104
105#
106# Certificate Authorities Alternative Names
107[ subject_alt_name ]
108URI = http://ca.example.net/
109email = certmaster@example.net
110
111#
112# Name Constraints
113[ name_constraints ]
114permitted;DNS.1 = example.net
115permitted;DNS.2 = example.org
116permitted;DNS.3 = lan
117permitted;DNS.4 = onion
118permitted;email.1 = example.net
119permitted;email.2 = example.org
120
121#
122# Certificate download addresses for the root CA
123[ auth_info_access ]
124caIssuers;URI = http://ca.example.net/certs/example.net_Root_Certification_Authority.cert.pem
125
126#
127# CRL Download address for the root CA
128[ crl_dist ]
129fullname = URI:http://ca.example.net/crl/example.net_Root_Certification_Authority.crl
130
131# EOF
Make sure that the OpenSSL configuration file for the root CA is active:
$ export OPENSSL_CONF=./root-ca.cnf
Generate CSR and new Key
The following commands create either a new password protected EC or RSA key and additionally a certificate signing request for the root:
# eliptic curves have smaller key sizes and a similar security level
$ openssl ecparam -genkey -name secp384r1 | openssl ec -aes256 -out private/root-ca.key.pem
read EC key
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
$ openssl req -new -key private/root-ca.key.pem -out root-ca.req.pem
Enter pass phrase for root-ca.key.pem:
Or RSA:
$ openssl req -new -out root-ca.req.pem
Generating a 4096 bit RSA private key
.......................................................................++
.......................................................................++
.......................................................................++
.......................................................................++
writing new private key to 'private/root-ca.key.pem'
Enter PEM pass phrase: ********
Verifying - Enter PEM pass phrase: ********
-----
You will find the key in private/root-ca.key
and the CSR in root-
ca.csr
.
Protect the private key:
$ chmod 400 private/root-ca.key.pem
Generate CSR from existing Key
If you need to update existing CA certificates you can use the already existing key to create a new CSR.
The following command creates a certificate signing request for the root using an already existing key:
$ openssl req -new \
-key private/root-ca.key.pem \
-out root-ca.req.pem
Enter pass phrase for private/root-ca.key.pem: ********
Show the CSR
You can peek in to the CSR:
$ openssl req -verify -in root-ca.req.pem \
-noout -text \
-reqopt no_version,no_pubkey,no_sigdump \
-nameopt multiline
Self-Signing the Root Certificate
If everything looks ok, self-sign your own request:
$ openssl rand -hex 16 > root-ca.serial
$ openssl ca -selfsign \
-in root-ca.req.pem \
-out root-ca.cert.pem \
-extensions root-ca_ext \
-startdate `date +%y%m%d000000Z -u -d -1day` \
-enddate `date +%y%m%d000000Z -u -d +10years+1day`
The signature will be valid for the next ten years.
View it with the following command:
$ openssl x509 -in ./root-ca.cert.pem \
-noout -text \
-certopt no_version,no_pubkey,no_sigdump \
-nameopt multiline
You can verify if it will be recognized as valid:
$ openssl verify -verbose -CAfile root-ca.cert.pem \
root-ca.cert.pem
root-ca.cert.pem: OK
Revocation List (CRL)
The Root CA publishes Certificate Revocation Lists at regular intervals or when a certificate has been revoked.
The Root CA is expected to only issue revocations of its own self-signed certificate or the Intermediate CA certificate.
There have not been any revocations yet, but still clients and servers verifying any of our certificates will request an up-to-date CRL from the web-address published in the certificates.
We therefore need to create initial, albeit empty CRLs of the Root CA:
$ openssl ca -gencrl -out crl/root-ca.crl
Install As Trusted CA
To be recognized by your systems, devices and software, the Root Certificate needs to be installed as a trusted CA on all Systems.
Install on Ubuntu Linux Systems
Steps to re-include the root certificate in Ubuntu as trusted CA:
$ sudo mkdir -p /usr/local/share/ca-certificates/example.net
$ cd /usr/local/share/ca-certificates/example.net/
$ sudo cp ./root-ca.pem \
example.net_Root_Certification_Authority.cert.crt
$ sudo dpkg-reconfigure ca-certificates