Creating a Certificate Authority and signing the SSL certificates using openssl

[Nov 17, 2015: the article is updated to follow modern security requirements for SSL certificates]

This article explains how to create your own Certificate Authority and create the SSL certificates signed by this authority. While there is a lot of articles which talk about how to create your own SSL certificates, in most cases they describe how to create self-signed certificates. It is simpler, but those certificates cannot be verified or tracked. Personally I prefer to create the personal Certificate Authority (CA) first and then issue the certificates from this authority. The main advantage of this approach is that you can import the certificate of your CA into your browser or your cell phone, and you won’t get any more warnings when accessing your own web site or connecting to SMTP/IMAP server as your certificate is now considered trusted. This is also necessary if you create the certificate hierarchy for your own project and want to be the only one who can issue the certificates for the users.


This post assumes you have the OpenSSL toolkit installed, and openssl command-line utility is working properly.

Creating the Certificate Authority configuration

Create the directory on your disk, and save the following configuration file there under the name ca.cnf. You can edit the parameters marked as “EDIT THOSE”, and you can change some parameters (for example, if you want your certificates to be valid for longer than one year you can change the default_days), but the defaults should be good enough for the vast majority of users

[ ca ]
default_ca = mypersonalca

[ mypersonalca ]
#
# WARNING: if you change that, change the default_keyfile in the [req] section below too
# Where everything is kept
dir = ./mypersonalca

# Where the issued certs are kept
certs = $dir/certs

# Where the issued crl are kept
crl_dir = $dir/crl

# database index file
database = $dir/index.txt

# default place for new certs
new_certs_dir = $dir/certs

#
# The CA certificate
certificate = $dir/certs/ca.pem

# The current serial number
serial = $dir/serial

# The current CRL
crl = $dir/crl/crl.pem

# WARNING: if you change that, change the default_keyfile in the [req] section below too
# The private key
private_key = $dir/private/ca.key

# private random number file
RANDFILE = $dir/private/.rand

# The extentions to add to the cert
x509_extensions = usr_cert

# how long to certify for
default_days = 365

# how long before next CRL
default_crl_days= 30

# which message digest to use
default_md = sha256

# keep passed DN ordering
preserve = no

# Section names
policy = mypolicy
x509_extensions = certificate_extensions

[ mypolicy ]
# Use the supplied information
commonName = supplied
stateOrProvinceName = supplied
countryName = supplied
emailAddress = supplied
organizationName = supplied
organizationalUnitName = optional

[ certificate_extensions ]
# The signed certificate cannot be used as CA
basicConstraints = CA:false

[ req ]
# same as private_key
default_keyfile = ./mypersonalca/private/ca.key

# Which hash to use
default_md = sha256

# No prompts
prompt = no

# This is for CA
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
string_mask = utf8only
basicConstraints = CA:true
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions

[ root_ca_distinguished_name ]
# EDIT THOSE
commonName = My Personal CA
stateOrProvinceName = California
countryName = US
emailAddress = certs@example.com
organizationName = My Personal Certification Authority

[ root_ca_extensions ]
basicConstraints = CA:true

Then create the directory structure which will be used by your CA. This assumes you did not change the directory name in the configuration file above:

# mkdir -p mypersonalca/certs
# mkdir -p mypersonalca/private
# mkdir -p mypersonalca/crl
# echo "01" > mypersonalca/serial
# touch mypersonalca/index.txt

Generating the Certificate Authority private key and certificate

To generate the Certificate Authority with a 2048 bit private key and with the certificate which is valid for ten years (3650 days) execute the following command:

 OPENSSL=ca.cnf openssl req -x509 -nodes -days 3650 \
    -newkey rsa:2048 -out mypersonalca/certs/ca.pem \
    -outform PEM -keyout ./mypersonalca/private/ca.key

It will ask you the questions about the information which will be embedded into your CA certificate. Answer meaningfully so when you can see this certificate in your browser you wouldn’t wonder what it is about.

Once the command above is completed you should have two files:  mypersonalca/certs/ca.pem and mypersonalca/private/ca.key. The key file must be kept in secret. Anyone who gets the ca.key will be able to sign the certificates for your CA. The ca.pem file is your public CA certificate which could be imported into your browser or mobile platform to make your root CA recognizable by the device.

Now you have the CA key you can start generating and signing the certificates.

Generating the certificate

