Managing your own CA with OpenSSL

You need to set up your own CA, self-signed or signed from outside, and all you have is the openssl tool.

Setup CA

Create working directory and structure (root not required):

$ export MYDOMAIN=$(hostname -d)
$ mkdir CA-$MYDOMAIN
$ cd CA-$MYDOMAIN
$ mkdir certs crl newcerts private
$ touch index.txt
$ echo '01' > serial
$ cp /etc/pki/tls/openssl.cnf .
$ vi openssl.cnf

Edit openssl.cnf file to fix following lines:

Pick up the passphrase and save it in a safe place. CA is not used very often, so you usually forget the passphrase. Without it, CA will be useless.

Issue a request for CA certificate:

$ openssl req -config ./openssl.cnf -new -x509 -keyout private/cakey.pem -out cacert.pem -days 3650
Generating a 2048 bit RSA private key
.................................................+++
...+++
writing new private key to 'private/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) [IL]:
State or Province Name (full name) [Central]:
Locality Name (eg, city) [Lod]:
Organization Name (eg, company) [Lab at Home]:
Organizational Unit Name (eg, section) [IT]:
Common Name (eg, your name or your server's hostname) []:CA-voleg.local
Email Address []:xxx@gmail.com

This command creates a cacert.pem request file and a private key, stored as private/cakey.pem. The requested certificate will be valid for 10 years. If you intend to sign this CA by an external CA, check its expiration date, win the shortest.

Now you have two options: 1. Send the received cacert.pem to the signing authority or 2. Sign it yourself. In the second case, your clients must install the resulting CA certificate as a trusted CA, otherwise the SSL connections will not works.

Sign the CA certificate by yourself. Skip this step if it will signed by someone else.

$ openssl x509 -in cacert.pem -out certs/CA-$MYDOMAIN.crt
$ openssl x509 -in certs/CA-$MYDOMAIN.crt -text -noout

The first command is quiet. The second command will show you the contents of the generated certificate for verification. As a result, we have private/cakey.pem (CA private key), encrypted with your passphrase, and certs/CA-$MYDOMAIN.crt - is the public certificate of certification authority.

Server certificate

Requesting server's sertificate

The certificate request for the server is issued by the server administrator and is not relevant to the working diractory of CA that we created above. Suppose we need to generate a certificate for our web server. It can be an OpenVPN server or other servers using TLS, the procedure will be the same. I will assume that you do not have access to the CA and you need to send a request to the CA administrator of your organization for signing it.

Prepare working directory (root not required)

$ mkdir ~/www.$(hostname -f) && cd ~/www.$(hostname -f)
$ cp /etc/pki/tls/openssl.cnf .
$ vi openssl.cnf

Edit openssl.cnf file to fix following lines:

Choose a passphrase. In contrast to the CA's passphrase, it will no longer be used, moreover, it will be removed from our encrypted key for automatic start of SSL based services.

Now, generate a server request:

$ openssl req -config ./openssl.cnf -new -keyout key.pem -out newreq.pem -days 1825
Generating a 2048 bit RSA private key
.........................................+++
.......+++
writing new private key to 'newreq.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) [IL]:
State or Province Name (full name) [Central]:
Locality Name (eg, city) [Lod]:
Organization Name (eg, company) [Lab at Home]:
Organizational Unit Name (eg, section) [IT]:
Common Name (eg, your name or your server's hostname) []:www.virt.voleg.local
Email Address []:xxx@gmail.com

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

Keep a challenge password and optional company name empty (press Enter to skip).

Important for Web servers: The Common Name must be an exact DNS name of the IP used for SSL connection, otherwise browsers will complain about a bad certificate. If you are using a load balancer before the server farm, this must be the load balancer IP address DNS name.

The command creates a key.pem file that contains the encrypted private key and the newreq.pem file that you will send to the CA administrator.

In the meantime, we will remove the encryption of the private key, otherwise you will be prompted to enter the passphrase every time the service starts.

$ openssl rsa -in key.pem -out unlocked-key.pem

After you unlock the private key, the passphrase is no longer needed.

Signing server's certificate at CA

Now we change the chairs and become the CA administrator, which gets the file newreq.pem from the crappy web administrator. Go to the CA working directory and sign the request:

$ openssl ca -config ./openssl.cnf -policy policy_anything -out newcert.pem -infiles /tmp/newreq.pem
Using configuration from ./openssl.cnf
Enter pass phrase for ./private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: May 20 11:22:50 2017 GMT
            Not After : May 20 11:22:50 2018 GMT
        Subject:
            countryName               = IL
            stateOrProvinceName       = Central
            localityName              = Lod
            organizationName          = Lab at Home
            organizationalUnitName    = IT
            commonName                = www.virt.voleg.local
            emailAddress              = xxx@gmail.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                9F:C5:92:B9:E2:F7:56:2E:3A:3D:F3:E1:CC:30:56:6D:68:F8:26:02
            X509v3 Authority Key Identifier: 
                keyid:A2:67:A0:DF:D5:6B:4D:C3:0C:79:02:00:1C:42:A5:9B:24:F8:18:3A

Certificate is to be certified until May 20 11:22:50 2018 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

A new signed certificate newcert.pem appears, send it to the web administrator. A copy of this certificate will appear as ./newcerts/01.pem. You can check the list of signed certificates with command:

$ cat index.txt
V       180520112250Z           01      unknown /C=IL/ST=Central/L=Lod/O=Lab at Home/OU=IT/CN=www.virt.voleg.local/emailAddress=xxx@gmail.com

Installing server's certificate

This part is completely off topic, but very close. Once you have received the signed certificate as a web administrator, place the following files in a safe place (for example /etc/httpd/certs): unlocked-key.pem, newcert.pem (rename it to something more meaningful), CA certificate and intermediate CA if your signing chain is long. Make them owned by root and readable by anyone except of unlocked-key.pem. This file must be readable only to the root user. Once httpd starts up, it will read the key, and then drop the privileges to the apache user, who will not be able to read this file.

Set values in your ssl.conf file to:

User certificates

Once you need to authenticate the user with SSL, you will need to issue certificates for users. Typically, users do not have the skills of a server administrator level, and you will even create a request for them. But, again, requests should not be executed from the working directory of the CA to keep it clean from debris.

Creating user certificate request

So, create temporary directory and copy openssl.cnf file there. Edit openssl.cnf file to fix following lines:

Select a passphrase. This passphrase will temporary if you plan to export the certificate to p12 format. You will need to pass this phrase to the user if you plan to use the PEM format. Create a query for the user:

$ openssl req -config ./openssl.cnf -new -keyout newreq.pem -out newreq.pem
Generating a 2048 bit RSA private key
........+++
......................+++
writing new private key to 'newreq.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) [IL]:
State or Province Name (full name) [Central]:
Locality Name (eg, city) [Lod]:
Organization Name (eg, company) [Lab at Home]:
Organizational Unit Name (eg, section) [IT]:
Common Name (eg, your name or your server's hostname) []:Oleg Volkov
Email Address []:xxx@gmail.com

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

A challenge password and optional company name keep empty by pressing Enter key.

A resulting newreq.pem will contains both encrypted private key and certificate request. Transfer it to CA server.

Sign user certificate in CA

$ openssl ca -config ./openssl.cnf -policy policy_anything -out newcert.pem -infiles /tmp/newreq.pem
Using configuration from ./openssl.cnf
Enter pass phrase for ./private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: May 20 12:35:31 2017 GMT
            Not After : May 20 12:35:31 2018 GMT
        Subject:
            countryName               = IL
            stateOrProvinceName       = Central
            localityName              = Lod
            organizationName          = Lab at Home
            organizationalUnitName    = IT
            commonName                = Oleg Volkov
            emailAddress              = xxx@gmail.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                3D:AA:A3:EA:84:2A:1B:5C:D9:D8:11:85:62:1A:77:D6:79:9C:26:5C
            X509v3 Authority Key Identifier: 
                keyid:A2:67:A0:DF:D5:6B:4D:C3:0C:79:02:00:1C:42:A5:9B:24:F8:18:3A

Certificate is to be certified until May 20 12:35:31 2018 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

newcert.pem file was created. A copy of this file is saved as ./newcerts/02.pem, the index file is updated. The newreq.pem file will be used as a private key (with a passphrase), and newcert.pem will be used as a user certificate. If you are asked for a P12 certificate, do the following (you need to know the user's passphrase). This can (and should) be done outside the working directory of the CA:

$ openssl pkcs12 -export -in newcert.pem -inkey newreq.pem -out newcert.p12 -name "Oleg Volkov"
Enter pass phrase for newreq.pem:	<- User's passphrase here
Enter Export Password:			<- Password to open P12, you should pass it to user
Verifying - Enter Export Password:
$ ll newcert.p12
-rw-rw-r-- 1 voleg voleg 2716 May 20 15:45 newcert.p12

Certificate Revocation List (CRL)

To be continued.


Updated on Sat May 20 16:42:31 IDT 2017 More documentations here