eclipse-threadx / netxduo

Eclipse ThreadX - NetXDuo is an advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/netx-duo/index.md
MIT License
247 stars 136 forks source link

MQTT with TLS1.3 on STMH563ZI nucleo board #271

Open Sahil-Kurkure opened 6 months ago

Sahil-Kurkure commented 6 months ago

Hello, I am facing an issue with MQTTs (TLS 1.3) implementation. I am using the STMH563ZI board (with TheadX as RTOS) and using the serverless emqx broker for testing. When I try to connect to the broker over TLS 1.3, I receive an fatal alert with alertcode 10 which is "unexpected_message". Following is my TLS setup :

/* Initialize TLS module */
_nx_secure_tls_initialize();

/* Create a TLS session */
ret = _nx_secure_tls_session_create(TLS_session_ptr, &nx_crypto_tls_ciphers_ecc,
                                crypto_metadata_client, sizeof(crypto_metadata_client));
if (ret != TX_SUCCESS)
{
    Error_Handler();
}

ret = _nx_secure_tls_ecc_initialize(TLS_session_ptr,
        nx_crypto_ecc_supported_groups,
        nx_crypto_ecc_supported_groups_size,
        nx_crypto_ecc_curves);
if (ret != TX_SUCCESS)
{
    Error_Handler();
}

/* Need to allocate space for the certificate coming in from the broker. */
memset((certificate_ptr), 0, sizeof(NX_SECURE_X509_CERT));

ret = _nx_secure_tls_session_time_function_set(TLS_session_ptr, nx_secure_mqtt_tls_session_time_function);

if (ret != TX_SUCCESS)
{
    Error_Handler();
}

/* Allocate space for packet reassembly. */
ret = _nx_secure_tls_session_packet_buffer_set(TLS_session_ptr, mqtts_tls_packet_buffer,
                                           sizeof(mqtts_tls_packet_buffer));
if (ret != TX_SUCCESS)
{
    Error_Handler();
}
/* allocate space for the certificate coming in from the remote host */
ret = _nx_secure_tls_remote_certificate_allocate(TLS_session_ptr, certificate_ptr,
        mqtts_tls_packet_buffer, sizeof(mqtts_tls_packet_buffer));
if (ret != TX_SUCCESS)
{
    Error_Handler();
}

/* initialize Certificate to verify incoming server certificates. */
ret = _nx_secure_x509_certificate_initialize(trusted_certificate_ptr, (UCHAR*)emqxsl_ca_der,
        emqxsl_ca_der_len, NX_NULL, 0, NULL, 0,
                                         NX_SECURE_X509_KEY_TYPE_NONE);
if (ret != TX_SUCCESS)
{
    Error_Handler();
}

/* Add a CA Certificate to our trusted store */

ret = _nx_secure_tls_trusted_certificate_add(TLS_session_ptr, trusted_certificate_ptr);
if (ret != TX_SUCCESS)
{
    Error_Handler();
}

/* Add a sni extension */
nx_secure_x509_dns_name_initialize(&dns_name,(UCHAR *)mqtts_broker_name,strlen(((const char*)mqtts_broker_name)));
nx_secure_tls_session_sni_extension_set(TLS_session_ptr, &dns_name);
 _nx_secure_tls_remote_certificate_allocate(TLS_session_ptr, &remote_certificate, remote_cert_buffer, sizeof(remote_cert_buffer));
_nx_secure_tls_remote_certificate_allocate(TLS_session_ptr, &remote_issuer, remote_issuer_buffer, sizeof(remote_issuer_buffer));

return ret;

I have added to root CA certificate and the SNI extension and have checked that tls1.3 is getting enabled. Moreover, I am able to connect to the broker over tls1.2 with no issue at all (tls1.3 is disabled), but when tls1.3 is enabled the connection fails even with tls1.2

I also tried my connection with hivemq serverless cloud, it was able to communicate over tls1.2 but with tls1.3 it failed with alert code of 51 which is "decrypt_error"

Is there anything i am missing? Thank you!

krshnarajd commented 3 months ago

NetXSecure doesn't support TLS1.3 with RSA key/certs. So if you are using RSA, you will see failure in TLS handshake.

Reference : https://github.com/eclipse-threadx/netxduo/issues/161

rubenax97 commented 2 months ago

I was facing same issue while trying setting up a Modbus TLS server.... (In your case, you are the client, so you only need the root CA or Identify CA, depends on how you define trust of chain...)

