Skip to content

Commit

Permalink
extmod/modussl_mbedtls: Wire in support for DTLS.
Browse files Browse the repository at this point in the history
Signed-off-by: Damien Tournoud <[email protected]>
  • Loading branch information
damz committed Jan 7, 2024
1 parent 42eab32 commit ddb064f
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 4 deletions.
21 changes: 21 additions & 0 deletions docs/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,32 @@ Exceptions

This exception does NOT exist. Instead its base class, OSError, is used.

DTLS support
------------

.. admonition:: Difference to CPython
:class: attention

This is a MicroPython extension.

This module supports DTLS in client and server mode via the `PROTOCOL_DTLS_CLIENT`
and `PROTOCOL_DTLS_SERVER` constants that can be used as the ``protocol`` argument
of `SSLContext`.

In this case the underlying socket is expected to behave as a datagram socket (i.e.
like the socket opened with ``socket.socket`` with ``socket.AF_INET`` as ``af`` and
``socket.SOCK_DGRAM`` as ``type``).

DTLS is only supported on ports that use mbed TLS, and it is not enabled by default:
it requires enabling ``MBEDTLS_SSL_PROTO_DTLS`` in the specific port configuration.

Constants
---------

.. data:: ssl.PROTOCOL_TLS_CLIENT
ssl.PROTOCOL_TLS_SERVER
ssl.PROTOCOL_DTLS_CLIENT (when DTLS support is enabled)
ssl.PROTOCOL_DTLS_SERVER (when DTLS support is enabled)

Supported values for the *protocol* parameter.

Expand Down
81 changes: 77 additions & 4 deletions extmod/modssl_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include "py/stream.h"
#include "py/objstr.h"
#include "py/reader.h"
#include "py/smallint.h"
#include "py/mphal.h"
#include "extmod/vfs.h"

// mbedtls_time_t
Expand All @@ -46,6 +48,9 @@
#include "mbedtls/pk.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#ifdef MBEDTLS_SSL_PROTO_DTLS
#include "mbedtls/timing.h"
#endif
#include "mbedtls/debug.h"
#include "mbedtls/error.h"
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
Expand All @@ -56,6 +61,14 @@

#define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)

#define MP_ENDPOINT_IS_SERVER (1 << 0)
#define MP_TRANSPORT_IS_DTLS (1 << 1)

#define MP_PROTOCOL_TLS_CLIENT 0
#define MP_PROTOCOL_TLS_SERVER MP_ENDPOINT_IS_SERVER
#define MP_PROTOCOL_DTLS_CLIENT MP_TRANSPORT_IS_DTLS
#define MP_PROTOCOL_DTLS_SERVER MP_ENDPOINT_IS_SERVER | MP_TRANSPORT_IS_DTLS

// This corresponds to an SSLContext object.
typedef struct _mp_obj_ssl_context_t {
mp_obj_base_t base;
Expand All @@ -78,6 +91,12 @@ typedef struct _mp_obj_ssl_socket_t {

uintptr_t poll_mask; // Indicates which read or write operations the protocol needs next
int last_error; // The last error code, if any

#ifdef MBEDTLS_SSL_PROTO_DTLS
mp_uint_t timer_start_ms;
mp_int_t timer_fin_ms;
mp_int_t timer_int_ms;
#endif
} mp_obj_ssl_socket_t;

STATIC const mp_obj_type_t ssl_context_type;
Expand Down Expand Up @@ -213,7 +232,10 @@ STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
mp_arg_check_num(n_args, n_kw, 1, 1, false);

// This is the "protocol" argument.
mp_int_t endpoint = mp_obj_get_int(args[0]);
mp_int_t protocol = mp_obj_get_int(args[0]);

int endpoint = (protocol & MP_ENDPOINT_IS_SERVER) ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT;
int transport = (protocol & MP_TRANSPORT_IS_DTLS) ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM;

// Create SSLContext object.
#if MICROPY_PY_SSL_FINALISER
Expand Down Expand Up @@ -250,7 +272,7 @@ STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
}

ret = mbedtls_ssl_config_defaults(&self->conf, endpoint,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
transport, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
mbedtls_raise_error(ret);
}
Expand Down Expand Up @@ -518,6 +540,41 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
}
}

