How to Create and Manage Certificates with OpenSSL

Lately I’ve been on a crusade to digitally sign my emails.  I tried some free email certificates from StartSSL and Thawte, but neither one was quite what I wanted (they just show an email address with something like a generic “free member” as the common name).  So I decided to try making my own certificate authority with OpenSSL.  There are tons of resources on the Internet for doing this, but in this magnum opus I’m attempting to distill it all down into one place.

Preparation

First download and install a binary distribution of OpenSSL.  I’ve used both the GNU Windows binary distribution and the Shining Light binary distribution.  Add the binaries to your path (I’ll assume you know how to do that – if not, you should probably stop reading now).

The OpenSSL tool makes use of a configuration file to cut down on the number of options you have to set on the command line.  Start by making a copy of the default openssl.cnf from the distribution and edit it to your liking.  In particular, edit the default country, location, organization name, etc., otherwise you’ll have to retype them every time you create a certificate request.

Here is the openssl.cnf file used for the following demonstrations, with the places you might want to change highlighted.  For brevity, I’ve stripped out tabs and comments.

# openssl.cnf

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = .
certs = $dir
crl_dir = $dir
new_certs_dir = $dir
database = $dir/index.txt
certificate = $dir/ca.crt
serial = $dir/serial.txt
crlnumber = $dir/crlnumber.txt
crl = $dir/revoked.crl
private_key = $dir/ca.key
RANDFILE = .rnd
name_opt = ca_default
cert_opt = ca_default
default_days = 365
default_crl_days = 30
default_md = sha1
preserve = no
policy = policy_match

[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ 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
string_mask = nombstr

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = MyState
localityName = Locality Name (eg, city)
localityName_default = MyCity
0.organizationName = Organization Name (eg, company)
0.organizationName_default = MyOrg
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = MyOrgUnit
commonName = Common Name (eg, 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

[ ca_ext ]
# Extensions for creating certificate authorities
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical,CA:true,pathlen:0
keyUsage = cRLSign,keyCertSign
extendedKeyUsage = serverAuth,clientAuth,codeSigning,emailProtection
subjectAltName = email:copy
issuerAltName = issuer:copy

[ mail_ext ]
# Extensions for client email certificates
basicConstraints = CA:false
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = emailProtection

[ ssl_ext ]
# Extensions for SSL certificates
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth

Make sure default_md is set to “sha1” instead of “md5.”  It’s more secure.

You’ll also need to create a file named serial.txt that contains just the number 01, like this:

01

If you plan to work with certificate revocation lists (CRLs), you’ll also need to create a file named crlnumber.txt that contains the number 01, and an empty index.txt file.


Create a Certificate Authority

This will create your certificate authority’s root certificate, which will be used to sign all your other certificates.  A “certificate authority” is a fancy name for someone that has the authority to issue and sign certificates.  In this case, that’ll be you – issuing certificates to yourself.  “Root certificates” are distinguished from other certificates because they are self-signed; the user must therefore trust the reputation of the certificate authority.  (We’ll assume you trust yourself.)

1. Start by creating a private key for the root certificate authority.  (On the following screens, you may get ‘unable to write random state’ messages; I could never fix them, but it seems to work anyway.)

> openssl genrsa -des3 -out ca.key 2048

Loading 'screen' into random state - done
Generating RSA private key, 2048 bit long modulus
....................................................+++
e is 65537 (0x10001)
Enter pass phrase for ca.key: password
Verifying - Enter pass phrase for ca.key: password

2. Next create a certificate request.

> openssl req -new -key ca.key -out ca.csr
-config openssl.cnf

Enter pass phrase for ca.key: password
Loading 'screen' into random state - done
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) [MyState]:
Locality Name (eg, city) [MyCity]:
Organization Name (eg, company) [MyOrg]:
Organizational Unit Name (eg, section) [MyOrgUnit]:
Common Name (eg, YOUR name) []:My Root Certificate Authority
Email Address []:ca@mydomain

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

3. Create and self-sign the root certificate.

> openssl x509 -req -in ca.csr -out ca.crt -signkey ca.key
-extfile openssl.cnf -extensions ca_ext

Loading 'screen' into random state - done
Signature ok
subject=/C=US/ST=MyState/L=MyCity/O=MyOrg/OU=MyOrgUnit/
CN=My Root Certificate Authority/emailAddress=ca@mydomain
Getting Private key
Enter pass phrase for ca.key: password

You can also do all 3 steps in one command if you want:

> openssl req -new -x509 -keyout ca.key -out ca.crt
-config openssl.cnf -extensions ca_ext

Loading 'screen' into random state - done
Generating a 2048 bit RSA private key
.......................+++
writing new private key to 'ca.key'
Enter PEM pass phrase: password
Verifying - Enter PEM pass phrase: password
-----
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) [MyState]:
Locality Name (eg, city) [MyCity]:
Organization Name (eg, company) [MyOrg]:
Organizational Unit Name (eg, section) [MyOrgUnit]:
Common Name (eg, YOUR name) []:My Root Certificate Authority
Email Address []:ca@domain

