Creating Your Root Certificate Authority

In our previous article, Introductions and Design Considerations for Eliptical Curves we covered the design requirements to create a two-tier ECC certificate authority based on NSA Suite B's PKI requirements. We can now begin creating our CA's root configuration. Creating the root CA requires us to generate a certificate and private key, since this is the first certificate we're creating, it will be self-signed. The root CA will not sign client and server certificates, it's job it only to create intermeidary certificates and act as the root of our chain of trust. This is standard practice across the public and private PKI configurations and so too should your lab environments.

Create Your Directory Structure

Create a directory to store your root CA pair and config files.

# sudo bash
# mkdir /root/ca

Yep, I did that. This is for a test lab and permissions may not match real world requirements. I sudoed into bash and created everything under root; aka playing with fire.  This affects ownership down the line if you chmod private key files and directories to user access only so determine for yourself what user/permission will be accessing files for certificate creation. I have a small team and trust them with root within a lab environment (snapshots allow me to be this trusting).

Create your CA database to keep track of signed certificates

# cd /root/ca
# mkdir private certs crl
# touch index.txt
# echo 1000 > serial

We begin by creating a working root directory with sub directories for the various files we'll be creating. This will allow you to apply your preferred security practices should you choose to do so. Since this is a test lab and I am operating as root, I won't be chmod'ing anything today. 

Create Your OpenSSL Config File

OpenSSL uses configuration files to simplify/template the components of a certificate.  Copy the GIST openssl_root.cnf file to /root/ca/openssl_root.cnf which is already prepared for this demo. For the root CA certificate creation, the [ CA ] section is required and will gather it's configuration from the [ CA_default ] section.

[ ca ]
# `man ca`
default_ca = CA_default

 

The [CA_default] section in the openssl_root.cnf file contains the variables OpenSSL will use for the root CA. If you're using alternate directory names from this demo, update the file accordingly. Note the long values for default days (10 years) as we don't care about renewing the root certificate anytime soon.

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

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

  # For certificate revocation lists.
  crlnumber         = $dir/crlnumber
  crl               = $dir/crl/ca.cheese.crl.pem
  crl_extensions    = crl_ext
  default_crl_days  = 3650

  # SHA-1 is deprecated, so use SHA-2 or SHA-3 instead.
  default_md        = sha384

  name_opt          = ca_default
  cert_opt          = ca_default
  default_days      = 3650
  preserve          = no
  policy            = policy_strict

 

For the root CA, we define [policy_strict] which will later force the intermediary's certificate to match country, state/province, and organization name fields.

[ policy_strict ]
The root CA should only sign intermediate certificates that match.
# See POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

 

The [ req ] section is used for OpenSSL certificate requests.  Some of the values listed will not be used since we are manually specifying them during certificate creation.

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 4096
distinguished_name  = req_distinguished_name
string_mask         = utf8only

# SHA-1 is deprecated, please use SHA-2 or greater instead.
default_md          = sha384

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

 

I pre-populate the [ req_distinguished_name ] section with values I'll commonly used to save typing down the road.

