Issue with provisioning device to communicate via TCP over TLS.

Dear All,

I am developing an application based on the nRF7002DK. I am using nRFConnect SDK v3.1.1.

I am producing my own CA, server and client keys to be used for TLS, with the following commands:

#1. Generate an RSA key for a server:
openssl genrsa -out Server/server_rsa.key 2048

#2. Generate a CSR for a server:
penssl req -new -key Server/server_rsa.key -out Server/server.csr

#3. Generate an RSA key for CA:
openssl genrsa -out CA/ca_rsa.key 2048

#4. Generate a self signed certificate for the CA:
openssl req -new -days 1800 -x509 -key CA/ca_rsa.key -out CA/ca.crt

#5. Sign server certificate:

openssl x509 -req -days 1800 -in Server/server.csr -CA CA/ca.crt -CAkey CA/ca_rsa.key -CAcreateserial -out Server/server.crt -extfile Server/server.v3.ext

#6. Generate an RSA key for a client:

openssl genrsa -out Client/client_rsa.key 2048

#7. Generate a CSR for a client:

openssl req -new -key Client/client_rsa.key -out Client/client.csr

#8. Sign client certificate:

openssl x509 -req -days 1800 -in Client/client.csr -CA CA/ca.crt -CAkey CA/ca_rsa.key -CAserial CA/ca.srl -out Client/client.crt -extfile Client/client.cnf



With these steps I am creating a CA certificate which I am using to sign both the client and the server certificates created with their respective keys.

What I end up with are the following PEM files:

CA/ca.crt

Client/client.crt

Client/client_rsa.key

Server/server.crt

Server/server_rsa.key

I start my server on my Linux machine like this:
openssl s_server -cert Server/server.crt -key Server/server_rsa.key -Verify 1 -CAfile CA/ca.crt -accept 51820

To test that this is working I start also a client on another terminal like this:

openssl s_client -connect localhost:51820 -cert Client/client.crt -key Client/client_rsa.key -CAfile CA/ca.crt.

So far this is working.

The next steps on the nRF7002DK project are:

add the ca.crt, client.crt, client_rsa.key in the cert folder in my root directory



Next I am trying to provision the keys to the nRF7002DK like this:

CMakeLists.txt

...

# Generate hex files from pem files
set(gen_dir ${CMAKE_CURRENT_BINARY_DIR}/certs)
zephyr_include_directories(${gen_dir})
generate_inc_file_for_target(app cert/client_rsa.key ${gen_dir}/client_rsa.key.inc)
generate_inc_file_for_target(app cert/client.crt ${gen_dir}/client.crt.inc)
generate_inc_file_for_target(app cert/ca.crt ${gen_dir}/ca.crt.inc)

...


prj.conf

#
# Copyright (c) 2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
CONFIG_WIFI=y
CONFIG_WIFI_NRF70=y

# WPA supplicant
CONFIG_WIFI_READY_LIB=y

# Networking
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y
CONFIG_POSIX_API=y
CONFIG_NET_LOG=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_DHCPV4=y

CONFIG_NET_PKT_RX_COUNT=16
CONFIG_NET_PKT_TX_COUNT=16
CONFIG_NRF70_RX_NUM_BUFS=16

# Below section is the primary contributor to SRAM and is currently
# tuned for performance, but this will be revisited in the future.
CONFIG_NET_BUF_RX_COUNT=16
CONFIG_NET_BUF_TX_COUNT=32
CONFIG_HEAP_MEM_POOL_SIZE=37000
CONFIG_HEAP_MEM_POOL_IGNORE_MIN=y
CONFIG_NRF_WIFI_CTRL_HEAP_SIZE=20000
CONFIG_NRF_WIFI_DATA_HEAP_SIZE=40000
CONFIG_NET_TC_TX_COUNT=1

CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1
CONFIG_NET_MAX_CONTEXTS=5
CONFIG_NET_CONTEXT_SYNC_RECV=y

CONFIG_INIT_STACKS=y

CONFIG_NET_L2_ETHERNET=y

CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_INIT_TIMEOUT=0

CONFIG_NET_SOCKETS_POLL_MAX=10

# Memories
CONFIG_MAIN_STACK_SIZE=5200
CONFIG_NET_TX_STACK_SIZE=4096
CONFIG_NET_RX_STACK_SIZE=4096

# Kernel options
# CONFIG_ENTROPY_GENERATOR=y

# Logging
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=2048


# printing of scan results puts pressure on queues in new locking
# design in net_mgmt. So, use a higher timeout for a crowded
# environment.
CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=5000

# CONFIG_MODEM_KEY_MGMT=y

# TLS networking
CONFIG_NET_SOCKETS_ENABLE_DTLS=n
CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=2
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y

# TLS credentials
CONFIG_TLS_CREDENTIALS=y
CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGE=y

# mbedTLS
CONFIG_NRF_SECURITY=y
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_BUILTIN=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=81920
CONFIG_MBEDTLS_RSA_C=y
CONFIG_MBEDTLS_DHM_C=y
CONFIG_MBEDTLS_TLS_LIBRARY=y
CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=y
CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y

# Optimize T-FM
CONFIG_TFM_PROFILE_TYPE_SMALL=y
CONFIG_PM_PARTITION_SIZE_TFM_SRAM=0xc000
CONFIG_PM_PARTITION_SIZE_TFM=0x20000

CONFIG_MBEDTLS_MPI_MAX_SIZE=512


main.c
...

#define TLS_CA_TAG		1
#define TLS_CERT_TAG    2

