SSL/TLS Certificates


SSL/TLS certificates are the cornerstone of making HTTPS work. A server certificate provides proof to the client (usually a browser) that the server it is connecting to is indeed the real thing and that communication between the two is secure. This article covers the basics and provides a prescriptive “cookbook” of openssl commands for creating your own certificates and testing them. 

In the beginning there was nothing. Then a private key was immaculately conceived from the darkness. The private key begat a public key and combined with a “distinguished name” a certificate signing request is presented to the almighty Certificate Authority (CA). In its infinite wisdom the Certificate Authority signs the request making it a bonafide Certificate.

Should it fall from grace, a Certificate will end up on a Certificate Revocation List and all will shun it.

private key → public key + identity of public key owner “Distinguished Name”→ certificate signing request (CSR) → certificate

The client (identified by distinguished name) creates a CSR and a certificate authority (CA) signs it to create a certificate.

Stated another way in pseudocode,

certificate = CertificateAuthority.sign(public_key + identity_of_public_key_owner)

If the certificate is for a server, the Common Name (CN) part of the Distinguished Name (DN) should be the Fully Qualified Domain Name (FQDN) like for example.

Certificates are a chain of trust. The intent of the root CA certificate is to be known and accepted by all. These certificates are preloaded into all browsers and potentially operating systems themselves. Any certificate that a client receives from a server as long as it has been (eventually) signed by a certificate the client trusts, will be accepted by that client.


  1. Create a self-signed certificate authority (CA) certificate
  2. Create a server certificate signed by our own certificate authority
  3. Alternatively, skip the first two steps and just create a self signed server certificate
  4. Create a client certificate signed by our own certificate authority


CA Certificate

To avoid the expense of actually getting the CA to sign your CSR, let’s create our own CA, or self signed root certificate. It’s the same as other root certificates, except that nobody trusts it so except for our own limited purposes it’s not very useful.

Generate the CA private key. You will be prompted for a new password.

openssl genrsa -des3 -out ca.key 2048

Verify the private key

openssl rsa -check -in ca.key

Create a certificate request. You will be prompted for address, email the CA key password and the Common Name. These should all relate to your fictional certificate authority.

Optionally you can pass these in at the command line

-subj "/C=CA/ST=Ontario/L=Toronto/O=CertAuth Co/"
openssl req -key ca.key -new -out ca.csr

Sign the certificate request (csr) with the CAs own private key (self-signed certificate)

openssl x509 -signkey ca.key -in ca.csr -req -days 9999 \ 
-out ca.crt

You can skip the CSR step entirely if you simply want to create a self-signed certificate

openssl req -key ca.key -new -x509 -days 9999 -out ca.crt

Server Certificate

Now create the server certificate.

Generate the server private key. You will be prompted for a new password.

openssl genrsa -des3 -out server.key 2048

(Optional) To avoid supplying a password when your listener process starts or supplying a password in application configuration, you can simply remove the password from the private key file (decrypts the private key file).

openssl rsa -in server.key -out nopass-server.key

Of course you can always just generate the private key and leave it unencrypted.

openssl genrsa -out server.key 2048

Create a certificate request. You will be prompted for address, email the server key password and the Common Name. The CN should be the FQDN of the server.

Optionally you can pass these in at the command line

-subj "/C=CA/ST=Ontario/L=Toronto/O=My Company/"
openssl req -key server.key -new -out server.csr

Verify the signature

openssl req -in server.csr -noout -verify -key server.key

Check info

openssl req -in server.csr -noout -text

Now have your fictitious CA sign the server certificate request and issue a server certificate. You will need the CA private key password.

openssl x509 -CA ca.crt -CAkey ca.key -CAcreateserial \
-in server.csr -req -days 9999 -out server.crt

If all you really want is a self-signed certificate for your server without dragging in a certificate authority (CA) or even worry about the added complication of an encrypted private key (which requires the passphrase to be maintained somewhere), then the following skips all the above steps

