Petri Kannisto's homepage – about software systems and research

Certificates for TLS-encrypted connections

(updated ) – Petri Kannisto

DISCLAIMER. This guide comes "as is". The author is no expert in cryptography. The guide aims to take a practical viewpoint on setting up encrypted connections, explaining enough to a developer to get started.


This guide tells you some basics about encryption with Transport Layer Security (TLS) and shows how to set up self-signed certificates into a server. In case you wonder, the predecessor of TLS is called Secure Sockets Layer (SSL), which still appears often even if the speaker actually referred to TLS.

Please note that your server needs a domain name, but you can fabricate one if you only want local experiments. The reason is you cannot associate a certificate to an IP address. For local experiments however, you can fabricate a domain name with the hosts file. In Linux, this is presumably located at /etc/hosts. In principle, you can use any domain name, but naturally you should select something that causes no confusion with real domains. For example, myhost.local is a good idea.

Basic of TLS

TLS uses an asymmetric encryption method where the recipient has two keys, public and private, to ensure the encrypted data remains secret. The data is encrypted with the public key of the recipient (visible to anyone) and decrypted with the secret key (only known to the recipient). This way, anyone could create encrypted data for the recipient but only the recipient can perform the decryption. The public key can be therefore delivered to anyone without any encryption when the encrypted connection is just being set up. Practically, each TLS-enabled server has its own private and public key.

Encryption and decryption illustrated
Encryption and decryption illustrated

In addition to keys, you also need certificates for authentication. A certificate enables a network node to verify that another node is who it claims to be. Typically, a certificate is associated to a domain name, such as example.com. In a client-server scheme, it's possible to authenticate both servers and clients with certificates, which would eliminate the need for any password-based authentication. However, often only the server has a certificate, whereas the clients either uses another authentication method or the server requires no authentication in the first place depending on the case.

Certificate authorities

Not everybody can create a trusted certificate, therefore there are trusted certificate authorities (CA) that do this. This is simply because nobody would trust anybody if you could just pretend that you are Google, Microsoft, or Amazon. The authenticity of the issuer of the certificate (i.e., the CA) is verified with cryptographic tools, usually in the background whenever you access a server over an encrypted connection. In practice, operating systems and platforms have a certificate store that contains the certificates of the trusted CAs. With these CA certificates, the platform can verify if a server certificate has been signed by a trusted CA.

However, in some cases you may want to create certificates by yourself. This applies to situations where you want to quickly experiment with something. In this case, you would generate the CA certificate by yourself. However, for such a CA certificate to work, you'll need to install the CA certificate manually into any system that should validate the self-signed certificates.

Getting certificate

From conventional CA

To get a proper certificate from a real CA, you would create a signing request and send this to the CA. This costs some money. This is, however, excluded from this guide.

Let's Encrypt

Update: added this section on 3 Jul 2022

You can as well use Let's Encrypt to get proper certificates without paying anything. This is excluded from this guide, but you can find the instructions here: https://letsencrypt.org/

As a limitation, Let's Encrypt requires your server to open port 80 to the public.

As another downside, Let's Encrypt certificates are valid for only three months at a time. That is, the certificates must be renewed often, but at least in Linux you can set up a bot to renew the certificates. See https://certbot.eff.org/

If you use Nginx and want the renewed certificates to be reloaded automatically, see the updated part of this post (at the bottom): https://www.guyrutenberg.com/2017/01/01/lets-encrypt-reload-nginx-after-renewing-certificates/

Create self-signed certificate

You can as well create the certificates by yourself. This costs nothing, but no one is going to trust your certificates by default. Usually, to make a client trust your certificates, you must manually install the related CA certificate into the client. This is excluded from this guide.

You'll use the openssl command in this section. This is easier in Linux than in Windows, therefore please use Linux if possible.

Please keep all of the files that result from the following steps. You may/will need these later.

Create a private key for the CA, which is you. This is supposed to remain secret!

openssl genrsa -des3 -out rootca.key 4096

Create a certificate for the CA:

openssl req -x509 -new -nodes -key rootca.key -sha256 -days 1024 -out rootca.crt

Now that we have a fabricated certificate authority, we can generate a certificate for our server.

First, create a private key for the server. This is supposed to remain secret!

openssl genrsa -out server.key 2048

Next, you generate a signing request:

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

Finally, based on the request, the CA generates you a certificate:

openssl x509 -req -in server.csr -CA rootca.crt -CAkey rootca.key -CAcreateserial -out server.crt -days 500 -sha256

How to install the certificate?

It depends on the system how you would actually install the certificate into the server.

Regarding the client, if you have a self-signed certificate, you must install the CA certificate into the client platform. This tells the system it can trust any certificate created by the CA (or you in this case). For example, Windows has a system-level certificate store, whereas Java has a "keystore" of its own.

Certificates come in many formats. Sometimes, the system requires a specific format that differs from what you have, but luckily you can convert these.

For example, PEM to DER:

openssl x509 -inform PEM -in cert.pem -outform DER -out cert.der