Openssl create certificate chain requires Root CA and Intermediate certificate, In this article I will share Step-by-Step Guide to create root and intermediate certificates and then use these certificates to create certificate CA bundle in Linux. I hope you have an overview of all the terminologies used with OpenSSL.
Root vs Intermediate Certificate
- A certificate chain or certificate CA bundle is a sequence of certificates, where each certificate in the chain is signed by the subsequent certificate.
- The Root CA is the top level of certificate chain while intermediate CAs or Sub CAs are Certificate Authorities that issue off an intermediate root.
- Typically, the root CA does not sign server or client certificates directly.
- The root CA is only ever used to create one or more intermediate CAs, which are trusted by the root CA to sign certificates on their behalf. This is best practice.
- It allows the root key to be kept offline and unused as much as possible, as any compromise of the root key is disastrous.
- An intermediate certificate authority (CA) is an entity that can sign certificates on behalf of the root CA.
- The root CA signs the intermediate certificate, forming a chain of trust.
- The purpose of using an intermediate CA is primarily for security.
- The root key can be kept offline and used as infrequently as possible.
- If the intermediate key is compromised, the root CA can revoke the intermediate certificate and create a new intermediate cryptographic pair.
Pre-requisites: Install OpenSSL
On RHEL/CentOS 7/8 you can use yum or dnf respectively while on Ubuntu use apt-get
to install openssl rpm
yum -y install openssl
OpenSSL encrypted data with salted password (Optional)
When we create private key for Root CA certificate, we have an option to either use encryption for private key or create key without any encryption. As if we choose to create private key with encryption such as 3DES, AES then you will have to provide a passphrase every time you try to access the private key.
I have already written another article with the steps for openssl encd data with salted password to encrypt the password file.
In this article we we will use RSA key which will not encrypt the private key, but you can decide to use AES or 3DES as your preferred algorithm.
Step 1: Create OpenSSL Root CA directory structure
We can also create CA bundle with all the certificates without creating any directory structure and using some manual tweaks but let us follow the long procedure to better understanding. In RHEL/CentOS 7/8 the default location for all the certificates are under /etc/pki/tls
. But for this article we will create a new directory structure /root/myCA/
to store our certificates.
Create a directory structure to store the CA files, certificates, and private keys:
mkdir -p ~/myCA/rootCA/{certs,crl,newcerts,private,csr} mkdir -p ~/myCA/intermediateCA/{certs,crl,newcerts,private,csr}
Each directory in your Certificate Authority (CA) folder structure serves a specific purpose:
- certs: This directory contains the certificates generated and signed by the CA. For the root CA, this includes the root CA certificate itself. For the intermediate CA, this includes the intermediate CA certificate and any server or client certificates signed by the intermediate CA.
- crl: The Certificate Revocation List (CRL) directory contains the CRLs generated by the CA. A CRL is a list of certificates that have been revoked by the CA before their expiration date.
- newcerts: This directory stores a copy of each certificate signed by the CA, with the certificate's serial number as the file name. It helps maintain a backup of all issued certificates.
- private: This directory contains the private keys for the CA, including the root CA and intermediate CA private keys. These keys are used to sign certificates and CRLs. The private keys should be kept secure and not shared.
A serial
file is used to keep track of the last serial number that was used to issue a certificate. It’s important that no two certificates ever be issued with the same serial number from the same CA. OpenSSL is somewhat quirky about how it handles this file. It expects the value to be in hex, and it must contain at least two digits. By setting the initial value to 1000
, we ensure that the serial numbers start from 1000 and increment for each subsequent certificate issued.
echo 1000 > ~/myCA/rootCA/serial echo 1000 > ~/myCA/intermediateCA/serial
A crlnumber
is a configuration directive specifying the file that contains the current CRL number. The CRL number is a unique integer that is incremented each time a new Certificate Revocation List (CRL) is generated. This helps in tracking the latest CRL issued by the CA and ensuring that CRLs are issued in a proper sequence. We have given a random digit in our crlnumber
file which will be used to keep track of all certs which are revocated.
echo 0100 > ~/myCA/rootCA/crlnumber echo 0100 > ~/myCA/intermediateCA/crlnumber
Next we will create index.txt
file which is a database of sorts that keeps track of the certificates that have been issued by the CA. Each line in the index.txt
file represents a certificate and contains information such as the certificate's status (e.g., valid, revoked), the certificate's expiration date, the certificate's serial number, and the certificate subject's distinguished name (DN).
Since no certificates have been issued at this point and OpenSSL requires that the file exist, we’ll simply create an empty file.
touch ~/myCA/rootCA/index.txt touch ~/myCA/intermediateCA/index.txt
Check the list of contents under /root/myCA
├── intermediateCA │ ├── certs │ ├── crl │ ├── csr │ ├── crlnumber │ ├── index.txt │ ├── newcerts │ ├── private │ └── serial └── rootCA ├── certs ├── crl ├── csr ├── crlnumber ├── index.txt ├── newcerts ├── private └── serial 10 directories, 6 files
Step 2: Configure openssl.cnf for Root and Intermediate CA Certificate
We will create 2 separate openssl.cnf
file (each for root and intermediate CA).
Here is our openssl_root.cnf
file:
[ ca ] # The default CA section default_ca = CA_default # The default CA name [ CA_default ] # Default settings for the CA dir = /root/myCA/rootCA # CA directory certs = $dir/certs # Certificates directory crl_dir = $dir/crl # CRL directory new_certs_dir = $dir/newcerts # New certificates directory database = $dir/index.txt # Certificate index file serial = $dir/serial # Serial number file RANDFILE = $dir/private/.rand # Random number file private_key = $dir/private/ca.key.pem # Root CA private key certificate = $dir/certs/ca.cert.pem # Root CA certificate crl = $dir/crl/ca.crl.pem # Root CA CRL crlnumber = $dir/crlnumber # Root CA CRL number crl_extensions = crl_ext # CRL extensions default_crl_days = 30 # Default CRL validity days default_md = sha256 # Default message digest preserve = no # Preserve existing extensions email_in_dn = no # Exclude email from the DN name_opt = ca_default # Formatting options for names cert_opt = ca_default # Certificate output options policy = policy_strict # Certificate policy unique_subject = no # Allow multiple certs with the same DN [ policy_strict ] # Policy for stricter validation countryName = match # Must match the issuer's country stateOrProvinceName = match # Must match the issuer's state organizationName = match # Must match the issuer's organization organizationalUnitName = optional # Organizational unit is optional commonName = supplied # Must provide a common name emailAddress = optional # Email address is optional [ req ] # Request settings default_bits = 2048 # Default key size distinguished_name = req_distinguished_name # Default DN template string_mask = utf8only # UTF-8 encoding default_md = sha256 # Default message digest prompt = no # Non-interactive mode [ req_distinguished_name ] # Template for the DN in the CSR countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name (full name) localityName = Locality Name (city) 0.organizationName = Organization Name (company) organizationalUnitName = Organizational Unit Name (section) commonName = Common Name (your domain) emailAddress = Email Address [ v3_ca ] # Root CA certificate extensions subjectKeyIdentifier = hash # Subject key identifier authorityKeyIdentifier = keyid:always,issuer # Authority key identifier basicConstraints = critical, CA:true # Basic constraints for a CA keyUsage = critical, keyCertSign, cRLSign # Key usage for a CA [ crl_ext ] # CRL extensions authorityKeyIdentifier = keyid:always,issuer # Authority key identifier [ v3_intermediate_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Here is our openssl_intermediate.cnf
file:
[ ca ] # The default CA section default_ca = CA_default # The default CA name [ CA_default ] # Default settings for the intermediate CA dir = /root/myCA/intermediateCA # Intermediate CA directory certs = $dir/certs # Certificates directory crl_dir = $dir/crl # CRL directory new_certs_dir = $dir/newcerts # New certificates directory database = $dir/index.txt # Certificate index file serial = $dir/serial # Serial number file RANDFILE = $dir/private/.rand # Random number file private_key = $dir/private/intermediate.key.pem # Intermediate CA private key certificate = $dir/certs/intermediate.cert.pem # Intermediate CA certificate crl = $dir/crl/intermediate.crl.pem # Intermediate CA CRL crlnumber = $dir/crlnumber # Intermediate CA CRL number crl_extensions = crl_ext # CRL extensions default_crl_days = 30 # Default CRL validity days default_md = sha256 # Default message digest preserve = no # Preserve existing extensions email_in_dn = no # Exclude email from the DN name_opt = ca_default # Formatting options for names cert_opt = ca_default # Certificate output options policy = policy_loose # Certificate policy [ policy_loose ] # Policy for less strict validation countryName = optional # Country is optional stateOrProvinceName = optional # State or province is optional localityName = optional # Locality is optional organizationName = optional # Organization is optional organizationalUnitName = optional # Organizational unit is optional commonName = supplied # Must provide a common name emailAddress = optional # Email address is optional [ req ] # Request settings default_bits = 2048 # Default key size distinguished_name = req_distinguished_name # Default DN template string_mask = utf8only # UTF-8 encoding default_md = sha256 # Default message digest x509_extensions = v3_intermediate_ca # Extensions for intermediate CA certificate [ req_distinguished_name ] # Template for the DN in the CSR countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address [ v3_intermediate_ca ] # Intermediate CA certificate extensions subjectKeyIdentifier = hash # Subject key identifier authorityKeyIdentifier = keyid:always,issuer # Authority key identifier basicConstraints = critical, CA:true, pathlen:0 # Basic constraints for a CA keyUsage = critical, digitalSignature, cRLSign, keyCertSign # Key usage for a CA [ crl_ext ] # CRL extensions authorityKeyIdentifier=keyid:always # Authority key identifier [ server_cert ] # Server certificate extensions basicConstraints = CA:FALSE # Not a CA certificate nsCertType = server # Server certificate type keyUsage = critical, digitalSignature, keyEncipherment # Key usage for a server cert extendedKeyUsage = serverAuth # Extended key usage for server authentication purposes (e.g., TLS/SSL servers). authorityKeyIdentifier = keyid,issuer # Authority key identifier linking the certificate to the issuer's public key.
pathlen
or just remove it in the following section. As pathlen
restricts creating any further intermediate CA in the chain. You may also create another section v3_intermediate_ca_n
and there you can add pathlen: 0
to make sure that is the last intermediate certificate in your chain.
Step 3: Generate the root CA key pair and certificate
Create an RSA key pair for the root CA without a password:
openssl genrsa -out ~/myCA/rootCA/private/ca.key.pem 4096
chmod 400 ~/myCA/rootCA/private/ca.key.pem
We will use openssl command to view the content of private key:
openssl rsa -noout -text -in ~/myCA/rootCA/private/ca.key.pem
Create the root CA certificate:
- OpenSSL create certificate chain requires Root and Intermediate Certificate. In this step you'll take the place of VeriSign, Thawte, etc.
- Use the Root CA key
cakey.pem
to create a Root CA certificatecacert.pem
- Give the root certificate a long expiry date. Once the root certificate expires, all certificates signed by the CA become invalid.
- Whenever you use the
openssl req
tool, you must specify a configuration file to use with the-config
option, otherwise OpenSSL will default to/etc/pki/tls/openssl.cnf
- We will use
v3_ca
extensions to create CA certificate
Use below command to create Root Certificate Authority Certificate cacert.pem
. I have specified the Subj inline to the same command, you can update the command based on your environment.
openssl req -config openssl_root.cnf -key ~/myCA/rootCA/private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out ~/myCA/rootCA/certs/ca.cert.pem -subj "/C=US/ST=California/L=San Francisco/O=Example Corp/OU=IT Department/CN=Root CA"
The CA certificate can be world readable so that it can be used to sign the cert by anyone.
chmod 444 ~/myCA/rootCA/certs/ca.cert.pem
Execute the below command for openssl verify root CA certificate
openssl x509 -noout -text -in ~/myCA/rootCA/certs/ca.cert.pem
Sample Output:
The output shows:
- the
Signature Algorithm
used - the
dates
of certificate Validity - the
Public-Key
bit length - the
Issuer
, which is the entity that signed the certificate - the
Subject
, which refers to the certificate itself
The output also shows the X509v3 extensions. We applied the v3_ca
extension, so the options from [ v3_ca ]
should be reflected in the output.
Step 4: Generate the intermediate CA key pair and certificate
Create an RSA key pair for the intermediate CA without a password and secure the file by removing permissions to groups and others:
openssl genrsa -out ~/myCA/intermediateCA/private/intermediate.key.pem 4096
chmod 400 ~/myCA/intermediateCA/private/intermediate.key.pem
Create the intermediate CA certificate signing request (CSR). If you are not familiar with the content to be provided with CSR then you should read Things to consider when creating CSR with OpenSSL
openssl req -config openssl_intermediate.cnf -key ~/myCA/intermediateCA/private/intermediate.key.pem -new -sha256 -out ~/myCA/intermediateCA/certs/intermediate.csr.pem -subj "/C=US/ST=California/L=San Francisco/O=Example Corp/OU=IT Department/CN=Intermediate CA"
Sign the intermediate CSR with the root CA key:
openssl ca -config openssl_root.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in ~/myCA/intermediateCA/certs/intermediate.csr.pem -out ~/myCA/intermediateCA/certs/intermediate.cert.pem
Sample Output:
Assign 444 permission to the CRT to make it readable by everyone:
chmod 444 ~/myCA/intermediateCA/certs/intermediate.cert.pem
The index.txt
file is where the OpenSSL ca tool stores the certificate database. Do not delete or edit this file by hand. It should now contain a line that refers to the intermediate certificate.
# cat ~/myCA/rootCA/index.txt
V 330503082700Z 1000 unknown /C=US/ST=California/O=Example Corp/OU=IT Department/CN=Intermediate CA
Here,
V
: This field indicates the status of the certificate. In this case,V
means "Valid." Other possible values areR
for "Revoked" andE
for "Expired."330503082700Z
: This field represents the expiration date of the certificate in the formatYYMMDDHHMMSSZ
. In this example, the certificate will expire on 30th May 2033 at 08:27:00 UTC.1000
: This field is the certificate serial number in hexadecimal format.unknown
: This field shows the revocation reason if the certificate has been revoked. For valid certificates, this field usually contains the value "unknown" or is left empty./C=US/ST=California/O=Example Corp/OU=IT Department/CN=Intermediate CA
: This field contains the subject's distinguished name (DN) in the certificate, which consists of various components such as country (C), state or province (ST), organization (O), organizational unit (OU), and common name (CN). In this example, the DN components are as follows:-
- C: US
- ST: California
- O: Example Corp
- OU: IT Department
- CN: Intermediate CA
-
Verify the Intermediate CA Certificate content
openssl x509 -noout -text -in ~/myCA/intermediateCA/certs/intermediate.cert.pem
Sample Output:
Next openssl verify intermediate certificate against the root certificate. An OK indicates that the chain of trust is intact.
openssl verify -CAfile ~/myCA/rootCA/certs/ca.cert.pem ~/myCA/intermediateCA/certs/intermediate.cert.pem
Output:
/root/myCA/intermediateCA/certs/intermediate.cert.pem: OK
Step 5: Generate OpenSSL Create Certificate Chain (Certificate Bundle)
To openssl create certificate chain (certificate bundle), concatenate the intermediate and root certificates together.
In the below example I have combined my Root and Intermediate CA certificates to openssl create certificate chain in Linux. We will use this file later to verify certificates signed by the intermediate CA.
cat ~/myCA/intermediateCA/certs/intermediate.cert.pem ~/myCA/rootCA/certs/ca.cert.pem > ~/myCA/intermediateCA/certs/ca-chain.cert.pem
After openssl create certificate chain, to verify certificate chain use below command:
openssl verify -CAfile ~/myCA/intermediateCA/certs/ca-chain.cert.pem ~/myCA/intermediateCA/certs/intermediate.cert.pem
Output:
/root/myCA/intermediateCA/certs/intermediate.cert.pem: OK
Step 6: Generate and sign server certificate using Intermediate CA
Create a private key for the server:
openssl genpkey -algorithm RSA -out ~/myCA/intermediateCA/private/www.example.com.key.pem chmod 400 ~/myCA/intermediateCA/private/www.example.com.key.pem
Create a certificate signing request (CSR) for the server:
openssl req -config ~/myCA/openssl_intermediate.cnf -key ~/myCA/intermediateCA/private/www.example.com.key.pem -new -sha256 -out ~/myCA/intermediateCA/csr/www.example.com.csr.pem
You'll be asked a series of questions about the certificate. For the Common Name question, you should enter the domain name of the server (e.g., www.example.com).
OR
You can automate the certificate signing request (CSR) creation by supplying default answers to the questions asked by the openssl req
command.
These defaults can be specified in the openssl.cnf
(or openssl_intermediate.cnf
in this case) file, under the [ req_distinguished_name ]
section.
[ req_distinguished_name ] countryName_default = US stateOrProvinceName_default = California localityName_default = San Francisco 0.organizationName_default = Example Corp organizationalUnitName_default = IT Department commonName_default = www.example.com emailAddress_default = admin@example.com
By including these lines in your openssl_intermediate.cnf
file, openssl req
will use these as the default values for the corresponding fields, allowing the command to be run non-interactively.
Then, you can use the -batch
option with openssl req
command to automatically use these defaults without prompting for them:
openssl req -config ~/myCA/openssl_intermediate.cnf -key ~/myCA/intermediateCA/private/www.example.com.key.pem -new -sha256 -out ~/myCA/intermediateCA/csr/www.example.com.csr.pem -batch
Sign the server CSR with the intermediate CA:
openssl ca -config ~/myCA/openssl_intermediate.cnf -extensions server_cert -days 375 -notext -md sha256 -in ~/myCA/intermediateCA/csr/www.example.com.csr.pem -out ~/myCA/intermediateCA/certs/www.example.com.cert.pem
Sample Output:
Using configuration from /root/myCA/openssl_intermediate.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 4096 (0x1000) Validity Not Before: Jun 12 05:32:08 2023 GMT Not After : Jun 21 05:32:08 2024 GMT Subject: countryName = US stateOrProvinceName = California localityName = San Francisco organizationName = Example Corp organizationalUnitName = IT Department commonName = www.example.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Cert Type: SSL Server X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Authority Key Identifier: A1:99:57:5D:B1:10:A2:24:C8:FE:09:D4:48:24:B7:0F:2B:C5:D2:2B Certificate is to be certified until Jun 21 05:32:08 2024 GMT (375 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
Verify the server certificate:
openssl x509 -noout -text -in ~/myCA/intermediateCA/certs/www.example.com.cert.pem
Sample Output:
Certificate: Data: Version: 3 (0x2) Serial Number: 4096 (0x1000) Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = California, O = Example Corp, OU = IT Department, CN = Intermediate CA Validity Not Before: Jun 12 05:32:08 2023 GMT Not After : Jun 21 05:32:08 2024 GMT Subject: C = US, ST = California, L = San Francisco, O = Example Corp, OU = IT Department, CN = www.example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:8f:1b:b4:59:15:07:5b:ba:89:97:cc:98:bf:53: 18:e9:e7:3a:a1:cd:e3:74:75:cd:1e:6d:02:7b:4f: 66:89:32:d0:ea:35:19:bc:d4:66:6a:71:e1:a2:66: a4:01:24:85:0a:c6:c8:17:3a:e8:63:12:bd:ef:78: cf:f4:e6:3c:67:1c:41:d5:12:d9:d7:3b:fb:3a:80: 7a:35:f6:0d:ee:33:c4:4a:3a:91:a9:e4:33:e0:63: 97:97:0e:06:ca:71:34:16:bc:29:93:83:cf:01:bf: da:29:b5:e2:48:01:3a:96:b6:1a:3b:9f:70:80:67: bd:7f:14:e4:bf:25:f7:0f:b2:1a:03:37:7f:f1:93: 7f:3d:08:6f:1e:ed:d7:13:50:f9:a3:e6:17:5e:7f: 8f:c4:8e:0e:a5:ce:d0:23:0d:bc:6a:85:d2:e5:28: bf:0a:84:53:93:a0:6d:d6:07:25:36:6b:df:c9:ba: dd:16:52:6a:7f:11:fd:5f:1d:ca:e0:50:87:19:00: c7:fc:ff:45:b4:7e:2f:7a:ca:26:62:44:9a:76:57: fe:6c:df:36:9c:3e:c8:a8:3c:62:34:c8:13:f9:48: 64:2b:a9:ed:fd:2f:0e:52:5c:7f:93:92:ed:d5:d5: 2b:88:b1:c4:b6:35:d7:74:00:0f:ef:b9:9b:3b:80: 98:c9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Cert Type: SSL Server X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Authority Key Identifier: A1:99:57:5D:B1:10:A2:24:C8:FE:09:D4:48:24:B7:0F:2B:C5:D2:2B X509v3 Subject Key Identifier: E3:6B:0E:75:91:EF:B6:06:AE:A3:18:AC:66:AD:F1:4C:90:85:F3:BE Signature Algorithm: sha256WithRSAEncryption Signature Value: 52:12:13:4f:44:69:44:94:21:c6:b3:6c:79:bb:59:c0:96:09: 98:4d:da:b5:74:f7:e9:b1:0b:a1:c0:ba:8a:17:20:97:40:5b: 48:c7:1a:fb:ee:23:bc:f2:b2:cb:24:82:6c:6a:83:d2:68:a5: 86:19:80:4b:fc:52:c2:22:6b:b3:80:50:da:c5:a2:dd:25:9a: 7c:08:84:c6:67:b1:36:30:91:63:8a:85:84:28:4f:92:a2:d6: 39:a6:6e:ff:ff:80:1b:4d:e7:26:8e:d5:04:55:b2:01:47:c5: 88:d2:14:9f:e9:26:6e:be:c9:d1:94:f9:04:c7:c9:bf:08:eb: 67:4f:3e:25:6d:1a:fa:37:c1:6f:e0:ea:88:87:11:0f:73:b7: a3:25:2a:7d:16:84:12:e6:42:b8:81:34:da:ba:66:44:dc:a6: 9f:f2:6f:8a:ae:34:20:d5:d4:b6:0d:b2:b5:a2:22:53:8e:3e: 39:ad:d3:35:a1:68:91:bb:f6:8e:80:31:cf:02:ae:4d:2c:d6: 0c:c0:26:12:6d:0f:89:a6:d0:c1:48:91:4a:c4:e7:00:1d:0b: e6:c5:c5:a5:19:e1:b9:93:03:22:42:59:57:31:4c:ac:37:53: cd:16:19:7a:67:d8:7c:c0:b0:7f:0a:1e:29:c2:53:16:b6:ff: 2b:40:8c:6c:ab:5e:a8:26:a8:0f:af:a2:6d:49:13:5b:ca:69: 64:92:6b:1b:aa:3d:fa:07:90:92:38:ad:97:b4:22:11:26:87: 61:7c:15:26:71:74:39:ef:93:b5:7b:74:47:67:e9:b4:53:8e: b4:a8:a4:da:a4:dd:68:79:5e:57:33:19:46:e7:f4:41:e3:20: dc:45:45:fe:4a:90:d9:e2:c1:0b:6d:3a:43:e0:1d:f5:a2:d2: d2:d9:68:c9:b4:b4:7f:62:85:8e:89:20:88:23:ab:f9:43:af: 3f:0f:55:15:32:ff:03:bf:83:b0:ac:9c:3a:d2:56:06:f5:a7: ae:ab:45:0f:68:84:86:11:23:6f:7a:1f:0f:5a:0f:1a:84:e1: 71:21:56:b6:61:98:8e:cc:f5:28:c3:70:8b:dc:9c:f8:61:d1: 01:4e:e8:e2:18:33:82:c0:b0:cd:ee:6d:c6:94:96:78:fb:92: fc:14:a6:80:85:28:43:bf:62:08:a0:94:16:20:1a:2b:7d:c0: 66:54:de:9b:ca:95:85:a7:dc:d6:a4:ea:ab:3e:0c:7a:e4:79: 6e:34:17:7e:a4:9d:75:63:bf:08:66:dd:6a:79:33:fe:38:68: 64:24:e8:0e:db:cc:92:13:44:de:0c:2f:64:5a:38:69:ee:98: 33:78:af:ab:04:4d:83:15
Bonus Tip: Signing and Revoking a certificate using Intermediate CA
You can read more about certificate revocation at Revoke certificate and generate CRL OpenSSL
Revoking a certificate is the process of invalidating a previously issued SSL/TLS certificate before its expiration date. A certificate may need to be revoked for various reasons, such as:
- The private key associated with the certificate has been compromised.
- The certificate was issued fraudulently.
- The information in the certificate has changed, and it no longer accurately represents the subject.
Here I have generated some certificates under /certs folder and signed it using my intermediate CA.
# cat ~/myCA/intermediateCA/index.txt V 240515083923Z 1000 unknown /C=US/ST=California/L=San Francisco/O=Example Corp/OU=IT Department/CN=example.com # cat ~/myCA/intermediateCA/serial 1001 # ls -l /certs/ total 12 -rw-r--r-- 1 root root 1769 May 6 14:09 server.cert.pem -rw-r--r-- 1 root root 1037 May 6 14:08 server.csr.pem -rw------- 1 root root 1704 May 6 14:07 server.key.pem
To revoke a certificate using OpenSSL, follow these steps:
Locate the certificate you want to revoke. You will need the certificate file (usually in PEM format, with the extension .crt
, .cer
, or .pem
) or its serial number.
Revoke the certificate using the openssl ca
command with the -revoke
option. If you are revoking an end-entity (server or client) certificate signed by the intermediate CA, you will use the intermediate CA configuration file. For example:
openssl ca -config ~/myCA/openssl_intermediate.cnf -revoke /certs/server.cert.pem
Output:
Using configuration from /root/myCA/openssl_intermediate.cnf Revoking Certificate 1000. Data Base Updated
openssl ca -config openssl_root.cnf -revoke /path/to/intermediate_certificate.pem
After revoking the certificate, update the Certificate Revocation List (CRL) to include the newly revoked certificate. The CRL is a list of revoked certificates that clients can check to determine if a certificate is still valid.
Generate an updated CRL using the openssl ca
command with the -gencrl
option:
openssl ca -config ~/myCA/openssl_intermediate.cnf -gencrl -out ~/myCA/intermediateCA/crl/intermediate.crl.pem
Output:
Using configuration from /root/myCA/openssl_intermediate.cnf
The line with 1000
in the index.txt
file represents a revoked certificate with the serial number 1000
. The fields indicate the certificate's status (R for revoked), revocation date, expiration date, serial number, and subject information.
# cat ~/myCA/intermediateCA/index.txt
R 240515083923Z 230506084237Z 1000 unknown /C=US/ST=California/L=San Francisco/O=Example Corp/OU=IT Department/CN=example.com
The crlnumber
file content 0101
represents the current CRL number, which is incremented each time a new Certificate Revocation List is generated.
# cat intermediateCA/crlnumber
0101
To get the list of revoked certificates from intermediate CA, we can use below command:
openssl crl -in ~/myCA/intermediateCA/crl/intermediate.crl.pem -text -noout
Output:
Conclusion
In this guide, we walked through the process of creating a certificate chain using OpenSSL. The certificate chain is an essential component of Public Key Infrastructure (PKI), which allows secure communication between clients and servers over the internet. We covered the following topics:
- Setting up a directory structure for the Root and Intermediate Certificate Authorities (CAs).
- Creating configuration files (
openssl.cnf
) for the Root and Intermediate CAs. - Generating a Root CA private key and self-signed certificate.
- Generating an Intermediate CA private key and Certificate Signing Request (CSR).
- Signing the Intermediate CA's CSR with the Root CA, resulting in the Intermediate CA certificate.
- Creating a Certificate Authority Bundle, which includes the Root and Intermediate CA certificates.
- Generating a server private key and CSR.
- Signing the server's CSR with the Intermediate CA, resulting in the server certificate.
- Revoking a server certificate, updating the Certificate Revocation List (CRL), and managing the CRL numbers.
By following these steps, you can establish a secure and trustworthy certificate chain for your web services, allowing clients to verify the authenticity of your server and communicate securely.
References
I have used below external references for this tutorial guide
OpenSSL create certificate chain with root and intermediate certificate
Network Security with OpenSSL
Related Searches: Openssl create certificate chain, root ca certificate, intermediate ca certificate, verify certificate chain, create ca bundle, verify ca certificate, openssl verify certificate, openssl view certificate, openssl get certificate info
My Version:
andre@Heimserver:~/Zertifikat Baustelle/root/tls$ openssl ca -config apache_intermediate_ca.cnf -extensions v3_intermediate_ca -days 3650 -notext -batch -passin file:andrepass.enc -in intermediate/csr/apache_intermediate.csr.pem -out intermediate/certs/apache_intermediate_ca.crt
Using configuration from apache_intermediate_ca.cnf
Could not open file or uri /root/tls/private/andre-root-ca-key.pem for loading CA private key
40C711AC187F0000:error::system library:file_open:Permission denied:crypto/store/loader_file.c:919:calling stat(/root/tls/private/andre-root-ca-key.pem)
Unable to load CA private key
Thanks for the great instructions and the wasted lifetime
I am glad you found the BUG
I found the bug, it was my fault. Sorry
[root@centos8-1 tls]# openssl verify -CAfile certs/cacert.pem intermediate/certs/intermediate.cacert.pem
[root@centos8-1 tls]# openssl verify -CAfile certs/cacert.pem intermediate/certs/ca-chain-bundle.cert.pem
Nice instructions, but there is a small mistake:
OpenSSL verify Certificate Chain
After openssl create certificate chain, to verify certificate chain use below command:
Not like this, but like this:
Thank you for highlighting this. You are right, the provided text and commands didn’t matched so I have updated the command snippet. We were actually supposed to verify the certificate chain instead of intermediate cert
Thanks for providing this. I have an implementation question however as we have run into variations on where the intermediary certificates should be vs the root CA certificates. There is a school of thought that the web server certificate should include the intermediary CA chain with it, and present it to clients, and the client’s trust store (CA Bundle) should only contain the root CA. It becomes problematic to have to overload a complex private CA heirarchy across all client nodes truststores (CA bundles) as opposed to only providing the root CA.
Is anyone else seeing this used as a practice?
Thank you, I really appreciate you taking the time and effort to explain such a complex topic. This was very educational.
Should /root/ca/intermediate/openssl.cnf be /root/tls/intermediate/openssl.cnf for step 8?
Yes, silly typo. Thank you for highlighting this, I have updated the article.
Hi – can I chain more certificates on to a certificate I purchased from a CA? How would I do that?
Thanks.
Do you mean you want to add certificates to existing bundle -in which case you have to add the new CA cert the same order as it was added earlier
For creating new CA chain bundle you can follow the same steps as I have mentioned here.
hi – thanks for the reply.
no, i meant create a server certificate that uses the chain in a wildcard certificate i bought from a commercial CA. it isn’t really possible of course. i asked before i really understood the concepts involved.
Hi, so once I have the root ca and the intermediate ca, how do i create a client certificate using the intermediate ca in way which the intermediate ca will actually log the creation of the client certificate in the intermediate/index.txt file?
I have followed the instructions here https://www.golinuxcloud.com/openssl-create-client-server-certificate/ and I can get a working client certificate but the intermediate ca has not logged the fact that it was signed in the index.txt file?
Am i right in thinking tls/openssl.cnf is for root ca, intermediate/openssl.cnf is for the intermediate ca, and I now need to create a new openssl.cnf for ultimate client certificates made using the intermediate ca? Is this right? or do I just use the intermediate/openssl.cnf?
Thanks for your help.
If i do need to create a new openssl.cnf, could you let me know what settings i need to change? many thanks!
In the above example I was using openssl.cnf from the root ca so the index.txt of the root CA was updated, you can use
intermediate/openssl.cnf
in step 11 so index.txt of the intermediate certificate would be updated but that wouldn’t make sense here as we were signing the intermediate certificate.I have used a different command to sign the certificates in the client-server certificate article which you shared, to update the
index.txt
every time you sign a certificate using intermediate certificate you can useFor example, here I have signed two server certificates:
STEP 11.
USING COMMAND LINE
can you help
You have to read the instructions carefully
i am not from the IT background and i am not able to figure it out , i tried like a 100 times.
can you help!!
You are using the provided
openssl.cnf
which uses/root/tls/private
to store the private key. Checkprivate_key
variable in theopenssl.cnf
file.I can only assume that you have not created the private key as explained in Step 5 or you have created it in a different location or with a different name.
Hello
Even am getting the same error at step 11.The only different thing I did is while creating encrypted password file as the pbkdf2 was not supported “openssl enc -aes256 -md sha512 -salt -in mypass -out mypass.enc “.
It works smoothly till step 11.Kindly Help.
For the above failure, the error message is quite clear
Have you copied the openssl.cnf as I have explained in step 8. If yes please share the exact error message what you see.
As per my setup you should be inside /root/tls or you can provide the absolute path of openssl.cnf created for intermediate certificate.
Congratz for the article. Very useful.
However, I would like to know how can I create a chain with 2 intermediate certificates. It is not clear to me what have to be changed on the intermediate CA creation to create the second intermediate CA.
What I want to achieve is something like this:
root CA –> Intermediate CA 1 –> Intermediate CA 2
I took the steps from 7 to 12 to try to create the second intermediate CA. But I guess I ended up creating something like this:
root CA –> Intermediate CA 1
root CA –> Intermediate CA 2
Can you please help me on that?
In my example I have used the primary root CA to sign the IM CA1 so in your case you can create further sub directory inside IM CA1 and then use IM CA1 to sign your IM CA2 to make it root CA -> IM CA1 -> IM CA2
Yeah, that was one of my attempts to accomplish that, but when I run openssl verify using the 3 CAs I am getting an error.
Searching on internet I’ve found I could use the flag -untrusted on openssl. And using that, I get a successful check. Is that the correct way to verify a chain of certificates?
Also, if I run the verify on the bundle, it returns me a failure as well:
I will retry the procedures to see if I get anything different, but if you could please advise I would be glad.
Thanks again.
Your observations are interesting, I would have assumed that it will work. I remember creating multi level ca bundle and the verification had worked. Let me do some test runs myself and then may be I can guide better. If you are able to crack this before me then please do share here.
I think I found the problem. I am setting
pathlen:0
underv3_intermediate_ca
which means that no non-self-issued intermediate CA certificates may follow in a valid certification path. So either we can give a higher value for this or just remove it and create another section for second intermedtiate CAWith this change I was able to create two level of intermediate CA certificate:
The verification was also success:
Also from the ca-bundle:
My directory structure (if it helps)
I don’t know if I did it right, but I am still having issues with intermediate 2.
What I did was to change v3_intermediate_ca and remove the pathlen:0 as basic constraint. The sections is like this:
How did you o it? Did you increase pathlen to 2 or something like that?
Sorry for the confusion, I made a mistake in my last trial. I used the root CA to sign both the intermediate certificate which is why the following command was successful
This is wrong because root CA is not supposed to sign level 2 CA. I have corrected it and re-verified and it worked. I have mailed you the detailed steps with all the output. Let me know if you are still facing any issues.
Just to add one more thing, the expiry of each intermediate certificate should be less than it’s parent CA certificate
Thank you very much for working on that.
In fact, you did exactly what I ended up doing after many attempts of making it work. Which was to change the the way to run the verify command.
At first I thought you could add all certificates after -CAfile parameter and then openssl would verify the last CA on the chain in order.
But, as you did:
I created one bundle with rootCA.pem and intermediateCA1.pem and then verified against intermediateCA2.pem and that returned OK.
The same pattern worked when I created the certificate to be used on my server. I’ve run something like:
Then I configured my server with the server certificate and my client with the bundle and everythink worked like a charm.
Thanks you so much for your help,
P.S.: I will try to create a script to automate this process and if you want I can share it here. But I strongly recommend people to follow the manual steps. If I had a script, I would not know what I’ve learned by doing everything manually.
I am glad it worked. You may share the script version here once ready, it may help someone.