2 Setting Up TLS/SSL with OpenSSL

This chapter describes the OpenSSL tools that are available in Oracle Linux and how to use them to create Certificate Signing Requests (CSRs), self-signed certificates, and privately owned CA certificates. Also covered in this chapter are instructions on how to use the OpenSSL tools to validate and test certificates that are configured for a protocol to confirm that services are configured correctly.

Features of the openssl Command

With the openssl command, which is included in the openssl package, you can perform a wide range of cryptography functions from the OpenSSL library, including the following:

  • Create and managing pairs of private and public keys.

  • Perform public key cryptographic operations.

  • Create self-signed certificates.

  • Create certificate signing requests (CSRs).

  • Create certificate revocation lists (CRLs).

  • Convert certificate files between various formats.

  • Calculate message digests.

  • Encrypt and decrypt files.

  • Test client-side and server-side TLS/SSL with HTTP and SMTP servers.

  • Verify, encrypt, and sign S/MIME email.

  • Generate and test prime numbers and generate pseudo random data.

Creating Key Pairs

As a first step to use any form of public key cryptography, create a public/private key pair. You can then use the private key to create a Certificate Signing Request (CSR) that contains the associated a public key. The CSR can be used to obtain a signed certificate from a CA. Typically, the steps to create a key pair and a CSR or a self-signed certificate, are performed as a single-step operation when using OpenSSL to generate these files.

In the following instructions and example, the creation of a key pair is treated as an atomic operation so that the process can be described and elements can be called out for better understanding. Usually, this step is incorporated into other commands for efficiency.

The following are the main elements that you need to consider when creating a key pair:

  • Algorithm

    OpenSSL provides the use of RSA and ECDSA key algorithms, with RSA keys being the most widely used. While DSA keys can be created, these must not be used unless required. ECDSA is a modern variant that provides much smaller and efficient key sizes than both RSA or DSA, along with corresponding security. ECDSA might be a good choice for performance. However, be aware that some environments might not recognize ECDSA keys.

  • Key Size

    The key size checks the complexity of the key for the algorithm, which is specified in bits. Bigger-sized keys are more secure because they're more complex and harder to decipher. Bigger-sized keys also come with a performance hit, because each decryption bit requires more memory and processing to complete. Therefore, selecting a key size is a balance between security and performance. Key sizes are complex, in that they relate to the algorithms and ciphers that are being used. In general, when creating RSA keys, a key size is 2048 bits, while ECDSA keys provide similar security using a key size of 256 bits.

  • Passphrase

    When creating a key that's encrypted and protected with a cipher, you're prompted for a passphrase that can be used to validate that you can use the key. Encrypting a key with a passphrase is optional but recommended. Using a passphrase with a key can be problematic when TLS is enabled for a system service, as the service can't be automatically restarted without user intervention. Often, where certificates are issued for services; for convenience, they're created without passphrases. If a private key is created without a passphrase, be aware that anyone who gains access to the private key file can emulate services to perform man-in-the-middle type snooping. When a key is protected with a passphrase, you can select a cipher algorithm to use to encrypt the contents of the private key. Many ciphers are available for this purpose. To obtain a complete list of ciphers, use the openssl list-cipher-commands command. The AES cipher is commonly used for this purpose and is typically specified with a key size of 128 or 256 (aes128 or aes256).

To generate an RSA key, use the openssl genrsa command, for example:

sudo openssl genrsa -out private.key 2048

Generating RSA private key, 2048 bit long modulus
...................................................
....................................................
...................................................+++
................................+++
e is 65537 (0x10001)

This command generates an unencrypted key in the local directory, named private.key. The contents of the key look similar to the following example:

cat private.key

-----BEGIN RSA PRIVATE KEY-----
...[certificate text]
-----END RSA PRIVATE KEY-----

Note that even though the file is called private.key and the file contains some text that suggests that this is only the private key, the public key is also embedded within this file. So the single file represents the complete key pair. Thus, obtaining a copy of the public key is easier because the key is stored on the same file as the private key.

To create an encrypted key with a passphrase, run the same command but specify a cipher to use to encrypt the key with, for example:

sudo openssl genrsa -aes256 -out private.key 2048

Generating RSA private key, 2048 bit long modulus
............+++
.............................................................+++
e is 65537 (0x10001)
Enter pass phrase for private.key:
Verifying - Enter pass phrase for private.key:

In the previous example, the AES cipher is used with a 256 bit key. The command prompts you to enter a passphrase and verify it. The contents of the key file indicate that the key is encrypted, as shown in the following example:

cat private.key

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,2417E359B45960CD107A390748945752

key-content
-----END RSA PRIVATE KEY-----

If you create an encrypted key file and then decide that you would prefer a file that's not encrypted or doesn't require a passphrase, you can decrypt it by running the following command:

sudo openssl rsa -in private.key -out unencrypted.key

Enter pass phrase for private.key:
writing RSA key

You're prompted for the passphrase on the encrypted key, which is stored in private.key, and the unencrypted version of the same key is written to the file unencrypted.key.

