TLS certs for internal OTS hardware - Proof of Concept

This project goes alongside my blog post TLS certs for internal OTS hardware and provides a full proof of concept demonstration of the concepts I set out in it. Full code for the project is available in my GitHub Repo.

To setup your own demo, all you need is:

  • A domain to issue certificates for.
  • A Cloudflare account and API key.

For the domain, remember, this should be similar to, but not, your main domain.

I chose Cloudflare for their simple to use DNS API. The DNS code for the project is modular so feel free to swap it out for a different provider if you do not agree with their choices of who they allow to use their platform.

You will need to set the domain up with Cloudflare so it is handling DNS for your chosen domain, it does not need to handle any web traffic. You then need to generate an API key so the server can interact and generate DNS entries.

If I could work out the correct way to do it, I would distribute binaries for the major platforms but it seems to be too tricky due to dependency issues so, instead, you'll need to compile your own. If you are not a developer, don't worry, it is very straight forward. I'm going to assume you are on a Linux based system, if you are on Windows, the commands will be very similar, you'll probably just need to add a ".exe" here and there and swap the slashes around.

First you'll need Go installed, you can do this either through your OS package management system or by following these Getting Started instructions.

Once you have that in place you can check out the source, this is done with:

go get -v github.com/digininja/ots-cert-demo

Now we have the code, let's build the server:

cd ~/go/src/github.com/digininja/ots-cert/server
go get -v ./...
go build
cp ots-cert-server.cfg-template ots-cert-server.cfg

At the end of this, you should have a binary called server and an empty configuration file. Populate the configuration file with your chosen domain and the Cloudflare API details, you should not need to update any of the other fields but have a look just in case.

The app needs to know the IP address of the host so the DNS can be setup correctly. As this is a demo, it will only bind on an internal IP address, so to find an IP, it scans through all the available interfaces looking for IPs in the RFC 1918 ranges, if it finds just one of these, it will use it, if it finds multiple then you have to tell it which interface you want it to take the address from, you can set this either in the config file or on the command line with --interface.

You should then be able to start the server:

./server 
INFO[0000] Starting the server
INFO[0000] No valid certificate found, going to create a new one 
INFO[0010] Creating DNS record
INFO[0011] Starting web server on: https://iotserver.ots-cert.space:9443

If there are no errors, then you've just tested all the key parts of the system and everything is good and working. This is because, when the server starts up, it has no certificate and no usable DNS name so the first thing it does is to go off and set itself up. It creates a new certificate, registers its name with the DNS provider and then starts up a web server listening on HTTPS. To save repeated calls to get new certificates, the server stores the certificate and key locally so the next time it starts, it doesn't need to go get a new one.

Now, lets get the client up and running. In a new terminal run:

cd ~/go/src/github.com/digininja/ots-cert/client
go get -v ./...
go build
cp ots-cert-client.cfg-template ots-cert-client.cfg

Similar to before, you should now have a client binary and an empty configuration file. The only change you will need to make to the config file is to set the hostname for your server.

Once the configuration is complete, let's run it and see what happens:

./client
INFO[0000] The hostname is: nifty-babbage.ots-cert.space
INFO[0010] The certificate was generated
INFO[0010] Setup complete, browse to https://nifty-babbage.ots-cert.space:8443

Hopefully you will get something which looks like the above and you will be able to browse to the URL you are shown:

curl https://nifty-babbage.ots-cert.space:8443
Congratulations, you should be viewing this over HTTPS on your custom domain.

A quick check on the server and you should see the steps it went through in generating the certificate and returning it.

./server
INFO[0000] Starting the server
INFO[0000] No valid certificate found, going to create a new one 
INFO[0010] Creating DNS record
INFO[0011] Starting web server on: https://iotserver.ots-cert.space:9443
INFO[0361] Call to register a client
INFO[0361] The client ID is: aeadc9da-2057-4c3d-8a75-63369c68af43
INFO[0361] Hostname generated for client: nifty-babbage
INFO[0361] Creating DNS record
INFO[0362] Call to generate a certificate
INFO[0372] Certificate generated and being returned to the client

And that is it, you how have a web server running on an internal IP address which has a valid certificate from Lets Encrypt.

The client writes the certificate to disk but deliberately does not reload it next time it starts up, this is to allow the process to be demonstrated, in the real world, the client would check the certificate on start up, and if it is valid, reuse it. If either the server or the client are likely to be up for a while, they would also need to periodically check the certificate expiry date so they can be renewed so they can be renewed at an appropriate time.

If you want to manually check the certificate, to confirm it is valid, you can do this as follows:

openssl x509 -in cert.pem -text -noout
Certificate:
  Data:
    Version: 3 (0x2)
    Serial Number:
      03:db:bb:db:00:46:81:9d:88:4d:c6:de:a3:8b:56:5b:25:b3
    Signature Algorithm: sha256WithRSAEncryption
    Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
    Validity
      Not Before: Jun 25 09:51:16 2019 GMT
      Not After : Sep 23 09:51:16 2019 GMT
    Subject: CN = nifty-babbage.ots-cert.space

When the server receives the initial request to register the client, it checks the IP address provided is an internal address, this is a way to prevent the server being used to setup DNS entries and certificates for sites which could be made internet facing. Despite the domain in use not being the main one for the company, having attackers being able to start up externally reachable websites with valid DNS and certificates is probably not the best thing to have.

I was originally planning to run a public server so users could see the concept running as it would in the wild, but as I've got the default restriction of only being able to issue a small number of Lets Encrypt certificates a day, I do not think it would work too well and might end up confusing rather than helping people.

If you like this demo, and are thinking of creating something based on it, please get in touch, it would be brilliant to know the process is being used in the real world and that there are manufacturers of OTS hardware that are taking security seriously.

Support The Site

I don't get paid for any of the projects on this site so if you'd like to support my work you can do so by using the affiliate links below where I either get account credits or cash back. Usually only pennies, but they all add up.