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.
Exercise steps
In the GitHub repository for this course, go to the base code for this exercise, found in l5/l5_e2.
1. Include and configure TLS relevant configurations.
1.1 Enable and configure the TLS credentials module.
Add the following lines to the prj.conf file
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_NRF_SECURITY=yKconfigCONFIG_NET_SOCKETS_SOCKOPT_TLS– Enables the TLS socket option supportCONFIG_NRF_SECURITY– Enable the nRF Security subsystem, which provides an integration to Mbed TLS
1.2 Enable TLS credentials library and set backend.
CONFIG_TLS_CREDENTIALS=y
CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE=yKconfigCONFIG_TLS_CREDENTIALS– Enables the TLS credentials management subsystemCONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE– Set the TLS credentials management backend to use the Protected Storage API to store the credentials
1.3 Enable Mbed TLS relevant configurations
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_RSA_C=y
CONFIG_MBEDTLS_DHM_C=y
CONFIG_MBEDTLS_TLS_LIBRARY=y
CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=yKconfigCONFIG_MBEDTLS– Enables Mbed TLSCONFIG_MBEDTLS_ENABLE_HEAP– Enables Mbed TLS to use the heapCONFIG_MBEDTLS_RSA_C– Enables support for RSA cryptosystem in Mbed TLSCONFIG_MBEDTLS_DHM_C– Enables the DHM module in Mbed TLSCONFIG_MBEDTLS_TLS_LIBRARY– Creates the Mbed TLS libraryCONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION– Enables support for server name indication
1.4 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=101920Kconfig1.5 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, in certificate/AmazonRootCA1.pem.
2.2 Convert the certificate from PEM to HEX file.
For the TLS credentials library to be able to read the certificate, we need to convert it into a HEX file. This will be done using the following CMake function generate_inc_file_for_target(), which has the following signature
function(generate_inc_file_for_target
target # The cmake target that depends on the generated file
source_file # The source file to be converted to hex
generated_file # The generated file
# Any additional arguments are passed on to file2hex.py
)CMakeWe 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.
Add the following code snippet in CMakeLists.txt
set(gen_dir ${CMAKE_CURRENT_BINARY_DIR}/certs)
zephyr_include_directories(${gen_dir})
generate_inc_file_for_target(
app
certificate/AmazonRootCA1.pem
${gen_dir}/AmazonRootCA1.pem.inc
)CMakeThis will create a directory certs in the build folder (build/l5_e2/certs) with the file AmazonRootCA1.pem.inc, which is our server certificate in hex format.
2.3 Include the certificate file in the application.
Include the generated server certificate file as char ca_certificate[].
Open main.c and add the following lines
static const char ca_certificate[] = {
#include "AmazonRootCA1.pem.inc"
IF_ENABLED(CONFIG_TLS_CREDENTIALS, (0x00))
};CNotice that we null terminate the certificate, which is required by the TLS credentials library.
3. Change the default port if TLS is enabled.
Change the default port for HTTP_SAMPLE_PORT to the standard HTTP over TLS port, which is 443, when TLS_CREDENTIALS is enabled.
In the Kconfig file, replace the definition of HTTP_SAMPLE_PORT with the following code snippet
config HTTP_SAMPLE_PORT
string "HTTP server port"
default "443" if TLS_CREDENTIALS
default "80"Kconfig4. Store the credentials in the device.
4.1 Define a macro for the credentials security tag.
Define the security tag used when storing the credentials on the device.
#define HTTP_TLS_SEC_TAG 42C4.2 Provision the credential to the device.
In the function setup_credentials(), add the TLS credential using tls_credential_add() from the TLS credentials library, which has the following signature

The security type has the following options, defined in enum tls_credential_type

We want to pass the security tag (HTTP_TLS_SEC_TAG), the type of certificate (TLS_CREDENTIAL_CA_CERTIFICATE) and the certificate, defined in ca_certificate.
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 == -EEXIST){
LOG_ERR("Certificate already exists, sec tag: %d", HTTP_TLS_SEC_TAG);
} else if (err < 0) {
LOG_ERR("Failed to provision server certificate: %d", 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, CONFIG_HTTP_SAMPLE_HOSTNAME, sizeof(CONFIG_HTTP_SAMPLE_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 ***
[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:07.789,367] <inf> Lesson5_Exercise2: Provisioning server certificate
[00:00:08.328,338] <inf> Lesson5_Exercise2: Connecting to rest.nordicsemi.academy:443
[00:00:08.578,302] <inf> Lesson5_Exercise2: Connected to server
[00:00:08.578,302] <inf> Lesson5_Exercise2: HTTP POST request
[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>
[00:01:37.411,712] <inf> Lesson5_Exercise2: Closing socket: 14TerminalTesting
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.

- Select the request method, in this case
GET. - Input the request-target, which is the hostname
rest.nordicsemi.academyfollowed by your specific client ID. - Click send to send the HTTP request to the server.
10. Observe the response from the server, which should be 0, in the window on the right.

Clicking on the arrow left of “HTTP/1.1 200 OK (11 headers)” will display more information about the HTTP packet.

11. Increment the counter.
Press button 1 on your nRF70 Series board several times to increment the counter that is sent to the server..
12. Repeat steps 9 and 10.
Repeat step 9 again, and in step 10 observe that the numbered response from the server has increased corresponding to the number of times you pushed the button.