All OpenSSL keys are generated in Privacy Enhanced Mail (PEM) format, which is a plain text format that encapsulates the content of the key as a base64 encoded string. Certificates can be encoded by using several different formatting conventions. For more information about changing the format of a certificate, see Changing Key or Certificate Format.

You can view the contents of a private key as follows:

sudo openssl rsa -text -in private.key

Notably, a private key also contains its public key counterpart. This public key component is used when submitting a CSR or when creating a self-signed certificate. The public key component can be viewed by using the following command:

sudo openssl rsa -pubout -in private.key

Creating Certificate Signing Requests With OpenSSL

A private key can be used to create a Certificate Signing Request (CSR). A public and private key can be used to encrypt communications. However, a client must still validate the public certificate presented for use with encrypted communication as coming from an expected and trusted source. Without some way to validate the public key, the client can easily succumb to man-in-the-middle style attacks that would render encryption futile.

To solve this problem, public key infrastructure typically involves third parties, called Certification Authorities (CAs), that can sign a certificate as authentic for a particular public key. If the client has a copy of the CA certificate, the client can validate a certificate for a domain, based on the signature in the certificate. Most systems are installed with some trusted CA certificates by default. To check the CA certificates that are trusted by the system, use the following command:

sudo openssl version -d

By default, this directory is /etc/pki/tls and the /etc/pki/tls/certs subdirectory contains all the trusted certificates.

To obtain a signed certificate from a CA, a CSR must be generated using the public key component within its associated private key. The CSR is then presented to the CA which can validate the information in the request and use this information to generate a valid and signed public certificate. The CSR is associated with a domain name for the host or hosts on which the certificate is be used. The CA uses this information to create a certificate with a specified expiry date.

The following example shows the command syntax for interactively creating a CSR from a private key:

sudo openssl req -new -key private.key -out domain.example.com.csr

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) [XX]:GB
State or Province Name (full name) []:.
Locality Name (eg, city) [Default City]:London
Organization Name (eg, company) [Default Company Ltd]:Example Ltd
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:domain.example.com
Email Address []:webmaster@example.com

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

Note that the default values can be configured in the /etc/pki/tls/openssl.cnf file. The Common Name is the most important value in the CSR. This value associates the certificate request with the hostname and domain name for the host on which the certificate is to be used. Note that if a client connects to a host that's issued a certificate for a different domain, the certificate is invalid.

You can generate a CSR and private key at the same time. With the following command, you can specify values for the different fields in the CSR on the command line:

sudo openssl req -new -nodes '/CN=domain.example.com/O=Example Ltd/C=GB/L=London' \
  -newkey rsa:1024 -keyout private.key -out domain.example.com.csr

You can view the information contained in a CSR as follows:

sudo openssl req -in domain.example.com.csr -noout -text

After you have a CSR, you can submit it to a CA. The CA uses the CSR to generate a signed certificate and then returns the certificate with a certificate chain that can be used to validate the certificate.

Signing Certificates With OpenSSL

For environments where you don't have control over client systems, always use a recognized, independent CA to sign certificates. Operating system and software vendors negotiate with independent CAs to include CA validation certificates, along with the software that they distribute. Obtaining validation certificates from major CA providers means that most users don't have to manage their own trusted CA certificate list. Any browser visiting a website over HTTPS can validate the site's public certificate by matching the CA signature to the CA certificates that it has in its own store.

If you have control over client systems, you can either provide the clients with the self-signed certificate, directly; or, you can set up private CA certificate to sign all the certificates that are used within the organization and then distribute the CA certificate to clients. Using the second approach validates all certificates that are signed within the organization, which results in tighter control over the security of the certificates within the organization, which can result in lower infrastructure costs.

Creating Self-Signed Certificates for Testing and Development

Self-signed certificates are often created for development and testing purposes. Because these certificates are not validated by trusted CAs, trust for these certificates need to be configured manually. If the private key is compromised it can't be revoked but must be manually removed from trust allow list. Never use these certificates in production environments. A CA-signed certificate is always preferable to a self-signed certificate. However, using self-signed certificates can be less costly and useful for testing and development, without the hassle of managing private CA or obtaining CA-signed certificates for every test platform.

With the openssl command, you can generate self-signed certificates that can be used immediately. This command creates a CSR for the private key and then generates an X.509 certificate directly from the CSR, signing the certificate with itself.

For this reason, the command is similar to the command that you would run to create a private key and CSR, with the exception that you must also specify the period of validity. As a good practice, only generate a self-signed certificate for the duration needed for testing purposes. This way, if the private key is compromised, the validity period is limited, and a new certificate can be generated when the old certificate expires.

For example, you would use the following command to create a self-signed X.509 certificate that's valid for 30 days.

sudo openssl req -new -x509 -days 30 -nodes -newkey rsa:2048 -keyout private.key \ 
  -out public.cert -subj '/C=US/ST=Ca/L=Sunnydale/CN=www.example.com'

The generated private.key file contains the private key and the public.cert file contains the self-signed certificate. Typically, you name these files with the same value as the Common Name so that you can track which certificates and keys apply to which host and domain name.

