primecoder.github.io

PrimeCoder GitHub Pages

Follow me on GitHub

🏡 Home > 📍

Create Certificates for Secure API Over TLS

Self Signed Cert

Environments

I did these steps, below, both on my Mac OS 11 and GCP Debian 10 Buster. They work and behave almost exactly the same.

Steps

Create Self-Signed Certificate (CA) for clients

Note: in this article, YOU are the Certificate Authority (CA) - hence the keyword self-signed. The certificates generated here are good for TEST and DEVELOPMENT purposes. For PRODUCTION, please get your certificates signed and verified by trust Certificate Authorities.

Step 1 - Generate CA key

$ openssl genrsa -out development-ca.key 4096

The above openssl genrsa command generates RSA key (4096 bit in this case) and saves the output to ‘development-ca.key’.

All the key files should be kept securely and should not be shared.

Step 2 - Create and process certificate request

$ openssl req -x509 -new -nodes -key development-ca.key -sha256 -days 365 -out development-ca.crt

openssl req creates and processes certificate requests. The input to this command is the private CA key created from step 1. This command saves the certificate into an output file (.crt). The option -x509 specifies that it creates a self-signed certificate instead of a certificate request.

That’s it! Now you have a self-signed certificate that can be distributed onto your test/dev client devices.

Step 3 - Install self-signed certificate on clients

Install CA certificate on Mac OS devices
Install CA certificate on iOS devices

Create Certificates for Server Side

Step 4 - Generate Server Key

$ openssl genrsa -out development.key 4096

Step 5 - Prepare Config File (.cnf)

[ req ]
prompt             = no
default_bits       = 4096
distinguished_name = req_distinguished_name
req_extensions     = req_ext
[ req_distinguished_name ]
countryName                = <YOUR_COUNTRY_CODE>
localityName               = <YOUR_LOCALITY_NAME>
organizationName           = <YOUR_ORGANIZATION_NAME>
commonName                 = <CERT_COMMON_NAME>
[ req_ext ]
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = <YOUR_SERVER_IP_ADDRESS_1>
IP.2 = 127.0.0.1
IP.3 = <YOUR_SERVER_IP_ADDRESS_2>

The [ req_distinguished_name ] block is pretty much standard info. However, I had to add IP addresses of all my servers under [alt_names] block. In my case, IP.1 is the ip address of my python/flask server running at home, i.e. 192.168.0.10. Whereas, my IP.3 is the external ip address of my server running on GCP.

This .cnf file will be used as one of the inputs in the next step.

Step 6 - Generate Certificate Request (.csr)

$ openssl req -new -key development.key -config config.cnf -out development.csr

Note, you pass in the server key (from step 4) and the config file from previous step as inputs.

Step 7 - Generate Server Certificate (.crt)

$ openssl x509 -req \
-in development.csr \
-CA development-ca.crt \
-CAkey development-ca.key \
-CAcreateserial \
-out development.crt \
-days 365 -sha256 \
-extfile config.cnf \
-extensions req_ext

Input files:

  1. -in development.csr - from step 6
  2. -CA development-ca.crt - from step 2
  3. -CAkey development-ca.key - from step 1
  4. -extfile config.cnf - from step 5

Output file:

  • -out development.crt

Step 8 - Install certificate on your server

Finally, install server key and certificate on your web/API server. In my case, I ran Python/Flask, my start-up python file is, for example:

if __name__ == '__main__':
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.load_cert_chain("certs/development.crt",
                            "certs/development.key")
    app.run(debug=False, host="192.168.0.112", port=5000, ssl_context=context)

Re-generate Certificate(.crt) for Server

See: Re-generate Self-Sign Certificate

Appreciations

My work here relies a lot on work done by Jaanus (see: [1]), and Grinberg [3], see References below.

I would like to thank them both for their excellent posts.

References

  1. How to configure development server certificates for iOS 13 and Mac clients, by Jaanus, Jaanus.com
  2. Technical Note TN2232, HTTPS Server Trust Evaluation, Apple Developer, developer.apple.com
  3. Running Your Flask Application Over HTTPS, by Miguel Grinberg
  4. HTTPS and Trush Chain in Flask, by Carolina Fernandez