Personal root Certificate Authority – CA

For the purposes of testing certain types of process over https, it is useful to be able to create certificate signing request and have them signed by a trusted certificate authority and be able to generate certificates for local test sites at will.

This is where a personal root CA can be used. I had a recent project developing some web services where I wanted a client to present a signed certificate trusted by the server before being allowed to upload its set of JSON data.

There’s no getting away from the fact that setting up a CA for the first time is hard. It will take time and it shouldn’t be expected to work first time; it took me three attempts, can be very difficult to troubleshoot and diagnose, and can be easier to start from scratch than try to fix.

Root CA

My primary guide for setting up the CA structure cn be found at [2] and is clearly written and easy to follow although still missing some crucial details that are more important now than when the article was originally produced.

This guide suggested setting a distinct root CA that signs the certificate for an intermediate CA that is actually used to sign the client and server certificates. While a bit more work is involved I liked the approach.

The basic steps are

$ mkdir root-ca
$ cd root-ca
$ mkdir certs crl newcerts private
$ chmod 700 private
$ touch index.txt
$ echo 1000 > serial

To create a configuration specific to the root CA, copy https://jamielinux.com/docs/openssl-certificate-authority/_downloads/root-config.txt
to root-ca-openssl.conf amending the top level dir entry as appropriate.

$ openssl genrsa -aes256 -out private/ca.key.pem 4096
$ chmod 400 private/ca.key.pem

Enter the private key passphrase and answer the questions

$ openssl req -config root-ca-openssl.conf  \
      -key private/ca.key.pem \
      -new -x509 -days 7300 -sha256 -extensions v3_ca \
      -out certs/ca.cert.pem
Enter pass phrase for private/ca.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) [GB]:
State or Province Name [England]:Myland
Locality Name []:Mylocal
Organization Name [Alice Ltd]:Org Services
Organizational Unit Name []:Org Services Root CA
Common Name []:root-ca.localdomain
Email Address []:root-ca@localhost
$ chmod 444 certs/ca.cert.pem

Verify the certificate

$ openssl x509 -noout -text -in certs/ca.cert.pem

This certificate can now ben used to sign the intermediate CAs request.

Intermediate CA

Create the intermediate pair, signed by the root, but used to sign the issued
certs on behalf of the root.

From https://jamielinux.com/docs/openssl-certificate-authority/create-the-intermediate-pair.html

$ mkdir intermediate-ca
$ cd intermediate-ca
$ mkdir certs crl csr newcerts private
$ chmod 700 private
$ touch index.txt
$ echo 1000 > serial
$ echo 1000 > crlnumber
$ echo "unique_subject = no" > index.txt.attr - see [15]
$ cp ../root-ca/root-ca-openssl.conf intermediate-openssl.conf

Make the following changes to the conf file:

[ CA_default ]


dir             = /root/ca/intermediate
private_key     = $dir/private/intermediate.key.pem
certificate     = $dir/certs/intermediate.cert.pem
crl             = $dir/crl/intermediate.crl.pem
policy          = policy_loose

Now generate the intermediate key

$ cd intermediate-ca
$ openssl genrsa -aes256 \
      -out private/intermediate.key.pem 4096
$ openssl req -config intermediate-openssl.conf -new -sha256 \
      -key private/intermediate.key.pem \
      -out csr/intermediate.csr.pem
      Enter pass phrase for private/intermediate.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) [GB]:
      State or Province Name [England]:Myland
      Locality Name []:Mylocal
      Organization Name [Alice Ltd]:Org Services
      Organizational Unit Name []:Org Services Intermediate CA
      Common Name []:intermediate-ca@localdomain
      Email Address []:intermediate-ca@localhost

When creating the certificate, use the root ca openssl configuration

$ openssl ca -config ../root-ca/root-ca-openssl.conf -extensions v3_intermediate_ca \
      -days 3650 -notext -md sha256 \
      -in csr/intermediate.csr.pem \
      -out certs/intermediate.cert.pem
      Check that the request matches the signature
      Signature ok
      Certificate Details:
