SETTING UP CERTIFICATES FOR A TIBBO DEVICE ACTING AS A TLS CLIENT
Applies to: Tibbo G3 devices (e.g. TPP2W(G3))
Sample project: SSL_MULTI_CLIENT [LINK: SSL_MULTI_CLIENT download]
OVERVIEW
When the Tibbo device is the TLS client, it connects to a server and checks the certificate the server presents. To do that, the device needs one file: the certificate of whoever issued (signed) the server's certificate, called the CA certificate. The device does not need a private key or a certificate of its own.
When the server uses a self-signed certificate, as in this article, the server's certificate signs itself, so the CA certificate is the server's own certificate. It is converted to DER, named ca_cert.der, added to the project and loaded with sock.tlsinit() before each handshake.
The SSL_MULTI_CLIENT sample opens six TLS connections to one server, one at a time, when you press the MD button, and closes them all when you press it again. This article shows how to create the server's certificate with OpenSSL, run a test server on a PC, prepare ca_cert.der for the device and run the sample.
For a server with a certificate from a public certificate authority, see the HTTPS_GET article [LINK: TLS_HTTPS_GET]; the device side is the same, only the source of ca_cert.der differs.
The steps are given for both ECDSA P-256 and RSA 2048 keys; we suggest using ECDSA P-256 for higher security and connection speed versus RSA 2048.
- ECDSA P-256 : Smaller and faster. The socket buffers in the sample (6 pages RX and TX) are sized for this key type.
- RSA 2048 : Widest compatibility. Needs larger buffers: set TLS_RX_BUFF and TLS_TX_BUFF to 8 pages.
WHAT YOU NEED
- OpenSSL 3.x on your PC.
- TIDE with the SSL_MULTI_CLIENT sample project.
- Python 3 on the PC, for the test server.
- The PC's IP address. The examples use 192.168.1.70 for the PC and 192.168.1.218 for the device; replace them with your own addresses.
All commands below are written on a single line so they work the same in Command Prompt, PowerShell and Git Bash.
IMPORTANT: THE CERTIFICATE IS TIED TO THE SERVER'S IP ADDRESS
During the handshake the device passes SERVER_IP to sock.tlshandshake(). The server's certificate must list that exact address in its Subject Alternative Name (SAN). If the server's IP address changes, create a new certificate and a new ca_cert.der.
PART 1 - CREATE THE SERVER CERTIFICATE
The examples use a PC at 192.168.1.70. Replace it everywhere with the address of your server.
Option A: ECDSA P-256
Step 1. Create a configuration file named server_ec.cnf with this content:
[req]
prompt = no
distinguished_name = dn
x509_extensions = v3_req
[dn]
CN = 192.168.1.70
[v3_req]
basicConstraints = critical,CA:TRUE
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.70
Step 2. Generate the private key:
openssl ecparam -name prime256v1 -genkey -noout -out server_ec.key
Step 3. Create the self-signed certificate, valid for 10 years:
openssl req -new -x509 -key server_ec.key -out server_ec.crt -days 3650 -config server_ec.cnf
Option B: RSA 2048
Step 1. Create a configuration file named server_rsa.cnf with this content:
[req]
default_bits = 2048
prompt = no
distinguished_name = dn
x509_extensions = v3_req
[dn]
CN = 192.168.1.70
[v3_req]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.70
Step 2. Generate the private key:
openssl genrsa -out server_rsa.key 2048
Step 3. Create the self-signed certificate, valid for 10 years:
openssl req -new -x509 -key server_rsa.key -out server_rsa.crt -days 3650 -config server_rsa.cnf
Check the certificate and confirm the SAN contains the server's address (use server_rsa.crt for RSA):
openssl x509 -in server_ec.crt -noout -ext subjectAltNameExpected output:
X509v3 Subject Alternative Name: IP Address:192.168.1.70The .crt and .key files are used by the server on the PC. The .key file is secret and stays on the PC; it never goes to the Tibbo device.
PART 2 - CREATE ca_cert.der FOR THE DEVICE
For a self-signed certificate, the server's certificate is also the CA certificate the device needs. Convert it to DER (use server_rsa.crt for RSA):
openssl x509 -in server_ec.crt -outform DER -out ca_cert.derCheck the file:
openssl x509 -inform DER -in ca_cert.der -noout -subject -ext subjectAltName
PART 3 - RUN THE TEST SERVER
Save the following as tls_echo_server.py in the same folder as the certificate and key. It accepts any number of clients, sends each one a welcome line and echoes back what it receives.
# Minimal TLS echo server for testing the device as a TLS client.
# Edit the settings below, or pass them on the command line:
# python tls_echo_server.py [certificate.crt] [private.key] [port]
import os, socket, ssl, sys, threading
CERT = "server_ec.crt" # server certificate (server_rsa.crt for RSA)
KEY = "server_ec.key" # matching private key (server_rsa.key for RSA)
PORT = 8444 # SERVER_PORT in SSL_MULTI_CLIENT
args = sys.argv[1:]
if len(args) > 0: CERT = args[0]
if len(args) > 1: KEY = args[1]
if len(args) > 2: PORT = int(args[2])
# Certificate paths are relative to this script's folder, wherever it is run from
HERE = os.path.dirname(os.path.abspath(__file__))
CERT = os.path.join(HERE, CERT)
KEY = os.path.join(HERE, KEY)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.minimum_version = ssl.TLSVersion.TLSv1_3
ctx.load_cert_chain(CERT, KEY)
def handle(conn, addr):
print(f"{addr[0]}:{addr[1]} connected ({conn.version()}, {conn.cipher()[0]})")
conn.sendall(b"Hello from the test server\r\n")
try:
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(b"ECHO: " + data)
except OSError:
pass
conn.close()
print(f"{addr[0]}:{addr[1]} disconnected")
listener = socket.create_server(("0.0.0.0", PORT))
print(f"TLS echo server listening on port {PORT}")
while True:
sock, addr = listener.accept()
try:
conn = ctx.wrap_socket(sock, server_side=True)
except (ssl.SSLError, OSError) as e:
print(f"{addr[0]}: handshake failed: {e}")
sock.close()
continue
threading.Thread(target=handle, args=(conn, addr), daemon=True).start()
Set CERT, KEY and PORT at the top of the script and run it:
python tls_echo_server.py
or give the values on the command line instead:
python tls_echo_server.py server_ec.crt server_ec.key 8444
Allow the port through Windows Firewall when prompted. You can check the server from the PC before involving the device:
openssl s_client -connect 192.168.1.70:8444 -CAfile server_ec.crt -verify_ip 192.168.1.70"Verify return code: 0 (ok)" and the welcome line mean the server and its certificate are ready.
PART 4 - CONFIGURE THE SSL_MULTI_CLIENT PROJECT
Step 1. Copy ca_cert.der into the SSL_MULTI_CLIENT project folder, replacing the existing file.
Step 2. In TIDE, make sure ca_cert.der is part of the project (add it as an existing file if it is not listed). The file name must match the CA_CERT define in global.tbh:
#define CA_CERT "ca_cert.der"
Step 3. Check the other settings in global.tbh:
const DEVICE_IP = "192.168.1.218" the device's own address
const DEVICE_MASK = "255.255.255.0"
const DEVICE_GW = "192.168.1.1"
const NUM_TLS_SOCKS = 6 number of client sockets
const SERVER_IP = "192.168.1.70" must match the IP in the certificate
const SERVER_PORT = 8444
const CONNECT_INTERVAL_TICKS = 1 delay between connections, 1 = 500 ms
#define TLS_RX_BUFF 6 use 8 for RSA 2048
#define TLS_TX_BUFF 6 use 8 for RSA 2048Keep NUM_TLS_SOCKS at 6 or below. The TLS engine can hold about seven sessions at once.
Step 4. Build the project and upload it to the device.
How the sample uses ca_cert.der: when a connection to the server is established (PL_SST_EST_AOPENED), the socket opens the file and starts the handshake:
romfile.open(CA_CERT)
tls_res = sock.tlsinit(romfile.offset)
tls_res = sock.tlshandshake(SERVER_IP)Passing the server's address to tlshandshake() makes the socket act as the TLS client and check that address against the certificate.
PART 5 - RUN THE TEST
Press the MD button. The device opens the sockets one at a time, one every 500 ms, and prints each step:
MD: connecting 6 sockets to 192.168.1.70:8444, one every 500 ms
sock[0] connecting...
sock[0] TCP connected to 192.168.1.70:8444
sock[0] TLS handshake started...
sock[0] TLS established. active: 1/6
...
sock[5] TLS established. active: 6/6Anything the server sends appears as "sock[n] RX[len]: ...", starting with the test server's welcome line. Press MD again to close all sockets; the active count falls back to 0/6.
The connections are started one at a time on purpose. The TLS handshake takes a noticeable amount of processing time, and starting them all at once can cause some to time out.
TROUBLESHOOTING
"Connection refused", or no connection at all
Check that the test server is running, that SERVER_PORT matches its port, and that Windows Firewall allows the port.
"tlsinit FAILED" in the device's debug output
ca_cert.der could not be loaded. Check that it is in the project, that its name matches CA_CERT, and that it is in DER format (see Part 2 for how to check).
"TLS handshake FAILED - resetting"
ca_cert.der must be made from the exact certificate the server uses, and SERVER_IP must appear in that certificate's SAN. For RSA 2048, use 8-page buffers. The server must support TLS 1.3.
Only some sockets connect
Increase CONNECT_INTERVAL_TICKS to give each handshake more time, and keep NUM_TLS_SOCKS at 6 or below.
Comments
0 comments
Article is closed for comments.