Note that you can set the -newkey value to suit custom algorithm and key size requirements. In this example, the algorithm is set to RSA and the key size is set at 2048 bits.

You can copy the self-signed certificate file to the trusted certificate store for any client system and the client system validates the certificate as a match whenever it makes a connection to the host that serves it.

You can also use the keytool command to generate self-signed certificates, but this command's primary purpose is to install and manage JSSE (Java Secure Socket Extension) digital certificates for use with Java applications. See Java for more information.

Creating a Private Certification Authority

By creating a private Certification Authority (CA), you can process CSRs for all the certificates within the organization. You're also capable of managing the Certificate Revocation List (CRL), which client systems can use to detect whether a certificate is still valid or if it has been revoked.

This approach is better than using self-signed certificates because you can control revocation. However, the CA certificate must still be distributed to all the client systems that need to validate public certificates within the organization.

Create the CA Root

The CA Root is the fundamental certificate for a CA and is not usually used to sign server or client certificates. The CA Root is usually used to sign one or more intermediary certificates to grant them power to sign other certificates. This model means that if a CA Intermediary private key is compromised, the CA Intermediary can be added to a certificate revocation list and all of the certificates that are signed by the Intermediary are automatically invalidated.

This model helps to protect the integrity of the entire public key infrastructure. Without a CA Root, there is no public key infrastructure, as the CA Root is used to create the chain of trust that is used to validate all certificates in the hierarchy. The CA Root should generally be created and maintained on a system that is completely isolated, ideally with minimal or no network access and no direct access to the Internet. The security measures that are implemented around the CA Root are critical to the security of the entire public key infrastructure. If the CA Root private key is compromised, every certificate that is ever signed by the entire chain may be compromised as well.

To create a CA Root for your organization, you must create a root key pair according to a defined configuration that OpenSSL can use to manage the CA configuration and the database of metadata for certificates that it issues.

There are several steps that you need to take to create the CA Root, which are described in the following procedures and examples.

Create a CA Directory Structure

All of the certificates and metadata that are managed by the CA Root are stored in a specific directory structure and within some preconfigured files. You should create the structure according to your own requirements, but follow these general steps:

  1. Create a directory to store all of the CA-related data:

    sudo mkdir /root/ca
                                  

    You can store this directory anywhere on the system. However, keep in mind that it contains very sensitive data, so ensure that it is located somewhere with very restricted access.

  2. Change to the CA directory to perform all of the subsequent steps in this procedure:

    sudo cd /root/ca
                                  
  3. Create directories to contain the following for your system: CA certificates, CA database content, Certificate Revocation List, all newly issued certificates, and your private keys:

    sudo mkdir certs db crl newcerts private
  4. Protect your private keys to ensure that access to the directory where these are stored is limited to the current user:

    sudo chmod 700 private
  5. Create the files that will be used for your CA database:

    sudo touch db/index.txt
    sudo openssl rand -hex 16  > db/serial
    sudo echo 1001 |sudo tee  db/crlnumber
Create a CA Root Configuration File

The CA Root configuration should be created and stored in the directory where all of the CA related content is stored. For example, you would create a file in /root/ca/ca-root.conf and populate it with the following content:

[default]
name                    = root-ca
domain_suffix           = example.com
aia_url                 = http://$name.$domain_suffix/$name.crt
crl_url                 = http://$name.$domain_suffix/$name.crl
ocsp_url                = http://ocsp.$name.$domain_suffix:9080
default_ca              = ca_default
name_opt                = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
countryName             = "AU"
organizationName        = "Example Org"
commonName              = "Root CA"

[ca_default]
home                    = .
database                = $home/db/index.txt
serial                  = $home/db/serial
crlnumber               = $home/db/crlnumber
certificate             = $home/$name.crt
private_key             = $home/private/$name.key
RANDFILE                = $home/private/random
new_certs_dir           = $home/certs
unique_subject          = no
copy_extensions         = none
default_days            = 3650
default_crl_days        = 30
default_md              = sha256
policy                  = policy_strict

[policy_strict]
# The root CA should only sign intermediary certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[policy_loose]
# Allow the intermediary CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` manual page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[req]
# Standard Req options
default_bits            = 4096
encrypt_key             = yes
default_md              = sha256
utf8                    = yes
string_mask             = utf8only
prompt                  = no
distinguished_name      = ca_dn
req_extensions          = ca_ext

[ca_ext]
# Extensions for a the CA root (`man x509v3_config`).
basicConstraints        = critical,CA:true
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash

[intermediary_ext]
# Extensions for an intermediary CA.
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[server_ext]
# Extensions for server certificates.
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[client_ext]
# Extensions for client certificates.
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[crl_ext]
# Extension for CRLs.
authorityKeyIdentifier=keyid:always

[ocsp]
# Extension for OCSP signing certificates.
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