The process of getting a valid certificate consists of two phases. First the certificate is generated, and then it is signed by your CA.

The following command is used to generate the certificate and the 1024-bit private key:

openssl req -newkey rsa:1024 -nodes -sha256 \
   -keyout cert.key -keyform PEM -out cert.req -outform PEM

This command will ask you a few questions about the certificate issuer. This information will be visible to anyone who connects to your server. If you create the SSL certificate for your web or mail server, pay special attention to the Common Name field. You must enter there the fully-qualified domain name this certificate will serve. For example, if your web server is https://mymail.example.com your common name must be mymail.example.com. You can also use the wildcard in the first part of the domain name: a certificate with the common name such as *.example.com could be used for all subdomains of the example.com. An e-mail address must also be supplied, although it doesn’t have to be valid.

Signing the certificate by the CA

Once the certificate is created it needs to be signed by your CA to be recognizable:

OPENSSL_CONF=ca.cnf openssl ca -batch -notext -in cert.req -out cert.pem

Now you got the pair: the signed certificate cert.pem and the corresponding private key, cert.key which you can use as needed.

Printing the certificate parameters

Once in a while you may want to peek inside a specific certificate to see what’s inside. The following command will print the content of the cert.pem certificate:

openssl x509 -in cert.pem -noout -text

The important fields in the output are the following:

  • Issuer (information about the CA which signed the certificate)
  • Subject (information about the entity which uses the certificate)
  • Validity (time period when the certificate is valid)

That’s it. Now you can generate the certificates signed by your own CA!

This entry was posted in Linux.

16 Responses to Creating a Certificate Authority and signing the SSL certificates using openssl

  1. pipop says:

    I’d rather put
    “# Which hash to use
    default_md = sha1”
    in the ca.cnf, since browsers now assume that md5 in not trusty enough anymore.

    For example, in chromium I get a warning like “The site’s security certificate was signed with a weak signature algorithm.” because I used md5 to sign the certificate.

  2. chris says:

    When creating the directory structure it should be # mkdir -p mypersonalca/crl. You have # mkdir -p mypersonalca/crt.

    Also, when generating the certificate authority shouldn’t it start out with OPENSSL_CONF=ca.crt as you have in the section on generating a certificate?

    • pipop says:

      I think yes.

      • George says:

        I don’t see it. There is OPENSSL_CONF=ca.crt in generating the certificate authority, and there is no such thing in generating the certificate (nor it should be). Could you please point out to a specific item?

  3. Bharat says:

    I had an issue when i was trying to generate a self signed CA cert with a conf file with default_md = sha1 under [ mypersonalca ]. It was not generating the cert with SHA1 because i had default_md = MD5 under [req]. So please make sure to change default_md =sha1 under [req] to have your CA cert generated with SHA-1 algorithm.

  4. Matthew says:

    Please excuse my ignorance, but when generating the Certificate Authority and Key, is this done in basic command line or in the Openssl command window? I’ve tried the code in both and get errors. Any dumding down for the layman here would be “GREATLY” appreciated. Thanks in Advance.

    • George says:

      Everything in this article is done in command line. Preferably in Cygwin shell (assuming you run Windows) as some operations might fail in “basic” command line shell.

  5. Ward says:

    Have you ever tried to create the CA using Public wildcard Security Certificate from Godaddy, Thwate, or some other verified source? I have several servers on my domain, Java email server, ISS and DNN, and and I am looking at adding a Linux file server. Setting up the wildcard in any of the servers and exporting out to formats the other servers use has been a disaster. My thinking is it is best to bring the wildcard cert into a program that is designed to create and issue certificated in different formats.

  6. Pingback: Setup Your Own Certificate Authority (CA) on Linux and Use it in a Windows Environment | VirtuallyHyper

  7. Dominic says:

    I think there is a mistake in the configuration file (“ca.cnf”) – prompts is set to “no”, when it should probably be set to “yes”. Without prompts, you don’t get to enter CA information, such as the common name.

  8. Xavier says:

    I am trying to use the steps above on my linux box.
    OPENSSL=ca.cnf: Command not found.

    do i need to add anything to make this work?

Leave a Reply

Your email address will not be published. Required fields are marked *


Warning: Use of undefined constant XML - assumed 'XML' (this will throw an Error in a future version of PHP) in /home/ulduzs/public_html/wp-content/plugins/wp-syntaxhighlighter/wp-syntaxhighlighter.php on line 1048