Making your own CA using openssl

This example was run on Fedora25, but it should work with other distributions, the only part of selinux may not be suitable.

Preparing CA structure

Select the location for the CA working directory. It should be in a safe place where no one else can overwrite your files. You can manage your CA by an ordinary user, you do not need to have a root. Then create a base directory for your CA. Give it a good name, for example:

$ mkdir CA.example.com && cd CA.example.com
CA.example.com $ mkdir certs crl newcerts private
CA.example.com $ touch index.txt
CA.example.com $ echo '01' > serial
CA.example.com $ cp /etc/pki/tls/openssl.cnf .
CA.example.com $ vi openssl.cnf

Edit this file carefully. Find the [ CA_default ] section. It describes all previously created directories and files. But the default working directory is in /etc/pki/CA. Let's change it to the real one:

 ..
[ CA_default ]

dir             = .                     # Where everything is kept
 ..

Continue to edit the file, focusing on many _default values.

 ..
countryName_default             = US
 ..
stateOrProvinceName_default     = FL
 ..
localityName_default            = Orlando
 ..
0.organizationName_default      = Example Company Ltd
 ..
organizationalUnitName_default  = IT
 ..

Now we ready to start.

Creating CA

It is common practice to create a self-signed CA for internal corporate needs. This is done by one command:

