OpenSSL Certificate Bundle / Chain [Root and Intermediate CA certificates]

Authenticity of a certificate is verified by signing from a Certificate Authority. We will be using CA cert and CA key for signing a Certificate Signing Request provided by the client. It is not recommended to sign a certificate directly with root CA, rather than use intermediate CA. This is because, if RootCA is compromised, it will be difficult to revoke a RootCA. In this article we will see how to create a RootCA and we will be using that RootCA to create an intermediate CA.

Create Root CA

Create directory structure for Root CA

We will be creating a directory structure in the parent directory ca

[root@3-vcp int]# mkdir ca;cd ca

[root@3-vcp ca]# mkdir certs crl newcerts pvt_key
[root@3-vcp ca]# ll
total 16
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 certs
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 crl
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 newcerts
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 pvt_key

Creating data base for issued certificates

We will be creating a flat file called serial and a file called index.txt. The serial file contain the next available serial number in Hex. Index.txt will have the details on the issued certificates

[root@3-vcp ca]# touch index.txt
[root@3-vcp ca]# echo 00 > serial
[root@3-vcp ca]# ll
total 20
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 certs
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 crl
-rw-r--r--. 1 root root 0 Aug 9 12:34 index.txt
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 newcerts
drwxr-xr-x. 2 root root 4096 Aug 9 12:15 pvt_key
-rw-r--r--. 1 root root 3 Aug 9 12:34 serial

openssl conf file preparation

We must prepare an openssl configuration file for us to use. Below code snippet shows the configuration file used for this article. Explanations for the section of interest is given below code snippet


# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.

[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ]
# Directory and file locations
dir               = /root/int/ca
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/pvt_key/.rand

# The root key and root certificate.
private_key       = $dir/pvt_key/ca.key.pem
certificate       = $dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_ca

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

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

