Certificate Authority with OpenSSL

Everything Linux, A.I, IT News, DataOps, Open Source and more delivered right to you.
"The best Linux newsletter on the web"

This article will show you how to set up a Certificate Authority with OpenSSL. Digital certificates are documents used to prove the ownership of a public key. For example, a digital certificates is used to authenticate an accessed website via HTPS. Another example of a common use are document signing.

Certificates includes information about the key, identity of its owner, and the digital signature of an entity that has verified the contents. A certificate authority (CA) is the organization that issues digital certificates.

Also this article will show how to tell other hosts to trust the certficates issued.

Warning: this should be only for testing purposes or proof of concept. For real-life uses you should acquire real certificates from a real certificate authority. For instance if you just want HTTPS and want the certificate for free, just go to https://letsencrypt.org/

Install OpenSSL

My main OS is FreeBSD, and I like to use the ports tree, to install it just run:

# cd /usr/ports/security/openssl
# make install clean

And wait until the compile and installation of the port is ready. Pay attention that you probably already have an openssl executable (under /usr/bin path) and if you install it anyway the ‘port’ binary will be at /usr/local/bin/openssl.

The first time I dealt with OpenSSL, the binary provided didn’t worked for me but the port does.

Configuration file

Although my main OS is FreeBSD, from now on, should be the same steps on any OS that support OpenSSL. Maybe you need to adjust some paths but that’s all.

You’ll find (again, in FreeBSD) an example and well commentend configuration file in /usr/local/openssl/openssl.conf. This is mine after some cleanup, I’ve highlighted the most important settings:

#OpenSSL Home current directory
HOME                    = /var/openssl #choose any reasonable location
#RANDFILE                = $ENV::HOME/.rnd

oid_section             = new_oids

[ new_oids ]
tsa_policy1 =
tsa_policy2 =
tsa_policy3 =

[ ca ]
default_ca      = YourCA              # The default Certificate Authority section

[ YourCA ] #most important section of your file
dir             = /var/openssl/yourCA           # Where everything is kept
                                                              # choose any reasonable location
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.
new_certs_dir   = $dir/newcerts         # default place for new certs.
certificate     = $dir/CA/yourCA.crt  # 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/CA/yourCA.crl  # The current CRL
private_key     = $dir/CA/yourCA.key  # The private key
RANDFILE        = $dir/private/.rand    # private random number file
x509_extensions = usr_cert              # The extentions to add to the cert

# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

default_days    = 365                   # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = default               # use public key default MD
preserve        = no                    # keep passed DN ordering
policy          = policy_match

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = supplied
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional
localityName            = supplied