The previous example shows a configuration that contains many optional entries that can help when performing different operations with OpenSSL. Most importantly, the configuration defines the extensions that can be applied to different certificate types to validate the types of operations the are valid for the certificate. This configuration also defines different policies that can be applied when signing certificates. For instance, you can use a strict policy to ensure that a particular metadata is specified; and, that it matches the CA values within a CSR, if the certificate is to be signed. This policy is important for generating intermediary CA certificates. A less restrictive policy can be applied for other certificates that are signed, either by the CA Root or any intermediary.

The following are descriptions of the various sections within this configuration file:

  • [default]

    The default section defines some basic configuration information such as URLs where information such as the root certificate and the published revocation list for this CA might be published. Note that the name and domain_suffix entries here are used as variables to help construct some of these URLs and are also used to name and reference key files and certificates. You may wish to use the system hostname and the system domain for these values. This configuration entry also references the location of the default CA configuration entry at ca_default.

  • [ca_dn]

    This section defines some default values for certificates that are generated for this CA's distinguished name. These values are written into the CSR and the self-signed certificate that is generated from it for the CA Root certificate.

  • [ca_default]

    This section provides the configuration that controls the entire CA. This information provided maps the directories that were created for this CA to the configuration so that OpenSSL can correctly update files and store certificates and keys in the correct places. This section also defines some default values such as how many days a certificate is valid for and how many days the certificate revocation list is valid. Because this configuration is for a root CA, the number of days that the certificate is valid for can be set to 10 years, since a change to the root CA would mean that all of subsequent certificates in the infrastructure would also need to be re-issued. You can view all of the configuration file options in the CA(1) manual pages.

  • [policy_strict]

    This section describes a strict policy that should be followed when signing some certificates, such as the intermediary CA certificates. The policy defines rules around the metadata within the certificate. For instance, there are rules that the country name and organizational name match the CA certificate. Other fields are optional, but a common name must be supplied.

  • [policy_loose]

    This section is used for other certificates that are signed by this CA and its intermediaries, where a less restrictive policy is allowed. This policy entry allows the majority of fields to be optional and only requires that the common name is supplied.

  • [req]

    This section is used one time to create the CA certificate request and defines the default options to use when the certificate request is generated, for example, a key length of 4096 bits for the root CA. There is also an option that points to the CA distinguished name that references the ca_dn section of this configuration file for obtaining the default values to use within the certificate request.

  • [ca_ext]

    This extensions section defines those operations for which a certificate is valid. For the root CA, this certificate must be valid in order to sign all of the intermediary CA certificates and essentially has full rights. For more information about extensions, see the X509V3_CONFIG(5) manual page.

  • [intermediary_ext]

    This section is separate extension configuration for certificates that are signed as intermediary CAs. This certificate has the same rights as the root CA, but is unable to sign certificates for further intermediary CAs, controlled with the pathlen:0 within the certificate's basicConstraints option.

  • [server_ext]

    This section includes typical extension options for server-side certificates, which are usually used for services like HTTPS and server-side mail services, and so on. These certificates are issued for validation and encryption purposes; they do not have signing rights. The configuration entry can be referenced when signing a certificate for this purpose.

  • [client_ext]

    This section includes client-side certificates, which are often used for remote authentication, where a user may provide a certificate to validate and authenticate access to a system. These certificates also have specific extensions that control usage. This configuration entry can be used when signing a certificate for client side certificates to ensure that the correct extensions are applied to the certificate.

  • [crl_ext]

    This extension is automatically applied when creating a CRL, but this extension is provided for completeness. See Manage a Certificate Revocation List

  • [ocsp]

    The Online Certificate Status Protocol (OCSP) is an alternative approach to CRLs. An OCSP server can be set up to handle requests by client software to obtain the status of a certificate from a resource that is referenced in a signed certificate. Special extensions exist for this purpose. The OCSP(1) manual page can provide more information. See also Configure and Run an OCSP Server.

Create and Verify the CA Root Key Pair

Create a private key and a certificate signing request for the CA root using the configuration values that you have specified in the ca-root.conf file and save the private key to private/root-ca.key. Since this is the most valuable key in your entire infrastructure, ensure that you use a lengthy and suitable passphrase to protect it.

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

Now, create a self-signed certificate by using the CSR and the ca-root.conf file. Take care to specify that the certificate must use the extensions defined in the ca_ext portion of the configuration.

sudo openssl ca -selfsign -config ca-root.conf -in root-ca.csr -out root-ca.crt -extensions ca_ext

