Secure TLS Client
This example demonstrates how to use the ZentriOS tls_client command to connect to a secure TLS server using a self-signed TLS certificate. The TLS server runs on a computer using python.
The following steps are covered by this example:
- Generate TLS certificates using OpenSSL
- Run a python TLS server
- Load a TLS certificate into the module
- Connect the module to the TLS server using the tls_client command
NOTE: The procedures below for running OpenSSL commands, and running the Python TLS server script, will work on Linux, Mac or Windows computers with the correct software packages installed. The examples shown are for a Linux machine. Notes are provided where a variation is required for a different platform, and references for Windows in particular are provided in the final section at the bottom of the page.
TLS Certificate Primer
TLS certificates are used to:
- Encrypt data passing between a client and server
- Verify the identity of the remote side of the connection to avoid 'man in the middle' attacks
Certificate File Types
There are two types of files used in TLS connections:
- Certificate (.crt or .pem)
This is essentially the public key. Receiving parties typically keep this file locally in a certificate store. Several formats are used, the two most popular being
.pem. ZentriOS accepts only
.pemformat which is a base64-encoded X.509 certificate.
- Private Key (.key)
This is a sensitive file used to generate the certificate and validate connections. The private key must be kept secure.
- Certificate Authority (CA) Certificate
This is essentially the master certificate. All other certificates are generated from this cert. If this certificate is trusted, all certificates generated from it are trusted as well. This certificate may be obtained by either (1) generating a self-signed CA cert or (2) using a CA cert from a 3rd Party.
You can generate a self-signed CA cert using a tool like OpenSSL. It is absolutely imperative the CA private key is secure. If it gets lost or comprised, all other certificates generated from it are vulnerable.
A 3rd party, such as VeriSign or GeoTrust, maintains a CA certificate and private key. The CA.crt is made public (and typically comes built-in to most browsers) and the CA.key is locked down in a secure location by the 3rd party.
- Server Certificate
A server certificate is provided by a server to a client to verify the server identity to the client. The server cert is 'signed' by the CA certificate. For example, when a web browser connects to a website secured by HTTPS/TLS, the web server provides the browser with the server certificate enabling the browser to verify the identity of the server/website.
- Client Certificate
A client certificate is provided by a client (device) to a server to verify the client identity to the server. The client cert is 'signed' by the Server Certificate. The client certicate enables the client (i.e. ZentriOS device) to securely log-in to the server without the need to supply a username and password. The client certificate is optional and not used by standard web browsers when accessing web sites secured by HTTPS/TLS (although a web browser can use a client cert if it is configured to do so). Client certs are not used in this example and are not discussed further here.
For the following steps in which certificates are generated, it is assumed you have OpenSSL installed on your computer and OpenSSL is in the PATH environment variable i.e. you can execute OpenSSL directly from a command line. OpenSSL may be downloaded here: https://www.openssl.org/community/binaries.html or on Ubuntu, run the command:
~$ sudo apt-get install openssl
The manual for OpenSSL may be found here: https://www.openssl.org/docs
In some instances, it may be necessary to set the
RANDFILE environment variable to avoid OpenSSL errors such as ''unable to write 'random state'''.
To temporarily set the
RANDFILE environment variable to a local file, use the following command:
Generating a Self-Signed CA Certificate
The first certificate to generate is a self-signed Certificate Authority (CA) certificate. This is the root certificate from which all other certificates are derived.
We start by generating the CA cert key. This is the most sensitive file in your secure TLS system. This should be placed in a secure location.
~$ openssl genrsa -aes256 -out my_ca.key 4096
After executing this command OpenSSL prompts for a password. This is used to secure this CA key. This is the same password used for the rest of the process.
Next we create the self-signed CA cert:
~$ openssl req -new -sha1 -x509 -key my_ca.key -out my_ca.crt
OpenSSL prompts for various values. Press enter to accept a default value. At the 'Common Name' prompt, you can enter any name, for example 'my_cert'.
First convert to an intermediate
~$ openssl x509 -in my_ca.crt -out my_ca.der -outform DER
Now convert the
~$ openssl x509 -in my_ca.der -inform DER -out my_ca.pem -outform PEM
~$ Delete the temporary
> rm my_ca.der
For a Windows platform, use
del instead of
You have now generated the self-signed CA certificate in the required
Generating a Server Certificate
Now that we have a CA certificate, we need to generate a server certificate. This is what our python server will use.
To generate the server certificate, you need to obtain the IP address of your computer on the local network. This is the IP address the module will use to connect to the python server (running on your computer).
For this example, we will assume the local IP address is:
NOTE: At every point where this address appears in the procedure below, you should substitute the IP address of the computer used to run the python TLS server script.
First generate the private key for our server certificate:
~$ openssl genrsa -aes256 -out 192.168.1.228.key 1024
OpenSSL prompts for another password. This can be the same as the CA cert's or different.
Next we need to create a Certificate Signing Request (CSR).
~$ openssl req -new -sha1 -key 192.168.1.228.key -out 192.168.1.228.csr
OpenSSL prompts for various values. Press enter to accept default values until reaching the 'Common Name' prompt, then ...
... AT THE PROMPT 'Common Name': enter the IP address of the computer! <- This is very important.
Afterwards, when OpenSSL asks for a 'Challenge password', do NOT enter anything, just press
Now, remove the passphrase on the server key to avoid the need for manual entry of a passphrase when the server starts:
~$ cp 192.168.1.228.key 192.168.1.228.key.tmp ~$ openssl rsa -in 192.168.1.228.key.tmp -out 192.168.1.228.key ~$ rm 192.168.1.228.key.tmp
For a Windows platform, you may need to use
copy instead of
del instead of
Next we generate the server certificate:
~$ openssl x509 -req -in 192.168.1.228.csr -CA my_ca.crt -CAkey my_ca.key -out 192.168.1.228.crt -set_serial 01
We now have everything needed to connect the ZentriOS device to the python server.
Starting the Python TLS Server
To start the server, run the echo_tls_server.py script, supplying the server IP address as an argument:
~$ python echo_tls_server.py 192.168.1.228
- The server IP address supplied must be the same IP address used when generating the server certificate.
- The server certificate, and the server certificate key (in this example
192.168.1.228.key) must be in the same directory as the
Loading the CA cert onto the Module (using ZentriOS)
Next we'll load the CA cert onto the ZentriOS device. Open
my_ca.pem in a text editor such as Notepad++ and determine the size of the file (number of characters, including whitespace and carriage returns).
Issue the following ZentriOS command:
> file_create my_ca.pem <file size>
Then copy and paste the contents of
my_ca.pem into the serial terminal. This will write the CA certificate to the flash file system on the module.
It is critical that the line endings of the file are correct. The .pem format expects a single
\n (0x0A) line terminator, and a single
\n character at the very end of the file.
Connecting to the Python TLS Server
We're now ready to connect the ZentriOS device to the python TLS echo server. Assuming ZentriOS already has valid credentials for the local Wi-Fi network, issue the following command (don't forget to specify the port number
3000 and to append
> tls_client 192.168.1.228 3000 my_ca.pem
If everything is working, ZentriOS responds with text similar to:
Resolving host: 192.168.1.228 [2014-11-03 | 05:58:34: Opening: 192.168.1.228:3000] Connecting (TLS): 192.168.1.228:3000 [2014-11-03 | 05:58:34: Opened: 0] 0
Issue the ZentriOS command (to write to the python server):
> write 0 15 Hello World!!!
You should see
Hello World!!! in the python server terminal on the PC.
Issue the ZentriOS command:
> read 0 1000
Hello World!!! should be returned.
The TLS server is created with a Python script:
The following example BASH scripts are provided to help automate the OpenSSL parts of the process described above if required.
Notes for Windows & Additional Links
To run this example on Windows, the following software packages are needed:
- MingGW - Minimum GNU for Windows (aka Linux tools for Windows). After install, don't forget to add MinGW & msys to your path. Here's an example of where these directories are located after installation in the default location:
- OpenSSL - executable installer for Windows
- Python - for Windows and other operating systems (be sure to install Python 2.7)