Certificates

Certificates are essentially keys, which have been certified by another party, that those keys indeed belong to a person or device.

Certificates signed by commercial certificate authorities are usually created directly on their website using built-in functions of web-browsers which require minimal interaction from the user.

Here we will manually create a CSR to be signed by a certification authority.

Preparations

Create a personal directory to store configuration, keys, CSR and certificates:

$ mkdir -p ~/.ssl/{certs,private}
$ chmod 700 ~/.ssl/private

Set some environment variables:

$ export CN=$HOSTNAME.example.net
$ export emailAddress=john.doe@example.net

Personal User Certificate Request

Personal certificates may be used to login on websites and to sign and encrypt email. They include information about a person.

OpenSSL Configuration

Create a new OpenSSL configuration file ~/.ssl/openssl-user.cnf:

 1#
 2# OpenSSL configuration for generation of client certificate requests.
 3#
 4# Environment variables 'emailAddress' **MUST** be defined or else
 5# OpenSSL aborts:
 6#    export emailAddress=user@example.net
 7#
 8# To use this configuration as default:
 9#    export OPENSSL_CONF=./openssl-user.cnf
10#
11
12emailAddress    = $ENV::emailAddress
13HOME            = $ENV::HOME/.ssl
14RANDFILE        = $HOME/private/.rnd
15oid_section     = new_oids
16
17[ new_oids ]
18xmppAddr = 1.3.6.1.5.5.7.8.5
19
20[ req ]
21default_bits        = 2048
22default_keyfile     = $HOME/private/$emailAddress.key.pem
23encrypt_key         = yes
24default_md          = sha256
25req_extensions      = user_req_ext
26prompt              = no
27distinguished_name  = req_distinguished_name
28string_mask         = utf8only
29utf8                = yes
30
31[ user_req_ext ]
32keyUsage                = digitalSignature
33extendedKeyUsage        = clientAuth, emailProtection
34subjectKeyIdentifier    = hash
35subjectAltName          = @subj_alt_names
36
37[ req_distinguished_name ]
38countryName             = US
39stateOrProvinceName     = California
40localityName            = Los Angeles
41organizationName        = example.net
42Name                    = John Doe
43emailAddress            = $emailAddress
44
45[ subj_alt_names ]
46email       = $emailAddress
47otherName   = xmppAddr;UTF8:$emailAddress

Change the highlighted lines to your needs.

Make the configuration the default to use by OpenSSL:

$ export OPENSSL_CONF=~/.ssl/openssl-user.cnf

Certificate Signing Request

Create the personal certificate request and key:

$ openssl req -new -out ~/.ssl/$emailAddress.req.pem
Generating a 2048 bit RSA private key
.......................................+++
...............................+++
writing new private key to '/home/john/.ssl/john.doe@example.net.key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

Protect the private key:

$ chmod 400 ~/.ssl/private/$emailAddress.key.pem

Take a peek in the request:

$ openssl req -verify -in ~/.ssl/$emailAddress.req.pem \
    -noout -text -nameopt multiline \
    -reqopt no_version,no_pubkey,no_sigdump

Send the file ~/.ssl/john.doe@example.net.req.pem to the CA for signing.

Client Device Certificate

Client host certificates may be used to identify a particular device. I.e. to establish a connection to a VPN service. They might also include information about its owner.

In todays connected world, mobile devices are lost and stolen every day. By using certificates for devices instead of its owners, a single lost or stolen device can be locked out, without affecting other devices of the same person.

OpenSSL Configuration

Create a new OpenSSL configuration file ~/.ssl/openssl-client.cnf:

 1#
 2# OpenSSL configuration for generation of client certificate requests.
 3#
 4# To use this configuration as default:
 5#    export OPENSSL_CONF=./openssl-client.cnf
 6#
 7# Environment variables '$CN' and 'emailAddress' **MUST** be defined or else
 8# OpenSSL aborts:
 9#    export CN=${HOSTNAME}.example.net
10#    export emailAddress=user@example.net
11#
12
13emailAddress         = $ENV::emailAddress
14CN                   = $ENV::CN
15HOME                 = $ENV::HOME/.ssl
16RANDFILE             = $HOME/private/.rnd
17oid_section          = new_oids
18
19[ new_oids ]
20id-on-xmppAddr       = 1.3.6.1.5.5.7.8.5
21
22[ req ]
23default_bits          = 2048
24default_keyfile       = $HOME/private/$CN.key.pem
25encrypt_key           = yes
26default_md            = sha256
27req_extensions        = device_req_ext
28prompt                = no
29distinguished_name    = req_distinguished_name
30string_mask           = utf8only
31utf8                  = yes
32
33[ device_req_ext ]
34keyUsage              = digitalSignature
35extendedKeyUsage      = clientAuth
36subjectKeyIdentifier  = hash
37subjectAltName        = @subj_alt_names
38
39[ req_distinguished_name ]
40countryName           = US
41stateOrProvinceName   = California
42localityName          = Los Angelees
43commonName            = $CN
44name                  = John Doe
45emailAddress          = $emailAddress
46
47[ subj_alt_names ]
48DNS.1                 = $CN
49email                 = $emailAddress
50otherName             = xmppAddr;UTF8:$emailAddress

Change the highlighted lines to your needs.

Make the configuration the default to use by OpenSSL:

$ export OPENSSL_CONF=~/.ssl/openssl-client.cnf

Certificate Signing Request

Create the client device request:

$ openssl req -new -out ~/.ssl/$CN.req.pem
Generating a 2048 bit RSA private key
.......................................+++
...............................+++
writing new private key to '/home/john/.ssl/host.example.net.key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

Protect the private key:

$ chmod 400 ~/.ssl/private/$CN.key.pem

Take a peek in the request:

$ openssl req  -verify -in ~/.ssl/$CN.req.pem \
    -noout -text \
    -reqopt no_version,no_pubkey,no_sigdump \
    -nameopt multiline

Send the file ~/.ssl/host.example.net.req.pem to the CA for signing.

Using the Certificate

After the CA has verified and signed the certificate singing request you get a the certificate in a file like host.example.net.cert.pem.

To view the certificate:

$ openssl x509 -in $CN.cert.pem \
    -noout -text \
    -certopt no_version,no_pubkey,no_sigdump \
    -nameopt multiline

To verify the certificate:

$ openssl verify -issuer_checks -policy_print -verbose \
    -untrusted intermed-ca.cert.pem \
    -CAfile root-ca.cert.pem \
    certs/$CN.cert.pem