Using configuration from ca-root.conf
Enter pass phrase for ./private/root-ca.key:
Check that the request matches the signature
Signature ok
Certificate Details:
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8f:75:11:1a:8e:33:b2:d1:09:a8:bf:07:9c:67:c8:3e
        Issuer:
            countryName               = AU
            organizationName          = Example Org
            commonName                = Root CA
        Validity
            Not Before: Oct 29 12:23:04 2019 GMT
            Not After : Oct 26 12:23:04 2029 GMT
        Subject:
            countryName               = AU
            organizationName          = Example Org
            commonName                = Root CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
                Modulus:
                    00:b9:41:d6:10:36:d4:12:d3:5d:52:29:60:fc:e0:
                    90:34:f6:fb:3e:99:10:33:a1:1d:54:77:3c:11:37:
                    2d:78:c3:3c:3f:40:69:37:fc:de:59:20:c1:1c:07:
                    83:f7:ae:2b:19:03:a7:e8:c6:d6:88:03:b4:ec:60:
                    36:3d:f6:da:59:58:cc:18:18:3e:43:c9:79:11:5b:
                    cf:9e:15:a7:29:fe:dc:4f:7b:0b:93:f0:9a:2b:97:
                    0f:ab:3e:38:7c:e7:c7:d3:5e:34:e2:40:d0:fd:f2:
                    e4:5e:2c:8a:8e:11:83:de:6b:c4:5c:b8:ec:4b:9c:
                    d2:3f:06:3d:53:a6:4b:a6:e3:c6:f6:24:a2:8c:fb:
                    bf:9e:19:d7:60:4b:c5:b6:48:e4:5d:60:4f:2c:47:
                    ca:4a:31:79:bc:7b:5a:25:90:fc:d2:44:a1:79:73:
                    2e:e1:88:a0:73:1f:82:d3:63:3e:67:94:20:f8:be:
                    21:9b:c3:14:4d:3e:9b:19:33:be:9b:cb:e5:54:9f:
                    a7:3f:05:d1:64:56:5f:43:62:65:5b:89:f4:f1:e3:
                    24:e8:1c:d5:03:36:86:ce:9e:76:c7:52:dc:88:f5:
                    d9:87:62:00:82:4d:14:de:a3:60:21:54:12:83:da:
                    8e:8e:5f:63:c3:93:5a:e2:b9:60:16:74:06:c7:46:
                    49:6d:c2:7e:6c:3a:50:3b:bf:c5:d6:20:65:bd:21:
                    a9:ad:b2:1c:4c:13:bf:fd:b8:e1:04:b8:46:c9:6c:
                    29:db:f3:a6:50:3d:2b:9b:83:49:bb:61:c2:8e:94:
                    08:52:84:f2:6d:33:4b:1f:e0:90:ea:a8:ec:d6:ff:
                    97:b8:3d:74:9a:64:d0:f7:22:7d:22:fc:93:47:68:
                    54:63:7c:10:0a:82:2f:84:3f:56:28:cf:8a:03:76:
                    77:b9:db:af:02:6d:b9:36:7e:63:da:f5:d2:a5:6d:
                    54:86:e1:be:f0:e1:54:13:dd:63:0a:53:8e:55:24:
                    90:40:af:f6:38:47:d3:00:0c:ba:66:6a:cc:4b:df:
                    28:fe:02:74:eb:28:15:11:ca:da:a7:86:0f:1f:bd:
                    c4:ac:b9:b1:c7:cc:2a:2a:db:6e:fd:e6:8e:7b:02:
                    17:5e:a7:7d:08:53:e2:a4:69:ca:6b:1f:f1:74:5b:
                    ac:86:2a:f2:b0:80:ea:b7:30:c5:14:c8:12:1e:66:
                    5e:2f:f5:d5:a8:09:39:b4:23:25:fc:ca:35:d5:c0:
                    73:79:a0:8a:12:25:27:ee:f5:ce:9a:97:c0:27:31:
                    ac:21:98:8f:34:25:a5:7a:42:5c:a0:a1:5d:64:39:
                    aa:6a:5e:54:50:5e:ad:c4:fe:c7:93:b1:c0:f7:c9:
                    91:43:93
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Subject Key Identifier: 
                3C:D9:C3:56:BD:C0:45:83:C8:2B:C7:0F:96:30:CF:2A:55:23:B5:9D
Certificate is to be certified until Oct 26 12:23:04 2029 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

You are prompted for your private key passphrase to continue. After being shown the values of the certificate, you are prompted to sign the certificate. After signing the certificate, you can commit it to your CA database. The database files are updated to track this certificate within your public key infrastructure.

You can view the db/index.txt file to see the CA root certificate entry:

sudo cat db/index.txt

V   291026122304Z        8F75111A8E33B2D109A8BF079C67C83E  unknown /C=AU/O=Example Org/CN=Root CA

The values that are displayed on each line within the database index include:

  1. Status (V for valid, R for revoked, E for expired).

  2. Expiry date in YYMMDDHHMMSSZ format.

  3. Revocation date or empty if not revoked (in this example output, the field is empty).

  4. Hexadecimal serial number.

  5. File location or unknown, if not known.

  6. Distinguished name.

Create an intermediary CA

The next step in creating your infrastructure is to create an intermediary CA that can process all of your server and client certificates. This is important because if the intermediary CA private key is compromised, the root CA can revoke its certificate and invalidate any other certificate that has been issued by that intermediary.

The intermediary CA should ideally be hosted on an alternate server with wider access as it will be used to handle the majority of your certificate requests. The intermediary CA is an exact model of the root CA, with the exception that its own certificate is signed by the root CA and is configured with the appropriate extensions to process signing requests.

Create A CA Directory Structure

