L0140 Make Your Own Intermediate CA Part 2

Creating Intermediate CA

Intermediate CA is almost the same as the root CA. We will follow the same steps; there will some small differences. I will use the name "iCA".

Intermediate CA File System

Everything needed for "iCA" must be placed into one file system. At the top we will have "iCA" folder, other files/folders are inside of the "iCA" folder.

iprivateThis is a folder where we will store the "iCA" private key.
inewcertsEvery certificate signed by the "iCA" will be stored here. Names of the files will be certificate serial numbers. This folder is used by OpenSSL to keep track of issued certificates, revocations, and duplicates.
iindex.txtThis is file that stores a list of all of the issued certificates.
V 280101120000Z 1000 unknown /CN=server1    # valid
E 280101120000Z 1001 unknown /CN=server2    # expired
R 270501120000Z 1002 unknown /CN=oldserver  # revoked
iserial.txtThis file will store the serial number for a new certificate. If that number is "X", the next certificate will be given serial number "X", and OpenSSL will update this text file to store the next serial number, which would be "X+1".
icertsThis directory is optional. Here we can place any certificate, and we can give meaningful names to those files. We can store here "iCA" certificate, and we can organize certificate chains for deployment.
icsrConvinient folder where we can place intermediate CA CSR's.
icrlThis is folder where we keep our CRL list.
icrlnumber.txtThis file is similar to "serial". It holds the number for the next version of CRL list.
iCA.cnfThis is configuration file used by the "iCA".

As we can see, everything is the same as for the root CA. I will use prefix "i" to differentiate root CA and intermediate CA files.

Permissions should be the same as for the "myCA" directories and files. I will not repeat those settings here.

Creation of the File System

cd /home/fff/Desktop
                                          
This is our current directory. 
mkdir iCAWe will make root folder. We will jump to that folder.cd iCA
mkdir iprivateThis empty folder is for a private key. 
mkdir inewcertsIssued certificates will be stored here. 
touch iindex.txtHere we will register newly issued certificates. 
touch iserial.txtInside of this file we will write initial hexadecimal serial number 2730.echo 5010 > serial.txt #even number of digits
mkdir icertsThis folder is optional. 
mkdir icsrHere we will place CSRs for leaf certificates. 
mkdir icrlEmpty folder for CRL file.                                                                                                 
touch icrlnumber.txtWe will set initial hexadecimal serial number for CRLs, in this file.echo 5010 > crlnumber.txt #even number of digits

Creation of the iCA Configuration File

[ca]
default_ca = CA_default
"[ca]" is one of the main sections. We will immediately refer to specialized section "[ca_default]".
[CA_default]
private_key       = ./iprivate/iCA.key
new_certs_dir     = ./inewcerts

database          = ./iindex.txt
serial            = ./iserial.txt
certs             = ./icerts
certificate       = ./icerts/iCA.crt
crl_dir           = ./icrl
crl               = ./icrl/iCA.crl
crlnumber         = ./icrlnumber.txt
default_days      = 365
default_crl_days  = 30
default_md        = sha256
copy_extensions   = none
crl_extensions    = crl_ext
x509_extensions   = v3_server
policy            = policy_leaf_certificate
unique_subject    = no
Not much is changed here.

Every folder/file has an "i" prefix. Length of the certificate is 365 days. That is shorter than 730 days for CA certificate.

Option "x509_extensions" refer to section with default extensions that this intermediate CA will use when signing a leaf certificate.    
[req]
default_md          = sha256
prompt              = no
distinguished_name  = intermediate_ca_dn
These settings are used for intermediate CA certificate. We will not provide any extensions for this certificate. Extensions, for intermediate CA, will be determined by the CA configuration file.
[intermediate_ca_dn]
countryName             = RS
stateOrProvinceName     = Serbia
localityName            = Belgrade
organizationName        = iCA organization
organizationalUnitName  = iCA unit
commonName              = Intermediate CA
These values will be used as intermediate CA distinguish name.
[policy_leaf_certificate]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
Distinguish name in leaf CSRs must match the same values in this configuration file. If they do not match then this intermediate CA can not sign that CSR.
match – they must match perfectly.
supplied – value doesn't have to match, but CSR should provide some value.
optional – whatever. There is no restriction.
[v3_server]
basicConstraints      = critical,CA:false
keyUsage              = critical,digitalSignature
extendedKeyUsage      = serverAuth
subjectKeyIdentifier  = hash
authorityKeyIdentifie = keyid:always,issuer
authorityInfoAccess   = @issuer_info
crlDistributionPoints = @crl_info
These are extensions that will be used when we sign some server certificate. These are the default extensions that will be used if we don't provide "-extensions" command line option.

For clients and users we will have to specify their extensions with the "-extensions" command line option.

[client_cert]                                                   
basicConstraints       = critical,CA:false
keyUsage               = critical,digitalSignature
extendedKeyUsage       = clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyed:always,issuer
authorityInfoAccess    = @issuer_info
crlDistributionPoints  = @crl_info
These are certificate extensions that are specific for client certificates.

[usr_cert]
basicConstraints      = critical,CA:false
keyUsage              = critical,digitalSignature
extendedKeyUsage      = emailProtection,clientAuth
authorityInfoAccess   = @issuer_info
crlDistributionPoints = @crl_info
These are certificate extensions that are specific for user certificates.
[v3_ocsp_responder]
basicConstraints       = critical,CA:false
keyUsage               = critical,digitalSignature
extendedKeyUsage       = critical,OCSPSigning
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always,issuer
noCheck                = ignored
For signing OCSP responds, we will use these extensions.
[issuer_info]
caIssuers;URI.0 = http://ica.example.com/ica.crt
OCSP;URI.0      = http://ocsp.example.com:7000
Here we can find intermediate CA certificate. Here is the address of the OCSP service.
[crl_info]
URI.0           = http://ica.example.com/iCa.crl  