[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 4096
distinguished_name  = req_distinguished_name
string_mask         = default

# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

[ req_distinguished_name ]
countryName = Country Name (2 letter code) 
countryName_default = AU 
countryName_min = 2 
countryName_max = 2
stateOrProvinceName = State or Province Name (full name) 
localityName = Locality Name (eg, city) 
organizationalUnitName = Organizational Unit Name (eg, section)
0.organizationName = Organization Name (eg, company) 
commonName = Common Name (eg, YOUR name)
commonName_max = 64 
emailAddress = Email Address 
emailAddress_max = 40

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

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

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

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
  • we will have to specify [ ca ], section to pick the options available from [ CA_default ]. This can be seen in the below code snippet.
  • We will have to update the directory path in the section under [ CA_default ], with the path we have created
[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ] 
# Directory and file locations 
dir = /root/int/ca 
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/pvt_key/.rand

# The root key and root certificate.
private_key       = $dir/pvt_key/ca.key.pem
certificate       = $dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber         = $dir/crlnumber
crl               = $dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256
name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_ca
  • we will be providing a separate policy for ca and intermediate ca
  • For CA , we will be providing [ policy_ca ], for intermediate CA, we will be providing [ policy_int ]
  • In the below code snippet, it can be seen phrases match, optional, supplied
  • If the value is "match" then the field value must match the same field in the CA certificate.
  • If the value is "supplied" then it must be present, but value need not to be same as CA
  •  If the value is "optional" then it may/maynot be present.
[ policy_ca ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ policy_int ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
  • Parameter mentioned in the [ req ] sections are applied when creating CSR or Certificates
[ req ]
# Options for the `req` tool (`man req`).
default_bits        = 4096
distinguished_name  = req_distinguished_name
string_mask         = default
# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca
  • The value given in the field "distinguished name"   need to be declared. This section contains the infomration which is required for creating a new Ceritifacte signing request (CSR)
 [ req_distinguished_name ]
countryName = Country Name (2 letter code) 
countryName_default = AU 
countryName_min = 2 
countryName_max = 2
stateOrProvinceName = State or Province Name (full name) 
localityName = Locality Name (eg, city) 
organizationalUnitName = Organizational Unit Name (eg, section)
0.organizationName = Organization Name (eg, company) 
commonName = Common Name (eg, YOUR name)
commonName_max = 64 
emailAddress = Email Address 
emailAddress_max = 40
  • The fields [ v3_ca ] and [ v3_intermediate_ca ] , will be used as extension parameter for creating root and intermediate certificate
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

 

Create Private key for RootCA

  • We will be creating a private key for with 4096 bits size and we will be using 3des encryption
  • It is necessary to ensure, we use protect the key with password, hence using 3des encryption and AES 256 encryption
[root@3-vcp ca]# openssl genrsa -aes256 -out pvt_key/ca.key.pem 4096
Generating RSA private key, 4096 bit long modulus
...............++
..............................................................................++
e is 65537 (0x10001)
Enter pass phrase for pvt_key/ca.key.pem:
Verifying - Enter pass phrase for pvt_key/ca.key.pem:
[root@3-vcp ca]#

Create Root CA Certificate

  • Certificate can be created by req  utility in openssl
  • For creating Root CA certificate, we will be mentioning the custom openssl config file.
[root@3-vcp ca]# openssl req -config openssl.cnf -key pvt_key/ca.key.pem -new -x509 -days 10000 -sha256 -extensions v3_ca -out certs/ca.cert.pem
Enter pass phrase for pvt_key/ca.key.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) [AU]:IN
State or Province Name (full name) []:Karnataka
Locality Name (eg, city) []:Bangalore
Organizational Unit Name (eg, section) []:LinuxDataHub_CA
Organization Name (eg, company) []:LinuxDataHub
Common Name (eg, YOUR name) []:linuxdatahub_ca_cert
Email Address []:[email protected]

Verify the Root CA

We can verify the Certificate to check the signature algorithm, validity, Issuer etc. Below code snippet shows the same

[root@3-vcp ca]# openssl x509 -noout -text -in certs/ca.cert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
b9:98:38:94:0c:bd:1d:ba
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=IN, ST=Karnataka, L=Bangalore, OU=LinuxDataHub_CA, O=LinuxDataHub, CN=linuxdatahub_ca_cert/[email protected]
Validity
Not Before: Aug 9 14:26:44 2022 GMT
Not After : Dec 25 14:26:44 2049 GMT
Subject: C=IN, ST=Karnataka, L=Bangalore, OU=LinuxDataHub_CA, O=LinuxDataHub, CN=linuxdatahub_ca_cert/[email protected]
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:

Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier: 
7E:B0:9C:31:D7:A9:A7:10:52:14:51:97:1E:52:13:1D:04:73:4F:3C
X509v3 Authority Key Identifier: 
keyid:7E:B0:9C:31:D7:A9:A7:10:52:14:51:97:1E:52:13:1D:04:73:4F:3C

X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption

It can be seen that in the X509v3 extensions, we can see the fields from the option [ v3_ca ] given in the openssl.conf file

Create Intermediate Certificates

Create directory structure for Intermediate Certificates

We will creating a directory structure for holding the files related to Intermediate cert generation

[root@3-vcp ca]# mkdir intermediate;cd intermediate
[root@3-vcp intermediate]# mkdir certs crl csr newcerts pvt_key
[root@3-vcp intermediate]# ll
total 20
drwxr-xr-x. 2 root root 4096 Aug 9 18:50 certs
drwxr-xr-x. 2 root root 4096 Aug 9 18:50 crl
drwxr-xr-x. 2 root root 4096 Aug 9 18:50 csr
drwxr-xr-x. 2 root root 4096 Aug 9 18:50 newcerts
drwxr-xr-x. 2 root root 4096 Aug 9 18:50 pvt_key

Creating data base for Intermediate certs

We will be creating a flat files called serial and crlnumber and a file called index.txt. The serial file contain the next available serial number in hex. Index.txt will have the details on the issued certificates. crlnumber file is used to keep track of the revoked  certificates.

[root@3-vcp intermediate]# pwd /root/int/ca/intermediate
[root@3-vcp intermediate]# touch index.txt
[root@3-vcp intermediate]# echo 00 > serial
[root@3-vcp intermediate]# echo 01 > crl/crlnumber

Creating Openssl configuration

We will be reusing the openssl configuration file which we have used, But with small modification

[ ca ]
# `man ca`
default_ca = CA_default

[ CA_default ]
# Directory and file locations
dir = /root/int/ca/intermediate
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/pvt_key/.rand

# The root key and root certificate.
private_key = $dir/pvt_key/inter_ca.key.pem
certificate = $dir/certs/inter_ca.cert.pem

# For certificate revocation lists.
crlnumber = $dir/crl/crlnumber
policy = policy_int

Create Private key for Intermediate CA

  • We will be creating an intermediate  private key for with 4096 bits size and we will be using 3des encryption
[root@3-vcp intermediate]# openssl genrsa -aes256 -out pvt_key/intermediate.key 4096
Generating RSA private key, 4096 bit long modulus
....................................++
...++
e is 65537 (0x10001)
Enter pass phrase for pvt_key/intermediate.key:
Verifying - Enter pass phrase for pvt_key/intermediate.key:
[root@3-vcp intermediate]#

Create  CSR for Intermediate CA

We will create a CSR using the private key which we have generated in the above step. It should be noted that the Common Name of the CSR should be different from the Root CA

[root@3-vcp intermediate]# openssl req -config openssl.cnf -new -sha256 -key pvt_key/intermediate.key -out csr/ntermediate.csr
Enter pass phrase for pvt_key/intermediate.key:
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) [AU]:IN
State or Province Name (full name) []:Karnataka
Locality Name (eg, city) []:Bangalore
Organizational Unit Name (eg, section) []:LDH-Banglore
Organization Name (eg, company) []:LinuxDataHub
Common Name (eg, YOUR name) []:LDH-Banglore-int-ca
Email Address []:[email protected]
[root@3-vcp intermediate]# 

 

