logIt Log Around The Clock

HTTPS Using Server-Client Certificate Pair (1): Generate & Sign by OpenSSL

Multiple command lines in the process of generating certificates using openssl can be quite confusing and easily mixed up over which-do-what. Most of them are repetitions of almost the same syntax (where the confusion comes).

Background:
I need to setup an HTTPS site with not just server certificate to secure it, but requiring also client side certificate. The site will only show the content to authorized users with the correct pair of server-client certificate. It will also expire after a certain date. The certificates are self-signed as they’re for closed environment usage.

This post covers two general processes: generating and signing.

How to generate SSL certificate using openssl is a straightforward process of:

  1. generate its key
  2. create certificate request with that key
  3. generate certificate from request and key

Hence, in any type of the certificate I have a general <some-cert-key>.key, <some-cert-request>.csr, and <some-cert>.crt. When I mean “type”, they are CA (Certificate Authority), one/more server certificate, and one/more client certificate.

ssl-certificate-ca-server-client-illustration-1.png

Generating Pairs of Key-Certificate with openSSL: CA, server, & client

In terms of signing the certificates, all of them are signed using the CA. Which files to be used in the server will become the subject of the next post.

openssl will run interactively. To go through all the recurring questions using prepared default answers, we need to create a config file first. I created caconfig.cnf (find it on the bottom of the post) and use -config caconfig.cnf option in some commands.

First, prepare set of directories to clearly separate what we’re working on (keys, requests, and resulting certificates in different places for server and user):

mkdir certs
mkdir private
mkdir server
mkdir server/certs
mkdir server/creqs
mkdir server/ckeys
mkdir user
mkdir user/certs
mkdir user/creqs
mkdir user/ckeys

Prepare “database” and index number to keep track of certificates issued:

echo 01 > serial
touch index.txt

Generate the CA: (again) generate key, create request (the interactive part), and create certificate:

openssl genrsa -out private/myCA.key 2048
openssl req -new -key private/myCA.key -out certs/myCA.csr -config caconfig.cnf 
openssl req -x509 -days 365 -in certs/myCA.csr -out certs/myCA.crt -key private/myCA.key

We can always check:

openssl x509 -in certs/myCA.crt -text

Now, generating for the server, I use the name lakmus as an example. First the key:

openssl genrsa -des3 -out server/ckeys/lakmus.key 2048

(Triple-DES cipher will ask for pass phrase of 4 characters minimum)

Enter pass phrase for server/ckeys/lakmus.key:
Verifying - Enter pass phrase for server/ckeys/lakmus.key:

Then, the request (which will ask for the above key pass phrase):

openssl req -new -key server/ckeys/lakmus.key -out server/creqs/lakmus.csr -config caconfig.cnf

Note that organizationName field needs to be the same with the CA certificate.

Then, signing it with the CA (and again check as text):

openssl ca -days 365 -in server/creqs/lakmus.csr -cert certs/myCA.crt -out server/certs/lakmus.crt -keyfile private/myCA.key -config caconfig.cnf
 
openssl x509 -in server/certs/lakmus.crt -text

During signing we’ll see something like (expiry date and validity periode)

Certificate is to be certified until <some date> (365 days)
Sign the certificate? [y/n]:

and index.txt is updated:

V	140123034822Z		01	unknown	/C=ID/ST=WEST JAVA/O=My Organization/CN=lakm.us
V	140123041441Z		02	unknown	/C=ID/ST=WEST JAVA/O=My Organization/CN=client

Finally, the same generate with own key and sign with CA except this time is for client:

openssl genrsa -des3 -out user/ckeys/client1.key 2048
openssl req -new -key user/ckeys/client1.key -out user/creqs/client1.csr -config caconfig.cnf
 
openssl ca -in user/creqs/client1.csr -cert certs/myCA.crt -keyfile private/myCA.key -out user/certs/client1.crt -config caconfig.cnf 
 
openssl x509 -in user/certs/client1.crt -text

For the client certificate to be usable when importing to browser, convert it to PKCS 12

openssl pkcs12 -export -clcerts -in user/certs/client1.crt -inkey user/ckeys/client1.key -out user/certs/client1.p12

It will ask for pass phrase and export password (that will be prompted when importing to browser)

Enter pass phrase for user/ckeys/client1.key:
Enter Export Password:
Verifying - Enter Export Password:


Troubleshooting

If the CA generation already worked smoothly, it is better to remove the key, request, and certificate files of subsequent signing process before repeating them when any error is found. Otherwise it will finally show error such as:

failed to update database
TXT_DB error number 2

Or something like

No certificate matches private key

when exporting to PKCS 12.

We can check the index.txt, index.old, serial, and serial.old to figure our situation by evaluating indexes of signed certificate.


CA Config

I used parts from Code Ghar post for my caconfig.cnf:

[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /home/arif/ssl
serial = $dir/serial
database = $dir/index.txt
new_certs_dir = $dir/certs
certificate = $dir/certs/myCAcert.crt
private_key = $dir/private/myCA.key
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = md5 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
# Variable name Prompt string
#------------------------- ----------------------------------
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (department, division)
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name (city, district)
stateOrProvinceName = State or Province Name (full name)
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
# Default values for the above, for consistency and less typing.
# Variable name Value
#------------------------ ------------------------------
0.organizationName_default = My Organization
localityName_default = BOGOR
stateOrProvinceName_default = WEST JAVA
countryName_default = ID
emailAddress_default = fake@lakm.us
commonName_default = lakm.us

4 thoughts on “HTTPS Using Server-Client Certificate Pair (1): Generate & Sign by OpenSSL

  1. Tamer

    hello i read your post. Thnx alot, But i have a question, What is the difference here between client and server put into consideration that you also used the CA config file to generate them.

  2. Arif Post author

    For some items of the config e.g. “certificate, private_key, default_days, default_md” they’re obviously the same for client. That’s why we can say that it is a client for a specific server.

    For other things, we only provide default-values so that in the interactive process of creating certificate we don’t have to retype if they’re the same (just press enter to accept the default value offered by the config) e.g. the client countryName is the same as the server.
    (This comes handy when I only trying things out: no need to retype everything)

  3. rik

    I have read many articles on ssl. Still confused because nobody says “who does what”.

    Lets say there is a serverguy and a clientguy. Does the serverguy generate the client certificate and give it to the clientguy???

    I am trying to connect to a ssl server of which I have no ability to manipulate other than read the output of openssl s_client commands.

    I know I need a client certificate. I can not figure out how I can generate a client certificate. Do I need to ask the serverguy for a client certificate? or can I generate a client certificate (me being the clientguy) without ANY help from the serverguy?

  4. Arif Post author

    Yes, you need the “server-guy” to sign it for you using the key that he only keep for himself. This is a concept of security where the other party is not given the key (private).

Leave a Reply