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.