L0150 Make Your Own Leaf Certificates Part 3

We will create a leaf certificate for our server.

Server Certificate Configuration

Creation of a Directory System and Configuration File

I will use letter "s" as a prefix to label server directories. I will not apply permissions, because this is just demonstration.

cd /home/fff/DesktopThis is our working directory. 
mkdir serverThis will be our root folder. I will jump to it "cd server".chmod 700 server
mkdir sprivateIn this folder we will save server private key.chmod 700 private
chmod 600 private/*
mkdir scsrFolder for the CSR request.chmod 755 csr chmod 644 csr/*
mkdir scertsWe will place certificate in this directory.chmod 755 certs chmod 644 certs/*
mkdir sp12Here we will save certificate and key as PKCS#12 container.chmod 755 sp12 chmod 644 sp12/*
touch server.cnfConfiguration file.chmod 644 server.cnf

Server Configuration File

We will paste this text into our configuration file.

[req]
prompt              = no
default_md          = sha256
distinguished_name  = server_dn
req_extensions      = server_req_ext
This time we don't have "ca" section.
[server_dn]
countryName             = RS
stateOrProvinceName     = Serbia
localityName            = Belgrade
organizationName        = Server organization
organizationalUnitName  = Server unit
commonName              = server01.example.com
Distinguish name of our server. Per the intermediate CA policy, we must supply "commonName".
[server_req_ext]
subjectAltName          = @server_alt_names
All other extensions are defined inside of the intermediate CA configuration file.
[server_alt_names]
DNS.1 = server01.example.com
DNS.2 = server02.example.com
IP.1  = 192.168.1.50
We will use the certificate to sign several domains.

Creation of a Private Key and Certificate

We will create the new private key.openssl genpkey -algorithm ed25519 -out sprivate/server.key

We should never encrypt this file. The server will have to access this key so I will leave it unencrypted.

We will create CSR request.openssl req -new -config server.cnf -key sprivate/server.key -out scsr/server.csr
We can read this CSR and verify it, in the same time.  
openssl req -in scsr/server.csr -noout -text -verify
SAN is the only extension.

We will copy CSR to intermediate CA directory.
cp scsr/server.csr ../iCA/icsr/server.csr  

We will jump to intermediate CA folder. From there we can sign the CSR.
cd /home/fff/Desktop/iCA  

We can now create certificate. We will confirm signing. We will write to the "index.txt" that belongs to intermediate CA.
openssl ca -config iCA.cnf -extfile iCA.cnf -extensions v3_server -in icsr/server.csr -out ../server/scerts/server.crt

We can read from our certificate.  
openssl x509 -in ../server/scerts/server.crt -noout -text

Inside of it we will find all of the extensions from the iCA.cnf file, but we will not find SAN extension. We have to fix this problem!

How to Include SAN extension?

Our extensions are currently inside of the intermediate ca "iCA.cnf" configuration file, while SAN extension is inside of the leaf "server.cnf" configuration file. The "ca" command will only accept extensions from one configuration file. We have somehow to consolidate these 2 files.

The solution is to use "include" command. We must go back to "iCA.cnf" file, and there we must include SAN extension.

At the top of this configuration file, we will place include command:
.include ../server/server.cnf

In the section "v3_server", of "iCA.cnf" file, I will add SAN extension.
[v3_server]
basicConstraints      = critical,CA:false
keyUsage              = critical,digitalSignature
extendedKeyUsage      = serverAuth
subjectKeyIdentifier  = hash
authorityKeyIdentifier= keyid:always,issuer
authorityInfoAccess   = @issuer_info
crlDistributionPoints = @crl_info
subjectAltName        = @server_alt_names

Now, I will again try to create correct certificate. We can verify certificate by reading from it.
openssl ca -config iCA.cnf -extfile iCA.cnf -extensions v3_server -in icsr/server.csr -out ../server/scerts/server.crt

openssl x509 -in ../server/scerts/server.crt -noout -text  
This time we will have all the extensions, including SAN.

Verifying the Certificate

We can verify the certificate.

openssl verify -CAfile icerts/iCA.crt ../server/scerts/server.crt
We can not verify it by using only intermediate CA certificate. We need the whole chain.
openssl verify -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../server/scerts/server.crt
                                                                                                                                                                                                         

We can also join both CA certificates into one file. Intermediate CA certificate must be first. We are starting from the bottom of a hierarchy.  
cat icerts/iCA.crt ../myCA/certs/myCA.crt > /home/fff/Desktop/all.crt
cat /home/fff/Desktop/all.crt


Now we have both certificates in one file.

We can verify the server certificate with the certificate chain file.
openssl verify -CAfile /home/fff/Desktop/all.crt ../server/scerts/server.crt
../server/scerts/server.crt: OK

We can verify purpose and hostname of a certificate as a separate property.

openssl verify -purpose sslserver -CAfile /home/fff/Desktop/all.crt ../server/scerts/server.crt../server/scerts/server.crt: OK
openssl verify -verify_hostname server01.example.com -CAfile /home/fff/Desktop/all.crt ../server/scerts/server.crt../server/scerts/server.crt: OK

Person Certificate Configuration

Creation of a Directory System and Configuration File for a Person

cd /home/fff/DesktopThis is our working directory. 
mkdir personThis will be our root folder. I will jump to it "cd person".chmod 700 person
mkdir pprivateIn this folder we will save server private key.chmod 700 pprivate
chmod 600 pprivate/*
mkdir pcsrFolder for the CSR request.chmod 755 pcsr chmod 644 pcsr/*
mkdir pcertsWe will place certificate in this directory.chmod 755 pcerts chmod 644 pcerts/*
mkdir pp12Here we will save certificate and key as PKCS#12 container.chmod 755 pp12 chmod 644 pp12/*
touch person.cnfConfiguration file.chmod 644 person.cnf

Person's Configuration File

This will be the text in the configuration file.

[req]
prompt              = no
default_md          = sha256
distinguished_name  = person_dn
req_extensions      = person_req_ext
We don't need "ca" section, only "req".
[person_dn]
countryName             = RS
stateOrProvinceName     = Serbia
localityName            = Belgrade
organizationName        = Users
organizationalUnitName  = Person
commonName              = Pera Peric
Distinguish name of person. Per the intermediate CA policy, we must supply "commonName".
[person_req_ext]
subjectAltName          = @person_alt_names
All other extensions are defined inside of the intermediate CA configuration file.
[person_alt_names]
email.1                 = pera@example.com
We will use the certificate to verify ownership of a mail address.

Person's Private Key and a CRS File

First, we will create a private key.openssl genpkey -algorithm ed25519 -out pprivate/pera.key

We'll use key to create CSR file.openssl req -new -config person.cnf -key pprivate/pera.key -out pcsr/pera.csr
We will verify CSR file.  
openssl req -in pcsr/pera.csr -noout -text -verify
We must copy CSR file to iCA folder.cp pcsr/pera.csr ../iCA/icsr/pera.csr

Person's Certificate

In order to include SAN extension in the certificate, we must include person configuration file in the "iCA" configuration file.  

At the top of the "iCA" configuration file we will add this line.
.include ../person/person.cnf  

In the "usr_cert" section, of the "iCA" file, we will add SAN extension.
[usr_cert]
basicConstraints      = critical,CA:false
keyUsage              = critical,digitalSignature
extendedKeyUsage      = emailProtection,clientAuth
authorityInfoAccess   = @issuer_info
crlDistributionPoints = @crl_info
subjectAltName        = @person_alt_names

We will jump to "iCA" folder before signing the certificate, "cd ../iCA".
openssl ca -config iCA.cnf -extfile iCA.cnf -extensions usr_cert -in icsr/pera.csr -out ../person/pcerts/pera.crt

We can list the purpose of the "pera.crt" certificate.

openssl x509 -in ../person/pcerts/pera.crt -noout -purpose

As a result, we will get a list of the purposes for which we can use this certificate.

Person's Certificate Verification

We can now verify the certificate.

openssl verify -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../person/pcerts/pera.crt../person/pcerts/pera.crt:OK
openssl verify -purpose sslclient -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../person/pcerts/pera.crt../person/pcerts/pera.crt:OK
openssl verify -verify_email pera@example.com -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../person/pcerts/pera.crt../person/pcerts/pera.crt:OK

Web Client Certificate Configuration

Web Client Files and Folders

Configuration for a web client is almost the same as for the Person, so I will just run through the settings.

cd /home/fff/Desktop
mkdir client #cd client
mkdir cprivate
mkdir ccsr
mkdir ccerts
mkdir cp12
touch client.cnf
chmod 700 client
chmod 700 cprivate      
chmod 600 cprivate/*
chmod 755 ccsr
chmod 644 ccsr/*
chmod 755 ccerts
chmod 644 ccerts/*
chmod 755 cp12
chmod 644 cp12/*
chmod 644 client.cnf
[req]
prompt = no
default_md = sha256
distinguished_name = client_dn  

[client_dn]
countryName = RS
stateOrProvinceName = Serbia
localityName = Belgrade
organizationName = Users
organizationalUnitName = Web Clients
commonName = Web Client
We have only changed
the names of folders,
and distinguished name.

Web client doesn't have
SAN extension. Other client
extensions are inside of the
"iCA" configuration file.

Creation of Key and Certificate for the Web Client

 We will create a private key for a web client.openssl genpkey -algorithm ed25519 -out cprivate/client.key
With the key we will create and verify CSR file.openssl req -new -config client.cnf -key cprivate/client.key -out ccsr/client.csr
openssl req -in ccsr/client.csr -noout -text -verify
We will copy CSR file, and we will jump to iCA folder.cp ccsr/client.csr ../iCA/icsr/client.csr cd ../iCA

We can now create a certificate.
openssl ca -config iCA.cnf -extfile iCA.cnf -extensions client_cert -in icsr/client.csr -out ../client/ccerts/client.crt

We can verify this certificate too. We can verify certificate chain, and we can verify its purpose.
openssl verify -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../client/ccerts/client.crt                                        # OK
openssl verify -purpose sslclient -CAfile ../myCA/certs/myCA.crt -untrusted icerts/iCA.crt ../client/ccerts/client.crt   # OK

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 5010.echo 5010 > iserial.txt #even number of digits
mkdir icertsThis folder is optional. 
mkdir icsrHere we will place CSRs for leaf certificates. 
mkdir icrlEmpty folder for CRL files.                                                                                                 
touch icrlnumber.txtWe will set initial hexadecimal serial number for CRLs, in this file.echo 5010 > icrlnumber.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.    
[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.
[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.
[v3_server]
basicConstraints      = critical,CA:false
keyUsage              = critical,digitalSignature
extendedKeyUsage      = serverAuth
subjectKeyIdentifier  = hash
authorityKeyIdentifier= 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.
[issuer_info]
caIssuers;URI.0 = http://ica.example.com/ica.crt
OCSP;URI.0      = http://ocsp.example.com:7000
This is web address of from which we can download intermediate CA certificate and web 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.
[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.

We will talk about OCSP responder later. For now, you should know that OCSP responder is a separate entity, placed on the internet facing server, that has its own private key and certificate. This OCSP responder certificate can not be verified with the same OCSP service, because that would create a circular dependency. That is the meaning behind extension "noCheck".

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/csr/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 according to policy. We have to correct.
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 serial.txtThe 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 "req" command. We will use extensions from v3_ca section. Note that when we create a certificate with "-x509" option, 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 "req" 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  = US
O  = Example CA
CN = Example Root CA
 
[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.
sudo chmod 644 openssl.cnf  
sudo 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.
sudo chmod 644 extensions.cnf  
sudo 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.

Usual 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 defines how Distinguished Name (DN) fields of certificate and a CSR should match.

Only [req] and [ca] sections are mandatory, and they are the entry points. All other sections are a convenient way to organize our settings.

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.[req]   # CERTIFICATE REQUEST
   distinguished_name  = req_dn       # Referring to other section
   x509_extensions     = server_cert  # Referring to section in included file
[req_dn] # DISTINGUISHED NAME
   countryName = RS

[server_cert]   # CERTIFICATE EXTENSIONS; from inluded file
   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, and they 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