[crl_ext]
authorityKeyIdentifier = keyid:always
Here are location and extensions of the CRL file.

We will create configuration file "touch iCA.cnf", and we will copy the text from above into that file.

Creating Private Key and Certificate for Intermediate CA

We will create private key for intermediate CA.openssl genpkey -algorithm ed25519 -out iprivate/iCA.key
We can read from this key.  
openssl pkey -in iprivate/iCA.key -text -noout

Next step is to create CSR file for intermediate CA.openssl req -new -config iCA.cnf -key iprivate/iCA.key -out icsr/iCA.csr
We can read and verify this CSR in one step.  
openssl req -in icsr/iCA.csr -noout -text -verify  

Creation of the Intermediate CA Certificate

For CA to sign our CSR request, we must first copy that request. We are copying it into "myCA" folder.  
cp icsr/iCA.csr ../myCA/icsr/iCA.csr
I will jump to "myCA" folder.

cd ../myCA

openssl ca -config myCA.cnf -extensions v3_intermediate_ca -in csr/iCA.csr -out ../iCA/icerts/iCA.crt

                                                                                                                                                                                                                  
We are now ready to sign intermediate CA certificate. We will use "ca" command.

We have a problem. In the DN section, organization name is different between CSR file and CA configuration file policy. We have to correct that.
I will correct intermediate CA configuration file, and I will again generate CSR file.

cd ../iCA
openssl req -new -config iCA.cnf -key iprivate/iCA.key -out icsr/iCA.csr

cp icsr/iCA.csr ../myCA/csr/iCA.csr

cd ../myCA
openssl ca -config myCA.cnf -extensions v3_intermediate_ca -in csr/iCA.csr -out ../iCA/icerts/iCA.crt


                                                                                                                                                                                                        
I will sign CSR file again. This time I will be asked to sign the certificate. I will confirm that.
We will be asked to update "index.txt" file. When using "ca" command everything will be updated.

Verifying Changes

We can read from our certificate.
cd ../iCA
openssl x509 -in icerts/iCA.crt -noout -text  

We can see that extensions are taken from the "myCA" configuration file.

We can also notice that "authorityKeyIdentifier" doesn't include issuer data. It seems that this version of OpenSSL doesn't do that.
We can verify our intermediate CA certificate. We are using CA certificate to verify intermediate CA certificate.
openssl verify -CAfile ../myCA/certs/myCA.crt icerts/iCA.crt

This time we will check whether intermediate CA certificate is revoked or not. For that we will use "myCA.crl" file.
openssl verify -CAfile ../myCA/certs/myCA.crt  -CRLfile ../myCA/crl/myCA.crl -crl_check icerts/iCA.crt

Certificate is not revoked.

Problem is that we want to check all CRL files in the chain. I will create an empty CRL file for "iCA".
openssl ca -config iCA.cnf -gencrl -out icrl/iCA.crl

We now have two CRL files. One is for "myCA" and the other for "iCA". We can provide only one file in the option "-CRLfile". Solution is to concatenate these two files into one.  
cat ../myCA/crl/myCA.crl icrl/iCA.crl > /home/fff/Desktop/all.crl
cat /home/fff/Desktop/all.crl
I will use this concatenated file to verify intermediate CA certificate.
openssl verify -CAfile ../myCA/certs/myCA.crt -CRLfile /home/fff/Desktop/all.crl -crl_check icerts/iCA.crt

Other Changes

This is the first time we created certificate using "ca" command. Many files will change. They will change in the "myCA" folder.

We will have a new entry in the "index.txt" file. Because we used "ca" command to create a certificate, we now have one valid entry.

The number in the file "serial.txt" is increased to 2731. That number will be used for the next signed certificate.

Two new files appeared. They are both "old" files used for backup.
"serial.txt.old" holds old serial number 2730.
The file "index.txt.attr.old" is a copy that still has a value "unique_subject = no".

L0130 Make Your Own CA Part 1

OpenSSL can be used to create a CA that we manage. A private CA is useful for creating an internal PKI and gaining control over internally used certificates. A private CA can be the best solution in networks that do not have access to the Internet. Without the Internet, it is not possible to access commercial CRL and OCSP services.

For larger projects, enterprises use dedicated software that provides web interface, access control, auditing. Examples of such software are Dogtag Certificate System, Microsoft Active Directory Certificate Services, HashiCorp Vault.

Creation of Your Own CA

We will use name "myCA" to refer to CA that we will create.

Directory Structure

Everything needed for "myCA" must be placed into one directory system. At the top we will have "myCA" folder, other files/folders are inside of the "myCA" folder.

privateThis is a folder where we will store the "myCA" private key.
newcertsEvery certificate signed by the "myCA" will be stored here. Names of the files will be certificate serial numbers. This folder is used by OpenSSL to keep track of issued certificates, revocations, and duplicates.
index.txtThis is file that stores a list of all of the issued certificates.
V 280101120000Z 1000 unknown /CN=server1    # valid
E 280101120000Z 1001 unknown /CN=server2    # expired
R 270501120000Z 1002 unknown /CN=oldserver  # revoked
serial.txtThis file will store the serial number for a new certificate. If that number is "X", the next certificate will be given serial number "X", and OpenSSL will update this text file to store the next serial number, which would be "X+1".
certsThis directory is optional. Here we can place any certificate, and we can give meaningful names to those files. We can store here "myCA" certificate, and we can organize certificate chains for deployment.
csrConvinient folder where we can place intermediate CA CSR's.
crlThis is folder where we keep our CRL list.
crlnumber.txtThis file is similar to "serial". It holds the number for the next version of CRL list.
myCA.cnfThis is configuration file used by the "myCA".

Creation of a Directory Structure

