Table of Contents
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.
I have already written multiple articles on OpenSSL, I would recommend you to also check them for more overview on openssl examples:
- Beginners guide to understand all Certificate related terminologies used with openssl
- Generate openssl self-signed certificate with example
- Create your own Certificate Authority and generate a certificate signed by your CA
- Create certificate chain (CA bundle) using your own Root CA and Intermediate Certificates with openssl
- Create server and client certificates using openssl for end to end encryption with Apache over SSL
- Create SAN Certificate to protect multiple DNS, CN and IP Addresses of the server in a single certificate
Step 1: Install OpenSSL
On RHEL/CentOS 7/8 you can use yum or dnf respectively while on Ubuntu use apt-get
to install openssl rpm
[root@centos8-1 ~]# yum -y install openssl
Step 2: OpenSSL encrypted data with salted password
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. So I will not repeat the steps here again.
We will use the same encrypted password file for all our examples in this article to demonstrate openssl create certificate chain examples.
Step 3: 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/tls/
to store our certificates.
Create a parent directory to store the certificates
[root@centos8-1 ~]# mkdir /root/tls [root@centos8-1 ~]# cd /root/tls
Within the CA’s root directory, we need to create two sub directories:
certs: This will be used to keep copies of all of the certificates that we issue with our CA.
private: This will be used to keep a copy of the CA certificate’s private key.
[root@centos8-1 tls]# mkdir certs private
Besides key generation, we will create three files that our CA infrastructure will need.
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, so we must pad the value by prepending a zero to it.
[root@centos8-1 tls]# echo 01 > serial
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. Since no certificates have been issued at this point and OpenSSL requires that the file exist, we’ll simply create an empty file.
[root@centos8-1 tls]# touch index.txt
Check the list of contents under /root/tls
[root@centos8-1 tls]# ls -l
total 32
drwxr-xr-x 2 root root 4096 Apr 8 22:29 certs
-rw-r--r-- 1 root root 0 Apr 9 03:36 index.txt
-rw-r--r-- 1 root root 32 Apr 8 23:25 mypass.enc
drwxr-xr-x 2 root root 4096 Apr 9 03:34 private
-rw-r--r-- 1 root root 3 Apr 9 03:37 serial
Step 4: Configure openssl.cnf for Root CA Certificate
We will have a default configuration file openssl.cnf
in RHEL/CentOS 7/8 under /etc/pki/tls/openssl.cnf
which is added by the openssl rpm. We will copy this file to your custom certificate location i.e. /root/tls
and will modify the content of this file to create Root CA Certificate
HOME = . RANDFILE = $ENV::HOME/.rnd oid_section = new_oids openssl_conf = default_modules [ default_modules ] ssl_conf = ssl_module [ ssl_module ] system_default = crypto_policy [ crypto_policy ] .include /etc/crypto-policies/back-ends/opensslcnf.config [ new_oids ]
The OpenSSL command for the CA functions is aptly named ca
, and so the first section that we’re interested in is named ca
. For our purposes, this section is quite simple, containing only a single key: default_ca
. The value is the name of a section containing the configuration for the default CA. The [ CA_default ]
section contains a range of defaults. Make sure you declare the directory you chose earlier /root/tls
.
The x509_extensions
key specifies the name of a section that will contain the extensions to be added to each certificate issued by our CA.
[ ca ] default_ca = CA_default # The default ca section [ CA_default ] dir = /root/tls # Where everything is kept certs = $dir/certs # Where the issued certs are kept database = $dir/index.txt # database index file. # several certs with same subject. new_certs_dir = $dir/certs # default place for new certs. certificate = $dir/certs/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL private_key = $dir/private/cakey.pem # The private key name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha256 # use SHA-256 by default preserve = no # keep passed DN ordering policy = policy_match
The policy
key specifies the name of a section that will be used for the default policy.
A policy definition is a set of keys with the same name as the fields in a certificate’s distinguished name. For each key or field, there are three legal values: match, supplied, or optional.
- match: means that the field by that name in a certificate request must match the same field in the CA’s certificate.
- supplied: means that the certificate request must contain the field.
- optional: means that the field is not required in the certificate request.
We will apply policy_match
for creating root CA certificates so we have added this as a default value for policy
under CA_default
.
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
And policy_anything
for creating Intermediate CA certificates
[ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional
The values under [ req ]
section are applied when creating Certificate Signing Requests (CSR) or Certificates. The x509_extensions
key specifies the name of a section that contains the extensions that we want included in the certificate.
[ req ] default_bits = 4096 default_md = sha256 default_keyfile = privkey.pem distinguished_name = req_distinguished_name x509_extensions = v3_ca string_mask = nombstr
The eq_distinguished_name
key determine how OpenSSL gets the information it needs to fill in the certificate’s distinguished name. I have given few default values while the Common Name must be supplied as we have defined under policy
key.
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IN
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
localityName_default = BANGALORE
0.organizationName = Organization Name (eg, company)
0.organizationName_default = GoLinuxCloud
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
These are the extensions we will use with openssl create certificate chain. We will use v3_ca
extension to create root CA certificate and v3_intermediate
extension for intermediate CA certificate.
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.[ v3_ca ] subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = critical,CA:true [ v3_intermediate_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Step 5: Generate Root CA Private Key
- We will create root CA key using 4096 bits and 3DES encryption
- I am using my encrypted password file to provide the passphrase for the private key. If you do not wish to have an encrypted password file then you can remove
-des3
from the below command so the default encryption algo will be used. - We will store this private key under
/root/tls/private
[root@centos8-1 tls]# openssl genrsa -des3 -passout file:mypass.enc -out private/cakey.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
.......................................................................++++
.......................++++
e is 65537 (0x010001)
OpenSSL verify Root CA key
We will use openssl command to view the content of private key:
[root@centos8-1 tls]# openssl rsa -noout -text -in private/cakey.pem -passin file:mypass.enc RSA Private-Key: (4096 bit, 2 primes) <Output trimmed>
Step 6: Create your own 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
[root@centos8-1 tls]# openssl req -new -x509 -days 3650 -passin file:mypass.enc -config openssl.cnf -extensions v3_ca -key private/cakey.pem -out certs/cacert.pem 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) [IN]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) [BANGALORE]: Organization Name (eg, company) [GoLinuxCloud]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:centos8-1 Email Address []:admin@golinuxcloud.com
To change the format of the certificate to PEM format
[root@centos8-1 tls]# openssl x509 -in certs/cacert.pem -out certs/cacert.pem -outform PEM
OpenSSL verify Certificate
Execute the below command for openssl verify root CA certificate
[root@centos8-1 tls]# openssl x509 -noout -text -in certs/cacert.pem Certificate: Data: Version: 3 (0x2) Serial Number: 55:b2:c2:5e:7b:95:4a:05:78:32:82:6f:b1:60:a0:92:03:96:0b:30 Signature Algorithm: sha256WithRSAEncryption Issuer: C = IN, ST = Some-State, L = BANGALORE, O = GoLinuxCloud, CN = centos8-1, emailAddress = admin@golinuxcloud.com Validity Not Before: Apr 11 11:34:22 2020 GMT Not After : Apr 9 11:34:22 2030 GMT Subject: C = IN, ST = Some-State, L = BANGALORE, O = GoLinuxCloud, CN = centos8-1, emailAddress = admin@golinuxcloud.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (4096 bit) <Output trimmed>
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.
X509v3 extensions:
X509v3 Subject Key Identifier:
0B:FE:44:49:A9:90:96:9A:19:17:56:55:2D:70:B0:0D:D8:5D:9A:73
X509v3 Authority Key Identifier:
keyid:0B:FE:44:49:A9:90:96:9A:19:17:56:55:2D:70:B0:0D:D8:5D:9A:73
X509v3 Basic Constraints: critical
CA:TRUE
Step 7: Create OpenSSL Intermediate CA directory structure
Now to complete setup of openssl create certificate chain, we will also need intermediate certificate for the CA bundle. We will create new directory structure /root/tls/intermediate
under our parent folder /root/tls
to keep both the certificate files separate.
[root@centos8-1 tls]# mkdir /root/tls/intermediate [root@centos8-1 tls]# cd /root/tls/intermediate
We will also create sub directories under /root/tls/intermediate
to store our keys and certificate files. We will also need a serial
and index.txt
file as we created for our Root CA Certificate.
[root@centos8-1 intermediate]# mkdir certs csr private [root@centos8-1 intermediate]# touch index.txt [root@centos8-1 intermediate]# echo 01 > serial
Add a crlnumber
file to the intermediate CA directory tree. crlnumber
is used to keep track of certificate revocation lists.
[root@centos8-1 intermediate]# echo 01 > /root/tls/intermediate/crlnumber
Step 8: Configure openssl.cnf for Intermediate CA Certificate
Copy the openssl.cnf
used for our Root CA Certificate from /root/tls/openssl.cnf
to /root/tls/intermediate/openssl.cnf
. Below are the options we have been changed compared to the root CA certificate configuration file:
dir = /root/tls/intermediate # Where everything is kept certificate = $dir/certs/intermediate.cacert.pem # The CA certificate private_key = $dir/private/intermediate.cakey.pem # The private key policy = policy_anything
Step 9: Generate Intermediate CA key
Generate intermediate CA key ca-intermediate.key
.using openssl genrsa with 3DES encryption and our encrypted passphrase file to avoid any password prompt.
[root@centos8-1 tls]# openssl genrsa -des3 -passout file:mypass.enc -out intermediate/private/intermediate.cakey.pem 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
...........................................................................++++
............................................................................++++
e is 65537 (0x010001)
Step 10: Create intermediate CA Certificate Signing Request (CSR)
- Use the intermediate CA key to create a certificate signing request (CSR).
- The details should generally match the root CA.
- The Common Name, however, must be different.
Next we will create intermediate CA certificate signing request (CSR) under /root/tls/intermediate/csr
with expiry value lesser than the root CA certificate
[root@centos8-1 tls]# openssl req -new -sha256 -config intermediate/openssl.cnf -passin file:mypass.enc -key intermediate/private/intermediate.cakey.pem -out intermediate/csr/intermediate.csr.pem 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) [IN]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) [BANGALORE]: Organization Name (eg, company) [GoLinuxCloud]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:centos8-1 Intermediate CA Email Address []:admin@golinuxcloud.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Step 11: Sign and generate intermediate CA certificate
Now the last step before we conclude openssl create certificate chain, we need to create intermediate CA certificate using our Certificate Signing request which we created in above step. We will use v3_intermediate_ca
extension from /root/tls/openssl.cnf
to create the intermediate CA certificate under /root/tls/intermediate/certs/intermediate.cacert.pem
[root@centos8-1 tls]# openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 2650 -notext -batch -passin file:mypass.enc -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cacert.pem Using configuration from openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Apr 9 13:40:23 2020 GMT Not After : Jul 12 13:40:23 2027 GMT Subject: countryName = IN stateOrProvinceName = Some-State organizationName = GoLinuxCloud commonName = centos8-1 Intermediate CA emailAddress = admin@golinuxcloud.com X509v3 extensions: X509v3 Subject Key Identifier: A4:07:28:66:F1:71:CD:0B:62:2E:01:8C:6B:04:5B:CC:D0:96:24:89 X509v3 Authority Key Identifier: keyid:0B:FE:44:49:A9:90:96:9A:19:17:56:55:2D:70:B0:0D:D8:5D:9A:73 X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign Certificate is to be certified until Jul 12 13:40:23 2027 GMT (2650 days) Write out database with 1 new entries Data Base Updated
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.
[root@centos8-1 tls]# cat index.txt
V 270712134023Z 01 unknown /C=IN/ST=Some-State/O=GoLinuxCloud/CN=centos8-1 Intermediate CA/emailAddress=admin@golinuxcloud.com
OpenSSL verify Certificate
Verify the Intermediate CA Certificate content
[root@centos8-1 tls]# openssl x509 -noout -text -in intermediate/certs/intermediate.cacert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = IN, ST = Some-State, L = BANGALORE, O = GoLinuxCloud, CN = centos8-1, emailAddress = admin@golinuxcloud.com
Validity
Not Before: Apr 9 13:40:23 2020 GMT
Not After : Jul 12 13:40:23 2027 GMT
Subject: C = IN, ST = Some-State, O = GoLinuxCloud, CN = centos8-1 Intermediate CA, emailAddress = admin@golinuxcloud.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Next openssl verify intermediate certificate against the root certificate. An OK indicates that the chain of trust is intact.
[root@centos8-1 tls]# openssl verify -CAfile certs/cacert.pem intermediate/certs/intermediate.cacert.pem intermediate/certs/intermediate.cacert.pem: OK
To convert the format of the Certificate to PEM format
[root@centos8-1 tls]# openssl x509 -in intermediate/certs/intermediate.cacert.pem -out intermediate/certs/intermediate.cacert.pem -outform PEM
Step 12: 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.
[root@centos8-1 tls]# cat intermediate/certs/intermediate.cacert.pem certs/cacert.pem > intermediate/certs/ca-chain-bundle.cert.pem
OpenSSL verify Certificate Chain
After openssl create certificate chain, to verify certificate chain use below command:
[root@centos8-1 tls]# openssl verify -CAfile certs/cacert.pem intermediate/certs/ca-chain-bundle.cert.pem intermediate/certs/ca-chain-bundle.cert.pem: OK
To verify certificate chain for online pages such as Google:
[root@centos8-1 certs]# openssl s_client -quiet -connect google.com:443
depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
verify return:1
depth=1 C = US, O = Google Trust Services, CN = GTS CA 1O1
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
verify return:1
To show certificates from the certificate chain for Google:
[root@centos8-1 certs]# openssl s_client -showcerts -connect google.com:443 CONNECTED(00000003) depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign verify return:1 depth=1 C = US, O = Google Trust Services, CN = GTS CA 1O1 verify return:1 depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com verify return:1 <Output trimmed>
Conclusion
In this tutorial we learned how to create certificate chain using openssl with root and intermediate certificate. You can add upto "n" number of intermediate certificates in the certificate chain depending upon your requirement.
Lastly I hope the steps from the article for openssl create certificate chain with Root and Intermediate Certificate on Linux was helpful. So, let me know your suggestions and feedback using the comment section.
Next we will use this Root and Intermediate CA bundle to sign and generate server and client certificates to configure end to end encryption for Apache web server in Linux.
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
Very well written article, thank you
One of the best articles on the Web about this littlebit complex thing
why the hell you are using des3 for keys?!
in a hope that some day some wise guy will give me insights on why we shouldn’t use a secure private key.
LOL. Maybe karloff is working on something, but I doubt it. I’m sure, just like me, he visits your site for the amazing content. Unlike karloff, I’m not jealous, but super grateful for the resource you created! 😉
One thing I’m still struggling with is to get the Intermediate CA to index the certs and for the certs to appear in the given directory. It works on the Root CA where I can see the Intermediate CA in the index.
I did a diff between the conf files and apart from the words root and intermediate, they are the same.
BTW, I’d love to buy you a coffee, but the credit card interface didn’t look right to me.
Never mind, I noticed you had older comments and found the issue there. My mistake was to use openssl x509:
I should have used openssl ca
Great article, thanks a lot.
Awesome article! Saved my day.
Hello,
Thank you for this very instructive article that made me understand better.
Anyway a question is struggling me, why using an encrypted password?
When you use the parameter -passout:mypass.enc openssl uses the encrypted password to encrypt the key, and not the password itself (openssl does not ask for the encryption key of your password). So, I changed your command line in a way the password is asked to the user which is more secure. Do you agree?
Regards
Agreed. The only reason I added in the command so that we can automate the whole process or else it is preferred to provide pass as an input.
Hi Experts,
I have followed every steps and every think is working fine for me.
but I couldn’t able to work with following command “openssl s_client -quiet -connect google.com:443”.
In my LDAP server I am trying to use my internal LDAP server for SSL and StartTLS.
SSL I am getting below mentioned error.
With StartTLS I can connect but certificates are not showing while connect.
you can refer this once Configure OpenLDAP over SSL/TLS [Step-by-Step] Rocky Linux 8 and/or Simple steps to configure LDAPS with TLS certificates CentOS 7 Linux
you saved my day. thank you.
Fantastic tutorial! Everything worked as described. Thank you so much for sharing!
You can simulate everything on Ubuntu by tweaking config as follows:
– `/root/tls` may be any temporary directory anywhere you like.
– remove `RANDFILE = $ENV::HOME/.rnd` line.
– remove lines from [ default_modules ], [ ssl_module ] and [ crypto_policy ] sections. Leave these empty.
Use
to generate random file.