[ 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

# Optionally, specify some defaults.
countryName_default             = US
stateOrProvinceName_default     = WA
localityName_default            = Seattle
0.organizationName_default      = Grilled Cheese Inc.
organizationalUnitName_default  = Grilled Cheese Root CA
emailAddress_default            = grilledcheese@yummyinmytummy.us

 

The [ v3_ca ] section will further define the Suite B PKI requirements, namely basicConstraints and acceptable keyUsage values for a CA certificate. This section will be used for creating the root CA's certificate.

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

Selecting the Suite B compliant elliptical curve

We're creating a Suite B infrastructure so we'll need to pick an acceptable curve following P-256 or P-384. To do this, run the following OpenSSL command:

openssl ecparam -list_curves

This will give you a long list of options but which one to pick? Let's isolate the suites within the 256 & 384 prime fields; we can grep the results for easier curve identification.

openssl ecparam -list_curves | grep '256\|384'

And we get the following results (your results may vary depending on the version of OpenSSL running):

# openssl ecparam -list_curves | grep '256\|384'

    secp256k1 : SECG curve over a 256 bit prime field
    secp384r1 : NIST/SECG curve over a 384 bit prime field
    prime256v1: X9.62/SECG curve over a 256 bit prime field
    brainpoolP256r1: RFC 5639 curve over a 256 bit prime field
    brainpoolP256t1: RFC 5639 curve over a 256 bit prime field
    brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
    brainpoolP384t1: RFC 5639 curve over a 384 bit prime field

I am going to use secp384r1 as my curve of choice. It's good to mention that RFC5480 notes secp256r1 (not listed) is referred to as prime256v1 for this output's purpose. Why not use something larger than 384? Thank Google. People absolutely were using secp521r1 then Google dropped support for it (read Chromium Bug 478225 for more). The theory is since NSA Suite B PKI did not explicitly call out anything besides 256 or 384, the Chromium team quietly decided it wasn't needed and dropped support for it. Yea... it kinda annoyed a few people. So to avoid future browser issues, we're sticking with what's defined in public standards.

Create the Root CA's Private Key

Using the names defined in the openssl_root.cnf's private_key value and our selected secp384r1 ECC curve we will create and encrypt the root certificates private key.

# openssl ecparam -genkey -name secp384r1 | openssl ec -aes256 -out private/ca.cheese.key.pem

  read EC key
  writing EC key
  Enter PEM pass phrase: ******
  Verifying - Enter PEM pass phrase: ******

Note:The ecparam function within OpenSSL does not encrypt the private key like genrsa/gendsa/gendh does. Instead we combined the private key creation (openssl ecparam) with a secondary encryption command (openssl ec) to encrypt private key before it is written to disk. Keep the password safe.

Create the Root CA's Certificate

Using the new private key, we can now generate our root's self-signed certificate. We do this because the root has no authority above it to request trust authority from; it is the absolute source of authority in our certificate chain.

# openssl req -config openssl_root.cnf -new -x509 -sha384 -extensions v3_ca -key private/ca.cheese.key.pem -out certs/ca.cheese.crt.pem

  Enter pass phrase for private/ca.cheese.key.pem: ******
  You are about to be asked to enter information that will be incorporated
  into your certificate request.
  What you are about to enter is what is called a Distinguished Name or a DN.
  There are quite a few fields but you can leave some blank
  For some fields there will be a default value,
  If you enter '.', the field will be left blank.
  -----
  Country Name (2 letter code) [US]:
  State or Province Name [WA]:
  Locality Name [Seattle]:
  Organization Name [Grilled Cheese Inc.]:
  Organizational Unit Name [Grilled Cheese Root CA]:
  Common Name []:Grilled Cheese Root Certificate Authority
  Email Address [grilledcheese@yummyinmytummy.us]:

Using OpenSSL we can validate the Certificate contents to ensure we're following the NSA Suite B requirements.

# openssl x509 -noout -text -in certs/ca.cheese.crt.pem

  Certificate:
      Data:
          Version: 3 (0x2)
          Serial Number:
              ff:bd:f5:2f:c5:0d:3d:02
      Signature Algorithm: ecdsa-with-SHA384
          Issuer: C = US, ST = WA, L = Seattle, O = Grilled Cheese Inc., OU = Grilled Cheese Root CA, CN = Grilled Cheese Inc. Root Certificate Authority, emailAddress = grilledcheese@yummyinmytummy.us
          Validity
              Not Before: Aug 22 23:53:05 2017 GMT
              Not After : Aug 20 23:53:05 2027 GMT
          Subject: C = US, ST = WA, L = Seattle, O = Grilled Cheese Inc., OU = Grilled Cheese Root CA, CN = Grilled Cheese Inc. Root Certificate Authority, emailAddress = grilledcheese@yummyinmytummy.us
          Subject Public Key Info:
              Public Key Algorithm: id-ecPublicKey
                  Public-Key: (384 bit)
                  pub:
                      04:a6:b7:eb:8b:9f:fc:95:03:02:20:ea:64:7f:13:
                      ea:b7:75:9b:cd:5e:43:ca:19:70:17:e2:0a:26:79:
                      0a:23:2f:20:de:02:2d:7c:8f:62:6b:74:7d:82:fe:
                      04:08:38:77:b7:8c:e0:e4:2b:27:0f:47:01:64:38:
                      cb:15:a8:71:43:b2:d9:ff:ea:0e:d1:c8:f4:8f:99:
                      d3:8e:2b:c1:90:d6:77:ab:0b:31:dd:78:d3:ce:96:
                      b1:a0:c0:1c:b0:31:39
                  ASN1 OID: secp384r1
                  NIST CURVE: P-384
          X509v3 extensions:
              X509v3 Subject Key Identifier:
                  27:C8:F7:34:2F:30:81:97:DE:2E:FC:DD:E2:1D:FD:B6:8F:5A:AF:BB
              X509v3 Authority Key Identifier:
                  keyid:27:C8:F7:34:2F:30:81:97:DE:2E:FC:DD:E2:1D:FD:B6:8F:5A:AF:BB

              X509v3 Basic Constraints: critical
                  CA:TRUE
              X509v3 Key Usage: critical
                  Digital Signature, Certificate Sign, CRL Sign
      Signature Algorithm: ecdsa-with-SHA384
           30:65:02:30:77:a1:f9:e2:ab:3a:5a:4b:ce:8d:6a:2e:30:3f:
           01:cf:8e:76:dd:f6:1f:03:d9:b3:5c:a1:3d:6d:36:04:fb:01:
           f7:33:27:03:85:de:24:56:17:c9:1a:e4:3b:35:c4:a8:02:31:
           00:cd:0e:6c:e0:d5:26:d3:fb:88:56:fa:67:9f:e9:be:b4:8f:
           94:1c:2c:b7:74:19:ce:ec:15:d2:fe:48:93:0a:5f:ff:eb:b2:
           d3:ae:5a:68:87:dc:c9:2c:54:8d:04:68:7f

Reviewing the above we can verify the certificate details:

  • The Suite B Signature Algorithm: ecdsa-with-SHA384
  • The certificate date validity when we specificed -days 3650:
    • Not Before: Aug 22 23:53:05 2017 GMT
    • Not After : Aug 20 23:53:05 2027 GMT
  • The Public-Key bit length: (384 bit)
  • The Issuer we defined in the openssl_root.cnf: C = US, ST = WA, L = Seattle, O = Grilled Cheese Inc., OU = Grilled Cheese Root CA, CN = Grilled Cheese Inc. Root Certificate Authority
  • The Certificate Subject, since this is self-signed, refers back to itself: Subject: C = US, ST = WA, L = Seattle, O = Grilled Cheese Inc., OU = Grilled Cheese Root CA, CN = Grilled Cheese Inc. Root Certificate Authority
  • The eliptical curve used when we created the private key: NIST CURVE: P-384

Verify the X.509 v3 extensions we defined within the openssl_root.cnf for a Suite B CA use:

X509v3 Basic Constraints: critical
    CA:TRUE
X509v3 Key Usage: critical
    Digital Signature, Certificate Sign, CRL Sign

 

The root certificate and private key are now compete and we have the first part of our CA complete. Step 1 complete! In our next article we will create the intermediary certificate to complete the chain of trust in our two-tier hierarchy.