Offline Root Certificate Authority for SSL Certificates - OpenBSD
For an internal organization, it is a good idea provide SSL certificates to protect data as it crosses your network. You have the option of using Self Signed Certificates or implementing a Certificate Authority. The added benefits of a Certificate Authority is that of being able to add the CA Root Certificate to your browsers so these are accepted as a normal SSL Certificate would be. You also will be able to manage your certificates in a central location, with the ability to revoke certificates and set up an Online Certificate Status Provider Responder to check the validity of these Certificates. This make sense when issuing Client Certificates as these need careful guarding. Finally, creating a Certificate Authority, is a great educational experience and will help you understand security issues in your network much more thoroughly.
Everything that is need to create a Certificate Authority is provided by OpenSSL. I am using LibreSSL as this is the default under OpenBSD. The will be no differences to the configuration files, however, man pages are different. In this post I will cover setting up an Offline Certificate Authority. When it is not issuing certificates, it can be powered off to increase security. I will go over creating the CA directory structure, creating the root-ca.crt and also creating server and client certificates. Finally I will discuss how to revoke certificates and the use of a Certificate Revocation List. The next post, I will implement an Online Certificate Status Provider Responder which should also be part of a Certificate Authority solution.
Create CA Directory Structure
This is the initial steps of implementing your CA and needs only be done once. I have chosen to use my host name as the directory in the SSL base directory.
# mkdir /etc/ssl/ca.pbdigital.org # cd /etc/ssl/ca.pbdigital.org/ # mkdir certs csr db private # chmod 700 private # touch db/index # openssl rand -hex 16 > db/serial # echo 1001 > db/crlnumber
Create OpenSSL Configuration File
This is the most important part of creating your CA, I have listed the root-ca.cnf that suits my purposes. Many administrators suggest setting a intermediary CA for issuing certificates, with the Root CA only issuing the Certificate for the intermediary. As my CA will not be registered with any Internet Authorities, I feel a single Root CA is sufficient, and also the fact that it will be powered of most of its life, I feel it will be also be secure.
You should read the man pages and study the options in the configuration file before creating any keys. In OpenBSD, the main man file is x509v3.cnf, under Linux it is the config man page. Another excellent source of information is Ivan Ristić's OpenSSL Cookbook, available free by following the link.
# OpenSSL root CA configuration file. [ default ] name = root-ca domain_suffix = pbdigital.org aia_url = http://ocsp.$domain_suffix/$name.crt crl_url = http://ocsp.$domain_suffix/$name.crl ocsp_url = http://ocsp.$domain_suffix:9080 default_ca = ca_default name_opt = utf8,esc_ctrl,multiline,lname,align [ca_dn] countryName = "ES" organizationName = "pbdigital.org" commonName = "PBDigital Root CA" emailAddress = "firstname.lastname@example.org" [ca_default] home = . database = $home/db/index serial = $home/db/serial crlnumber = $home/db/crlnumber certificate = $home/$name.crt private_key = $home/private/$name.key RANDFILE = $home/private/random new_certs_dir = $home/certs unique_subject = yes copy_extensions = none default_days = 365 default_crl_days = 35 default_md = sha256 policy = policy_c_o_match [policy_c_o_match] countryName = match stateOrProvinceName = optional organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [req] default_bits = 4096 encrypt_key = yes default_md = sha256 utf8 = yes string_mask = utf8only prompt = no distinguished_name = ca_dn [ca_ext] basicConstraints = critical,CA:true,pathlen:0 keyUsage = critical,keyCertSign,cRLSign subjectKeyIdentifier = hash authorityInfoAccess = @issuer_info authorityKeyIdentifier = keyid:always crlDistributionPoints = @crl_info extendedKeyUsage = clientAuth,serverAuth nameConstraints = @name_constraints [crl_info] URI.0 = $crl_url [issuer_info] caIssuers;URI.0 = $aia_url OCSP;URI.0 = $ocsp_url [name_constraints] permitted;DNS.0=pbdigital.org excluded;IP.0=0.0.0.0/0.0.0.0 excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0 [ocsp_ext] authorityKeyIdentifier = keyid:always basicConstraints = critical,CA:false extendedKeyUsage = OCSPSigning keyUsage = critical,digitalSignature subjectKeyIdentifier = hash [server_ext] authorityInfoAccess = @issuer_info authorityKeyIdentifier = keyid:always basicConstraints = critical,CA:false crlDistributionPoints = @crl_info extendedKeyUsage = clientAuth,serverAuth keyUsage = critical,digitalSignature,keyEncipherment subjectKeyIdentifier = hash [client_ext] authorityInfoAccess = @issuer_info authorityKeyIdentifier = keyid:always basicConstraints = critical,CA:false crlDistributionPoints = @crl_info extendedKeyUsage = clientAuth keyUsage = critical,digitalSignature subjectKeyIdentifier = hash
Create Root CA Key & Certificate
Once you are happy with your root-ca.cnf file, you can know create the key and certificate signing request, then self sign the request to create the root-ca.crt certificate.
# openssl req -new -config root-ca.cnf -out root-ca.csr -keyout private/root-ca.key # openssl ca -selfsign -config root-ca.cnf -in root-ca.csr -out root-ca.crt -extensions ca_ext
Copy Root Certificate to Authority Information Access URL
As I have provided Authority Information Access URL in the conf file, I will now make this available on the server which will host this. In my case, I will host this on the Apache webserver, that will also be the server that is responsible for the Online Certificate Status Provider Responder.
# scp root-ca.crt ocsp.pbdigital.org:/var/www/htdocs/root-ca.crt
That is all there is to creating a Certificate Authority, you can now power it down until you are ready to issue some certificates.
Issuing Client and Server Certificates
Now that we have a fully operational Certificate Authority, and it is powered down for enhanced security, we can power it up for the express purpose of issuing certificates.
Create Server Certificate and Install
It is normal when a certificate is issued, the client who requests the certificate will create a Certificate Signing Requests. This allows the client to create their own keys, it is considered very bad practice should the Certificate Authority provide the Private key as it would no longer be private.
So on the system that the certificate will be used, the user creates a key and csr. This key is not encrypted (i.e. no password), as it will be used unattended to start services on the system. You will want to make sure the correct permissions are set on the key and directory to keep this key private.
# openssl genrsa -out server.key 2048 # openssl req -new -key server.key -out server.csr # scp server.csr email@example.com:/etc/ssl/ca.pbdigital.org/csr/
After creating the key and csr, the csr is securely copied to the Certificate Authority. Depending on your level of paranoia, you may have disabled any network interfaces on your CA and will have to arrange an alternative way to deliver your csr to the CA.
The CSR contains information identifying the applicant (such as a distinguished name in the case of an X.509 certificate), and the public key chosen by the applicant. If this is all that it contains, it should be safe to email the CSR.
Once we have the Certificate Signing Request on the CA, we can create the server.crt.
# openssl ca -config root-ca.cnf -in csr/server.csr -out certs/server.crt -extensions server_ext
The final step is grabbing the root-ca.crt and the server.crt from the CA.
# scp ca.pbdigital.org:/etc/ssl/ca.pbdigital.org/certs/server.crt . # scp ca.pbdigital.org:/etc/ssl/ca.pbdigital.org/root-ca.crt .
These certificates will need to be placed in the appropriate directories with the appropriate permissions that your service requires.
If you are using the certificate for a webserver, you will want to add the root-ca.crt certificate to the Authorities Section of your browsers Certificate Manager, so that the server certificate can be verified as coming from your Root CA.
Create Client Certificate and Install
As with a server certificate, we follow the same steps. Note that we have used a password when we request a client certificate.
# openssl genrsa -aes128 -out client.key 2048 # openssl req -new -key client.key -out client.csr # scp client.csr firstname.lastname@example.org:/etc/ssl/ca.pbdigital.org/csr/
On the CA
# openssl ca -config root-ca.cnf -in csr/client.csr -out certs/client.crt -extensions client_ext
On the system that the certificate will be used, we grab the certificates from the CA.
# scp ca.pbdigital.org:/etc/ssl/ca.pbdigital.org/certs/client.crt . # scp ca.pbdigital.org:/etc/ssl/ca.pbdigital.org/root-ca.crt .
That is all the work the CA needs to do and can now be powered down again.
PKCS 12 Key & Certificate File
In order to use your client certificate with a browser, such as Firefox, you will need to combine your private key and the client certificate before it is added to Firefox's Certificate Manager. Follow the link for more information on the PKCS 12 File Format.
We can create a PKCS file with the following command.
$ openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile root-ca.crt
CAUTION: This pkcs12 key contains your private key so make sure you take steps to protect this.
One of the main reasons to use a CA over Self Signed Certificates is the management of Revoking Certificates. I will cover revoking a certificate and publishing the Certificate Revocation List.
On the CA, we have all our certificates stored in the certs directory which means we can easily revoke a certificate without requesting it from the client. We issue the following command to revoke the desired certificate.
# openssl ca -config root-ca.cnf -revoke certs/client.crt -crl_reason keyCompromise
Revocation reason, where reason is one of: unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold or removeFromCRL. The matching of reason is case insensitive.
Create the CRL and Make Available on Web Server
We need to create a CRL any time we revoke certificates and make it available at the crl_url.
# openssl ca -gencrl -config root-ca.cnf -out root-ca.crl # scp root-ca.crt ocsp.pbdigital.org:/var/www/htdocs/root-ca.crl
Certificate Revocation Lists are being phased out in favor of OCSP. In fact, Firefox does not use CRLs anymore. However, it is good practice to publish the CRL as other clients may have uses for it.
In this post we have created a Certificate Authority, however it is very important that we can trust the certificates we have issued, so in the following post I will cover creating an OCSP Responder. While many feel that OCSP is inherently broken, it is still invaluable in the use of SSL Stapling and also if you have the ability to programmatically check in web applications for revocation status.