Azure/azure-c-shared-utility

tlsio_mbedtls.c and mbedTLS v3.6.0

ASeidelt opened this issue · 0 comments

Hi,

because mbedTLS 2.28.x is only supported until end of 2024 [1] I tried to compile Azure-SDK using mbedTLS 3.6.0.

I found the following issues with adapters/tlsio_mbedtls.c and mbedTSL v3.6:

  • The following includes are no longer available/needed [2]
#include "mbedtls/certs.h"
#include "mbedtls/entropy_poll.h"
  • In [3] size_t max_len = mbedtls_ssl_get_output_max_frag_len(&tls_io_instance->ssl); must be replaced by size_t max_len = mbedtls_ssl_get_max_out_record_payload(&tls_io_instance->ssl);
  • In [4] mbedtls_ssl_conf_min_version(&tls_io_instance->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); must be replaced by mbedtls_ssl_conf_min_tls_version(&tls_io_instance->config, MBEDTLS_SSL_VERSION_TLS1_2);
  • In [5] mbedtls_pk_parse_key(&tls_io_instance->pKey, (const unsigned char*) temp_key, (int) (strlen(temp_key) + 1), NULL, 0) now needs an entropy source: mbedtls_pk_parse_key(&tls_io_instance->pKey, (const unsigned char*) temp_key, (int) (strlen(temp_key) + 1), NULL, 0, mbedtls_ctr_drbg_random, &tls_io_instance->ctr_drbg)
  • I also changed [6] to use the constants from mbedTLS: mbedtls_ssl_conf_renegotiation(&tls_io_instance->config, set_renegotiation ? MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION : MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION);

These were the easy/obvious changes. Sadly there are two more changes I'm not sure/happy about:

first
decode_ssl_received_bytes() [7] does not report SSL-errors via indicate_error(). I added an else block where all return values <0 and != MBEDTLS_ERR_SSL_WANT_READ will report an error:

static int decode_ssl_received_bytes(TLS_IO_INSTANCE *tls_io_instance)
{
  int result = 0;
  unsigned char buffer[64];
  int rcv_bytes = 1;

  while (rcv_bytes > 0)
  {
    rcv_bytes = mbedtls_ssl_read(&tls_io_instance->ssl, buffer, sizeof(buffer));
    if (rcv_bytes > 0)
    {
      if (tls_io_instance->on_bytes_received != NULL)
      {
        tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, buffer, rcv_bytes);
      }
    }
    else
    {
      if (rcv_bytes != MBEDTLS_ERR_SSL_WANT_READ)
      {  // no data is not an error
        LogError("ERROR for mbedtls_ssl_read() := 0x%04X", -rcv_bytes);
        indicate_error(tls_io_instance);
      }
    }
  }

  return result;
}

This now does reliably report TLS errors for us. Did I miss something here?

second
The other problem is a change in policy for some of the variables in mbedTLS structures. These are 'private' now.
on_io_send() [8] does access tls_io_instance->ssl.out_msgtype to access the type of the TLS message it sends. I'm not sure why this is necessary and only messages of type MBEDTLS_SSL_MSG_APPLICATION_DATA shall report an on_send_complete(), but I found the following hack to get it to work:

#define MBEDTLS_ALLOW_PRIVATE_ACCESS    // emulate mbedTLS 2 API access level
#include "mbedtls/private_access.h"
[...]
static int on_io_send(void *context, const unsigned char *buf, size_t sz)
{
[...]
    // Only allow Application data type message to send on_send_complete callback.
    // note: visibility of out_msgtype was changed to private in mbedTLS 2->3
    if (tls_io_instance->ssl.MBEDTLS_PRIVATE(out_msgtype) == MBEDTLS_SSL_MSG_APPLICATION_DATA)
    {
      on_complete_callback = on_send_complete;
      context = tls_io_instance;
    }
[...]

Can someone give me some reasoning why this check for the TLS message type is necessary? I asume it has something to do with mbedTLS' behaviour of only accepting 16KiB blocks of data when mbedtls_ssl_write() is called?
What would be an appropriate solution w/o accessing the now private out_msgtype?

Thanks Andre

[1] https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.8
[2]

#include "mbedtls/certs.h"

[3]
size_t max_len = mbedtls_ssl_get_max_frag_len(&tls_io_instance->ssl);

[4]
mbedtls_ssl_conf_min_version(&tls_io_instance->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); // v1.2

[5]
else if (mbedtls_pk_parse_key(&tls_io_instance->pKey, (const unsigned char *)temp_key, (int)(strlen(temp_key) + 1), NULL, 0) != 0)

[6]
mbedtls_ssl_conf_renegotiation(&tls_io_instance->config, set_renegotiation ? 1 : 0);

[7]
static int decode_ssl_received_bytes(TLS_IO_INSTANCE *tls_io_instance)

[8]
static int on_io_send(void *context, const unsigned char *buf, size_t sz)