Some of my (and others) notes of managing PKI with the excellent openssl. Its simple and just works. To get going will create a root CA (Certificate Authority) and an intermediate signing CA. Using the CA's will issue three keypairs; one for email protection, one for TLS, and one for digital signatures. The digital signature keypair will be presented in the form of a CSR (Certificate Signing Request), as if generated by a third party that would like a keypair, signed by our CA hierarchy.

Content

Create the Root CA

First setup a neat directory tree, to keep things clear.

mkdir -p ca/root-ca/private ca/root-ca/db crl certs
chmod 700 ca/root-ca/private

Create the various CA database files, which must exist prior to using the openssl ca command. These are all referenced in the configuration file passed in to openssl, which we'll see shortly.

touch ca/root-ca/db/root-ca.db ca/root-ca/db/root-ca.db.attr
echo 01 > ca/root-ca/db/root-ca.crt.srl
echo 01 > ca/root-ca/db/root-ca.crl.srl

After this setup, should have a similar directory tree to this:

.
├── ca
│   └── root-ca
│       ├── db
│       │   ├── root-ca.db
│       │   └── root-ca.db.attr
│       └── private
├── certs
├── crl
├── email.conf
├── root-ca.conf
├── server.conf
└── signing-ca.conf

The Request (CSR)

Start by producing a new keypair, in the form of a Certificate Signing Request (CSR). A CSR, breaks out the private and public keys, so you can provide just the public key portion to another trusted party for signing. Once signed, and now part of a trust chain, you can combine the two pieces together again.

openssl req -new -config root-ca.conf -out ca/root-ca.csr -keyout ca/root-ca/private/root-ca.key

Refer to root-ca.conf below.

The Certificate

Using the ca command, can now issue a root CA based on the CSR. The root certificate is self signed, and is the base of all trust relationships in the PKI.

openssl ca -selfsign -config root-ca.conf -in ca/root-ca.csr -out ca/root-ca.crt -extensions root_ca_ext

Create the Intermediate CA

A very similar procedure for the root CA. Some setup:

mkdir -p ca/signing-ca/private ca/signing-ca/db crl certs
chmod 700 ca/signing-ca/private

And the the files (databases) themselves:

touch ca/signing-ca/db/signing-ca.db ca/signing-ca/db/signing-ca.db.attr
echo 01 > ca/signing-ca/db/signing-ca.crt.srl
echo 01 > ca/signing-ca/db/signing-ca.crl.srl

The Request (CSR)

As for the root CA, spawn a new keypair in the form of a CSR:

openssl req -new -config signing-ca.conf -out ca/signing-ca.csr -keyout ca/signing-ca/private/signing-ca.key

Refer to signing-ca.conf below.

The Certificate

Again use the ca command to issue a certificate based on a CSR.

openssl ca -config root-ca.conf -in ca/signing-ca.csr -out ca/signing-ca.crt -extensions signing_ca_ext

Notes:

  • Configure against the root CA root-ca.conf, which is signing the intermediate signing CA CSR.
  • The signing_ca_ext extension is used, as opposed to the root_ca_ext used earlier, and is defined as a section in root-ca.conf (see below)

signing_ca_ext:

[ signing_ca_ext ]
keyUsage = critical,keyCertSign,cRLSign
basicConstraints = critical,CA:true,pathlen:0
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always

Create Working Certificates

Email Protection Certificate

The Request (CSR)

The req -new command to create a new keypair (in the form of a CSR).

openssl req -new -config email.conf -out certs/ben-email.csr -keyout certs/ben-email.key

Generating a 2048 bit RSA private key
..+++
.............+++
writing new private key to 'certs/ben-email.key'
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.
-----
1. Domain Component (DC=net)       []:DC=net
2. Domain Component (DC=bencode)   []:DC=bencode
3. Domain Component (DC=pki)       []:DC=pki
4. Organization Name (O=bEncode Labs)   []:O=bEncode Labs
5. Organizational Unit Name (OU=section)   []:
6. Common Name (CN=Benjamin Simmonds) []:CN=Benjamin Simmonds
7. Email Address (emailAddress=ben@bencode.net) []:emailAddress=ben@bencode.net