On the intermediary CA host, perform the same operations that you performed to create the root CA directory structure, but name the parent directory appropriately so that it is clear that the configuration is for an intermediary, for example:

sudo mkdir /root/ca-intermediary
sudo cd /root/ca-intermediary/
sudo mkdir certs db crl newcerts private
sudo chmod 700 private
sudo touch db/index.txt
sudo openssl rand -hex 16  > db/serial
sudo echo 1001 |sudo tee  db/crlnumber
Create the intermediary CA Configuration

The intermediary CA configuration is almost identical to the configuration that you created for the CA root, with a few modifications that make it specific to the intermediary. Modifications are indicated in bold text in the following example:

[default]
name                    = 
                              sub-ca
                           
domain_suffix           = example.com
aia_url                 = http://$name.$domain_suffix/$name.crt
crl_url                 = http://$name.$domain_suffix/$name.crl
ocsp_url                = http://ocsp.$name.$domain_suffix:9080
default_ca              = ca_default
name_opt                = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
countryName             = "AU"
organizationName        = "Example Org"
commonName              = "
                              Intermediary CA
                           "

[ca_default]
home                    = .
database                = $home/db/index.txt
serial                  = $home/db/serial
crlnumber               = $home/db/crlnumber
certificate             = $home/$name.crt
private_key             = $home/private/$name.key
RANDFILE                = $home/private/random
new_certs_dir           = $home/certs
unique_subject          = no
copy_extensions         = none
default_days            = 3650
default_crl_days        = 30
default_md              = sha256
policy                  = policy_strict

[policy_strict]
# The root CA should only sign intermediary certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[policy_loose]
# Allow the intermediary CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` manual page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[req]
# Standard Req options
default_bits            = 4096
encrypt_key             = yes
default_md              = sha256
utf8                    = yes
string_mask             = utf8only
prompt                  = no
distinguished_name      = ca_dn
req_extensions          = intermediary_ext

[ca_ext]
# Extensions for a the CA root (`man x509v3_config`).
basicConstraints        = critical,CA:true
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash

[intermediary_ext]
# Extensions for an intermediary CA.
subjectKeyIdentifier = hash
# authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[server_ext]
# Extensions for server certificates.
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[client_ext]
# Extensions for client certificates.
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[crl_ext]
# Extension for CRLs.
authorityKeyIdentifier=keyid:always

[ocsp]
# Extension for OCSP signing certificates.
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

Note that in the intermediary_ext section, a line has been commented out because the intermediary will not issue any further intermediary certificates. The intermediary is unaware of the certificate issuer until the certificate is signed. If you attempt to create the CSR while this line is still included in the configuration, it fails because it cannot determine which certificate issuer to include this metadata in the CSR.

Save the configuration file as intermediary.conf.

Create a CSR for the intermediary CA

Create a CSR for the intermediary certificate:

sudo openssl req -new -config intermediary.conf -out sub-ca.csr -keyout private/sub-ca.key

This certificate is also a signing certificate, so it is important to protect it with a passphrase to help prevent its unauthorized use and maintain the security of your infrastructure. Enter the passphrase when prompted.

Create a signed certificate for the intermediary CA

Copy the sub-ca.csr that you generated in the previous step to the /root/ca directory on the system where your root CA is hosted. On the root CA host, run the following commands to generate a signed certificate from the CSR and apply the intermediary signing extension:

sudo cd /root/ca
sudo openssl ca -config ca-root.conf -in sub-ca.csr -out newcerts/sub-ca.crt \
-extensions intermediary_ext

You are prompted for the root CA passphrase, then presented with the certificate content and prompted to sign it. Check that the certificate contents make sense before you sign it. You can see that the certificate is issued by the Root CA and contains the Intermediary CA in the Subject. You can also see that the correct extensions are applied to the certificate.

After the certificate is signed, you are prompted to update the database.

The newly signed certificate is created as newcerts/sub-ca.crt.

Create a certificate chain file

Because no systems are aware of the root CA certificate, you should create a certificate chain that includes the public certificate for the root CA with the newly created intermediary CA certificate. In this way, hosts only need a copy of the chained certificate to validate any certificates that are issued by the intermediary CA. To create the certificate chain, simply join the two public certificates by running the following command on the root CA host:

sudo cat root-ca.crt newcerts/sub-ca.crt > newcerts/chained-sub-ca.crt
sudo chmod 444 newcerts/chained-sub-ca.crt

Copy the newcerts/sub-ca.crt and newcerts/chained-sub-ca.crt certificate back to the /root/ca-intermediary/ directory on the intermediary CA host. You can now use this certificate to process server and client CSRs and to generate CRLs.

When you return a signed certificate for any given CSR, include the chained-sub-ca.crt certificate so that it can be installed on the host where the certificate will be used and distributed to any client that needs to validate the signed certificate.

Process CSRs and Sign Certificates

As systems generate CSRs using the process that is described in Creating Certificate Signing Requests With OpenSSL, they must submit them to a CA to be signed.