...
Certificate is to be certified until Nov 26 21:57:04 2026 GMT (3650 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 UpdatedCertificate is to be certified until Nov 26 21:57:04 2026 GMT (3650 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
$ chmod 444 certs/intermediate.cert.pem

Check that the root CA index.txt file contains an entry like,

$ more ../root-ca/index.txt
V    263326226815P        1000    unknown    /C=GB/ST=Myland/O=Org Services/OU=Org Services Certificate Authority/CN=Org Services Intermediate CA

Verify the certificate and the chin of trust

$ openssl x509 -noout -text -in certs/intermediate.cert.pem
$ openssl verify -CAfile ../root-ca/certs/ca.cert.pem certs/intermediate.cert.pem
certs/intermediate.cert.pem: OK

Create a certificate chain so that clients can verify the intermediate against
the root certificate,

$ cat certs/intermediate.cert.pem ../root-ca/certs/ca.cert.pem > certs/ca-chain.cert.pem
$ chmod 444 certs/ca-chain.cert.pem

The final part of preparing the CA for use is to add a section to the intermediate openssl configuration that includes Subject Alternate Name (SAN) entries, something similar to,

[ alternate_names ]
DNS.1 = inventory-master.localdomain
DNS.2 = *.inventory-master.localdomain

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alternate_names
...

[req]
...
req_extensions     = v3_req

Although there is much scope in the other options for requests, so long as ‘subjectAltName’ resolves then the configuration is good.

I will describe the detail of setting up a web server to make use of the CA in another page soon.

References

In no particular order (of preference or usefulness) I found the following resources helpful in developing my working system.

[1] http://blog.nategood.com/client-side-certificate-authentication-in-ngi
[2] https://jamielinux.com/docs/openssl-certificate-authority/ – an excellent
guide except that it is missing the need to use SubjectAlternateNames.
[3] https://pypi.python.org/pypi/blitz-ca/0.1.1 – Python local CA; not used here
[4] http://stackoverflow.com/questions/33504746/doing-ssl-client-authentication-is-python
[5] http://stackoverflow.com/questions/9093289/how-to-create-a-dual-authentication-https-client-in-python-without-lgpl-libs
[6] http://twistedmatrix.com/documents/current/core/howto/ssl.html#client-authentication
[7] http://wiki.cacert.org/FAQ/subjectAltName – Adding SubjectAltName to a cert
[8] http://apetec.com/support/generatesan-csr.htm – for creating SAN server
certificates (even though the cert creation command is missing a space in the
argument list).
[9] http://stackoverflow.com/questions/21488845/how-can-i-generate-a-self-signed-certificate-with-subjectaltname-using-openssl – gives a good description; ignore the off-topic moan; it is directly related to programming as I can testify in this example.
[10] http://serverfault.com/questions/721572/nginx-verifying-client-certs-only-on-a-particular-location – Location-based authorisation so that CSRs and heartbeats can be processed without requiring a cert;
[11] https://support.globalsign.com/customer/portal/articles/1353601-converting-certificates—openssl – Converting certs and keys from one format to another. Lots of sites will do this
[12] https://kb.wisc.edu/middleware/page.php?id=4064 – Verifying that a certificate and key match.
[13] http://stackoverflow.com/questions/9496698/how-to-revoke-an-openssl-certificate-when-you-dont-have-the-certificate – How to get past certificate database errors when re-requesting a replacement
[14] http://stackoverflow.com/questions/7885785/using-openssl-to-get-the-certificate-from-a-server – Getting openssl to report the certificates in use on a server. This is hugely useful and should be included as a key validity test. I was at the point of giving up when trying this show an invalid cert chain on the server.
[15] http://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-opensslhttp://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl
Perhaps a better guide to correctly setting up root CA to self-sign trusted certs
[16] http://serverfault.com/questions/453300/openssl-client-authentication-error-tlsv1-alert-unknown-ca-ssl-alert-numbe
Another problem that can occur when using openssl to diagnose http 400 errors
[17] http://pages.cs.wisc.edu/~zmiller/ca-howto/ – General root CA setup

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s