Now you have a root certificate. Note that you’ll need to publish the root certificate so that people can install it as a Trusted Root Certificate Authority.  Do NOT publish the private key.  Keep it backed up and safe from prying eyes.  (I keep it on a USB thumb drive; ie. not stored on a computer connected to the Internet.)


Create an S/MIME Email Certificate

This will create a certificate signed by your root certificate authority, which you can use to sign and encrypt your emails in S/MIME-compatible programs.

Creating certificates is normally a two-stage process:  A user provides their certificate request and credentials to a certificate authority and then the CA returns a signed certificate.  This demonstration does it all on one machine.

1. First the client creates a private key.

> openssl genrsa -des3 -out mail.key 2048

2. Then the client creates a certificate request.

> openssl req -new -key mail.key -out mail.csr
-config openssl.cnf

Alternatively, you can do both steps in one command:

> openssl req -new -out mail.csr -keyout mail.key
-config openssl.cnf

3. The client would then transmit the certificate request to the certificate authority, where the CA would sign a certificate and return it.

> openssl x509 -req -in mail.csr -out mail.crt
-CA ca.crt -CAkey ca.key -CAserial serial.txt
-extfile openssl.cnf -extensions mail_ext

The signed certificate file would then be sent back to the client for him to use.

Create an SSL Certificate

This will create an SSL certificate signed by your root certificate authority, which you can import into Apache and IIS to create secure web sites.  The process is almost identical to creating an email certificate except that the private key is not encrypted for Apache installations, and the extensions are slightly different.

