LibreSSL Logo 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.

/etc/ssl/ca.pbdigital.org/root-ca.cnf

# 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		= "ca@pbdigital.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 root@ca.pbdigital.org:/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 root@ca.pbdigital.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.

Certificate Revocation

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.

Revoke Certificate

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.

Wrapping Up

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.