# For the 'anything' policy. At this point in time, you must list all 
# acceptable 'object' types.
[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
default_bits            = 2048
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = utf8only

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = AR #I'm on ARgentina
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Salta # i.e. the province I live on

localityName                    = Locality Name (eg, city)

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Your company name

organizationalUnitName          = Organizational Unit Name (eg, section)
organizationalUnitName_default  = Section Name. # eg. IT
commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20
unstructuredName                = An optional company name

[ usr_cert ]
nsComment                       = "OpenSSL Generated Certificate"

[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca ]
# Extensions for a typical CA
# PKIX recommendation.
basicConstraints = CA:true

[ crl_ext ]

[ proxy_cert_ext ]
nsComment                       = "OpenSSL Generated Certificate"
# This really needs to be in place for it to be a proxy certificate.

[ tsa ]
default_tsa = tsa_config1       # the default TSA section

[ tsa_config1 ]
# These are used by the TSA reply generation only.
dir             = ./demoCA              # TSA root directory
serial          = $dir/tsaserial        # The current serial number (mandatory)
crypto_device   = builtin               # OpenSSL engine to use for signing
signer_cert     = $dir/tsacert.pem      # The TSA signing certificate
                                        # (optional)
certs           = $dir/cacert.pem       # Certificate chain to include in reply
                                        # (optional)
signer_key      = $dir/private/tsakey.pem # The TSA private key (optional)
default_policy  = tsa_policy1           # Policy if request did not specify it
                                        # (optional)
other_policies  = tsa_policy2, tsa_policy3      # acceptable policies (optional)
digests         = md5, sha1             # Acceptable message digests (mandatory)
accuracy        = secs:1, millisecs:500, microsecs:100  # (optional)
clock_precision_digits  = 0     # number of digits after dot. (optional)
ordering                = yes   # Is ordering defined for timestamps?
                                # (optional, default: no)
tsa_name                = yes   # Must the TSA name be included in the reply?
                                # (optional, default: no)
ess_cert_id_chain       = no    # Must the ESS cert id chain be included?
                                # (optional, default: no)


Before we continue a little tiny glossary of the acronyms used in the file:

  • CA: stands for Certificate Authority
  • CRL: stands for Certificate Revocation Lists
  • CSR: stands for Certificate Signing Request
  • MD: stands for Message Digest
  • TSA: stands for Time Stamping Authority

Certificates repository

Next, create the directories and (for now empty) files to store our keys and certificates:

# cd /var/openssl
# mkdir -p yourCA/CA
# mkdir -p yourCA/newcerts
# mkdir -p yourCA/certs/keys
# mkdir -p yourCA/certs/requests
# mkdir -p yourCA/certs/certificates
# cd yourCA
# touch index.txt
# echo 01 > serial

CA certificate

Now you can create your Certificate Authority certificate and sign it. But first, we need to create a private key with the following command:

# /usr/local/bin/openssl genrsa -out yourCA/CA/yourCA.key 2048

Secondly, create a CSR by running:

# /usr/local/bin/openssl req -new -key ./yourCA/CA/yourCA.key -out yourCA/CA/yourCA.csr

Follow the instructions on screen, paying attention to fill the correct information. Finally, self-sign your certificate:

# /usr/local/bin/openssl x509 -req -days 365 \
> -in yourCA/CA/yourCA.csr -out yourCA/CA/yourCA.crt \
> -signkey yourCA/CA/yourCA.key
Screenshot of the previous process
Screenshot of the previous process

And this is it: now you can start signing your client and or web certificates

Client certificates

The process is pretty similar as the former one. But we are using our CA certificate to sign the client certificate. And, ideally, the client will generate his own private key and the CSR.

Anyway, we are just testing stuff, so I’m doing every step and then distributing the generated certificates to my user. The following commands can be runned everywhere, but just to keep some order I’m using the previously created folders (under /var/openssl/yourCA/certs). Our user, John Doe, need a private key first:

# cd /var/openssl/yourCA/certs
# /usr/local/bin/openssl genrsa -des3 -out keys/johndoe.key 2048

Don’t forget the passprhase as will be asked several times; next create the certificate signing request:

# /usr/local/bin/openssl req -new -key keys/johndoe.key -out requests/johndoe.csr
Screenshot of the CSR generation
Screenshot of the CSR generation

Next, sign the certificate with this command:

# /usr/local/bin/openssl ca -in requests/johndoe.csr -cert ../CA/yourCA.crt -keyfile ../CA/yourCA.key -out certificates/johndoe.crt
signing the certificate...
signing the certificate…

Finally, export the certificate to the PKCS12 format, you’ll be asked for the passphrase of the PK:

# /usr/local/bin/openssl pkcs12 -export -clcerts -in certificates/johndoe.crt -inkey keys/johndoe.key -out certificates/johndoe.p12

Installing the certificate

Now you can emit your own certificates your user needs to install them in order to use it. You need to deliver two files: yourCA.crt and the personal johndoe.p12.

To install it on windows use the Certificate Manager Tool. I’m not uploading several screenshots because, as my windows is in spanish, I wouldn’t find it very useful. Click on start menu an run “certmgr.msc”, the following screen will popup:

screenshot of certmgr.msc
screenshot of certmgr.msc

Right-click on the folder Root Certification Authority and choose “Import”. Start with yourCA.crt and choose the store Root Certification Authority, follow the wizard.

Screenshot (in spanish) of the last step of the wizard.

Now right-click on the Personal folder and repeat the wizard with the johndoe.p12 file. You will be asked for the passprhase. When the wizard completes you can see your installed valid certificate and the details:

Remember, this is for learning purposes only. But this is also a matter of trust. If your organization is small enough and there is trust, you should be able to work with this DIY certificates.

Everything Linux, A.I, IT News, DataOps, Open Source and more delivered right to you.
"The best Linux newsletter on the web"
Gonzalo Rivero
Gonzalo Rivero
I am Gonzalo, I live in Salta, a city located in the NW of Argentina. I play the guitar and a little harmonica. I also like to bike.


Please enter your comment!
Please enter your name here

Latest articles

Join us on Facebook