All subsequent CSR processing for server and client-side certificates should be performed by an intermediary CA that is configured within your environment or by an external third party CA.

To process a CSR, copy it to the /root/ca-intermediary directory on your intermediary CA host and then use the openssl ca command to sign it with the appropriate extension configuration.

For example, to sign a server-side certificate for a CSR named www.example.com.csr, run the following command:

sudo openssl ca -config intermediary.conf -extensions server_ext -days 375 \
-in www.example.com.csr -out newcerts/www.example.com.crt
                     

Note that we specify the number of days for which the certificate is valid. For a server-side certificate, the number of days should be limited to a value significantly lower than a CA certificate's validity. It is important to select the correct extensions to apply to the certificate. These extensions map to definitions that are within your configuration file.

You are prompted for the intermediary CA key passphrase and then prompted to sign the certificate and update the database.

You should return the certificate, along with the chained CA certificate, so that these can be distributed to validate the certificate.

Manage a Certificate Revocation List

The certificate revocation list is used to identify certificates that have been issued by a signing CA and revoked. The list also tracks the reason that a certificate was revoked.

Generate the CRL

On each CA host, you should create an empty CRL that can be updated as you need to revoke certificates. For example, on an intermediary CA, you would use the following command:

sudo cd /root/ca-intermediary
sudo openssl ca -config intermediary.conf -gencrl -out crl/sub-ca.crl

Note that the CRL should be published to the URL that is defined in your configuration file to keep track of certificates that are revoked by the CA. You should configure a web service to serve the sub-ca.crl, if possible.

You can check the contents of a CRL as follows:

sudo openssl crl -in crl/sub-ca.crl -noout -text

If the CRL was just created, it is empty. A new CRL should be created periodically, based on the configuration value that is set in the CA configuration file for default_crl_days. By default, it is set for every 30 days.

Revoke a certificate

Every signed certificate contains the serial number that is issued by the signing CA. You can view this serial number within a certificate as follows:

sudo openssl x509 -serial -noout -in server.crt
                        

This serial number identifies the certificate within the CA signing database and can also be used to identify the certificate stored by the CA that signed it so that the CA can revoke it.

On the CA where the certificate was issued, you can find the certificate with the matching serial number in the certs directory. For example, on an intermediary host, for a certificate with serial number 8F75111A8E33B2D109A8BF079C67C83F, it would be as follows:

sudo cd /root/ca-intermediary
sudo ls certs/8F75111A8E33B2D109A8BF079C67C83F*

certs/8F75111A8E33B2D109A8BF079C67C83F.pem

You can also check the details for the certificate in the CA database:

sudo grep 8F75111A8E33B2D109A8BF079C67C83F db/index.txt

To revoke this certificate, the signing CA must issue the following command:

sudo openssl ca -config intermediary.conf -revoke certs/8F75111A8E33B2D109A8BF079C67C83F.pem \
-crl_reason keyCompromise
                        

Note that you should specify the reason for revoking the certificate, as this reason is used in the certificate revocation list. Options include the following: unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, and removeFromCRL. For more information, see the CA(1) manual page.

When a certificate is revoked, the CA database is updated to reflect this change and the status is set to R for the certificate that is listed in the db/index.txt file.

The database file is used to generate the CRL each time it is created. It is good practice generating a new CRL as soon as you revoke a certificate. In this way, this list is kept up to date. See Generate the CRL for more information.

Configure and Run an OCSP Server

The Online Certificate Status Protocol (OCSP) provides an alternative to CRLs and includes its own publishing mechanism. OpenSSL includes an option to run as an OCSP server that can respond to OCSP queries.

Note that OCSP is preferred over CRLs. Usually, it is a good idea to make sure that an OCSP server is running for your CA, particularly if the OCSP URL appears in your configuration, as this URL is included in each certificate that is signed by the CA. Any client software can confirm the revocation status of a certificate by querying the OCSP server.

For any CA, create a key and CSR for the OCSP server:

sudo openssl req -new -newkey rsa:2048 -subj "/C=AU/O=Example Org/CN=OCSP Responder" \
-keyout private/ocsp.key -out ocsp.csr

Create a signed certificate from the ocsp.csr CSR file:

sudo openssl ca -config intermediary.conf -extensions ocsp -days 187 -in ocsp.csr \
-out newcerts/ocsp.crt

Because the OCSP certificate is responsible for handling revocation, it cannot be revoked. Therefore, it is a good practice to set the validity period on the certificate to a manageable, but relatively short period. In this example, the validity period has been set to 187 days, which means that it needs to be refreshed every 6 months.

To run an OCSP server on the current CA, you can use the tool provided within OpenSSL. For example, you could use the following command:

sudo openssl ocsp -port 9080 -index db/index.txt -rsigner newcerts/ocsp.crt \
-rkey private/ocsp.key -CA sub-ca.crt -text

Note that the command specifies the CA db/index.txt file directly, which means that as certificates are revoked, the OCSP server becomes aware of them automatically. When you run the command, you are prompted for the OCSP key passphrase. The server continues to run until you kill the process or escape by using a control sequence such as Ctrl-C.

