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/
$ cd /media/$USER/safe_storage
$ mkdir -p example.net.ca/intermed-ca/{certreqs,certs,crl,newcerts,private}
$ cd example.net.ca/intermed-ca
The directory used to store private keys should not be accessible to others:
$ chmod 700 private
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 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #
# OpenSSL configuration for the Intermediate Certification Authority.
#
#
# This definition doesn't work if HOME isn't defined.
CA_HOME = .
RANDFILE = $ENV::CA_HOME/private/.rnd
oid_section = new_oids
#
# XMPP address Support
[ new_oids ]
xmppAddr = 1.3.6.1.5.5.7.8.5
dnsSRV = 1.3.6.1.5.5.7.8.7
#
# Default Certification Authority
[ ca ]
default_ca = intermed_ca
#
# Intermediate Certification Authority
[ intermed_ca ]
dir = $ENV::CA_HOME
certs = $dir/certs
serial = $dir/intermed-ca.serial
database = $dir/intermed-ca.index
new_certs_dir = $dir/newcerts
certificate = $dir/intermed-ca.cert.pem
private_key = $dir/private/intermed-ca.key.pem
default_days = 396 # 1 year + 31 days
crl = $dir/crl/intermed-ca.crl
crl_dir = $dir/crl
crlnumber = $dir/intermed-ca.crlnum
name_opt = multiline, align
cert_opt = no_pubkey
copy_extensions = copy
crl_extensions = crl_ext
default_crl_days = 30
default_md = sha256
preserve = no
email_in_dn = no
policy = policy
unique_subject = no
#
# Distinguished Name Policy
[ policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
#
# Distinguished Name Policy for Personal Certificates
[ user_policy ]
countryName = supplied
stateOrProvinceName = optional
localityName = supplied
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
#xmppAddr = optional # Added to SubjAltName by req
#
# Intermediate CA request options
[ req ]
default_bits = 3072
default_keyfile = private/intermed-ca.key
encrypt_key = yes
default_md = sha256
string_mask = utf8only
utf8 = yes
prompt = no
req_extensions = req_ext
distinguished_name = distinguished_name
subjectAltName = subject_alt_name
#
# Intermediate CA Request Extensions
[ req_ext ]
subjectKeyIdentifier = hash
subjectAltName = @subject_alt_name
#
# Distinguished Name (DN)
[ distinguished_name ]
organizationName = example.net
commonName = example.net Intermediate Certification Authority
#
# Server Certificate Extensions
[ server_ext ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
issuerAltName = issuer:copy
authorityInfoAccess = @auth_info_access
crlDistributionPoints = crl_dist
#
# Client Certificate Extensions
[ client_ext ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
issuerAltName = issuer:copy
authorityInfoAccess = @auth_info_access
crlDistributionPoints = crl_dist
#
# User Certificate Extensions
[ user_ext ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, clientAuth, emailProtection
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
issuerAltName = issuer:copy
authorityInfoAccess = @auth_info_access
crlDistributionPoints = crl_dist
#
# CRL Certificate Extensions
[ crl_ext ]
authorityKeyIdentifier = keyid:always
issuerAltName = issuer:copy
#
# Certificate Authorities Alternative Names
[ subject_alt_name ]
URI = http://ca.example.net/
email = certmaster@example.net
#
# Certificate download addresses for the intermediate CA
[ auth_info_access ]
caIssuers;URI = http://ca.example.net/certs/example.net_Intermediate_Certification_Authority.cert.pem
#
# CRL Download address for the intermediate CA
[ crl_dist ]
fullname = URI:http://ca.example.net/crl/example.net_Intermediate_Certification_Authority.crl
# EOF
|
Switch the OpenSSL configuration to the Intermediate CA:
$ export OPENSSL_CONF=./intermed-ca.cnf
Generate CSR and new 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). It also should be made write-protected and private and have a strong password.
Make a new Certificate Signing Request (CSR) for the intermediate signing authority:
$ 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.