Simpler times

Creating a SSL Certificate

Let’s implement SSL for development for a PWA.

First thing I found out was that HTTPS is not using SSL anymore: it was substituted by TLS and deprecated in 2015. But both are public-key encryption protocols and use the same type of certificates. I'm not going to do any research on how the protocols work right now, so in principle, this is not relevant.

The objective is to include my root certificate in the Android System and generate certificates for development signed with it. I could use a ‘localhost’ certificate this way, impossible to obtain in another way.

I didn’t know how certificates work. What I found out is that certificates used for TLS are in a standard format called X.509. They can be stored in a file using different formats, usually identified by file extension: .pem, .crt, .cer, .p12… but they contain the same information.

The steps to generate a valid X.509 certificate are these:

  1. First, you must generate a public-private key pair.
  2. Then, you generate an intermediate certificate which contains your data, including the domain or domains which can be used with it. This certificate is still not valid.
  3. The intermediate certificate must be signed with your private key. With that, you create a Certificate Signing Request (csr)
  4. You send the csr to a certification authority with your public key so it can decrypt it and obtain the csr
  5. The certification authority will verify your identity, and then it will sign the csr with its private key, generating a valid certificate.

So let’s see how can we do it for a development environment.

Step 1

The first step is to generate a key pair. This is done with:

openssl genrsa -out development.server.private.key 2048

This will generate ‘development.server.private.key’ file with a key length of 2048 bits. That’s the key we will use to sign the csr, and we shouldn’t send it to anyone. But it is for a development server, so you don’t need to worry very much about it.

The key is in .pem format:


-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA8NBI...
...
-----END RSA PRIVATE KEY-----

Steps 2 and 3

Steps 2 and 3 are done together. We are specifying that we should use the key generated in step 1 in ‘-key’ parameter:

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

This command will ask you some information to generate the request, but you can automate it using a configuration file which contains all the certificate’s data. X.509 is a very complex format and you can fill a lot of fields, but a basic configuration for development could be this one. I’ve named the file ‘development.server.cnf’:


[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=ES
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = development.server

Then we can use it with:

openssl req -new -key development.server.private.key -out development.server.csr -config <( cat development.server.cnf )

Now you have a csr called ‘development.server.csr’ in PKCS#10 format:


-----BEGIN CERTIFICATE REQUEST-----
MIICpzCCAY8CAQ...
...
-----END CERTIFICATE REQUEST-----

We can examine the contents of the csr with `openssl req -in development.server.csr -text -noout` or using an online tool like this.

Steps 4 and 5

Step 4 is to send the certificate to the Certification Authority. You will be the certification authority; to become one, the first thing to do is to generate a key pair with the same command we used in step one:

openssl genrsa -out rootCA.key 2048

We will use a command similar to the one used for steps 2 and 3, but this time we use the -x509 option. This will generate a self-signed certificate: a certificate which nobody has trusted:

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1048576 -out rootCA.pem -config <( cat rootCA.cnf )

‘-nodes’ option is for generating it unencrypted (no-DES). ‘-days’ is the duration of the certificate. The .cnf file used for the certification authority is:


[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=US
ST=RandomState
L=RandomCity
O=AAA FAKE CERTIFICATION AUTHORITY
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = FAKE DEVELOPMENT root certification authority

Then you must install the root certificate in your browser. In Firefox, for example, you have it in about:preferences#privacy. There is a tab for root certificates with an import button. It will appear at the top of the list thanks to “AAA FAKE CERTIFICATION AUTHORITY” in O field.

Now you are the certification authority. The last step is to sign the development server csr.

openssl x509 -req -in development.server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out development.server.crt

With that, you have ‘development.server.crt’, which is the file to use in the server along with the private key.

The certificate must contain a unique serial number assigned by the Certification Authority. This number will be stored in ‘rootCA.srl’ file. It’s generated randomly and you can ignore it if you don’t plan to generate a lot of certificates with that authority.

Then you will need to configure the certification along with the server key to serve https pages.

All this process is too complex to remember every time you need an https environment, so I will encapsulate it in a Docker container.