Well, here you find how I faced the issue, I hope will help you to clarify and implement in your application. FYI, I am using web addon, it is very handy for to use tcpserver implementation...

I am using XCA tool to generate CAs and crypto stuff. Below you find steps I strictly followed as.

  1. Generate root CA image
  2. Generate End-Identity CA (STM32 server CA) from root CA image
  3. In both CAs, I used EC to generate private key, because I found it is supported by netxduo secure API image

Then, in firmware side I make sure to define some important macros in nx_user.h file.

#define NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
#define NX_SECURE_TLS_ENABLE_TLS_1_3
#define NX_SECURE_AEAD_CIPHER_CHECK
#define NX_SECURE_ENABLE_AEAD_CIPHER
#define NX_SECURE_TLS_USE_SCSV_CIPHPERSUITE
#define NX_SECURE_ENABLE_ECC_CIPHERSUITE

Then in the file where you are going to initialize server/client stuff:

#define ca_cert_der             ca_cert
#define ca_cert_der_len         ca_cert_len
#define private_key_der         private_key
#define private_key_der_len     private_key_len
#define trusted_ca_cert_der     trusted_ca_cert
#define trusted_ca_cert_der_len trusted_ca_cert_len

/* TLS buffers and certificate containers. */
static CHAR  crypto_metadata_server[20000 * MAX_CLIENTS];
static UCHAR tls_packet_buffer[40000];
static NX_SECURE_X509_CERT  identify_ca;
static NX_SECURE_X509_CERT  trusted_ca;
static NX_SECURE_X509_CERT* trusted_ca_list[1];

/// ECC ciphers for TLSv1.3 is needed
extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers_ecc;
extern const USHORT               nx_crypto_ecc_supported_groups;
extern const NX_CRYPTO_METHOD*    nx_crypto_ecc_curves;
extern const UINT                 nx_crypto_ecc_supported_groups_size;

Finally, to initialize all the stuff related to TLS v1.3

/* Initialize server Identify CA */
  memset(&identify_ca, 0, sizeof(identify_ca));
  status = nx_secure_x509_certificate_initialize(&identify_ca, ca_cert_der, (USHORT)ca_cert_der_len, NX_NULL, 0,
                                                 private_key_der, (USHORT)private_key_der_len,
                                                 NX_SECURE_X509_KEY_TYPE_EC_DER);
  if (status != NX_SECURE_X509_SUCCESS)
  {
      LOG_ERROR("iface=%s, Identify CA, error: 0x%04x", iface_ptr->name, status);
      return 1;
  }

  /* Initialize Trusted CA */
  memset(&trusted_ca, 0, sizeof(trusted_ca));
  status = nx_secure_x509_certificate_initialize(&trusted_ca, trusted_ca_cert_der, (USHORT)trusted_ca_cert_der_len,
                                                 NX_NULL, 0, NX_NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE);
  if (status != NX_SECURE_X509_SUCCESS)
  {
      LOG_ERROR("iface=%s, Trusted CA, error: 0x%04x", iface_ptr->name, status);
      return 1;
  }
  trusted_ca_list[0] = &trusted_ca;

  /* Setup TLS session data for the TCP server. */
  status = nx_tcpserver_tls_setup(&iface_ptr->server, &nx_crypto_tls_ciphers_ecc, crypto_metadata_server,
                                  sizeof(crypto_metadata_server), tls_packet_buffer, sizeof(tls_packet_buffer),
                                  &identify_ca, trusted_ca_list, 1, NX_NULL, 0, NX_NULL, 0);
  if (status != NX_SUCCESS)
  {
      LOG_ERROR("iface=%s, TLS configuration failed, error: 0x%04x", iface_ptr->name, status);
      return 1;
  }

  status = nx_tcpserver_tls_ecc_setup(&iface_ptr->server, &nx_crypto_ecc_supported_groups,
                                      nx_crypto_ecc_supported_groups_size, &nx_crypto_ecc_curves);
  if (status != NX_SUCCESS)
  {
      LOG_ERROR("iface=%s, TLS ecc configuration failed, error: 0x%04x", iface_ptr->name, status);
      return 1;
  }

To test all those configurations, I used openssl CLI

openssl s_client -connect 192.168.1.10:802 -tls1_3 -CAfile certs/root_CA.crt -verify_return_error -debug

I hope you find interesting and useful... 😄