Refer to email.conf below.

The Certificate

Here's where it all comes together. Given the email CSR from above, will now attempt sign it using the Intermediate Signing CA that was setup earlier.

openssl ca -config signing-ca.conf -in certs/ben-email.csr -out certs/ben-email.crt -extensions email_ext

Note that the signing CA config signing-ca.conf is used.

The extension email_ext is defined as a section in signing-ca.conf as follows, which stamps the certificate with certain usage properties relating to email validation and signing.

[ email_ext ]
keyUsage = critical,digitalSignature,keyEncipherment
basicConstraints = CA:false
extendedKeyUsage = emailProtection,clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always

TLS Server Certificate

The Request (CSR)

Almost identical, but with some different usage properties. Note you can read environment variables within the OpenSSL configuration for example $ENV::SAN reads the SAN variable.

SAN=DNS:www.bencode.net
openssl req -new -config tls-server.conf -out certs/bencode.net.csr -keyout certs/bencode.net.key

Refer to tls-server.conf below.

The Certificate

Use the signing CA to issue the TLS server certificate.

openssl ca -config signing-ca.conf -in certs/bencode.net.csr -out certs/bencode.net.crt -extensions server_ext

Output Formats

OpenSSL supports a range of standard formats, including DER and PKCS#7 and PKCS#12 (standards based version of Microsoft's PFX).

DER (RFC2585) Certificate

openssl x509 -in certs/ben-email.crt -out certs/ben-email.cer -outform der

DER (RFC2585) CRL (Revocation List)

Using the gencrl command to create a CRL, that is all revoked, but not yet expired certificates.

Tip: A new CRL must be generated at regular intervals.

openssl ca -gencrl -config signing-ca.conf -out crl/signing-ca.crl
cat crl/signing-ca.crl 
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQUFADCBiTETMBEGCgmSJomT8ixkARkWA25l
dDEXMBUGCgmSJomT8ixkARkWB2JlbmNvZGUxFTATBgNVBAoMDGJFbmNvZGUgTGFi
...

This can be converted to DER by:

openssl crl -in crl/signing-ca.crl -out crl/signing-ca.crl -outform der
cat crl/signing-ca.crl 
0��10H��
...

PKCS#12 (p12) Bundle

A standards, cleaned up version of Microsofts PFX format. Typically used for bundling a certificate and its private key. Additional certificates (e.g. those needed to build the trust chain up to the Root CA) can be included. For example:

cat ca/signing-ca.crt ca/root-ca.crt certs/ben-email.crt > certs/ben-email-with-chain.pem
openssl pkcs12 -export -name "Ben Simmonds" -inkey certs/ben-email.key -in certs/ben-email-with-chain.pem -out certs/ben-email.p12
Enter pass phrase for certs/ben-email.key:
Enter Export Password:
Verifying - Enter Export Password:

PEM Bundle

Super simple. Involves concatenating other PEM formatted files together. This could be the trust chain certificates, or the private key and its certificate, or the private key its certificate and the trust chain certificates, or any other combination.

The trust chain of CA certificates:

cat ca/signing-ca.crt ca/root-ca.crt > ca/signing-ca-chain.pem

The private key and certificate:

cat certs/ben-email.key certs/ben-email.crt > certs/ben-email.pem

Viewing Artifacts

CSR (Signing Request)

openssl req -in certs/ben-email.csr -noout -text

DER Certificate

openssl x509 -in certs/ben-email.cer -noout -text -inform der

CRL (Revocation List)

openssl crl -in crl/signing-ca.crl -inform der -noout -text

PKCS#12 Bundle

openssl pkcs12 -in certs/ben-email.p12 -nodes -info

