Sunday, 14 July 2019

Private CA Part 2: Issuing certificates

In the first part, I outlined how to create a new root and an intermediate Certificate Authority using OpenSSL. Once these are created, we can get to the fun part of creating certificates we'll be using for signing web server responses, documents, assemblies etc.

Each certificate has a number of fields that describe it. There are some core fields, like the Serial Number, the Validity periods, Subject, Issuer, Thumbprint etc. These are also extended fields that describe the usage constraints for the certificate - for example, you could create a certificate that can only be used to sign web responses from a specific domain. You could create a certificate that could be used to sign e-mails and documents.

You could just create a certificate that doesn't have any restrictions, and could be used for just about anything. That would be ok for testing purposes, but it's generally recommended to create certificates for individual purposes. This way, if a certificate's private key is compromised, you will only have to reconfigure a single application with a new certificate.

This article is split into multiple parts:

If you used the intermediary certificate openssl.conf file I linked in part 1, you can see that I've added several extension sets at the bottom, that can be used to create different types of certificates:

  • usr_cert used for user identification, digital signatures, document signing
  • usr_cert_smart - similar to the above, but also allows to be used to authenticate a user using a smart card
  • server_cert - the most common type of certificate, used on webservers to create secure https connections.
  • bitlocker_cert - can be used to secure and encrypt data, including BitLocker drives
  • codesig_cert - can be used for code signing purposes, including authenticode, windows assemblies, nuget packages and so on.

When creating a certificate, in most cases you just need to populate the subject field - a combination of Country, City, Organization name, Common name etc. In the case of a web server certificate, you'll also need to specify the dns names / IP addresses that the certificate will be used for.

The process to create a certificate is similar to the one in step 1, when we were creating the intermediary certificate:

  1. Create a certificate request with a key
  2. Sign it using the intermediary certificate

The CSR can come from anywhere. In the case of web certificates, you can create the certificate in the web server itself. If you already have the CSR file you can jump straight to step 2.

Creating the certificate request

Creating the CSR is pretty straightforward in OpenSSL. In case of web certificate, where you specify the DNS/IP of the server, you'll have to create a request configuration file. I have created openssl_csr.conf for that very reason. You'll just have to populate the certificate details and the IPs/DNS names for the certificate you want to create.

Note that when adding multiple domain names, you'll have to increment the index on the record type. For example, if you need a certificate that will be used for two domains and also two IPs, you would have something like this:

[alt_names]
IP.1 = 127.0.0.1
IP.2 = 192.168.0.1
DNS.1 = www.router.com
DNS.2 = www.server.com
DNS.3 = server.com

Once ready run the following:


openssl req -out requests\router.csr -newkey rsa:4096 -nodes -keyout private\router.key -config openssl_csr.conf
Generating a RSA private key
.....................++++
........................................................++++
writing new private key to 'private\router.key'
-----

In the case of most other certificates, you can just run the request command without passing in the config file, and you will be prompted for the certificate Subject fields:


openssl req -out requests\user.csr -newkey rsa:4096 -nodes -keyout private\user.key
Generating a RSA private key
................................................................................................................++++
......................................++++
writing new private key to 'user.key'
-----
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) [AU]: GB
State or Province Name (full name) [Some-State]: .
Locality Name (eg, city) []: London
Organization Name (eg, company) [Internet Widgits Pty Ltd]: MyCompany Ltd
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []: John Smith
Email Address []: [email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
-----

Signing the certificate

Once we have the certificate request, we go back to our CA folder (in our case our intermediate CA) and sign the certificate. This is the point where the CA picks which certificate will be created. To do this, we have to pass the correct extension set as an argument to openssl. For example, this is the command to create a server certificate using the server_cert extension:


openssl rand -out serial -hex 20
openssl ca -config openssl.conf -extensions server_cert -notext -in requests\router.csr -out certs\router.crt
Using configuration from openssl.conf
Enter pass phrase for /root/interm/private/interm.key:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            46:3b:33:c8:81:36:09:34:4a:bd:56:0e:37:fe:c2:2a:65:c9:1b:7b
        Validity
            Not Before: May 12 17:26:30 2019 GMT
            Not After : May 10 17:26:30 2024 GMT
        Subject:
            countryName               = GB
            localityName              = London
            organizationName          = MyCompany Ltd
            commonName                = 10.0.0.1
            emailAddress              = [email protected]
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Subject Key Identifier:
                9C:1B:74:B1:D6:F9:C9:95:34:83:65:4B:F2:A0:7A:40:8A:9A:C1:E5
            X509v3 Authority Key Identifier:
                keyid:BB:8F:1A:71:F8:70:47:FE:30:02:DB:CF:C9:05:CF:42:78:2E:E3:56
                DirName:/C=GB/L=London/O=FlexLabs Ltd/CN=FlexLabs Ltd Test CA/[email protected]
                serial:AA:CB:1C:D1:F0:8A:EF:D2:8A:7C:33:F2:29:53:18:0F:1F:F4:53:A9

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

            X509v3 Subject Alternative Name:
                IP Address:10.0.0.1, DNS:router.com
Certificate is to be certified until May 10 17:26:30 2024 GMT (1825 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

You have successfully created a new certificate!

One more thing you will sometimes need is combine the private and the public keys into a single .pfx file - this is very easily accomplished using a quick command. In most cases, I try add the full certificate chain into the pfx, to ensure whoever receives this certificate can verify the full chain:

openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile interm.chain.crt

References

-extensions and -reqexts in openssl

More on key usage