Creating the Intermediate CA
Directories and Files
The certificate authority uses a specific directory structure to safe keys, signed certificates, singing requests and revocation lists. The directory structure is defined within the OpenSSL configuration file:
intermed-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/intermed-ca/{certreqs,certs,crl,newcerts,private}
$ cd example.net.ca/intermed-ca
Some data files are needed to keep track of issued certificates, their serial numbers and revocations.
$ touch intermed-ca.index
$ echo 00 > intermed-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 > intermed-ca.serial
OpenSSL configuration
The configuration for the intermediate certificate authority is in the file
intermed-ca/intermed-ca.cnf
.
The complete configuration is available for download as
intermed-ca.cnf
.
1#
2# OpenSSL configuration for the Intermediate Certification Authority.
3#
4
5#
6# This definition doesn't work if HOME isn't defined.
7CA_HOME = .
8RANDFILE = $ENV::CA_HOME/private/.rnd
9oid_section = new_oids
10
11#
12# XMPP address Support
13[ new_oids ]
14xmppAddr = 1.3.6.1.5.5.7.8.5
15dnsSRV = 1.3.6.1.5.5.7.8.7
16
17#
18# Default Certification Authority
19[ ca ]
20default_ca = intermed_ca
21
22#
23# Intermediate Certification Authority
24[ intermed_ca ]
25dir = $ENV::CA_HOME
26certs = $dir/certs
27serial = $dir/intermed-ca.serial
28database = $dir/intermed-ca.index
29new_certs_dir = $dir/newcerts
30certificate = $dir/intermed-ca.cert.pem
31private_key = $dir/private/intermed-ca.key.pem
32default_days = 396 # 1 year + 31 days
33crl = $dir/crl/intermed-ca.crl
34crl_dir = $dir/crl
35crlnumber = $dir/intermed-ca.crlnum
36name_opt = multiline, align
37cert_opt = no_pubkey
38copy_extensions = copy
39crl_extensions = crl_ext
40default_crl_days = 30
41default_md = sha384
42preserve = no
43email_in_dn = no
44policy = policy
45unique_subject = no
46
47#
48# Distinguished Name Policy
49[ policy ]
50countryName = optional
51stateOrProvinceName = optional
52localityName = optional
53organizationName = optional
54organizationalUnitName = optional
55commonName = supplied
56
57#
58# Distinguished Name Policy for Personal Certificates
59[ user_policy ]
60countryName = supplied
61stateOrProvinceName = optional
62localityName = supplied
63organizationName = optional
64organizationalUnitName = optional
65commonName = supplied
66emailAddress = supplied
67#xmppAddr = optional # Added to SubjAltName by req
68
69#
70# Intermediate CA request options
71[ req ]
72default_bits = 3072
73default_keyfile = private/intermed-ca.key
74encrypt_key = yes
75default_md = sha384
76string_mask = utf8only
77utf8 = yes
78prompt = no
79req_extensions = req_ext
80distinguished_name = distinguished_name
81subjectAltName = subject_alt_name
82
83#
84# Intermediate CA Request Extensions
85[ req_ext ]
86subjectKeyIdentifier = hash
87subjectAltName = @subject_alt_name
88
89#
90# Distinguished Name (DN)
91[ distinguished_name ]
92organizationName = example.net
93commonName = example.net Intermediate Certification Authority
94
95#
96# Server Certificate Extensions
97[ server_ext ]
98keyUsage = critical, digitalSignature, keyEncipherment
99extendedKeyUsage = critical, serverAuth, clientAuth
100subjectKeyIdentifier = hash
101authorityKeyIdentifier = keyid:always
102issuerAltName = issuer:copy
103authorityInfoAccess = @auth_info_access
104crlDistributionPoints = crl_dist
105
106#
107# Client Certificate Extensions
108[ client_ext ]
109keyUsage = critical, digitalSignature
110extendedKeyUsage = critical, clientAuth
111subjectKeyIdentifier = hash
112authorityKeyIdentifier = keyid:always
113issuerAltName = issuer:copy
114authorityInfoAccess = @auth_info_access
115crlDistributionPoints = crl_dist
116
117#
118# User Certificate Extensions
119[ user_ext ]
120keyUsage = critical, digitalSignature
121extendedKeyUsage = critical, clientAuth, emailProtection
122subjectKeyIdentifier = hash
123authorityKeyIdentifier = keyid:always
124issuerAltName = issuer:copy
125authorityInfoAccess = @auth_info_access
126crlDistributionPoints = crl_dist
127
128#
129# CRL Certificate Extensions
130[ crl_ext ]
131authorityKeyIdentifier = keyid:always
132issuerAltName = issuer:copy
133
134#
135# Certificate Authorities Alternative Names
136[ subject_alt_name ]
137URI = http://ca.example.net/
138email = certmaster@example.net
139
140#
141# Certificate download addresses for the intermediate CA
142[ auth_info_access ]
143caIssuers;URI = http://ca.example.net/certs/example.net_Intermediate_Certification_Authority.cert.pem
144
145#
146# CRL Download address for the intermediate CA
147[ crl_dist ]
148fullname = URI:http://ca.example.net/crl/example.net_Intermediate_Certification_Authority.crl
149
150# EOF
Switch the OpenSSL configuration to the Intermediate CA:
$ export OPENSSL_CONF=./intermed-ca.cnf
Generate CSR and new Key
Once again, you may choose between an EC and an RSA key. The RSA private key of the intermediate signing certificate needs to be 3072 bits strong. As this is considered safe for the next 8 years (up to 2023).
Make a new Certificate Signing Request (CSR) for the intermediate signing authority:
# eliptic curves have smaller key sizes and a similar security level
$ openssl ecparam -genkey -name secp384r1 | openssl ec -aes256 -out private/intermed-ca.key.pem
read EC key
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
$ openssl req -new -key private/intermed-ca.key.pem -out intermed-ca.req.pem
Enter pass phrase for intermed-ca.key.pem:
Or RSA:
$ openssl req -new -out intermed-ca.req.pem
Generating a 3072 bit RSA private key
.......................................................................++
.......................................................................++
.......................................................................++
writing new private key to 'private/intermed-ca.key.pem'
Enter PEM pass phrase: ********
Verifying - Enter PEM pass phrase: ********
-----
You should find the key in private/intermed-ca.key.pem
and the
CSR in intermed-ca.req.pem
.
Protect the private key:
$ chmod 400 private/intermed-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 intermediate using an already existing key:
$ openssl req -new \
-key private/intermed-ca.key.pem \
-out intermed-ca.req.pem
Enter pass phrase for private/intermed-ca.key.pem: ********
You can peek in to the CSR:
$ openssl req -verify -in intermed-ca.req.pem \
-noout -text \
-reqopt no_version,no_pubkey,no_sigdump \
-nameopt multiline
If everything looks alright, copy the CSR to the Root CA for later signing:
$ cp intermed-ca.req.pem \
/media/$USER/safe_storage/example.net.ca/root-ca/certreqs/
Sign the Intermediate with the Root CA
Change your working directory to the where the Root CA stores its files:
$ cd /media/$USER/safe_storage/example.net.ca/root-ca
Switch the OpenSSL configuration back to the root CA:
$ export OPENSSL_CONF=./root-ca.cnf
Sign the intermediate CSR with the root key for the next 5 years using the intermediate extensions:
$ openssl rand -hex 16 > root-ca.serial
$ openssl ca \
-in certreqs/intermed-ca.req.pem \
-out certs/intermed-ca.cert.pem \
-extensions intermed-ca_ext \
-startdate `date +%y%m%d000000Z -u -d -1day` \
-enddate `date +%y%m%d000000Z -u -d +5years+1day`
You can peek in to the signed certificate:
$ openssl x509 -in certs/intermed-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 \
certs/intermed-ca.cert.pem
certs/intermed-ca.cert.pem: OK
If the certificate looks as expected, copy it to the Intermediate CA directory:
$ cp certs/intermed-ca.cert.pem \
/media/$USER/safe_storage/example.net.ca/intermed-ca/
Revocation List (CRL)
The Intermediate CA publishes Certificate Revocation Lists at regular intervals or when a certificate has been revoked.
The Intermediate CA is expected to publish revocations of any server or client certificate that has been issued by it.
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 Intermediate CA.
Change your working directory to the where the Intermediate CA stores its files:
$ cd /media/$USER/safe_storage/example.net.ca/intermed-ca
Switch the OpenSSL configuration back to the Intermediate CA:
$ export OPENSSL_CONF=./intermed-ca.cnf
Create the Intermediate CA certificate revocation list (CRL):
$ openssl ca -gencrl -out crl/intermed-ca.crl
Install and use the Intermediate CA
Copy the Intermediate CA files to your working environment:
cp /media/$USER/safe_storage/example.net.ca/intermed-ca ~/
Unmount and lock the safe storage and lock the storage medium away.