static void cert_provision(void)
{
	int err;

	LOG_INF("Provisioning certificate\r\n");

	err = tls_credential_delete(TLS_CERT_TAG, TLS_CREDENTIAL_SERVER_CERTIFICATE);
	LOG_INF("Credential delete 1 err: %d\r\n", err);
	err = tls_credential_add(TLS_CERT_TAG,
				 TLS_CREDENTIAL_SERVER_CERTIFICATE,
				 cert,
				 sizeof(cert));
	if (err == -EEXIST) {
		LOG_INF("Server certificate already exists, sec tag: %d\n", TLS_CERT_TAG);
	} else if (err < 0) {
		LOG_ERR("Failed to register Server certificate: %d\n", err);
		return err;
	}

	err = tls_credential_delete(TLS_CERT_TAG, TLS_CREDENTIAL_PRIVATE_KEY);
	LOG_INF("Credential delete 2 err: %d\r\n", err);
	err = tls_credential_add(TLS_CERT_TAG,
				 TLS_CREDENTIAL_PRIVATE_KEY,
				 key,
				 sizeof(key));
	if (err == -EEXIST) {
		LOG_INF("Server private key already exists, sec tag: %d\n", TLS_CERT_TAG);
	} else if (err < 0) {
		LOG_ERR("Failed to register Server private key: %d\n", err);
		return err;
	}

	err = tls_credential_delete(TLS_CA_TAG, TLS_CREDENTIAL_CA_CERTIFICATE);
	LOG_INF("Credential delete 3 err: %d\r\n", err);
	err = tls_credential_add(TLS_CA_TAG,
				 TLS_CREDENTIAL_CA_CERTIFICATE,
				 ca_root,
				 sizeof(ca_root));
	if (err == -EEXIST) {
		LOG_INF("CA already exists, sec tag: %d\n", TLS_CA_TAG);
	} else if (err < 0) {
		LOG_ERR("Failed to register CA: %d\n", err);
		return err;
	}
}

...

static int tls_setup(int fd)
{
	int err;
	int verify;

	/* Security tag that we have provisioned the certificate with */
	const sec_tag_t tls_sec_tag[] = {
		TLS_CA_TAG,
		TLS_CERT_TAG,
	};

	/* Set up TLS peer verification */
	enum {
		NONE = 0,
		OPTIONAL = 1,
		REQUIRED = 2,
	};

	verify = NONE; //REQUIRED;

	err = setsockopt(fd, SOL_TLS, TLS_HOSTNAME,
			TCP_SERVER_ADDRESS,
			sizeof(TCP_SERVER_ADDRESS) - 1);
	if (err) {
		printk("Failed to setup TLS hostname, err %d\n", errno);
		return err;
	}

	/* Associate the socket with the security tag
	 * we have provisioned the certificate with.
	 */
	err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag, sizeof(tls_sec_tag));
	if (err) {
		printk("Failed to setup TLS sec tag, err %d\n", errno);
		return err;
	}

	err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify));
	if (err) {
		printk("Failed to setup peer verification, err %d\n", errno);
		return err;
	}
}

...

static bool tcp_connect(void) {
	bool res = false;
	struct sockaddr_in serverAddress = {0};
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_port = htons(TCP_SERVER_PORT);
	inet_pton(AF_INET, TCP_SERVER_ADDRESS, &serverAddress.sin_addr);

	tcpClientSocket = socket(serverAddress.sin_family, SOCK_STREAM, IPPROTO_TLS_1_2);
	tls_setup(tcpClientSocket);
	if (tcpClientSocket < 0)	{
		LOG_ERR( "TCP Client error: socket: %d\n", errno );
	} else {
		int connectionResult = connect(tcpClientSocket,	( struct sockaddr * )&serverAddress, sizeof( serverAddress ));
		if ( connectionResult < 0 )	{
			LOG_ERR( "TCP Client error: connect: %d\n", errno );
		} else {
			LOG_INF( "TCP Client connected correctly" );
			res = true;
		}
	}
	return res;
}

...

int main(void)
{
    ... // Wait for nRF7002 to become available
	cert_provision();
	... // Wait for modem to connect to my AP
	tcp_connect(); // Attempt to connect to TCP server over TLS
	...
}
	


In the tls_setup, I am assigning the verify variable to be NONE or REQUIRED.

In the NONE scenario, I am able to connect to my server and receive and send messages. I can see the client certificate landing on the server and the communication starts
In the REQUIRED scenario I am getting this on my device:

<err> net_sock_tls: TLS handshake error: -0x2700


on my server I see this:

40A7441E7A720000:error:0A000412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../ssl/record/rec_layer_s3.c:1599:SSL alert number 42
shutting down SSL
CONNECTION CLOSED


I am under the impression that I need to have the verify variable equal to REQUIRED in order to make sure that I am talking to proper server, which is checked by the ca.crt (right?)

Is there something that I am missing regarding the provisioning and using the certificates?

Thank you in advance.

  • After some deeper investigation inside the MBEDTLS stack I found out that the handshake was failing at the point where it was checking the name of the server that I was passing in the 

    err = setsockopt(fd, SOL_TLS, TLS_HOSTNAME, TCP_SERVER_NAME, sizeof(TCP_SERVER_NAME) - 1);

    Since I was testing on a server running locally, the name of the server had the format 192.168.X.X, but the certificate that I was using to verify the server had another name on it. So the authentication was failing at that point.

    Thank you very much for the assistance  

Related