Enter Import Password:
MAC:sha1 Iteration 2048
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Bag Attributes
    localKeyID: 4E CB 73 0B 90 E7 A4 6E 15 27 BD 3B B7 03 33 1A 8A C9 CF 88 
    friendlyName: Ben Simmonds
subject=/DC=net/DC=bencode/O=bEncode Labs/CN=Benjamin Simmonds
issuer=/DC=net/DC=bencode/O=bEncode Labs/OU=bEncode Labs Signing CA/CN=bEncode Labs Signing CA
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBATANBgkqhkiG9w0BAQUFADCBiTETMBEGCgmSJomT8ixk

Configuration Files

root-ca.conf

{% highlight ini %}

Root CA OpenSSL Configuration

Original source : https://pki-tutorial.readthedocs.io/en/latest/simple/root-ca.conf.html

The [default] section contains global constants that can be referred to from

the entire configuration file.

[ default ] ca = root-ca # CA name dir = . # Top dir

The next part of the configuration file is used by the openssl req command.

It defines the CA's key pair, its DN, and the desired extensions for the CA

certificate.

[ req ] default_bits = 2048 # RSA key size encrypt_key = yes # Protect private key default_md = sha1 # MD to use utf8 = yes # Input is UTF-8 string_mask = utf8only # Emit UTF-8 strings prompt = no # Don't prompt for DN distinguished_name = ca_dn # DN section req_extensions = ca_reqext # Desired extensions

[ ca_dn ] 0.domainComponent = “net” 1.domainComponent = “bencode” organizationName = “bEncode Labs” organizationalUnitName = “bEncode Labs Root CA” commonName = “bEncode Labs Root CA”

[ ca_reqext ] keyUsage = critical,keyCertSign,cRLSign basicConstraints = critical,CA:true subjectKeyIdentifier = hash

The remainder of the configuration file is used by the openssl ca command.

The CA section defines the locations of CA assets, as well as the policies

applying to the CA.

[ ca ] default_ca = root_ca # The default CA section

[ root_ca ] certificate = $dir/ca/$ca.crt # The CA cert private_key = $dir/ca/$ca/private/$ca.key # CA private key new_certs_dir = $dir/ca/$ca # Certificate archive serial = $dir/ca/$ca/db/$ca.crt.srl # Serial number file crlnumber = $dir/ca/$ca/db/$ca.crl.srl # CRL number file database = $dir/ca/$ca/db/$ca.db # Index file unique_subject = no # Require unique subject default_days = 3652 # How long to certify for default_md = sha1 # MD to use policy = match_pol # Default naming policy email_in_dn = no # Add email to cert DN preserve = no # Keep passed DN ordering name_opt = ca_default # Subject DN display options cert_opt = ca_default # Certificate display options copy_extensions = none # Copy extensions from CSR x509_extensions = signing_ca_ext # Default cert extensions default_crl_days = 365 # How long before next CRL crl_extensions = crl_ext # CRL extensions

Naming policies control which parts of a DN end up in the certificate and

under what circumstances certification should be denied.

[ match_pol ] domainComponent = match # Must match ‘bencode.net’ organizationName = match # Must match ‘bEncode Labs’ organizationalUnitName = optional # Included if present commonName = supplied # Must be present

[ any_pol ] domainComponent = optional countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = optional emailAddress = optional

Certificate extensions define types of certificates the CA can create

[ root_ca_ext ] keyUsage = critical,keyCertSign,cRLSign basicConstraints = critical,CA:true subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always

[ signing_ca_ext ] keyUsage = critical,keyCertSign,cRLSign basicConstraints = critical,CA:true,pathlen:0 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always

CRL extensions point to the CA certificate that has issued the CRL

[ crl_ext ] authorityKeyIdentifier = keyid:always {% endhighlight %}

signing-ca.conf

{% highlight ini %}

Intermediate Signing CA OpenSSL Configuration