CA.example.com $ 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) [US]:
State or Province Name (full name) [FL]:
Locality Name (eg, city) [Orlando]:
Organization Name (eg, company) [Example Company Ltd]:
Organizational Unit Name (eg, section) [IT]:
Common Name (eg, your name or your server's hostname) []:CA.example.com
root@example.com []:
CA.example.com $ find . -type f -newer openssl.cnf 
./cacert.pem
./private/cakey.pem
CA.example.com $

Keep the "PEM pass phrase" somewhere in a secret place. CA is very rarely used, then everyone forgets the passphrase often. CA will be useless without this passphrase.

As a result of the command, two files were created: ./private/cakey.pem is a private certificate key, encrypted with a passphrase, and ./cacert.pem is the public part of the certificate. Let's inspect it with the command:

CA.example.com $ openssl x509 -in cacert.pem -text -noout

Now you are ready to sign certificates.

Creating CA signed externally

Less common practice is the external signing of your CA.

I doubt that root certificate authorities will rely on you to sign other certificates on their behalf. And if this happens, you will use a more professional CA than openssl.

However, this is possible if your corporate self-signed CA delegates part of its work to your department. In this case, instead of one previous command, you must do CSR (Certificate Signing Request), and then get the final certificate from the corporate root CA.

CA.example.com $ openssl req -config ./openssl.cnf -new -keyout private/imcakey.pem -out imcareq.pem -days 3650

The resulting imcareq.pem file must be sent to the corporate CA for sign. The signed request will be a public CA certificate (like ./cacert.pem from the chapter above). The file private/imcakey.pem is a private key and is encrypted with a passphrase.

BTW, you can check the content of the certificate request with the command:

CA.example.com $ openssl req -in imcareq.pem -text -noout

Server certificates

Let's talk about who is responsible for the server certificate? That's right, the server administrator is, but not the administrator of the CA. Usually this still falls on you, but keep in mind that now you have changed the hat. Therefore, the request for a server certificate is not performed from the working directory of the CA, but usually somewhere on the server itself that needs a certificate.

As a server administrator, create a directory somewhere in a secure location for working with the certificate. Copy /etc/pki/tls/openssl.cnf and edit it as described above. The only difference with the previous configuration is the value of nsCertType, which should be server:

 ..
nsCertType = server
 ..

Usually this line is commented out, so just delete the comment.

Now create a CSR. Note that the Common Name, which you will be asked for, corresponds to the name of the service. For example, if the L2 load balancer serves host1.example.com and host2.example.com under a common VIP, resolving as service.example.com, then Common Name must be service.example.com, even if the certificate is going to installed on host1 and host2.

Usually I make a request for 5 years. This is enough for server itself becomes obsolete before the certificate expires.

$ openssl req -config ./openssl.cnf -new -keyout server_private_key.pem -out server_newreq.pem -days 1825

I remind you, remember the passphrase of the key, otherwise the private key will be useless. If you use a certificate with apache, you will have to enter this passphrase every time the server is restarted. This is not so convenient and excludes any automation. In this case, you can remove the encryption from the private key:

$ openssl rsa -in server_private_key.pem -out unlocked_server_private_key.pem

Do you remember the second, public, part of the request? Send it to the CA administrator. He will return the signed server certificate to you. To work with SSL you will need a certificate, a private key (can be unlocked), a root CA certificate and an intermediate CA if your certificate is signed by it.

Renew server certificate

Renew is a similar procedure includes request creation and signing it. A single difference is re-use private key. Otherwice, it will be not re-new, but issue a brand new valid certificate, that is also good.

Making request using existing key:

$ openssl req -config ./openssl.cnf -new -key server_private_key.pem -out server_newreq.pem

You will be asked for private key passphrase, don't you keep it somewhere year ago ? TIP: you can use unlocked key that you've generated for apache.

User certificates

The server can be configured to request a user certificate and deny service without it. If the certificates are really unique and personal, you can even use it instead of authentication. This allows passwordless access to the user's personal area based on the contents of the certificate.

Again, requesting a user certificate is not a CA administrator task. Of course, rarely the user can make the request himself, usually it is done by the system administrator, but not by the CA administrator! So, again, change the hat and somewhere in a different safe place, make the working directory for user certificates. Copy the /etc/pki/tls/openssl.cnf file there and edit it as described above, but now you need to fix nsCertType according to your needs. This can be a "client" that is sufficient for HTTPS authentication. This may be an "email", which may be required by some mailers for signing emails. This can be an "objsign" that I have never seen in use, but suppose that some software developers know what it means.

Then request the certificate, similar to the request for the server. In this query, I use the default expiration period, which is defined in the openssl.cnf file as 365 days (1 year). People retire faster than servers, so a shorter period adds more security.

Use "First Last" as Common Name and use correct user's email address

$ openssl req -config ./openssl.cnf -new -keyout user_private_key.pem -out user_req.pem

The passphrase is less important to remember here, because it will be used in a very short period of time. Send CSR to the CA administrator and get user_cert.pem in response.

The most common format for the user certificate is PKCS12, which includes both public and private parts and is encrypted with the so-called "Export password". You will be prompted to enter a passphrase to decrypt the private key and "export password" to encrypt the resulting certificate. You must send the resulting p12 certificate to the user and tell him which export password was used. The normal user will not know at all what to do with all this information, so you probably will have to import this certificate yourself onto his workstation using this password.

A command to convert PEM certificate to PKCS12 format:

$ openssl pkcs12 -export -in user_cert.pem -inkey user_private_key.pem -out user_cert.p12 -name "First Last"

Signing certificate

What is left as a CA administrator? Sign, sign and sign.

CA.example.com $ openssl ca -config ./openssl.cnf -policy policy_anything -out newcert.pem -infiles 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:
 ..
Certificate is to be certified until Aug 21 18:59:15 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

Inspect content of serial, index.txt and newcerts.

CRL - Certificate Revocation List (TBD)

The most important thing in this procedure is a reliable way to deliver CRL to each SSL server. After the certificate is revoked in the CA, it should be distributed everywhere, otherwise it is useless and only the expiry date will revoke certificate.

Certificates and selinux

This part is not related to the CA, but it is related to the placement of certificates on the selinux enforced servers. For certificates files, there is a special type cert_t. An easy way is to place certificates in the places intended for this:

# grep cert_t /etc/selinux/targeted/contexts/files/file_contexts
 ..

Looks good to place certificate files into /etc/pki, /etc/ssl, /usr/share/ssl/certs, /usr/share/ssl/private.

It is not enough to place the file in the correct place, the rules must apply to them:

# restorecon /usr/share/ssl/certs/CA.crt
# ls -lZ /usr/share/ssl/certs/CA.crt
-rw-r--r--. 1 root root unconfined_u:object_r:cert_t:s0 1452 Apr 23 15:28 /usr/share/ssl/certs/CA.crt

Updated on Tue Aug 22 17:29:19 IDT 2017 More documentations here