#ifdef MBEDTLS_SSL_PROTO_DTLS
STATIC void _mbedtls_timing_set_delay(void *ctx, uint32_t int_ms, uint32_t fin_ms) {
mp_obj_ssl_socket_t *o = (mp_obj_ssl_socket_t *)ctx;

o->timer_int_ms = int_ms;
o->timer_fin_ms = fin_ms;

if (fin_ms != 0) {
o->timer_start_ms = mp_hal_ticks_ms() & (MICROPY_PY_TIME_TICKS_PERIOD - 1);
}
}

STATIC int _mbedtls_timing_get_delay(void *ctx) {
mp_obj_ssl_socket_t *o = (mp_obj_ssl_socket_t *)ctx;

if (o->timer_fin_ms == 0) {
return -1;
}

mp_uint_t now = mp_hal_ticks_ms() & (MICROPY_PY_TIME_TICKS_PERIOD - 1);
mp_int_t elapsed_ms = ((now - o->timer_start_ms + MICROPY_PY_TIME_TICKS_PERIOD / 2) & (MICROPY_PY_TIME_TICKS_PERIOD - 1))
- MICROPY_PY_TIME_TICKS_PERIOD / 2;

if (elapsed_ms >= o->timer_fin_ms) {
return 2;
}

if (elapsed_ms >= o->timer_int_ms) {
return 1;
}

return 0;
}
#endif

STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname) {

Expand Down Expand Up @@ -558,6 +615,12 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
mp_raise_ValueError(MP_ERROR_TEXT("CERT_REQUIRED requires server_hostname"));
}

#ifdef MBEDTLS_SSL_PROTO_DTLS
mbedtls_ssl_set_timer_cb(&o->ssl, o,
_mbedtls_timing_set_delay,
_mbedtls_timing_get_delay);
#endif

mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);

if (do_handshake_on_connect) {
Expand Down Expand Up @@ -760,6 +823,12 @@ STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
#ifdef MBEDTLS_SSL_PROTO_DTLS
{ MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&mp_stream_read1_obj) },
{ MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&mp_stream_write1_obj) },
{ MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&mp_stream_write_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
#if MICROPY_PY_SSL_FINALISER
Expand Down Expand Up @@ -853,8 +922,12 @@ STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {

// Constants.
{ MP_ROM_QSTR(MP_QSTR_MBEDTLS_VERSION), MP_ROM_PTR(&mbedtls_version_obj)},
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(MBEDTLS_SSL_IS_CLIENT) },
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(MBEDTLS_SSL_IS_SERVER) },
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(MP_PROTOCOL_TLS_CLIENT) },
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(MP_PROTOCOL_TLS_SERVER) },
#ifdef MBEDTLS_SSL_PROTO_DTLS
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_DTLS_CLIENT), MP_ROM_INT(MP_PROTOCOL_DTLS_CLIENT) },
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_DTLS_SERVER), MP_ROM_INT(MP_PROTOCOL_DTLS_SERVER) },
#endif
{ MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(MBEDTLS_SSL_VERIFY_NONE) },
{ MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(MBEDTLS_SSL_VERIFY_OPTIONAL) },
{ MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(MBEDTLS_SSL_VERIFY_REQUIRED) },
Expand Down
2 changes: 2 additions & 0 deletions ports/esp32/boards/sdkconfig.base
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
CONFIG_MBEDTLS_HAVE_TIME_DATE=y
CONFIG_MBEDTLS_PLATFORM_TIME_ALT=y
CONFIG_MBEDTLS_HAVE_TIME=y
# Enable DTLS
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y

# Disable ALPN support as it's not implemented in MicroPython
CONFIG_MBEDTLS_SSL_ALPN=n
Expand Down
3 changes: 3 additions & 0 deletions ports/unix/mbedtls/mbedtls_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
// Set mbedtls configuration
#define MBEDTLS_CIPHER_MODE_CTR // needed for MICROPY_PY_CRYPTOLIB_CTR

// Enable DTLS
#define MBEDTLS_SSL_PROTO_DTLS

// Enable mbedtls modules
#define MBEDTLS_HAVEGE_C
#define MBEDTLS_TIMING_C
Expand Down

0 comments on commit ddb064f

Please sign in to comment.