You can test the service by checking the ocsp.crt file. Use the openssl command as follow to run an OCSP query:

sudo openssl ocsp -issuer sub-ca.crt -CAfile chained-sub-ca.crt -cert newcerts/ocsp.crt \
-url http://127.0.0.1:9080
                        
Response verify OK
newcerts/ocsp.crt: good
        This Update: Oct 30 15:48:11 2019 GMT

The response in the previous example indicates whether the verification has succeeded and provides a status of good if the certificate has not been revoked. A status of revoked is returned if it has been revoked.

Debugging and Testing Certificates With OpenSSL

The following are some examples that show how you can use OpenSSL commands to work with existing certificates to debug and test the infrastructure. The examples provided here aren't comprehensive and are intended to supplement the existing OpenSSL manual pages.

Examining Certificates

Display the information contained in an X.509 certificate.

sudo openssl x509 -text -noout -in server.crt

Display the SHA1 fingerprint of a certificate.

sudo openssl x509 -sha1 -noout -fingerprint -in server.crt

Display the serial number of a signed certificate:

sudo openssl x509 -serial -noout -in server.crt

Check That a Private Key Matches a Certificate

The modulus and the public exponent parts of the key and the certificate must match. These values are usually long and difficult to check. The easiest way to compare the modulus in the key and certificate is to create an MD5 hash of each and compare those instead, for example:

sudo openssl x509 -noout -modulus -in server.crt | openssl md5
sudo openssl rsa -noout -modulus -in server.key | openssl md5

You can equally check the modulus in a CSR to see if it matches a key or certificate as follows:

sudo openssl req -noout -modulus -in server.csr | openssl md5

Changing Key or Certificate Format

Convert a root certificate to a form that can be published on a website for downloading by a browser:

sudo openssl x509 -in cert.pem -out rootcert.crt

Convert a base64 encoded certificate (also referred to as PEM or RFC 1421) to binary DER format:

sudo openssl x509 -in cert.pem -outform der -out certificate.der

Convert the base64 encoded certificates for an entity and its CA to a single PKCS7 format certificate:

sudo openssl crl2pkcs7 -nocrl -certfile entCert.cer -certfile CACert.cer -out certificate.p7b 

Check Certificate Consistency and Validity

Verify a certificate including the signing authority, signing chain, and period of validity:

sudo openssl verify cert.pem

Decrypting Keys and Adding or Removing Passphrases

If you create an encrypted key file and decide that the file isn't encrypted or doesn't require a passphrase, you can decrypt it by using the following command:

sudo openssl rsa -in private.key -out unencrypted.key
                     
Enter pass phrase for private.key:
writing RSA key

You're prompted for the passphrase on the encrypted key, which is stored in private.key, and the unencrypted version of the same key is written to the unencrypted.key file.

To encrypt an unencrypted key and add a passphrase to protect it, run the following command:

sudo openssl rsa -aes256 -in unencrypted.key -out private.key

In the previous example, the AES cipher is used with a 256 bit key. The command prompts you to enter a passphrase and to verify it. The new encrypted key file is written to private.key.

You can add or remove a passphrase from the private key at any time without affecting its public key counterpart. Adding a passphrase protects the private key from use by an unauthorized or malicious user, but comes with an added inconvenience, in that services that use the private key always require manual intervention to start or restart. If you remove the passphrase from a key, ensure that it's stored with strict permissions and that it's not copied to systems that don't require it.

Using OpenSSL to Test SSL/TLS Configured Services

Test a self-signed certificate by configuring a server that listens on port 443:

sudo openssl s_server -accept 443 -cert cert.pem -key prikey.pem -www

Test the client side of a connection. This command returns information about the connection including the certificate by which you can directly input HTTP commands:

sudo openssl s_client -connect server:443 -CAfile cert.pem

Extract a certificate from a server as follows:

sudo echo | openssl s_client -connect server:443 2>/dev/null | \
sed -ne '/BEGIN CERT/,/END CERT/p' |sudo tee svrcert.pem

Using OpenSSL for File Encryption and Validation

You can also use OpenSSL to encrypt or decrypt any file type and to create digests that can be signed and used to validate the contents and the origin of a file. The following are some examples of how you might use the openssl command.

Encrypt a file by using Blowfish:

sudo openssl enc -blowfish -salt -in file -out file.enc

Decrypt a Blowfish-encrypted file:

sudo openssl enc -d -blowfish -in file.enc -out file.dec

Create an SHA1 digest of a file:

sudo openssl dgst -sha1 file

Sign the SHA1 digest of a file using the private key stored in the file prikey.pem:

sudo openssl dgst -sha1 -sign prikey.pem -out file.sha1 file

Verify the signed digest for a file using the public key stored in the file pubkey.pem:

sudo openssl dgst -sha1 -verify pubkey.pem -signature file.sha1 file

More information About OpenSSL

For more information about OpenSSL, see the openssl(1), ciphers(1), dgst(1), enc(1), req(1), s_client(1), s_server(1), verify(1), and x509(1) manual pages.