(If the private key is encrypted, Apache will prompt you for the password when it starts, which would be bad if the web server restarted unattended.  For IIS, you’ll need to import the certificate as a PKCS#12 file (see below), so it doesn’t matter.)

Again, this is normally a process that takes place between a client and a certificate authority, but we’re doing it all on one machine for this demonstration.

1. The client creates a private key.

> openssl genrsa -out ssl.key 1024 [note: no -des3 for Apache]

2. The client creates a certificate request.

> openssl req -new -key ssl.key -out ssl.csr
-config openssl.cnf

3. The certificate authority receives the request, then signs and returns a certificate.

> openssl x509 -req -in ssl.csr -out ssl.crt
-CA ca.crt -CAkey ca.key -CAserial serial.txt
-extfile openssl.cnf -extensions ssl_ext


Exporting to PKCS#12

Often times you need to export a certificate and its accompanying private key to PKCS#12 format (usually identified by a .pfx or .p12 extension). This is necessary, for example, when you want to import a certificate into Outlook for encrypting emails or IIS to secure a web site.

> openssl pkcs12 -export -clcerts 
-in mail.crt -out mail.p12 -inkey mail.key

Loading 'screen' into random state - done
Enter pass phrase for mail.key: password
Enter Export Password: exportpassword
Verifying - Enter Export Password: exportpassword


Revoke a Certificate

You may need to revoke a certificate if the private key has been compromised, or if you decide not to use it anymore.  This is an area I’ve only started experimenting with, so I don’t know much about it.

Make sure you’ve setup the [CA_default] section in openssl.cnf and created an empty index.txt database file.

> openssl ca -revoke (file).crt -crl_reason reason 
-config openssl.cnf

The “reason” will probably be either “superseded” or “keyCompromise.”


Create a Certificate Revocation List (CRL)

The above revocation will just add the revoked certificate to the index.txt database.  From there, you need to create a certificate revocation list (CRL) to publish.  Again, I’ve just started experimenting with this so I’m not sure how the CRL propagates yet.

Make sure you’ve created a file named crlnumber.txt containing just the number 01 (or whatever serial number you want to start with) the first time you do this.

> openssl ca -gencrl -out revoked.crl -config openssl.cnf


Notes

If you don’t want to mess with OpenSSL and the command line, Windows Server has a bunch of certificate services, but based on my meager experience with them, one could argue that they are just as hard to setup and use, especially since they are geared more for “the enterprise.”  One nice thing about OpenSSL is you can put the whole operation onto a USB thumb drive and keep your “certificate authority” completely safe… assuming you don’t lose it.

There doesn’t seem to be any kind of standard for the extensions on these files.  The PEM formats are all basically base64-encoded text files, and they have extensions like .key, .csr, .cer or .crt.  It really doesn’t matter what you call them, but it’s convenient to name certificates .crt or .cer in Windows because there are built-in associations for them.

If you post your certificates on the web, make sure your web server correctly associates them with the MIME type application/x-x509-ca-cert.  Also, if you post CRLs, associate them with application/x-pkcs7-crl.

Make sure you import PKCS#12 certificates with public AND private keys to sign emails in Windows Mail or Windows Live Mail.  They won’t work if you import public key certificates (.crt files) and you’ll see this cryptic error message whenever you try to send a signed email:  “The message could not be sent. An error has occurred.”

Name-Brand Certificates

My shared Linux web host won’t let me install my own SSL certificates, which I presume is because a) they don’t trust users, b) they want to charge money for it and c) it involves rebooting their web server.  Bummer.

When you buy certificates, they come in Class 1, Class 2 and Class 3 (also Class 4 and 5).  Class 1 certificates don’t have much in the way of identity verification – just a simple email or domain verification.  They are fast and easy to get (in minutes) and don’t cost very much, if anything.  Class 2 certificates have more robust identity verification and generally involves sending personally identifiable or corporate documentation to the certificate authority.  Class 3 certificates (which may also be called “extended validation” or EV certificates) involve “extensive” independent vetting of the client credentials (generally something that only large corporations would need).

Obviously if you’re building a major e-commerce site or something, you’ll have no choice but to buy Class 2+ certificates.  At the time of this writing, the cheapest Class 2 certificate I could find was $29 from StartSSL.  (It wasn’t clear if that’s a yearly charge or a one-time charge.)  GoDaddy Class 2 (“Deluxe”) certificates are $89/year.  Certificate prices range all the way up to VeriSign’s insanely expensive $1500+/year extended validation certificates.

I haven’t tested this theory, but it seems like there should be some way to buy a name-brand authority certificate and use it in turn to sign your own subordinate certificates.  On the other hand, that might potentially wreck the reputation of the trusted certificate authority.

As far as I know, there’s no way make an “extended validation” certificate because web browser makers (Mozilla, Microsoft, etc.) internally maintain their own lists of recognized EV certificate authorities.  You’ll just have to buy into the racket and pay big bucks for those.


References, in no particular order

http://www.openssl.org/docs/apps/openssl.html

http://www.sonicwall.com/downloads/Using_Openssl_to_Create_a_Private_Certificate_Authority.pdf

http://www.freebsdmadeeasy.com/tutorials/freebsd/create-a-ca-with-openssl.php

http://www.freebsdmadeeasy.com/tutorials/web-server/apache-ssl-certs.php

http://www.davidpashley.com/articles/cert-authority.html

http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/x195.html

One Reply to “How to Create and Manage Certificates with OpenSSL”

Comments are closed.