Creating a PKI in Ubuntu

Author
By Darío Rivera
Posted On in Laravel

A PKI (Public Key Infrastructure) is the solution to a problem called "Man-in-the-Middle Attack". You can learn more about this problem in our post Public Key Infrastructure. In this post, we will see how to easily set up a PKI on Ubuntu.

Configuring a PKI in OpenSSL

The first thing we need to do is find the example configuration file for OpenSSL, which could be located in /etc/ssl/openssl.cnf. To verify the actual location of this configuration file, we can run the following command:

openssl version -a

This command will give a result similar to the following:

OpenSSL 1.1.1  11 Sep 2018
built on: Thu Jun 20 17:36:28 2019 UTC
platform: debian-amd64
options:  bn(64,64) rc4(16x,int) des(int) blowfish(ptr) 
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-cn9tZy/openssl-1.1.1=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPADLOCK_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1"
Seeding source: os-specific

The second-to-last line in this case contains the value of OPENSSLDIR, where the configuration file, certificates, and other important files will be located. 

The OpenSSL configuration file contains a default configuration. For testing purposes, you should not change anything. However, you should verify that there is a [ ca ] section similar to the following:

####################################################################
[ ca ]
default_ca  = CA_default    # The default ca section

####################################################################
[ CA_default ]

dir   = ./demoCA    # Where everything is kept
certs   = $dir/certs    # Where the issued certs are kept
crl_dir   = $dir/crl    # Where the issued crl are kept
database  = $dir/index.txt  # database index file.
#unique_subject = no      # Set to 'no' to allow creation of
          # several certs with same subject.
new_certs_dir = $dir/newcerts   # default place for new certs.

certificate = $dir/cacert.pem   # The CA certificate
serial    = $dir/serial     # The current serial number
crlnumber = $dir/crlnumber  # the current crl number
          # must be commented out to leave a V1 CRL
crl   = $dir/crl.pem    # The current CRL
private_key = $dir/private/cakey.pem# The private key

This file first indicates that the default CA (Certificate Authority) is defined in the CA_default section. In this section, you will see that all files point to ./demoCA, in this case /usr/lib/ssl/demoCA. However, this folder and its subfolders are not created. To do this, you can run the following command to create the directory structure:

mkdir -p demoCA/certs
mkdir demoCA/crl
mkdir demoCA/newcerts
mkdir demoCA/private

You also need to create the certificate database file and the serial file that will keep track of the last signed certificate's serial number:

touch demoCA/index.txt
echo "C001" > demoCA/serial

Once this is done, we can proceed with the creation of the Certificate Authority.

Creating the Certificate Authority

To create the Certificate Authority, we will use the -x509 standard, which defines how the certificate information should be encoded. It all starts with the trusted entity and a root certificate, which we can generate by executing the following command:

openssl req -new -x509 -keyout demoCA/private/cakey.pem -out demoCA/cacert.pem

This command will create the private key cakey.pem and the self-signed certificate cacert.pem, which includes the public key of the Certificate Authority. Since we are creating a certificate, we will be prompted for some information similar to the following:

Generating a RSA private key
...................+++++
.................................................................................+++++
writing new private key to 'cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CO
State or Province Name (full name) [Some-State]:Antioquia
Locality Name (eg, city) []:Medellin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Pleets
Organizational Unit Name (eg, section) []:Tech Dept.
Common Name (e.g. server FQDN or YOUR name) []:https://pleets.org
Email Address []:example@pleets.org
ChatGPT

The certificate created earlier is the certificate that will be used to sign other certificates (user certificates). It is also possible to create intermediate certificate authorities that will sign user certificates (we won't cover this configuration in this post).

Creating a User Certificate

Before performing this signing, i.e., before the trusted entity issues a certificate to us, each user must create a certificate signing request which can be done with the following command:

openssl req -new -keyout userkey.pem -out usercert-req.pem

This command will create the private key userkey.pem and the associated certificate request usercert-req.pem. Since we are creating a certificate, we will be prompted for the information that a certificate should have:

Generating a RSA private key
..............................+++++
....................................+++++
writing new private key to 'userkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CO
State or Province Name (full name) [Some-State]:Antioquia
Locality Name (eg, city) []:Medellin
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Pleets         
Organizational Unit Name (eg, section) []:Tech     
Common Name (e.g. server FQDN or YOUR name) []:Dario Rivera
Email Address []:example@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:    
An optional company name []:

It is important to understand the difference between a CSR (Certificate Signing Request) and a certificate itself. What we did earlier was to create a certificate signing request (CSR) that needs to be signed by the CA.

All this information is sent to the trusted entity for certification, in this case, your own CA. Before signing, it is recommended to review the certificate information again to ensure everything is correct. You can do this with the following command:

openssl req -text -in usercert-req.pem -noout

To sign this certificate with the trusted entity, we need to use the following command:

openssl ca -in usercert-req.pem -out usercert.pem

If everything goes well, the output of this command should be similar to the following:

Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 49153 (0xc001)
        Validity
            Not Before: Aug 30 05:38:48 2019 GMT
            Not After : Aug 29 05:38:48 2020 GMT
        Subject:
            countryName               = CO
            stateOrProvinceName       = Antioquia
            organizationName          = Pleets
            organizationalUnitName    = Tech
            commonName                = Dario Rivera
            emailAddress              = fermius.us@gmail.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                89:3D:33:63:A9:76:31:9D:0D:47:11:8D:41:A2:74:C4:EE:19:BB:02
            X509v3 Authority Key Identifier: 
                keyid:09:15:1A:A3:42:C4:79:4E:A0:30:F2:47:C6:5A:C5:55:16:5D:CC:0E

Certificate is to be certified until Aug 29 05:38:48 2020 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

This indicates that the certificate usercert.pem has been generated correctly. To convert this certificate to an installable format in the browser, you can use the following command:

openssl pkcs12 -export -in usercert.pem -inkey userkey.pem > usercert.p12

Finally, as a test, notice that if we had entered a different organizationName than the initial one (Pleets), we would have received the following response:

Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
The organizationName field is different between
CA certificate (Pleets) and the request (ENCOM)

This indicates that a certificate cannot sign certificates for organizations other than its own. I hope you have learned a lot from this post. Until next time.


Acerca de Darío Rivera

Author

Application Architect at Elentra Corp . Quality developer and passionate learner with 10+ years of experience in web technologies. Creator of EasyHttp , an standard way to consume HTTP Clients.

LinkedIn Twitter Instagram

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.