Create  Intermediate CA certificate.

  • We will be using the Root CA to sign the intermediate CSR.
  • Below code snippet shows the signing process, we will be using the v3_intermediate_ca extension
[root@3-vcp intermediate]# openssl ca -config /root/int/ca/openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in csr/ntermediate.csr -out certs/int.ca
Using configuration from /root/int/ca/openssl.cnf
Enter pass phrase for /root/int/ca/pvt_key/ca.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 0 (0x0)
Validity
Not Before: Aug 9 14:32:20 2022 GMT
Not After : Aug 6 14:32:20 2032 GMT
Subject:
countryName = IN
stateOrProvinceName = Karnataka
organizationName = LinuxDataHub
organizationalUnitName = LDH-Banglore
commonName = LDH-Banglore-int-ca
emailAddress = [email protected]
X509v3 extensions:
X509v3 Subject Key Identifier: 
54:D1:6D:89:6D:22:9A:39:0C:F0:65:29:30:9E:5B:D9:50:DF:EB:C1
X509v3 Authority Key Identifier: 
keyid:7E:B0:9C:31:D7:A9:A7:10:52:14:51:97:1E:52:13:1D:04:73:4F:3C

X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Certificate is to be certified until Aug 6 14:32:20 2032 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

  • Since we have signed the intermediate CSR with RootCA, the index file belonging to RootCA will have the details. The Database file have been mentioned on the openssl conf file
[root@3-vcp ca]# cat index.txt
V 320806143220Z 00 unknown /C=IN/ST=Karnataka/O=LinuxDataHub/OU=LDH-Banglore/CN=LDH-Banglore-int-ca/[email protected]

Verify the Intermediate Certificate

  • We can list the content of the Intermediate certificate to view the issuer, expiry and other details for the certificates.
[root@3-vcp newcerts]# openssl x509 -noout -text -in int.ca
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=IN, ST=Karnataka, L=Bangalore, OU=LinuxDataHub_CA, O=LinuxDataHub, CN=linuxdatahub_ca_cert/[email protected]
Validity
Not Before: Aug 9 14:32:20 2022 GMT
Not After : Aug 6 14:32:20 2032 GMT
Subject: C=IN, ST=Karnataka, O=LinuxDataHub, OU=LDH-Banglore, CN=LDH-Banglore-int-ca/[email protected]
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier: 
54:D1:6D:89:6D:22:9A:39:0C:F0:65:29:30:9E:5B:D9:50:DF:EB:C1
X509v3 Authority Key Identifier: 
keyid:7E:B0:9C:31:D7:A9:A7:10:52:14:51:97:1E:52:13:1D:04:73:4F:3C

X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption

 

  • We can verify the intermediate certificate validity by checking against the Root CA
[root@3-vcp newcerts]# openssl verify -CAfile ../certs/ca.cert.pem int.ca 
int.ca: OK

Create Certificate Bundle.

For an application to verify the authenticity of a certificate, it need to verify the signing authority of signing CA. If we use an intermediate CA as the signing authority. The application need to verify the validity of the intermediate CA. For that we need to provide the Root CA also to the application. We will have to create a certificate bundle which contains the RootCA and the intermediate CA , for the application to verify.

For creating a certificate bundle, we need to concatenate the RootCA and intermediate CA to one file

[root@3-vcp intermediate]# cat ../certs/ca.cert.pem certs/int.ca > cert-bundle.pem

Verify Certificate Bundle

Openssl certificate chain can be verified against RootCA using the below command

[root@3-vcp intermediate]# openssl verify -CAfile ../certs/ca.cert.pem cert-bundle.pem
cert-bundle.pem: OK

Practical Example of the certificate chains

Below pic shows the certificate bundle of our website linuxdatahub.com provided by the CA providers

Root and Intermediate certificates with openssl

References

Directory structure

Below is the complete directory structure after the exercise of creating RootCA and intermediate CA

[root@3-vcp int]# tree .
.
└── ca
├── certs
│   └── ca.cert.pem
├── crl
├── index.txt
├── index.txt.attr
├── index.txt.old
├── intermediate
│   ├── cert-bundle.pem
│   ├── certs
│   │   ├── int.ca
│   │   └── int.ca.crt
│   ├── crl
│   │   └── crlnumber
│   ├── csr
│   │   └── ntermediate.csr
│   ├── index.txt
│   ├── newcerts
│   ├── openssl.cnf
│   ├── pvt_key
│   │   └── intermediate.key
│   └── serial
├── newcerts
│   └── 00.pem
├── openssl.cnf
├── pvt_key
│   └── ca.key.pem
├── serial
└── serial.old

11 directories, 18 files

Search on LinuxDataHub

2 thoughts on “OpenSSL Certificate Bundle / Chain [Root and Intermediate CA certificates]”

Leave a Comment