Generating an SSL certificate

A little bit of theory

An SSL certificate (with SSL standing for Secure Sockets Layer) is a digital certificate that allows you to verify that the server responsible for transmitting data to the client 1. has not been tampered with, and 2. is actually the one that sent you the data. 

A typical SSL certificate consists of:

  • a private key, which is kept secret and helps the server to encrypt data; 
  • a certificate itself along with a public key, which allows the client to decrypt received data.

If there is no private key, it is practically impossible to encrypt any data in a way that would enable the client to decode it with their corresponding public key.

The most important information contained in an SSL certificate concerns the organisation to whom it was issued, or in other words, the domain name. Other details encoded in a certificate can include issuer data, that is, some information about the authority that signed the server’s certificate – including a digital signature that can only be generated by a holder of the issuer’s certificate’s private key. Like that, the issuer is the only “entity” that can generate and sign a valid SSL certificate. 

As a client, you can consider the connection secure if, in the course of following a certificate chain, you reach a certification authority’s “trusted root certificate” embedded into your system or browser, which, in turn, proves to be self-signed.

Why do you need an SSL certificate?

When programming locally, you may come across a number of applications that require a valid SSL certificate, namely:

  • PWA, or progressive web applications, 
  • applications that involve WebRTC technologies.

Generating a valid SSL certificate

To get a valid SSL certificate, you can pick and follow one of these routes:

  1. Generate a self-signed certificate and install it in the Trusted Root Certification Authorities store, so that your device can interpret it as a valid certificate. As suggested by its name, a self-signed certificate is a certificate that has been signed using its own private key. 
  2. Generate a root certificate and install it in the Trusted Root Certification Authorities store, then generate a certificate for your server and sign it using the previously-created root certificate.

Getting started

First, you will need to install OpenSSL (binary files for Windows can be found here).

openssl.cfg configuration file

[ req_distinguished_name ]
countryName         = CO
stateOrProvinceName = ST
localityName        = ST
organizationName    = O

####################################################################
# Extensions for when we sign normal certs (specified as default)
[ usr_cert ]
basicConstraints = CA:false
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
subjectAltName = email:move

####################################################################
# Same as above, but cert req already has SubjectAltName
[ usr_cert_has_san ]
basicConstraints = CA:false
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

####################################################################
# Extensions to use when signing a CA
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
subjectAltName=email:move