Original source: https://pki-tutorial.readthedocs.io/en/latest/simple/signing-ca.conf.html

The [default] section contains global constants that can be referred to from

the entire configuration file. It may also hold settings pertaining to more

than one openssl command.

[ default ] ca = signing-ca # CA name dir = . # Top dir

The next part of the configuration file is used by the openssl req command.

It defines the CA's key pair, its DN, and the desired extensions for the CA

certificate.

[ req ] default_bits = 2048 # RSA key size encrypt_key = yes # Protect private key default_md = sha1 # MD to use utf8 = yes # Input is UTF-8 string_mask = utf8only # Emit UTF-8 strings prompt = no # Don't prompt for DN distinguished_name = ca_dn # DN section req_extensions = ca_reqext # Desired extensions

[ ca_dn ] 0.domainComponent = “net” 1.domainComponent = “bencode” organizationName = “bEncode Labs” organizationalUnitName = “bEncode Labs Signing CA” commonName = “bEncode Labs Signing CA”

[ ca_reqext ] keyUsage = critical,keyCertSign,cRLSign basicConstraints = critical,CA:true,pathlen:0 subjectKeyIdentifier = hash

The remainder of the configuration file is used by the openssl ca command.

The CA section defines the locations of CA assets, as well as the policies

applying to the CA.

[ ca ] default_ca = signing_ca # The default CA section

[ signing_ca ] certificate = $dir/ca/$ca.crt # The CA cert private_key = $dir/ca/$ca/private/$ca.key # CA private key new_certs_dir = $dir/ca/$ca # Certificate archive serial = $dir/ca/$ca/db/$ca.crt.srl # Serial number file crlnumber = $dir/ca/$ca/db/$ca.crl.srl # CRL number file database = $dir/ca/$ca/db/$ca.db # Index file unique_subject = no # Require unique subject default_days = 730 # How long to certify for default_md = sha1 # MD to use policy = match_pol # Default naming policy email_in_dn = no # Add email to cert DN preserve = no # Keep passed DN ordering name_opt = ca_default # Subject DN display options cert_opt = ca_default # Certificate display options copy_extensions = copy # Copy extensions from CSR x509_extensions = email_ext # Default cert extensions default_crl_days = 7 # How long before next CRL crl_extensions = crl_ext # CRL extensions

Naming policies control which parts of a DN end up in the certificate and

under what circumstances certification should be denied.

[ match_pol ] domainComponent = match # Must match ‘bencode.net’ organizationName = match # Must match ‘bEncode Labs’ organizationalUnitName = optional # Included if present commonName = supplied # Must be present

[ any_pol ] domainComponent = optional countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = optional emailAddress = optional

Certificate extensions define types of certificates the CA can create

[ email_ext ] keyUsage = critical,digitalSignature,keyEncipherment basicConstraints = CA:false extendedKeyUsage = emailProtection,clientAuth subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always

[ server_ext ] keyUsage = critical,digitalSignature,keyEncipherment basicConstraints = CA:false extendedKeyUsage = serverAuth,clientAuth subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always

CRL extensions point to the CA certificate that has issued the CRL

[ crl_ext ] authorityKeyIdentifier = keyid:always {% endhighlight %}

email.conf

{% highlight ini %}

Email Protection Certificate OpenSSL Configuration

[ req ] default_bits = 2048 # RSA key size encrypt_key = yes # Protect private key default_md = sha1 # MD to use utf8 = yes # Input is UTF-8 string_mask = utf8only # Emit UTF-8 strings prompt = no # Prompt for DN distinguished_name = naming_section # DN template req_extensions = extensions_section # Desired extensions

[ naming_section ] 0.domainComponent = “net” 1.domainComponent = “bencode” organizationName = “bEncode Labs” commonName = “Benjamin Simmonds” emailAddress = “ben@bencode.net

