In this exercise, we will alter the code from the previous exercise to add security to our HTTP connection. We will learn how to achieve this by using certificates, to verify the authenticity of the server, and also by establishing TLS-secured communication between the device and the server.
In the GitHub repository for this course, go to the base code for this exercise, found in lesson5/wififund_less5_exer2
.
1. Include and configure the TLS credentials module.
1.1 Enable and configure the TLS credentials module.
This is similar to what we did in the previous lesson, with the addition being CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION
, which we add in step 1.2. This Kconfig symbol is needed for adding support for the Server Name Indication extension. SNI is an extension to the TLS protocol which facilitates server verification using certificates.
Add the following lines to the prj.conf
file
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_TLS_CREDENTIALS=y
CONFIG_MBEDTLS_RSA_C=y
CONFIG_MBEDTLS_DHM_C=y
Kconfig1.2 Enable support for server name indication (SNI).
Enable support for SNI in the mbedTLS cryptography library through the Kconfig CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION
.
CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=y
Kconfig1.3 Increase the size allocated to the mbedTLS heap, if building with TF-M.
Open boards/nrf7002dk_nrf5340_cpuapp_ns.conf
or boards/nrf5340dk_nrf5340_cpuapp_ns.conf
, depending on the board you are using, and increase the mbedTLS heap size by changing the following Kconfig line
CONFIG_MBEDTLS_HEAP_SIZE=81920
Kconfig1.4 Include the header file for the TLS credentials library.
#include <zephyr/net/tls_credentials.h>
C2. Add the necessary certificate to the application.
2.1 To verify the authenticity of the HTTP server, we will use the Amazon Root CA 1 certificate, which you will find in the base code for this exercise, saved as ca_certificate.pem
.
2.2 Convert the certificate into a header file in C.
We will use a Python script (can be found in the scripts subdirectory in this exercise’s code base directory) that converts a certificate into a header file certificate.h
that will contain the converted certificate as a C string.
Open a new terminal, navigate to the script folder (lesson5/wififund_less5_exer2/script
), and then run the Python script cert_to_header.py
with the name of the certificate you want to convert as an argument.
python.exe .\cert_to_header.py ca_certificate.pem
This will generate the converted certificate.h
in the /src
subdirectory
2.3 Include the certificate file in the application.
static const char ca_certificate[] = {
#include "certificate.h"
};
C3. Change the HTTP port number.
Change the HTTP port we are using, by changing the value to 443, which is the standard TLS port for HTTP.
#define HTTP_PORT 443
C4. Store the credential in the device.
4.1 Define a macro for the security tag used to store the certificate.
#define HTTP_TLS_SEC_TAG 1
C4.2 Define a function to add the credentials.
In the function setup_credentials()
, add the TLS credential by calling tls_credential_add()
.
Add the following code snippet in main.c
int err = tls_credential_add(HTTP_TLS_SEC_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, ca_certificate, sizeof(ca_certificate));
if (err < 0) {
LOG_ERR("Failed to add TLS credentials, err: %d", err);
return err;
}
C5. Set the TLS relevant socket options for the socket
Before connecting to the HTTP server, we need to set the TLS relevant socket options using setsockopt(),
which has the following signature
We need to set the security tag of the stored certificate and the hostname of the HTTP server.
5.1 Configure the socket with the security tag for the certificate.
Set the option TLS_SEC_TAG_LIST
to the security tag for the certificate, stored in HTTP_TLS_SEC_TAG
.
This is the security tag that the credentials will be referenced with, and must be attached to the socket before connecting.
sec_tag_t sec_tag_opt[] = {
HTTP_TLS_SEC_TAG,
};
err = setsockopt(sock, SOL_TLS, TLS_SEC_TAG_LIST, sec_tag_opt, sizeof(sec_tag_opt));
if (err) {
LOG_ERR("Failed to set TLS security TAG list, err: %d", errno);
(void)close(sock);
return -errno;
}
C5.2 Configure the socket with the hostname of the HTTP server.
Set the option TLS_HOSTNAME
to be the hostname for the HTTP server.
err = setsockopt(sock, SOL_TLS, TLS_HOSTNAME, HTTP_HOSTNAME, sizeof(HTTP_HOSTNAME));
if (err) {
LOG_ERR("Failed to set TLS_HOSTNAME option, err: %d", errno);
(void)close(sock);
return -errno;
}
C6. Build and flash the application to your board.
This exercise uses the PSA backend for storing the Wi-Fi credentials. Therefore, you must build with TF-M.
Board | Build with TF-M | Extra CMake arguments |
---|---|---|
nRF7002 DK | nrf7002dk_nrf5340_cpuapp_ns | N/A |
nRF5340 DK + nRF7002 EK | nrf5340dk_nrf5340_cpuapp_ns | -DSHIELD=nrf7002ek |
If necessary, input the commands to connect to Wi-Fi, as we have done in previous exercises.
On a successful connection, you should see the following log output.
*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
[00:00:01.476,898] <inf> Lesson5_Exercise2: Waiting to connect to Wi-Fi
[00:00:07.511,627] <inf> Lesson5_Exercise2: Network connected
[00:00:07.558,746] <inf> Lesson5_Exercise2: IPv4 address of HTTP server found 54.230.111.103
[00:00:08.277,709] <inf> Lesson5_Exercise2: Successfully connected to server
[00:00:08.849,731] <inf> Lesson5_Exercise2: Response status: Created
[00:00:08.849,792] <inf> Lesson5_Exercise2: Successfully acquired client ID: <your client ID>
TerminalTesting
7. Set up an HTTP client.
To test the application, we need to setup an HTTP client to remotely read the counter value that was sent to the HTTP server. You will need an HTTP client running on your PC, smartphone, or tablet. In this exercise, we will use HTTPie’s web app, an in-browser HTTP client that does not require any installation or setup.
8. Copy the client ID from your device’s log output.
Copy the unique client ID that your device retrieves when first connecting to the HTTP server, it is marked in the log above as <your_client_ID>
. You will need your device’s specific client ID to be able to retrieve the value that your device has posted to the server.
9. Open a web browser and go to httpie.io/app.
GET
.echo.thingy.rocks
followed by your specific client ID. 10. Observe the response from the server, number “4” for example, at the bottom of this window.