####################################################################
# Same as above, but CA req already has SubjectAltName
[ v3_ca_has_san ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true

[ req ]
prompt             = no
default_bits       = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.0 = example.com
DNS.1 = *.example.com

Generating a self-signed certificate

1. Generate a private key:

mkdir example.com
openssl genrsa -out example.com/example.com.key

You get:

Generating RSA private key, 2048 bit long modulus (2 primes)
........................+++++
..........................................................+++++
e is 65537 (0x010001)

2. Create a certificate signing request:

openssl req -new -key example.com/example.com.key -out example.com/example.com.csr -config openssl.cfg -subj "/CN=example.com certificate"

3. In the configuration file openssl.cfg, locate the [alt_names] block and type in the name(s) of your domain. Previously, the solution only supported one name – the one declared in the CN field – but now it became possible to write down multiple different names, and even create a so-called wildcard certificate for all of your subdomains:

[ alt_names ]
DNS.0 = example.com
DNS.1 = *.example.com

4. Generate a certificate:

openssl x509 -req -in example.com/example.com.csr -extensions
req_ext -extfile openssl.cfg -signkey
example.com/example.com.key  -out example.com/example.com.crt
-days 1825

Check the result:

openssl x509 -in example.com/example.com.crt -text

You get:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0f:63:6b:b8:76:27:71:d1:e9:f3:53:01:11:11:7c:52:d6:c7:ea:c6
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = example.com certificate
        Validity
            Not Before: Sep 27 05:08:48 2022 GMT
            Not After : Sep 26 05:08:48 2027 GMT
        Subject: CN = example.com certificate
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c9:...:3b:24:
                    26:0f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:*.example.com
    Signature Algorithm: sha256WithRSAEncryption
         20:a9:...:fe:fd:
         5f:30:e8:4a
-----BEGIN CERTIFICATE-----
MIIC+zCCAeO…8w6Eo=
-----END CERTIFICATE-----

And so, you now have the certificate itself (example.com.crt), and the key file to go along with it (example.com.key) – both of which can be used in your applications. 

Generating a root certificate + a server certificate

1. Generate a private key for a root certificate:

mkdir ca
openssl genrsa -out ca/ca.key

You get:

Generating RSA private key, 2048 bit long modulus (2 primes)
...........................................+++++
...................................+++++
e is 65537 (0x010001)

2. Create a root certificate:

openssl req -x509 -new -key ca/ca.key -days 1825 -out
ca/ca.crt  -extensions v3_ca_has_san -config openssl.cfg -subj
"/CN=Root CA"

3. Follow the steps 1 through 5 from the instruction above (Generating a self-signed certificate).

4. Generate a server certificate that will be signed by your root certificate:

openssl x509 -req -in example.com/example.com.csr -C
 ca/ca.crt -CAkey ca/ca.key -CAcreateserial -extensions req_ext
-extfile openssl.cfg -out example.com/example.com.ca.crt -days
1825

5. Check the result: 

openssl x509 -in example.com/example.com.ca.crt -text

You get:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            27:f4:ec:08:a8:36:b8:38:81:53:d9:8f:b5:fe:91:13:79:f0:9e:dc
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = Root CA
        Validity
            Not Before: Sep 27 05:46:19 2022 GMT
            Not After : Sep 26 05:46:19 2027 GMT
        Subject: CN = example.com certificate
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c9:...:26:0f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:*.example.com
    Signature Algorithm: sha256WithRSAEncryption
         9e:72:...:57:17
-----BEGIN CERTIFICATE-----
MIIC…JXFw==
-----END CERTIFICATE-----

As a result, you get two key-certificate sets: the server certificate example.com.crt with its key example.com.key, and the root certificate ca.crt with its key ca.key

So now, if the root certificate you’ve created gets installed in the Trusted Root Certification Authorities store of your system and/or browser, all of the certificates signed using this root certificate will automatically become valid. 

Installing a root certificate on Windows (Chrome)

Google Chrome uses your operating system’s certificate store, which makes the certificate installation process quite straightforward:

Installing a root certificate on Windows (Chrome)

Installing a root certificate in Firefox

Mozilla Firefox, on the other hand, has its own certificate store – so, in order to install a root certificate there, you should do the following:

Installing a root certificate in Firefox

Installing a root certificate in Firefox (2)

You may have to disable the DNS over HTTPS option in your browser’s connection settings, so that it would use the system’s DNS instead – which, in turn, is linked to the hosts file (a bit more about it later):

Installing a root certificate in Firefox (3)

Installing a root certificate in Firefox (4)

Example: Using a certificate with create-react-app

1. Add the following variables to your .env:

HTTPS=true
SSL_CRT_FILE=certs/example.com.crt
SSL_KEY_FILE=certs/example.com.key
HOST=example.com

2. Open the hosts file (Windows – C:\Windows\System32\Drivers\etc\hosts, Ubuntu – /etc/hosts) and add the following entry:

192.168.2.116 example.com

By doing so, you make the system resolve your domain name example.com locally (to find your PC’s local IP address, make sure to check Network Settings). 

3. Finally, launch the application – as you can see, the connection is secure, and you have a valid SSL certificate:

Using a certificate with create-react-app

Working with SSL certificates on mobile devices

Now, let’s take a look at how you can install an SSL certificate on Android and test your application on a mobile device. 

Installing a root certificate on Android

1. Make sure that your PC and mobile device are connected to the same local network. 

2. Use create-react-app. 

3. Place your ca.crt certificate in the public folder. 

4. Add the local IP address of your computer to .env:

HOST=192.168.2.116

5. Launch create-react-app without https

6. On your mobile device, open http://192.168.2.116:3000/ca.crt and install the certificate:

Installing a root certificate on Android

Adding a domain name on Android

In order to be able to test your application on a mobile device, you need to make sure that the domain name you’ve created is resolved to the local IP address of your computer.

To do so, you can do one of the following:
 

1. If you have root access on your mobile device, simply edit the hosts file. 

If you don’t have the access, you can use an app called Postern – it’s a VPN server launched directly from your smartphone that can not only modify your device’s network traffic, but intercept and respond to DNS queries as well. Using Postern, you can easily map the domain name example.com to your computer’s local IP address – just like this (don’t forget to have webpack-dev-server running in your local network):

Adding a domain name on Android

To check whether Postern is running at any given moment, take a look at the right-hand corner of your smartphone’s status bar – a small key (or sometimes a lock) icon indicates that you have VPN enabled, and all requests are currently going through Postern

Once the mapping is done, you can try and open your application in a mobile browser:

application in a mobile browser

And voilà! Now you know a little bit more about SSL certificates – and since you’ve just learned how to generate and install them, you can put all this new knowledge into practice on your own projects! :)