[ extensions_section ] keyUsage = critical,digitalSignature,keyEncipherment extendedKeyUsage = emailProtection,clientAuth subjectKeyIdentifier = hash subjectAltName = email:move {% endhighlight %}

tls-server.conf

{% highlight ini %}

TLS server certificate request OpenSSL Configuration

This file is used by the openssl req command. The subjectAltName cannot be

prompted for and must be specified in the SAN environment variable.

[ default ] SAN = DNS:www.bencode.net # Default value

[ req ] default_bits = 2048 # RSA key size encrypt_key = no # Protect private key default_md = sha1 # MD to use utf8 = yes # Input is UTF-8 string_mask = utf8only # Emit UTF-8 strings prompt = yes # Prompt for DN distinguished_name = server_dn # DN template req_extensions = server_reqext # Desired extensions

[ server_dn ] 0.domainComponent = “net” 1.domainComponent = “bencode” organizationName = “bEncode Labs” commonName = “www.bencode.net"

[ server_reqext ] keyUsage = critical,digitalSignature,keyEncipherment extendedKeyUsage = serverAuth,clientAuth subjectKeyIdentifier = hash subjectAltName = $ENV::SAN {% endhighlight %}

Key usage extensions

Key usage extension Description
Digital signature Use when the public key is used with a digital signature mechanism to support security services other than non-repudiation, certificate signing, or CRL signing. A digital signature is often used for entity authentication and data origin authentication with integrity.
Non-repudiation Use when the public key is used to verify digital signatures used to provide a non-repudiation service. Non-repudiation protects against the signing entity falsely denying some action (excluding certificate or CRL signing).
Key encipherment Use when a certificate will be used with a protocol that encrypts keys. An example is S/MIME enveloping, where a fast (symmetric) key is encrypted with the public key from the certificate. SSL protocol also performs key encipherment.
Data encipherment Use when the public key is used for encrypting user data, other than cryptographic keys.
Key agreement Use when the sender and receiver of the public key need to derive the key without using encryption. This key can then can be used to encrypt messages between the sender and receiver. Key agreement is typically used with Diffie-Hellman ciphers.
Certificate signing Use when the subject public key is used to verify a signature on certificates. This extension can be used only in CA certificates.
CRL signing Use when the subject public key is to verify a signature on revocation information, such as a CRL.
Encipher only Use only when key agreement is also enabled. This enables the public key to be used only for enciphering data while performing key agreement.
Decipher only Use only when key agreement is also enabled. This enables the public key to be used only for deciphering data while performing key agreement.

Digital Signatures - how they work

This does have an XML flavour to it.

To validate (i.e. to prove)

  1. First the message can be normalised, and in the case of XML will use something like the “Exclusive XML Canonicalization” (XML-C14N), so we're comparing apples with apples. This will disgard things like usage of white space.
  2. Using the normalised representation, compute a hash (e.g. SHA1) of the timestamp (contained WS-Security header) and entire message payload (the SOAP body).
  3. Using the public key from the partner organisation certificate, RSA decrypt the hash computed by partner organisation.
  4. If the two hashes are identical, we know the message has not been tampered with.
  5. (optional) Validate the timestampt (TTL) defined by partner organisation (typically 7 minutes).

To sign (i.e. to create)

  1. Wraps the response message in a SOAP envelope, which includes some WS-Security related headers including a timestamp.
  2. The timestamp is set to a configurable number of minutes (e.g. 10 minutes) in the future.
  3. Normalises the message using the “Exclusive XML Canonicalization” (XML-C14N)
  4. Using the noramlised message, computes a (e.g. SHA1) hash of the timestamp (WS-Security header) and entire response message payload (e.g. the SOAP body).
  5. Uses the private key of signing certificate, RSA signs the computed hash, and stores the result in the relevant security header (the SignatureValue header).
  6. The message is then delivered to partner organisation.

References

OpenSSL PKI Tutorial

IBM Knowledge Center: Key usage extensions and extended key usage