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 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=y
KconfigCONFIG_NET_SOCKETS_SOCKOPT_TLS
– Enables the TLS socket option supportCONFIG_NRF_SECURITY
– Enable the nRF Security subsystem, which provides an integration to Mbed TLS1.2 Enable TLS credentials library and set backend.
CONFIG_TLS_CREDENTIALS=y
CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE=y
KconfigCONFIG_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 credentials1.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=y
KconfigCONFIG_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 indication1.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=101920
Kconfig1.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 42
C4.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 2.9.0-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: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: 14
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
.rest.nordicsemi.academy
followed by your specific client ID.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.
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 l5/l5_e2
.
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.7.0-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.
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 l5/l5_e2
.
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.0-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.