We will create files/folders needed for "myCA". We will place initial values into some of the files.

cd /home/fff/Desktop      This is our current directory. 
mkdir myCAWe will make root folder. We will jump to that folder.cd myCA
mkdir privateThis empty folder is for a private key. 
mkdir newcertsIssued certificates will be stored here. 
touch index.txtHere we will register newly issued certificates. 
touch serial.txtInside of this file we will write initial hexadecimal serial number 2730.echo 2730 > serial.txt #even number of digits
mkdir certsThis folder is optional. 
mkdir csrHere we will place CSRs for intermediate CAs. 
mkdir crlEmpty folder for CRL file. 
touch crlnumber.txtWe will set initial hexadecimal serial number for CRLs, in this file.echo 2730 > crlnumber.txt #even number of digits

Creation of OpenSSL Configuration File

[ca]
default_ca = CA_default
This section will direct us toward "CA_default" section.
[CA_default]
private_key       = ./private/myCA.key
new_certs_dir     = ./newcerts
database          = ./index.txt
serial            = ./serial.txt
certs             = ./certs
certificate       = ./certs/myCA.crt
crl_dir           = ./crl
crl               = ./crl/myCA.crl
crlnumber         = ./crlnumber.txt
default_days      = 730
default_crl_days  = 30
default_md        = sha256
copy_extensions   = none
crl_extensions    = crl_ext
x509_extensions   = v3_intermediate_ca
policy            = policy_intermediate_ca
unique_subject    = no
This section is the major section. Here we will write locations of all of the main folders and files, and other CA related data.

Option "x509_extensions" refers to default extensions that CA will use when it signs some certificate. Because this CA will only sign intermediate CA's certificates, we will be explicit and we will place those extensions in the section "v3_intermediate_ca".

Section "policy" will refer to section where we will specify what Distinguish Name values ( Country, State, City ) must match between intermediate CA CSR and this configuration file.

New option is "copy-extension". That means that none of the intermediate CA CSR extensions will be copied to certificate. Ony extensions specified in the section "v3_intermediate_ca" will be used. We want the full control.

Option "unique_subject" will allow us to issue several certificates for the same Subject. Without this option, we will be prohibited to have two valid certificates for the same subject in "index.txt".
[req]
default_md = sha256
prompt = no
distinguished_name = ca_dn
x509_extensions    = v3_ca
Here we will place data that will define characteristics of the CA self-signed certificate.
[ca_dn]
countryName            = RS
stateOrProvinceName    = Serbia
localityName           = Belgrade
organizationName       = CA organization
organizationalUnitName = CA unit
commonName             = Root CA
This is a section for distinguished name for the CA self-signed certificate.
[v3_ca]                                                    
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true,pathlen:1
keyUsage = critical,digitalSignature,  \            cRLSign,keyCertSign
These extensions will be added to CA certificate. Pathlen is set to 1 because we only allow one intermediate CA.

Here we can see keyword "always". This keyword means that if we can not include some element ( key hash in this case ) in a certificate, then creation of a certificate should fail.

[policy_intermediate_ca]         
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied  
This section will tell what options from the CSR must match options in "myCA.cnf" file. Possible values are "match, supplied, optional".
- match     >   the values must match. If they do not match, we will not be able to sign CSR.
- supplied  >   option must exist, but it does not have to have the same value as in "myCA.cnf" file.
- optional  >   we can do whatever.

For internal CA, we should mostly use "optional".

[v3_intermediate_ca]
subjectKeyIdentifier    = hash

authorityKeyIdentifier  = keyid:always,issuer
basicConstraints        = critical,CA:true,pathlen:0
keyUsage                = critical,keyCertSign,cRLSign
crlDistributionPoints   = @ca_crl_distribution_point

[ca_crl_distribution_point]
URI.0                   = http://ca.example.com/myCa.crl

[crl_ext]
authorityKeyIdentifier  = keyid:always
These are extensions that will be added to intermediate CA certificates.

Notice that we are using the sign "@" for "crlDistributionPoints". Some options expect a section name so there is no need for "@" sign. This option "crlDistributionPoints" is not expecting a section name. That is why in this case we use "@" prefix.

We can notice that only sections "ca" and "req" are colored in black. They are the main sections that must exist. Every other section is just for better organization, must be referenced from somewhere, and can be named anyway we like.

Sections "req, ca_dn, v3_ca" are for the self signed CA certificate. Sections "policy_intermediate_ca" and "v3_intermediate_ca" are for the certificates of the intermediate CAs.

We will create configuration file "touch myCA.cnf", and we will copy the text from above into that file.

Random Serial Numbers

Inside of the [CA_default] section, we can have this option. If we use this option, then the "serial" file will be unused.
rand_serial = yes
This option means that serial number of certificates will not be serial number ( 1000, 1001, 1002… ). Instead of that, it will be random hexadecimal number ( 4F8A91D03B7E2C11, A93C72E5B18D904F…).

We should use this option set to "yes". That would make our setup safer, and it is recommended. I will not set it to "yes" in my example. Instead of that I used random number 2730 as my first serial number. This is usually enough to distinguish serial numbers from "myCA" and some other internal CA that could also exist in our organization.

We should always have file "serial" file. Some OpenSSL commands and external tools expect this file to be present.

Permissions of the Files and Folders

Now that we have all of the files and folders, we can protect them. I will not apply these permissions because this is just educational demonstration, but in production these are the levels of protection that you need. I will remind you that "4 (read) + 2 (write) + 1 (execute) = 7".

