Home‎ > ‎Dabbles‎ > ‎RaspberryPi‎ > ‎

RaspberryPi 220 - Implementing a Certificate Authority (CA)

posted Nov 14, 2015, 7:56 AM by Joshua S   [ updated Nov 29, 2015, 7:03 PM ]
This tutorial will implement a Certificate Authority (CA) using the builtin OpenSSL framework.  This CA will be local and untrusted (self signed) in the broader web of trust, but should work well for the systems we are standing up locally.

A Certificate Authority will allow us to issue certificates on our local domain for a number of reasons including implementing a VPN, encrypting LDAP and other sensitive communication, and loading into embedded devices (routers, IP cameras, etc.).  While this lesson covers establishing the CA; there will be future lessons exploring how to issue certificates and use the CA.

To give credit where credit is due; this lesson is based heavily off of both this lesson and this lesson from others.  For a really good overview of the concepts behind CAs and PKI, check out this post.

With any of the Dabbles on this site, if you have questions, suggestions, or thoughts, please feel free to send me an eMail (I'm still working to figure out how to enable comments on Google Sites -- suggestions would be appreciated)!

Supply List:
  • RaspberryPi  The actual RaspberryPi hardware this will all be built around.  In this tutorial, a Raspberry Pi 2 is used and has a memory card with the Raspbian operating system pre-installed.
  • PuTTY SSH Client – PuTTY is a free and open-source terminal emulator, serial console and network file transfer application. It supports several network protocols, including SCP, SSH, Telnet, rlogin, and raw socket connection.  Other SSH tools can be used, but this tutorial will leverage PuTTY.

  • I know I said this guide was going to be comprehensive and not skip any steps, so what better way to start this off than by skipping steps.  I am not writing out instructions for the following (and illustrating from XKCD):
    • Buying a MicroSD Card
    • Buying a RaspberryPi 
    • Finding the IP Address of your Pi
      • This can be done in many ways, including on your router or using an IP scanner such as (AngryIP Scanner or NMAP) -- if there are requests from the "Contact Me" form; I'll look to create a tutorial for this.
    • Obtaining and installing PuTTY
  • Using PuTTY (or the SSH client of your choice) enter the IP Address or DNS Name of the RaspberryPi.
  • If this is the first time you connect, you will get a warning that the RaspberryPi's host key is unknown.  Click "Accept" or "Connect Once" to proceed with the connection.
  • Once connected, log onto the Pi using the credentials you created.  If you have not defined your own credentials, you should, but these are the default credentials:
  • UserID:  pi 
  • Password:  raspberry
  • First things first, we need to create a directory structure to hold all of the files and configurations related to the Certificate Authority (CA).  In this case, we'll start with /root/ca and create subfolders for certs, crl, newcerts, and private.  Note, we need to apply fairly restrictive permissions to these directories given the sensitive nature of the CA when the generated certificates are used for Authentication and Authorization.  
sudo mkdir /root/ca
sudo mkdir /root/ca/certs
sudo mkdir /root/ca/crl
sudo mkdir /root/ca/newcerts
sudo mkdir /root/ca/private
sudo chmod 700 /root/ca/private

  • OpenSSL uses the index.txt and serial files as a flat file database.  We need to create both files, and create the serial file with an initial value of 1000 inside the file.
sudo touch /root/ca/index.txt
sudo nano /root/ca/serial

  • Now, let's use nano to create the file with the Certificate Authority default configurations.  I've attached a sample copy of the configuration file at the end of this lesson.
sudo nano /root/ca/openssl.cnf

  • With the file created, let's add our header and CA sections:
# OpenSSL root CA configuration file

[ ca ]
# 'man ca'
default_ca = CA_default

[CA_default ]
# Directory and file locations
dir                                  = /root/ca
certs                                = $dir/certs
crl_dir                              = $dir/crl
new_certs_dir                        = $dir/newcerts
database                             = $dir/index.txt
serial                               = $dir/serial
RANDFILE                             = $dir/private/.rand

# The root key and root certificate
private_key                          = $dir/private/ca.key.pem
certificate                          = $dir/certs/ca.cert.pem

# For certificate revocation lists
crlnumber                            = $dir/crlnumber
crl                                  = $dir/crl/ca.crl.pem
crl_extensions                       = clr_ext
default_crl_days                     = 30

# Additional configurations
default_md                           = sha256
name_opt                             = ca_default
cert_opt                             = ca_default
default_days                         = 3650
preserve                             = no
policy                               = policy_strict

  • With the CA sections defined, it's time to lay out the Policy sections.
[ policy_strict ]
# The root CA should only sign intermediate certificates that match
# See the POLICY FORMAT section of 'man ca'
countryName                          = match
stateOrProvinceName                  = match
localityName                         = match
organizationName                     = match
organizationalUnitName               = optional
commonName                           = supplied
emailAddress                         = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates
# See the POLICY FORMAT section for the 'ca' man page
countryName                          = optional
stateOrProvinceName                  = optional
localityName                         = optional
organizationName                     = optional
organizationalUnitName               = optional
commonName                           = supplied
emailAddress                         = optional

  • Now that we have the Policy sections created, it's time to create the Req sections:
[ req ]
# Options for the 'req' tool ('man req')
default_bits                         = 2048
distinguished_name                   = req_distinguished_name
string_mask                          = utf8only
default_md                           = sha256
x509_extensions                      = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>
countryName                          = Country Name (2 letter code)
stateOrProvinceName                  = State or Province Name
localityName                         = Locality Name
0.organizationName                   = Organization Name
organizationalUnitName               = Department Unit Name
commonName                           = Common Name
emailAddress                         = Email Address

# Optional, default values
countryName_default                  = GB
stateOrProvinceName_default          = England
localityName_default                 = London
0.organizationName_default           = AcademicDabbling
#organizationalUnitName_default       = 
emailAddress_default                 = Joshua@AcademicDabbling.Com

  • Good, the Req section is complete -- now let's create the X509v3 configuration sections:
[ v3_ca ]
# Extensions for a typical CA ('man x590v3_config')
subjectKeyIdentifier                 = hash
authorityKeyIdentifier               = keyid:always,issuer
basicConstraints                     = critical, CA:true
keyUsage                             = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA ('man x509v3_config')
subjectKeyIdentifier                 = hash
authorityKeyIdentifier               = keyid:always,issuer
basicConstraints                     = critical, CA:true, pathlen:0
keyUsage                             = critical, digitalSignature, cRLSign, keyCertSign

  • The X509v3 configuration sections are now finished, let's add the configuration for our User Certificates:
[ usr_cert ]
# Extensions for client configurations ('man x509v3_config)
basicConstraints                     = CA:FALSE
nsCertType                           = client, email
nsComment                            = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier                 = hash
authorityKeyIdentifier               = keyid,issuer
keyUsage                             = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage                     = clientAuth, emailProtection

  • The User Certificate configuration is done, now let's add the configuration for the Server Certificates:
[ server_cert ]
# Extensions for server certificates ('man x509v3_config')
basicConstraints                     = CA:FALSE
nsCertType                           = server
nsComment                            = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier                 = hash
authorityKeyIdentifier               = keyid,issuer:always
keyUsage                             = critical, digitalSignature, keyEncipherment
extendedKeyUsage                     = serverAuth

  • OK -- let's finish it up with the CRL and OCSP configurations:
[ crl_ext ]
# Extension for CRLs ('man x509v3_config')

[ ocsp ]
# Extension for OCSP signing certificates ('man ocsp')
basicConstraints                     = CA:FALSE
subjectKeyIdentifier                 = hash
authorityKeyIdentifier               = keyid,issuer     
keyUsage                             = critical, digitalSignature
extendedKeyUsage                     = critical, OCSPSigning

  • Great work, now that the configuration file is complete, we need to create the root pair which will allow us to issue trusted certificates.  It is important that this key pair is closely guarded as a compromise would result in a fundamental compromise of the Public Key Infrastructure (PKI) we are creating with this CA.  We will be protecting it by generating it with AES-256 bit encryption and a strong password and issuing restrictive file level permissions.  Additionally, we'll use a 4096-bit key length within the certificate to safeguard any certificates it generates.
sudo openssl genrsa -aes256 -out /root/ca/private/ca.key.pem 4096
sudo chmod 400 /root/ca/private/ca.key.pem

  • OK, with the root key created, we can create the root certificate.  Every certificate gets an expiration date, but for this certificate, we should choose a very long time -- perhaps 20 years.  The reason this is important, is that when the root certificate expires, then all certificates signed by the root will also expire.
sudo openssl req -config /root/ca/openssl.cnf -key /root/ca/private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out /root/ca/certs/ca.cert.pem
<CA Password (from the previous step)>
<Your CA / Organization specific details>
sudo chmod 444 /root/ca/certs/ca.cert.pem

  • Perfect, we're almost there.  With the root certificate created, we can now verify the cert to make sure everything was generated correctly.  We are verifying the:
    • Signature algorithm
    • Dates of validity
    • Public-Key bit length
    • Issuer (Identical to Subject)
    • Subject (Identical to Issuer)
sudo openssl x509 -noout -text -in /root/ca/certs/ca.cert.pem

  • Congratulations!  Your Certificate authority is now configured and ready to go!  
Joshua S,
Nov 29, 2015, 5:55 AM