openssl req -x509 -nodes -days 9999 -sha256 \
-subj ‘/C=US/ST=NY/L=NYC/’ \
-newkey rsa:2048 -keyout server.key -out server.crt

keyout and out may refer to the same file – this will result in the certificate and private key being contained within a single PEM formatted file.

Not that this private key is not encrypted and protected by a passphrase (nodes)

Client / User Certificate

The final step is to create the client certificate. This is necessary when configuring SSL for mutual authentication.

It starts with generating a private key for the client. You will be asked to provide a client key password (omit -des3 to leave unencrypted; no passphrase required).

openssl genrsa -des3 -out user.key 2048

Next is to create a certificate request for the client certificate.

You will be prompted for address, email the server key password and the Common Name. The CN should identify the client. Either a person’s legal name, or a machines domain name. Either way the server accepts and trusts whatever the CN is because it trusts the CA that signed the user certificate.

openssl req -new -key user.key -out user.csr

You can optionally combine the private key creation (without passphrase) and certificate signing request:

openssl req -new -newkey rsa:2048 -nodes \
-subj ‘/C=US/ST=NY/L=NYC/CN=some user identity’ \
-keyout user.key -out user.csr

The CA takes the client’s certificate request and signs it to generate a certificate.

openssl x509 -CA ca.crt -CAkey ca.key -CAcreateserial \
-in user.csr -req -days 9999 -out user.crt

Combine the private key and certificate into a single P12 formatted file.

You will be asked for the client’s private key password.  You will also be asked for an export password.

openssl pkcs12 -export -clcerts -in user.crt \
-inkey user.key -out user.p12

PKCS#12 (P12) files define a file format for storing multiple cryptographic objects as a single file. The keystore should contain both a private and public certificate granted by the CA along with intermediate CA certificates used for signing.

Your P12 file can contain a maximum of 10 intermediate certificates.


Server Certificate

Start a web server listening to SSL using your server certificate on port 4433. If the key is encrypted you will be prompted for the passphrase.

openssl s_server -cert server.crt -key server.key -www \
-accept 4433

With the server running, attempt to connect to it.

openssl s_client -connect localhost:4433

Mutual SSL

For mutual SSL authentication to work, the client certificate offered MUST be signed by any of the root or intermediary CAs.

openssl s_client -connect host:port -key user.key \
-cert user.crt -showcerts
Certificate chain
0 s:/C=US/ST=New York/L=Armonk/O=International Business Machines Corporation/CN=*
  i:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
1 s:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA
  i:/C=US/O=DigiCert Inc/ Global Root CA
Server certificate
subject=/C=US/ST=New York/L=Armonk/O=International Business Machines Corporation/CN=*
issuer=/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA

Ensure that the server certificate can be verified by the CA certificate. Note that clients will additionally check that the FQDN in the server certificate matches the origin. This openssl check does not do that.

openssl s_client -connect host:port -CAfile ca.crt

Finally make a full request. For now let’s say that the server is installed locally on port 8443. A request to https://localhost:8443 will find the service, but unfortunately the server certificate refers to a domain other than localhost. A curl request will be rejected.

You can either disable the certificate check entirely, or you can pretend that the service is actually hosted on your production domain.

In curl to disable the certificate check include –insecure

The –cacert refers to the certificate authority certificates to use to verify the server certificate returned in the response.

curl --insecure --cacert ca.crt --request GET \ 

For example, is your production domain, but you wish to test locally.

Add the following entry to your /etc/hosts file:

Now you can make the request without disabling the certificate check:

curl --cacert ca.crt --request GET \


ca.key Certificate authority private key (PEM format)
ca.csr Certificate request for the authority (PKCS10 format)
ca.crt Self signed CA Certificate (PEM format)
server.key Server private key (PEM format)
server.csr Certificate request for the server (PKCS10 format)
server.crt Server certificate signed by the CA (PEM format)
user.key Client/user private key (PEM format)
user.csr Certificate request for the user/client (PKCS10 format)
user.crt Client/user certificate signed by the CA (PEM format)
user.p12 Client/user certificate and private key (PKCS#12 (P12) format)



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s