chmod 700 /home/fff/Desktop/myCAOnly administrator should have access to "myCA" folder.
chmod 700 private
chmod 600 private/*
It is the same for a "private" folder and its content.
chmod 755 newcerts chmod 644 newcerts/*Certificates are public. For them we can put less restrictive permissions.
chmod 600 index.txtIndex file is important for functioning of the CA, so we will protect it strictly.
chmod 600 serialThe same as for "index.txt", because messing with this folder can corrupt CA.
chmod 755 certs chmod 644 certs/*This is the same as for "newcerts" folder.
chmod 755 csr chmod 644 csr/*These are the permissions for CSRs.
chmod 755 crl chmod 644 crl/*CRLs are public information. The same as for certificates.
chmod 600 crlnumber chmod 600 crlnumber/*It is recommended that only root has access to this folder.
chmod 644 myCA.cnfConfiguration file should be protected, too.

Creation of the CA Private Key and Certificate

We will create the CA private key and we will place it into "private" folder.openssl genpkey -algorithm ed25519 -out private/myCA.key

Now that we have a key, we can create CA CSR file. For it, we have to provide the name of a configuration file.
openssl req -config myCA.cnf -new -key private/myCA.key -out csr/myCA.csr

Inside of the CSR file we can see our Subject, and no Extensions.
openssl req -in csr/myCA.csr -noout -text  

We will sign CA certificate using x509 command. We will use extensions from v3_ca section. Note that when we create a certificate with "-x509" command, there will be no new entry in "index.txt, newcerts or serial.txt". There is no need to register CA certificate.

openssl req -new -x509 -config myCA.cnf -key private/myCA.key -extensions v3_ca -out certs/myCA.crt 
When we use "ca" command for signing, only then there will be changes in the "index.txt, serial.txt, newcerts". For selfsigning CA certificate we don't need that. That is why we will use ordinary "-x509" command.

We can read from the newly create certificate.  
openssl x509 -in certs/myCA.crt -noout -text

We can notice one thing. There is no "issuer" for "Authority Key Identifier", we only have "keyID". This is normal because we are using self signed certificate, so there is no need for repetition. Subject and Authority are the same.
openssl verify -CAfile certs/myCA.crt certs/myCA.crtcerts/myCA.crt: OK    # We can verify certificate.

CRL

We can use "ca" command to create CRL file.openssl ca -config myCA.cnf -gencrl -out crl/myCA.crl
A new file will be created inside of the "crl" folder. This file will look like any other certificate or key, some text and base64 encoding between. Inside of the "crlnumber.txt" file, a number will increase by 1, and will become 2730 + 1 = 2731.
One new file will appear. This is a copy of "crlnumber.txt" file. It will have the old CRL serial number 2730.

We can read from the CRL file. We will see inside that there are no revoked certificates.  
openssl crl -in crl/myCA.crl -noout -text
We will verify the CRL file.
openssl crl -in crl/myCA.crl -CAfile certs/myCA.crt -noout -verify

# scp crl/myCa.crl webserver:/var/www/html/myCa.crlWe must copy the CRL file onto web server for download.

Certificate Revocation

This is how we revoke the certificate we made.  
openssl ca -config myCA.cnf -revoke certs/myCA.crt -crl_reason keyCompromise

These are the possible values for "-crl_reason".

unspecifiedkeyCompromiseCACompromiseaffiliationChangedsuperseededcessationOfOperationprivilegeWithdrawn
No specific reason.Subject private key is compromised.CA private key is compromised.Subject had organizational change.A new certificate is issued.Subject is closed.Usage and constraints of a certificate are changed.

Revoked certificate will be registered in the "index.txt" file. Letter "R" means that this certificate is Revoked.
cat index.txt

The first time we write something into "index.txt" database, the new files could appear. The file "index.txt.old" is backup of the "index.txt" file. In our case it is empty, because there was nothing in the "index.txt" file previously.
The file "index.txt.attr" contains the value of the option "unique_subject = no".

Crating a New CA Key and Certificate

We will again create the CA key and certificate.openssl genpkey -algorithm ed25519 -out private/myCA.key
openssl req -config myCA.cnf -new -key private/myCA.key -out csr/myCA.csr
openssl req -new -x509 -config myCA.cnf -key private/myCA.key -extensions v3_ca -out certs/myCA.crt

                                                                                                                                                                                                         

Now that we have a new key, we will create a new CRL file.
openssl ca -config myCA.cnf -gencrl -out crl/myCA.crl
We can read from this new CRL file.
openssl crl -in crl/myCA.crl -noout -text  

Inside of the CRL file, we will see our certificate revoked.
We can verify our CRL file.
openssl crl -in crl/myCA.crl -CAfile certs/myCA.crt -verify
# scp crl/myCa.crl webserver:/var/www/html/myCa.crlWe must copy the CRL file onto web server for download.

Because we created CRL file twice, the number in the "crlnumber.txt" file is 2732.

L0120 Configuration File for CSR and for a Certificate

OpenSSL Configuration File Sections Naming Convention

Names of configuration file sections are following established convention, but there is nothing that enforce that convention. We don't have to name our sections "req, req_dn, v3_req". We can name them "req, req_distinguish_name, req_ext". These are just labels for better organization.

The only time a section name matters is when something references it.req_extensions = my_ext

There are a few exceptions. If we want to use configuration file with "openssl -req" command, we should have "[req]" section. For "openssl -ca" command we should prepare "[ca]" section.

Configuration File for Creation of a CSR

When we want to create CSR file, we usually use these three sections:

[req] – major CSR options.[req_dn] – country, state, city.[v3_req] – extensions.

[req] Section

prompt = noThis option means that we will not be asked for Country, State, City. Instead of entering these values through interactive prompt, the values will be taken from configuration file.
If we say "prompt = yes", the values from the configuration file will be default values inside of the interactive prompt.
default_bits = 4096The size of RSA key.
default_md = sha256We use this option if we want to specify what hash algorithm should be used.
default_keyfile = private.keyThe default filename for the generated private key. This name will be used if not specified on the CLI.
encrypt_key = noShould the private key be encrypted.
distinguished_name = req_dn req_extensions = v3_reqThese are pointers toward sections that contains subject data and extensions.
utf8 = yesForces UTF-8 interpretation of config file input.
string_mask = utf8onlyCharacter set/encoding used for distinguished name string fields ( Country, State, City ).

[req_dn] Section

C: 2-letter ISO country codeL: CityOU: Organization unitemailAddress: Contact address
ST: State or ProvinceO: OrganizationCN: Domain or a person name  

[v3_req] Section

subjectAltName = DNS:example.com,IP:192.168.1.50Domain names and IP addresses that certificate will be used for.
basicConstraints = CA:FALSEThis option determines whether the certificate will be able to sign other certificates.
keyUsage = digitalSignature, keyEnciphermentWhat cryptographic operations the certificate's public key is allowed to perform
extendedKeyUsage = serverAuthExtension specifies for what scenarios a key may be used.
tlsfeature = status_requestThis requests the OCSP Must-Staple extension. Not all CAs honor it.

All the possible values for "keyUsage" are these. They are explained in the article about certificate extensions ( L0090 ).

digitalSignaturecontentCommitmentdataEnciphermentkeyAgreementkeyEncipherment
keyCertSigncRLSignencipherOnlydecipherOnly 

All the possible values for "extendedKeyUsage" are these. They are explained in the article about certificate extensions ( L0090 ).

serverAuthclientAuthcodeSigning
emailProtectiontimeStampingOCSPSigning

One Real Configuration File for CSR

I will create one configuration file with these options:  

cd /home/fff/Desktop
touch csr.cnf
[req]                              
default_bits       = 4096
default_md         = sha256 default_keyfile    = private.key
encrypt_key        = no
prompt             = no
distinguished_name = req_dn
req_extensions     = v3_req
[req_dn]               
C  = RS
ST = Serbia
L  = Belgrade
O  = Corporation
OU = Infra Team
CN = example.com
[v3_req]
basicConstraints = CA:FALSE
keyUsage         = digitalSignature extendedKeyUsage = serverAuth
subjectAltName   = DNS:example.com  

We will create RSA key and CSR using this configuration file. We can read the content of a CSR file.openssl req -new -newkey rsa -out request.csr -config csr.cnf
openssl req -in request.csr -text -noout

                                                                                                                                 

– We will not be asked to provide DN data, we will not be asked for a password for the private key.
– The name of a file with a private key will be taken from configuration file.

We can use the same configuration file to create elliptic curve key and associate CSR file.
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout ECprivate.key -out ECrequest.csr -config csr.cnf

Configuration File for Creation of a Certificate

This time, a Certificate Authority will sign our CSR file. I don't have a CA private key, so I will again use custom made private key. We will pretend that it was a CA that signed my CSR file.

I will create new configuration file. This file is different because it doesn't have "[v3_req]" section. This configuration file will have "[server_cert]" that is used when a CA sign a leaf certificate.
touch cert.cnf
[req]                                             
distinguished_name = req_dn prompt = no
x509_extensions = server_cert
[req_dn]                     
C  = RS
O  = My Company
CN = www.example.com
 
[server_cert]                           
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer subjectAltName = DNS:www.example.com

"[server_cert]" section is for extensions as we can see from its content.

subjectKeyIdentifier = hashWe will get this in a certificate:
X509v3 Subject Key Identifier:  
   24:A5:57:C8:96:47:19:44:19:EC:AB:0C:18:A5:D7:49:58:EF:E0:A1
This extension is asking for inclusion of SKI in the final certificate. We will use hash in the SKI.
authorityKeyIdentifier = keyid,issuer  
                                                                           
We will get this in certificate:
X509v3 Authority Key Identifier:
      keyid:AB:CD:EF:12:C8:96:47:19:44:19:EC:AB:0C:18:A5:D7:49:58:EF:E0:A1
      DirName:/C=US/O=Example CA/CN=Example Root CA
This extension is the same, but for AKI. Here we will use hash and distinguish name.

Creation of a Certificate

I will create one EC key, and only the key.
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out server.key
I will use settings from the configuration file to create CSR file.
openssl req -new -key server.key -out server.csr -config cert.cnf

I will read from the new CSR file. We will see no extensions. Extensions will appear in CSR file only when we have "[v3_req]" section. This time we assume that CA is the one who will define what extensions will be used. That is why we placed extensions in the "[server_cert]" section.
openssl req -in server.csr -text -noout

I will assume that we are now Certificate authority. We will sign the CSR. In the certificate we will place extensions from the "[server_cert]".
openssl x509 -req -in server.csr -signkey server.key -days 365 -out server.crt -extfile cert.cnf -extensions server_cert

Notice that we explicitly had to declare what is our configuration file and from where to pull extensions. When we create a certificate based on the CSR file, the command must be explicit what extensions to use. When the CA sign CSR file, CA must declared what extensions to use from the configuration file.

We will take a look into our certificate.
openssl x509 -in server.crt -text -noout  

Now, we can see the extensions. We have 6 extensions in our configuration file, and we can see all of their values here.    

Self Creation of a Certificate

There is another way how we can create a certificate. We can create a certificate directly from the private key. This is again a self signed certificate, but we are doing everything in two steps. First, we run a command to create a private key, and then we run a command to create a certificate from that private key. This time we will not create CSR file at all.

This time, CA is not involved, we will consider that "cert.cnf" file is our configuration file.

What is interesting about this command is that we don't have to be explicit. This command knows about "x509_extensions" option. That option will direct this command to "[server_cert]" section.openssl req -new -x509 -key server.key -config cert.cnf -out server2.crt  
If we read from this certificate, we will see the same extensions as previous. There will be no difference in the certificate.  
openssl x509 -in server2.crt -text -noout

Why is OpenSSL API so Convoluted?

You've probably noticed by now that the OpenSSL API is far from easy to use. While it's the most important cryptographic library in existence, OpenSSL certainly has a "cryptic" user interface. Every command looks the same. This is due to:

– the complexity of the problem
– the accumulated decades of compatibility requirements
– the need to introduce new cryptographic technologies and methods
– the limitations of the ecosystem, a library with millions of users cannot be developed as aggressively as a newer project
– OpenSSL provides low-level primitives that support many workflows
– OpenSSL was created by cryptographic experts, but is now used by self-taught hobbyists

This is the same problem that plagues Qt, Git and Python Pandas. They seemingly perform simple functions, but somehow always seem overly complicated. Software entropy is a price for a long-term success.

L0110 OpenSSL Configuration File

Configuration File

Let's run this command to find configuration file.
openssl version -d
I will jump to this folder "/usr/lib/ssl". Inside of it we will find "openssl.cnf". We can see that this is not a file, but a symlink toward "/etc/ssl/openssl.cnf".
I will open the folder symlink is directed to. The file inside is writable only by the root.
cd /etc/ssl

I will open this file, as a read only. I will see there one big configuration file. This is configuration file for OpenSSL.  
nano /etc/ssl/openssl.cnf
This file is organized as a INI file. It is divided in sections, where the name of the section is between square brackets ( [policy_match] ). Settings are in the form of "key=value". Comments are starting with "#".

This configuration file is used to define default values that OpenSSL will use. This makes the usage of OpenSSL standardized and predictable.

Making of a Configuration File

We will never make changes in the configuration file provided by OpenSSL installation. We will make our own file that contains only those settings that we need. "Openssl.cnf" file is a huge file with many settings, but in reality, only some of them are regularly used.

I will create a file and I will paste this text into that file. For now, you don't have to know what this text means.
cd /home/fff/Desktop
touch openssl.cnf


After pasting, I will protect this file.
chmod 644 openssl.cnf  
chown root:root openssl.cnf
HOME = .                          # Unused variable. Dot is current directory.
KEY_SIZE = 2048                   # Variable
.include extensions.cnf           # Inclusion of another file
[req]   # CERTIFICATE REQUEST
   prompt = no
   default_bits
                  = $KEY_SIZE    # Key size when generating a new key
   default_md
                      = sha256             # Hash algorithm
   distinguished_name   = req_dn
             # Referring to other section
   x509_extensions
            = server_cert   # Referring to section in included file
[req_dn] # DISTINGUISHED NAME
   countryName             = RS

   organizationName        = Organization
   commonName              = Common Name                                          
                                                                            

Inclusion of Other File

The third line in the configuration file is for including another configuration subfile. Everything we place in this other configuration file will be available inside of the main configuration file.
.include extensions.cnf  

I will create this subfile.
touch extensions.cnf  

I will add the content to this file, and I will set safety attributes.
chmod 644 extensions.cnf  
chown root:root extensions.cnf
[server_cert]   # CERTIFICATE EXTENSIONS
   basicConstraints = critical,CA:FALSE
   keyUsage = critical, \
              digitalSignature,  \
              keyEncipherment
   extendedKeyUsage = serverAuth
   subjectKeyIdentifier = hash
   authorityKeyIdentifier = keyid
   subjectAltName = @alt_names
[alt_names]   # SUBJECT ALTERNATIVE NAMES
   DNS.1 = example.com
   DNS.2 = www.example.com
   DNS.3 = mail.example.com
   IP.1  = 192.168.1.100
                                                                                               

Using The Configuration File

We can use the configuration file we created to create self signed key.
openssl req -new -newkey rsa -noenc -x509 -days 365 -config openssl.cnf -keyout private.key -out certificate.crt

We can read some segments from our certificate. Inside data is taken from the configuration file.

openssl x509 -in certificate.crt -text -noout

Characteristics of a Configuration File

Variables

At the top we can see two variables. We can later refer to these variables like this. We write the dollar sign before the variable name.
default_bits = $KEY_SIZE   
HOME = .        # Unused variable. Dot is current directory.
KEY_SIZE = 2048 # Variable

Inclusion of Other File

We have already saw how to include another file. Here, I will tell you to include another file only after the variables.KEY_SIZE = 2048            # Variable
.include extensions.cnf    # Inclusion of other file
If we reverse the order, subfile will be expanded above variables. Because the section [alt_names] ends when the new section starts, the variable KEY_SIZE will be considered as a part of the [alt_names] section. This will raise an error. This is why it is important to first declare variables.

Major Sections in "openssl.cnf" File

[req]Here we place fields that are important for creation of CSR and self signed certificates.
[req_dn]Fields that explain subject are here ( Country, State, City… ).
[v3_req],[usr_cert],[ v3_ca ]This is where we place extensions ( basicConstraints, keyUsage, authorityKeyIdentifier … ).
[ca],[CA_default]You can be your own CA. For that you use these sections.
[policy_match],[policy_anything]Used when we are CA. It limits possible values in CSR ( countryName=match, organizationName=match ).

Multiline Settings

We can turn a long line into a multi-line line by putting a backslash at the end of each line.keyUsage = critical, \
          digitalSignature,  \
          keyEncipherment

Comments

Comments start with a sharp sign.# See doc/man5/config.pod for more info.

Referring to Another Section

For better organization, we can divide some sections into several sections. We can then reference the detailed sections by their name within the main section. The detailed sections can be from an included file.distinguished_name  = req_dn       # Referring to other section
x509_extensions     = server_cert  # Referring to section in included file
[req]   # CERTIFICATE REQUEST
   prompt = no
[server_cert]   # CERTIFICATE EXTENSIONS
   basicConstraints = critical,CA:FALSE
                                                                                                                                                                          

Long Lists

Long lists, like this one, can be difficult to read. We can break such list into lines inside of the auxiliary section.
subjectAltName = DNS:example.com,DNS:www.example.com,DNS:mail.example.com,IP:192.168.1.100

Auxiliary sections are created as any other section, but can have custom names. When we refer to them, we must use the sign "@" before their name.[server_cert]  
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = mail.example.com
IP.1 = 192.168.1.100
There are other items where we can break a list into separate section, too.crlDistributionPoints = @crldp
[crldp]

URI.1 = http://example.com/root.crl

Safety

Configuration file will never contain private keys, but it can contain sensitive paths or passwords. Sensitive paths can lead to private keys. We should avoid placing delicate data inside of this file.

Location of "openssl.cnf" File

1) OpenSSL will first search for a configuration file on the location written inside of the environment variable "OPENSSL_CONF".
2) We can write the exact location of the configuration file in the command that we use ( -config /home/fff/Desktop/openssl.cnf ).
3) We will use default configuration file that was created during installation ( openssl version -d ).

I will create a new folder. I will copy the files "extensions.cnf" and "openssl.cnf" in that folder. We now have 2 versions of these 2 files. We also have official "openssl.cnf" file. We will use them all for testing.

1) IncludeIF ( Official Configuration File )

I will open official configuration file in nano text editor.
sudo nano /etc/ssl/openssl.cnf
I will add this line into it, below variables.
.includeif nonExistentFile.cnf

The purpose of this command is to include another configuration file, but only if that file exists. Otherwise, it will be ignored.

I will create certificate using official certification file. I am expecting that no error will be raised. This time, we don't use "-config" option.
openssl req -new -newkey rsa -noenc -x509 -days 365 -keyout privateOfficial.key -out certificateOfficial.crt

We will be asked to provide subject data, but no error will appear. "IncludeIF" command is ignored.I will now read the content of my certificate. Inside of it I can see that the default organization is "Internet Widgits Pty Ltd".
openssl x509 -in /home/fff/Desktop/certificateOfficial.crt -text -noout

If we read from the official "openssl.cnf" file, we can see where from the organization name comes from.
sudo cat /etc/ssl/openssl.cnf | grep Widgits

2) Variables from Other Sections ( Version 1 Files )

Inside of the version 1 "openssl.cnf" file I will make some changes.
I will create a new variable inside of the "req" section with a name "newVariable". I will reference that variable in "req_dn" section.
[req]   # CERTIFICATE REQUEST
   newVariable = Ultra Organization  # we will add new variable
[req_dn] # DISTINGUISHED NAME

   organizationName = $req::newVariable
                                                                                                                                            

I will create new certificate by using Version 1 configuration file.
openssl req -new -newkey rsa -noenc -x509 -days 365 -config openssl.cnf -keyout privateNewV.key -out certificateNewV.crt

I will read from this new certificate. We read variable from other section.
openssl x509 -in certificateNewV.crt -text -noout | grep Subject

3) Environment Variables ( Version 2 Files )

I will read the content of the USERNAME environment variable.env | grep USERNAME   # USERNAME=fff
We can use this environment variable inside of the "openssl.cnf" file, version 2. I will change the value of "organizationName" into the value of this environ.organizationName = $ENV::USERNAME
This time I will set "OPENSSL_CONF" environment variable.export OPENSSL_CONF="/home/fff/Desktop/CNF Version2/openssl.cnf"

I will create new key and certificate. Let's see what version of configuration file will this command use.
openssl req -new -newkey rsa -noenc -x509 -days 365 -keyout privateENV.key -out certificateENV.crt

Version 2 of a configuration file is used. This is thanks to "OPENSS_CONF" environ. The value of organization field is the same as USERNAME environ.
openssl x509 -in certificateENV.crt -text -noout | grep Subject

L0100 Certificate Extensions Part 2

We will continue talking about certificate extensions from Reddit.
openssl s_client -connect reddit.com:443 </dev/null | openssl x509 -text -noout

Authority Information Access ( AIA )

This extension offers two pieces of information:
– On-line register to check certificate validity.
– Site to download CA issuer certificate.

Both OCSP and "CA Issuers" are using HTTP ( not HTTPS ). They only contain public data and are signed ( integrity is protected ).

OCSP

OCSP ( On-line Certificate Status Protocol ) is online white list of valid certificates. When the client receives the certificate, the client will read OCSP web site address from that certificate. The client will send serial number of a certificate and public key hash to that web site, and it will get an answer whether the certificate is valid. The answer can be: good, revoked or unknown.  

OCSP vs CRL ( Certificate Revocation List )

OCSP has two major advantages over CRL.1) The size of CRL file is in MB, OCSP traffic is in KB.2) OCSP lists are updated more often.

Unfortunately, OCSP has two drawbacks:
1) If OCSP service is down, it is not possible to verify a certificate. In that case, most internet browser will ignore OCSP if it is not available.
2) OCSP is now informed about each web site the client visited. That is a compromise of privacy.

OCSP vs OCSP Stapling

Instead of OCSP, modern browsers use OCSP stapling. This is how OCSP stapling works. Every few hours, the server will download a signed confirmation from a certificate authority that the server's certificate is valid. That confirmation is time stamped and has a limited lifespan. Now the server has proof that its certificate is valid.
During TLS handshake between the server and client, the server will give the client its certificate, and signed confirmation. We can think of OCSP confirmation stapled to a certificate. Client can now trust the server's certificate.

These are the benefits of OCSP stapling:
1) CA can not monitor what web addresses the client is visiting. The privacy is preserved.
2) Less of internet traffic and less burden on OCSP server.
3) It is not a problem if OCSP stapling service is down. The server can cache OCSP stapling, so everything works until OCSP stapling service is up again.

Modern browsers will try OCSP Stapling, if that fails, they will try OCSP, and as a last resort they will try CRL.

CA Issuers

According to CRT extension, this link certainly contains a certificate.http://cacerts.digicert.com/DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt
We will download that certificate with WGET command.cd /home/fff/Desktop                                                                                                               
wget http://cacerts.digicert.com/DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt

This is DER certificate. We can read its content.openssl x509 -in DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt -inform DER -text -noout
                                                                                                                                                                        
Inside of this certificate we will see familiar numbers. Based on them we know that this is intermediate certificate.

To verify a server certificate, a client must have the entire certificate chain, from the root CA certificate to the leaf certificate. However, misconfigured web servers often forget to include intermediate certificates, sending only their own end-entity certificate. In this case, we can use the CA certificate issuer link to follow the certificate chain upstream and complete the entire certificate chain. This is known as AIA Chaining.

How to Use OCSP for Manual Check?

We already know that OCSP link is "http://ocsp.digicert.com". We can get it separately like this:
openssl s_client -connect reddit.com:443 </dev/null | openssl x509 -noout -ext authorityInfoAccess

We already have intermediate certificate ( from AIA link ↑ ). I will download the leaf certificate.
openssl s_client -connect reddit.com:443 </dev/null | openssl x509 -out LeafCert.crt
Now that we have both certificate ( leaf and intermediate ), and we know OCSP link, we can use ocsp command.
openssl ocsp -issuer DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt -cert LeafCert.crt -url http://ocsp.digicert.com

This will be the result. According to OCSP response, our certificate has status good. This answer will be valid for 7 days.

How to Check if CA Supports OCSP Stapling?

We will read Reddit.com certificate. We will use option "-status".openssl s_client -connect reddit.com:443 -status </dev/null

If we get a response that contains this block of data, that means that our CA supports OCSP stapling.

Basic Constraint

For Reddit, this extension is FALSE. That means that this certificate can not be used to validate other certificates. Only certificates of Certification Authorities have this extension set to TRUE.
We can read this extension from intermediate certificate. For DigiCert, this extension is set to TRUE.
openssl x509 -in http://cacerts.digicert.com/DigiCertGlobalG2TLSRSASHA2562020CA1-1.crt -noout -ext basicConstraints

We can also notice that there is "pathlen" property for DigiCert basic constraint. If the value for "pathlen" is 0, that means that below this certificate there can be zero intermediate certificates. This value shows how many intermediate certificates can be below DigiCert certificate.

On the image we can see that this limit makes impossible for someone to prolong certificate chain. Without this setting, anyone would be able to use legitim certificate to sign fake certificates.

This extension is always labeled as "critical". A client must obey this extension. If a client doesn't understand this extension, then it must reject connection with a server.

CT Precertificate SCTs

Certificate Authorities can be hacked or they can make a mistake. CAs can be coerced by the local government. This can lead to CA creating fake certificates for important web sites. For example, a new certificate can be created for a fraudulent bank web site. When a client access that web site, a client will not know that it is a rogue web site. That web site can now steal the client's password.

Solution is to monitor creation of the new certificates. These days every new certificate must be registered on online lists that are known as "Certificate Transparency logs". CA will create uncomplete certificate "Precertificate" (1). The precertificate will be send to CT (2). CT will create final certificate (3). Final certificate will have "CT Precertificate SCTs"  (4) extension. Thanks to that extension, certificate now has a proof that it is registered in CT logs.
Now it is possible to check whether someone issued an illegal certificate for the web site we own.  This is done by searching for a web site name on CT logs.

SCT is "Signed Certificate Timestamp". SCT is signed promise that CT received a precertificate and will add it to its list. SCT registries are append-only. After the certificate is in the CT logs, it will never be deleted.

Structure of SCT

All SCTs are version 1. This is version of SCT specification.Version: v1 (0x0)
SHA-256 hash identifying which specific CT log issued this receiptLog ID: C2:31:7E:57:45:19:A3:45:EE:7F:38:DE:B2:90:41:EB
The moment when the CT log accepted the certificate submission.Timestamp: Apr 8 00:01:08.826 2026 GMT
Reserved for future protocol extensions.Extensions: none
This is SCT, signed by the CT.Signature: ecdsa-with-SHA256
           30:46:02:21:00:96:D3:21:12:DC:D0:84:D9:A9:A4:F2

Modern certificates must have at least two or three SCTs, so that browser would trust them.
            certificate < 180 days                 2 SCTs
180 days  < certificate < 15 months    
     3 SCTs
15 months < certificate
                                     more than 3

CT logs are operated by different independent organizations (Google, Cloudflare, DigiCert, Sectigo, and others each run logs).

We can isolate and read SCTs with the option "ct_precert_scts".
openssl s_client -connect reddit.com:443 </dev/null | openssl x509 -noout -ext ct_precert_scts

CT logs

I will give you two web sites where you can search through SCTs.https://crt.sh                              # this may often be unavailable https://www.certkit.io/tools/ct-logs/
On these web sites you can type the name of your domain and you will get a list of all of the certificates that are issued for that domain.
SCTs are stored in so called "Merkle tree". Each pair of SCTs is hashed, and then results are hashed, until we get a root hash. All SCTs are connected in one big hierarchy. That makes impossible for someone to tamper with SCTs.

Merkle tree is technology that is internally used by blockchain.

Other Extensions

Reddit has the most used and important certificate extensions. There are many more possible extensions, which are usually specialized.

Freshest CRL:
    URI:http://ca.example.com/delta.crl
Because CRL files have size too big, it is possible to download them incrementally. In that case we only download delta CRL that contains only changes since the last full CRL.
X509v3 Subject Information Access:
   CA Repository - URI:ldap://ldap.example.com/cn=ExampleCA
This is opposite to AIA. AIA is about CA. SIA is about the certificate owner.
S/MIME Capabilities:
    AES-256-CBC
    AES-192-CBC
This email server supports next symmetric encryption algorithms.