Building an OpenSSL Certificate Authority - Creating ECC Certificates

Creating ECC Certificates

Previously on Building an OpenSSL CA, we created a certificate revocation list, OCSP certificate, and updated our OpenSSL configuration file to include revokation URI data. Now we are ready to create our first server certificate and sign them with our fully armed and operational CA. What's becoming a theme there are two caveats to note prior to creating our first server CSR. Stop rolling your eyes and stay with me.

  • Certificates MUST have subjectAltName (SAN) extensions of type DNSName defined1.
  • Openssl currently supports population of SubjectAltName through configuration files only, including the current version v1.1.0f (true at guides publication date)2.


Copy the Gist openssl_server.cnf file to

/root/ca/intermediate/openssl_server.cnf 
and modify the contents for your own naming conventions. The
openssl_server.cnf
file has new entries at the 
[server_cert]
location to create the
subjectAltName
field our certificate mentioned in the earlier noted points. This alternative name should match what we enter for the
[commonName]
field.

[ server_cert ]
subjectAltName = @alt_names

[alt_names]
DNS.0 = webby.grilledcheese.us

You can add additional names to the certificate by iterating the [alt_names] section. Below is an example of the openssl config formatting for multiple names. Example:

[alt_names]
DNS.0 = yourdomain.com
DNS.1 = sassymolassy.yourdomain.com
DNS.2 = *.skeletor.yourdomain.com
DNS.3 = *.orco.greyskull.yourdomain.com

RFC 5280 regarding subject alternative names states no upper bound limit is defined (no limit to how many names you can enter). However there are practical and application limitations so plan your certificate's alternate names wisely and try to match what you would implement in production. You're also thinking, how does this scale for multiple CSRs? It doesn't. You'll need to either update the openssl_server.cnf every time you want to create a new certificate or create a copy for each new certificate. We'll worry about scripting and simplifying that process in another followup article.

Create the private key and CSR.

Create the private key and CSR and specify either P-256 or P-384 approved curves. Since the root and intermediary CA's use P-384, Suite B allows us to use either. If we created the CA using P-256, we would not be able to use P-384 for the client/server certificate. We also need to ensure our certificate's hash function matches the signing CA, in our case SHA-384.

# cd /root/ca
# openssl req -config intermediate/openssl_server.cnf -new -newkey ec:<(openssl ecparam -name secp384r1) -keyout intermediate/private/webby.cheese.key.pem -out intermediate/csr/webby.cheese.csr

Generating an EC private key
writing new private key to 'intermediate/private/webby.cheese.key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
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 Dev Lab]:
Common Name []:webby.grilledcheese.us
Email Address [grilledcheese@yummyinmytummy.us]:

Create the Certificate

Use the intermediary certificate to create and sign the CSR for webby.grilledcheese.us.

# cd /root/ca
# openssl ca -config intermediate/openssl_server.cnf -extensions server_cert -days 730 -in intermediate/csr/webby.cheese.csr -out intermediate/certs/webby.cheese.crt.pem

Using configuration from intermediate/openssl_server.cnf
Enter pass phrase for /root/ca/intermediate/private/int.cheese.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4104 (0x1008)
        Validity
            Not Before: Sep  6 20:10:39 2017 GMT
            Not After : Sep  6 20:10:39 2019 GMT
        Subject:
            countryName               = US
            stateOrProvinceName       = WA
            localityName              = Seattle
            organizationName          = Grilled Cheese Inc.
            organizationalUnitName    = Grilled Cheese Dev Lab
            commonName                = webby.grilledcheese.us
            emailAddress              = grilledcheese@yummyinmytummy.us
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Cert Type:
                SSL Server
            Netscape Comment:
                Grilled Cheese Generated Server Certificate
            X509v3 Subject Key Identifier:
                E0:48:57:7E:F9:92:BA:B9:F9:23:41:8D:3D:85:86:82:25:5C:FC:92
            X509v3 Authority Key Identifier:
                keyid:7E:2D:A5:D0:9B:70:B9:E3:D2:F7:C0:0A:CF:70:9A:8B:80:38:B1:CD
                DirName:/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
                serial:10:01

            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 CRL Distribution Points:

                Full Name:
                  URI:http://crl.grilledcheese.us/whomovedmycheese.crl

            Authority Information Access:
                CA Issuers - URI:http://ocsp.grilledcheese.us/cheddarcheeseroot.crt
                OCSP - URI:http://ocsp.grilledcheese.us/

            X509v3 Subject Alternative Name:
                DNS:webby.grilledcheese.us
