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
- Create the Intermediate CA
- Create Working Certificates
- Output Formats
- Viewing Artifacts
- Configuration Files
- Key usage extensions
- References
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 theroot_ca_ext
used earlier, and is defined as a section inroot-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)
- 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.
- Using the normalised representation, compute a hash (e.g. SHA1) of the timestamp (contained WS-Security header) and entire message payload (the SOAP body).
- Using the public key from the partner organisation certificate, RSA decrypt the hash computed by partner organisation.
- If the two hashes are identical, we know the message has not been tampered with.
- (optional) Validate the timestampt (TTL) defined by partner organisation (typically 7 minutes).
To sign (i.e. to create)
- Wraps the response message in a SOAP envelope, which includes some WS-Security related headers including a timestamp.
- The timestamp is set to a configurable number of minutes (e.g. 10 minutes) in the future.
- Normalises the message using the “Exclusive XML Canonicalization” (XML-C14N)
- 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).
- Uses the private key of signing certificate, RSA signs the computed hash, and stores the result in the relevant security header (the SignatureValue header).
- The message is then delivered to partner organisation.
References
IBM Knowledge Center: Key usage extensions and extended key usage