This tutorial will guide you step-by-step to creating a certificate authority using OpenSSL, with a three-tier structure (root, intermediate, application). All key materials are created with ECC.
The first step is to create the directory in which the CA will reside. As a simple example, we will work out of /root/ca. We will create a directory, /root/ca/db, to store the CA database flat files. Within this directory, three files must be created as follows:
touch /root/ca/db/index.txt
touch /root/ca/db/index.txt.attr
echo 100000 > /root/ca/db/serial
Then, create a directory for the new certificates to go:
mkdir /root/ca/newcerts
Additionally, we will be creating an openssl.cnf file in the /root/ca directory as follows:
[ ca ]
default_ca = ca_conf
[ ca_conf ]
dir = /root/ca/
private_key = $dir/ca-root-private-enc.pem
certificate = $dir/ca-root-certificate.pem
new_certs_dir = $dir/newcerts
database = $dir/db/index.txt
serial = $dir/db/serial
default_md = sha512
policy = policy_strict
[ policy_strict ]
countryName = supplied
stateOrProvinceName = supplied
organizationName = supplied
organizationalUnitName = supplied
commonName = supplied
emailAddress = optional
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = ca_root
default_md = sha512
[ ca_root ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
nsComment = "LEVEL 1 ROOT CERTIFICATE"
[ ca_intermediate ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
nsComment = "LEVEL 2 INTERMEDIATE CERTIFICATE"
[ ca_user ]
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "LEVEL 3 CLIENT CERTIFICATE"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ ca_server ]
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "LEVEL 3 SERVER CERTIFICATE"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ ca_ocsp ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
nsComment = "LEVEL 3 OCSP SERVICE CERTIFICATE"
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
countryName_default = COUNTRY
stateOrProvinceName_default = PROVINCE
localityName_default = CITY
0.organizationName_default = ORGANIZATION
First, create the private key, in this example we are using the NIST curve secp521r1.
openssl ecparam -name secp521r1 -genkey -noout -out ca-root-private.pem
Then ensure that it is encrypted. We will be using AES-256. Afterwards, it is recommended to delete ca-root-private.pem.
openssl ec -in ca-root-private.pem -out ca-root-private-enc.pem -aes256
rm ca-root-private.pem
Finally, create the public key.
openssl ec -in ca-root-private-enc.pem -pubout -out ca-root-public.pem
With the private and public keys it is now possible to create the root certificate as follows:
openssl req -config openssl.cnf -key ca-root-private-enc.pem -new -x509 -days 7300 -sha512 -extensions ca_root -out ca-root-certificate.pem
We can validate the entered information by invoking the following command:
openssl x509 -noout -text -in ca-root-certificate.pem
As this is a root certificate, it is recommended to keep this offline at all times unless required for signing intermediate certificates. It is the source of all trust within this CA environment, and should it be compromised, all trust will be destroyed!
The intermediate certificate is used to sign application certificates that can be used for clients, servers, etc. Follow the same steps as the root certificate to generate the private and public keys:
openssl ecparam -name secp521r1 -genkey -noout -out ca-int-private.pem
openssl ec -in ca-int-private.pem -out ca-int-private-enc.pem -aes256
rm ca-int-private.pem
openssl ec -in ca-int-private-enc.pem -pubout -out ca-int-public.pem
Then, generate a certificate using the ca_intermediate extensions.
openssl req -config openssl.cnf -key ca-int-private-enc.pem -new -sha512 -extensions ca_intermediate -out ca-int-csr.pem
We must now sign the intermediate certificate. We do this by invoking:
openssl ca -config openssl.cnf -extensions ca_intermediate -days 3650 -notext -md sha512 -in ca-int-csr.pem -out ca-int-certificate.pem
We can validate the signature is OK by invoking:
openssl verify -CAfile ca-root-certificate.pem ca-int-certificate.pem
At this point, a new certificate will be placed into the newcerts directory with the first serial number, in this case, 100000. This transaction is also logged in the database.
The chain certificate will include the root and intermediate certificates in one file:
cat ca-int-certificate.pem ca-root-certificate.pem > ca-chain-certificates.pem
In order to start creating end-of-line certificates, the process is similar to creating intermediate certificates. The only difference is we point the signing entity to the intermediate certificate. To do this, in openssl.cnf, switch the privatekey and certifiacte to point to the intermediate pairs as follows:
[ ca_conf ]
dir = /root/ca/
private_key = $dir/ca-int-private-enc.pem
certificate = $dir/ca-int-certificate.pem
Then follow the same steps as before. The CN will be the subdomain for which the certificate will be deployed.
openssl ecparam -name secp521r1 -genkey -noout -out www.example.com-pri.pem
openssl ec -in www.example.com-pri.pem -pubout -out www.example.com-pub.pem
openssl req -config openssl.cnf -key www.example.com-pri.pem -new -sha512 -extensions ca_server -out www.example.com-csr.pem
openssl ca -config openssl.cnf -extensions ca_server -days 365 -notext -md sha512 -in www.example.com-csr.pem -out www.example.com-cert.pem
For Apache, you will need the following three files:
ca-chain-certificates.pem www.example.com-cert.pem www.example.com-pri.pem
And the corresponding Apache VHOST config would look like:
SSLEngine On
SSLCertificateFile /etc/pki/www.example.com-cert.pem
SSLCertificateKeyFile /etc/pki/www.example.com-pri.pem
For client certificate authentication (if you wish to use this), an additional set of configurations will be used:
SSLVerifyClient require
SSLVerifyDepth 10
SSLCACertificateFile /etc/pki/ca-chain-certificates.pem