Certificate is to be certified until Sep  6 20:10:39 2019 GMT (730 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Validate the certificate

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

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4104 (0x1008)
    Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = US, ST = WA, O = Grilled Cheese Inc., OU = Grilled Cheese Intermediary CA, CN = Grilled Cheese Inc. Intermediary Certificate Authority, emailAddress = grilledcheese@yummyinmytummy.us
        Validity
            Not Before: Sep  6 20:10:39 2017 GMT
            Not After : Sep  6 20:10:39 2019 GMT
        Subject: C = US, ST = WA, L = Seattle, O = Grilled Cheese Inc., OU = Grilled Cheese Dev Lab, CN = webby.grilledcheese.us, emailAddress = grilledcheese@yummyinmytummy.us
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:bf:48:5b:9b:b2:e2:cf:de:e6:5a:33:3a:9f:73:
                    70:82:75:86:bd:6f:6a:98:e6:5e:31:fb:af:c5:9f:
                    68:dc:8b:bc:24:69:08:d8:35:c9:be:76:d4:3d:c5:
                    48:b3:8f:f6:fd:4a:b9:75:70:58:2c:65:f5:72:61:
                    62:b8:58:ae:ba:f1:cc:95:1e:bd:60:b2:18:92:19:
                    d2:c3:fd:60:10:60:5a:ad:e5:29:94:f8:37:1b:5b:
                    e5:41:50:fe:39:b9:1c
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Cert Type:
                SSL Server
            Netscape Comment:
                Grilled Cheese Generated Server Certificate
            X509v3 Subject Key Identifier:
                E0:48:57:7E:F9:92:BA:B9:F9:23:41:8D:3D:85:86:82:25:5C:FC:92
            X509v3 Authority Key Identifier:
                keyid:7E:2D:A5:D0:9B:70:B9:E3:D2:F7:C0:0A:CF:70:9A:8B:80:38:B1:CD
                DirName:/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
                serial:10:01

            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 CRL Distribution Points:

                Full Name:
                  URI:http://crl.grilledcheese.us/whomovedmycheese.crl

            Authority Information Access:
                CA Issuers - URI:http://ocsp.grilledcheese.us/cheddarcheeseroot.crt
                OCSP - URI:http://ocsp.grilledcheese.us/

            X509v3 Subject Alternative Name:
                DNS:webby.grilledcheese.us
    Signature Algorithm: ecdsa-with-SHA384
         30:65:02:31:00:b1:ab:4e:4f:21:86:14:12:fe:34:ea:47:00:
         67:29:cb:47:70:b2:ad:22:a0:dc:5b:65:7b:22:10:5e:ea:08:
         7d:09:8d:c5:77:f5:8b:ff:fa:d2:5b:7a:1e:c6:57:e2:12:02:
         30:64:f1:fb:14:ea:cf:b4:20:7d:f3:f5:bc:d0:82:0c:06:03:
         fc:05:84:5d:f9:37:dc:d6:51:83:7b:8b:f6:91:08:d6:22:4f:
         16:96:ff:0a:52:68:47:09:0c:71:90:23:d4

Validation of the webby.cheese.crt.pem file shows the updated x509 fields that define our server certificate:

X509v3 extensions:
           X509v3 Basic Constraints:
               CA:FALSE
           Netscape Cert Type:
               SSL Server
           Netscape Comment:
               Grilled Cheese Generated Server Certificate

The certificate also includes full CRL and OCSP endpoints.

           X509v3 CRL Distribution Points:

               Full Name:
                 URI:http://crl.grilledcheese.us/whomovedmycheese.crl

           Authority Information Access:
               CA Issuers - URI:http://ocsp.grilledcheese.us/cheddarcheeseroot.crt
               OCSP - URI:http://ocsp.grilledcheese.us/


And it includes our required subjectAltname.

           X509v3 Subject Alternative Name:
               DNS:webby.grilledcheese.us

The

index.txt
file we created for our intermediary certificate now has a new entry. Confirm the CA's database is updated with the newly created certificate. This file will prevent new certificates from being created with the same CN. If you need to recreate the certificate with the same name AND YOU'RE IN A LAB ENVIRONMENT, you can use vi/vim/nano/whatever to delete this line. The production-preferred method is to revoke and reissue.

# cat intermediate/index.txt

V       180828222314Z           1007    unknown /C=US/ST=WA/L=Seattle/O=Grilled Cheese Inc./OU=Grilled Cheese Intermediary CA/CN=ocsp.grilledcheese.us/emailAddress=grilledcheese@yummyinmytummy.us
V       190906201039Z           1008    unknown /C=US/ST=WA/L=Seattle/O=Grilled Cheese Inc./OU=Grilled Cheese Dev Lab/CN=webby.grilledcheese.us/emailAddress=grilledcheese@yummyinmytummy.us

The intermediary certificate was responsible for signing the OCSP certificate and our new server certificate; both are listed in the index.txt file. Lastly we can validate the entire certificate chain using the previously created chain.cheese.crt.pem against our newly created server certificate.

# openssl verify -CAfile intermediate/certs/chain.cheese.crt.pem intermediate/certs/webby.cheese.crt.pem

intermediate/certs/webby.cheese.crt.pem: OK

Deploying Your Certificate

Your application or server will usually accept PEM format or a PFX bundle which contains certificate, key and certificate chain (if you desire to). In production environments you would not distribute the root certificate along with the intermediate. Even in lab environments, you should distribute the root certificate independently to clients to simulate real world environments. In production systems all mainstream certificate authorities are packaged with operating systems or independent key stores. The intermediary used should match one of these existing root CAs only... For our example, if you were deploying the PEM formatted files, you would need to provide:

  • webby.cheese.key.pem (our server certificate's private key)
  • webby.cheese.crt.pem (our server certificate)
  • int.cheese.crt.pem or chain.cheese.crt.pem (our intermediary CA's certificate or root and certificate concatenated into one file)


If you plan to install the certificate and chain in PFX format:

# openssl pkcs12 -export -out intermediate/certs/webby.cheese.pfx -inkey intermediate/private/webby.cheese.key.pem -in intermediate/certs/webby.cheese.crt.pem -certfile intermediate/certs/chain.cheese.crt.pem

Enter pass phrase for intermediate/private/webby.cheese.key.pem: ******
Enter Export Password: ******
Verifying - Enter Export Password: ******

Validate the PFX bundle

# openssl pkcs12 -info -in intermediate/certs/webby.cheese.pfx
Enter Import Password: ******

MAC:sha1 Iteration 2048
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Bag Attributes
    localKeyID: F7 6B 18 13 DD 04 4E 31 D7 A4 8D AE F5 1F 3B DC AD F3 F8 E8
subject=/C=US/ST=WA/L=Seattle/O=Grilled Cheese Inc./OU=Grilled Cheese Dev Lab/CN=webby.grilledcheese.us/emailAddress=grilledcheese@yummyinmytummy.us
issuer=/C=US/ST=WA/O=Grilled Cheese Inc./OU=Grilled Cheese Intermediary CA/CN=Grilled Cheese Inc. Intermediary Certificate Authority/emailAddress=grilledcheese@yummyinmytummy.us

-----BEGIN CERTIFICATE-----
MIIFSDCCBM6gAwIBAgICEAgwCgYIKoZIzj0EAwMwgdIxCzAJBgNVBAYTAlVTMQsw
....
lv8KUmhHCQxxkCPU
-----END CERTIFICATE-----

Certificate bag
Bag Attributes: no attributes=""
subject=/C=US/ST=WA/O=Grilled Cheese Inc./OU=Grilled Cheese Intermediary CA/CN=Grilled Cheese Inc. Intermediary Certificate Authority/emailAddress=grilledcheese@yummyinmytummy.us
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

-----BEGIN CERTIFICATE-----
MIID/TCCA4OgAwIBAgICEAEwCgYIKoZIzj0EAwMwgdQxCzAJBgNVBAYTAlVTMQsw
....
wO2cWbcYwybr33gTaEdmtUM=
-----END CERTIFICATE-----

Certificate bag
Bag Attributes: no attributes=""
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
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

-----BEGIN CERTIFICATE-----
MIIDQTCCAsegAwIBAgIJAP+99S/FDT0CMAoGCCqGSM49BAMDMIHUMQswCQYDVQQG
....
/kiTCl//67LTrlpoh9zJLFSNBGh/

-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Bag Attributes
    localKeyID: F7 6B 18 13 DD 04 4E 31 D7 A4 8D AE F5 1F 3B DC AD F3 F8 E8
Key Attributes: no attributes=""

Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBEzBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQItDjLLd4ozIkCAggA
....
GxO/udVd0Bg0zY6eSQV1xyXhGd4GJexnKv/IHeYWjpJMyNqa4O9o
-----END ENCRYPTED PRIVATE KEY-----

We've completed building a two-tier NSA Suite B certificate authority for use within dev or lab environment. You'll still want to create web services to home the CRL list and act as OCSP Resolvers if you need that level of testing. The big drawback to manually using OpenSSL is the requirement of configuration files for

SAN
requirements. Manually updating or iterating a new OpenSSL configuration file for each certificate (requiring subjetAltName) is not efficient but I have yet to find a clean script to resolve this. I guess we'll just build one. Later.

Notes:

(1)The subjectAltName field was proposed to be preferred instead of the commonName (CN) field in RFC 2818 by Mozilla's E. Rescorla (who submitted it under his company RTFM, Inc... look up the acronym). No one really knew about it because the RFC also allowed defaulting back to the CN field if no subjectAltName existed. But combined with the seldom read CA/Browser forum's Baseline Requirements Certificate Policy for the Issuance and Management of Publicly-Trusted Certificates (released April of 2017), the subjectAltName field is now the only field of consequence for defining hostnames or IP's in a certificate.  Guess how everyone found about this.  Browsers simply removed support for the CN field as the host name and broke everyone's web sites siting "correcting a 17 year old requirement".  Fortunately for some of us, our public CA's started auto-populating this field for a several years prior to the browser abandonment and reduced the impact to public sites. However internal CA's were left floundering (unless you read every RFC that comes out and then that doesn't even cover it). Thanks E. Rescorla for your vaugely worded RFC and Google's inability to provide visibility like they did to SHA1 deprecation (with advanced public warning and careful planning).  Let's forget that the field is called ALTERNATE NAME... that annoys me at a core level.  You have nothing better to do than read every RFC that could potentially affect your life, 17 years down the road... right?

(2) OpenSSL Git pull request #341 "Add 'copy and 'move configuration values for DNS Subject Alternative Names" exists in the Post 1.1.0 milestone but code commit is still pending into openssl:master branch.  So we're stuck with config files for each certificate you want to use for now, unless you want to script it yourselves. Alternativly, OpenSSL has an GIT open Issue #3311 for "Interactivly specify subjecAltName (SAN). Here's to hoping.

Updated Jun 06, 2023
Version 2.0
  • For anyone needing a copy of openssl_server.cnf:

    https://pastebin.com/vk6jLpqS

     

    [ ca ]
    default_ca = CA_default
     
    [ CA_default ]
    # Directory and file locations.
    dir               = /root/ca/intermediate
    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/int.cheese.key.pem
    certificate       = $dir/certs/int.cheese.crt.pem
     
    # For certificate revocation lists.
    crlnumber         = $dir/crlnumber
    crl               = $dir/crl/whomovedmycheese.crl
    crl_extensions    = crl_ext
    default_crl_days  = 180
     
    # 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      = 3000
    preserve          = no
    policy            = policy_loose
     
    [ policy_loose ]
    # Allow the intermediate CA to sign a more diverse range of certificates.
    # See the POLICY FORMAT section of the `ca` man page.
    countryName             = optional
    stateOrProvinceName     = optional
    localityName            = optional
    organizationName        = optional
    organizationalUnitName  = optional
    commonName              = supplied
    emailAddress            = optional
     
    [ req ]
    # Options for the `req` tool (`man req`).
    default_bits        = 2048
    distinguished_name  = req_distinguished_name
    string_mask         = utf8only
     
    # SHA-1 is deprecated, so use SHA-2 or SHA-3 instead.
    default_md          = sha384
     
    # Extension to add when the -x509 option is used.
    x509_extensions     = v3_ca
     
    [ 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 Intermediary CA
    emailAddress_default            = grilledcheese@yummyinmytummy.us
     
    [ 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
     
    [ 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
    crlDistributionPoints = @crl_info
    authorityInfoAccess = @ocsp_info
     
    [ usr_cert ]
    # Extensions for client certificates (`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
     
    [ server_cert ]
    # Extensions for server certificates (`man x509v3_config`).
    basicConstraints = CA:FALSE
    nsCertType = server
    nsComment = "Grilled Cheese Generated Server Certificate"
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer:always
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    crlDistributionPoints = @crl_info
    authorityInfoAccess = @ocsp_info
    subjectAltName = @alt_names
     
    [alt_names]
    DNS.0 = CN Name Here
    DNS.1 = Whatever else here
     
    [ crl_ext ]
    # Extension for CRLs (`man x509v3_config`).
    authorityKeyIdentifier=keyid:always
     
    [ ocsp ]
    # Extension for OCSP signing certificates (`man ocsp`).
    basicConstraints = CA:FALSE
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer
    keyUsage = critical, digitalSignature
    extendedKeyUsage = critical, OCSPSigning
     
    [crl_info]
    URI.0 = http://crl.grilledcheese.us/whomovedmycheese.crl
     
    [ocsp_info]
    caIssuers;URI.0 = http://ocsp.grilledcheese.us/cheddarcheeseroot.crt
    OCSP;URI.0 = http://ocsp.grilledcheese.us/