Skip to content

extmod/modssl_mbedtls: Implement SSLSession support. #12780

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions docs/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ facilities for network sockets, both client-side and server-side.
Functions
---------

.. function:: ssl.wrap_socket(sock, server_side=False, key=None, cert=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True)
.. function:: ssl.wrap_socket(sock, server_side=False, key=None, cert=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True, session=None)

Wrap the given *sock* and return a new wrapped-socket object. The implementation
of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket`
Expand All @@ -28,6 +28,9 @@ Functions
- *cadata* is a bytes object containing the CA certificate chain (in DER format) that will
validate the peer's certificate. Currently only a single DER-encoded certificate is supported.

- *session* allows a client socket to reuse a session by passing a SSLSession object
previously retrieved from the ``session`` property of a wrapped-socket object.

Depending on the underlying module implementation in a particular
:term:`MicroPython port`, some or all keyword arguments above may be not supported.

Expand Down Expand Up @@ -66,7 +69,7 @@ class SSLContext
Set the available ciphers for sockets created with this context. *ciphers* should be
a list of strings in the `IANA cipher suite format <https://wiki.mozilla.org/Security/Cipher_Suites>`_ .

.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None)
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None, session=None)

Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, wrapping the underlying stream.
Expand All @@ -89,6 +92,9 @@ class SSLContext
server certificate. It also sets the name for Server Name Indication (SNI), allowing the server
to present the proper certificate.

- *session* allows a client socket to reuse a session by passing a SSLSession object
previously retrieved from the ``session`` property of a ssl.SSLSocket object.

.. warning::

Some implementations of ``ssl`` module do NOT validate server certificates,
Expand All @@ -110,6 +116,19 @@ class SSLContext
`mpremote rtc --set <mpremote_command_rtc>` or ``ntptime``, and ``server_hostname``
must be specified when on the client side.

class SSLSession
----------------

.. class:: SSLSession(buf)

This constructor is a MicroPython extension to reconstruct a SSLSession object using
a bytes object previously returned by the ``serialize`` method.

.. method:: SSLSession.serialize()

This function is a MicroPython extension to return a bytes object representing the
session, allowing it to be stored and reconstructed at a later time.

Exceptions
----------

Expand Down
135 changes: 131 additions & 4 deletions extmod/modtls_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@
#include "mbedtls/asn1.h"
#endif

#if defined(MBEDTLS_CONFIG_FILE)
#include MBEDTLS_CONFIG_FILE
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
#include "mbedtls/ssl_ticket.h"
#endif

#ifndef MICROPY_MBEDTLS_CONFIG_BARE_METAL
#define MICROPY_MBEDTLS_CONFIG_BARE_METAL (0)
#endif
Expand All @@ -86,6 +94,9 @@
mbedtls_x509_crt cacert;
mbedtls_x509_crt cert;
mbedtls_pk_context pkey;
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
mbedtls_ssl_ticket_context ticket;
#endif
int authmode;
int *ciphersuites;
mp_obj_t handler;
Expand All @@ -94,6 +105,12 @@
#endif
} mp_obj_ssl_context_t;

// This corresponds to an SSLSession object.
typedef struct _mp_obj_ssl_session_t {
mp_obj_base_t base;
mbedtls_ssl_session session;
} mp_obj_ssl_session_t;

// This corresponds to an SSLSocket object.
typedef struct _mp_obj_ssl_socket_t {
mp_obj_base_t base;
Expand All @@ -111,13 +128,14 @@
#endif
} mp_obj_ssl_socket_t;

static const mp_obj_type_t ssl_session_type;
static const mp_obj_type_t ssl_context_type;
static const mp_obj_type_t ssl_socket_type;

static const MP_DEFINE_STR_OBJ(mbedtls_version_obj, MBEDTLS_VERSION_STRING_FULL);

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);
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname, mp_obj_t ssl_session);

/******************************************************************************/
// Helper functions.
Expand Down Expand Up @@ -253,6 +271,60 @@
return mp_obj_get_int(mp_call_function_2(o->handler, MP_OBJ_FROM_PTR(&cert), MP_OBJ_NEW_SMALL_INT(depth)));
}

/******************************************************************************/
// SSLSession type.

static mp_obj_t ssl_session_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);

mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);

mp_obj_ssl_session_t *self = m_new_obj(mp_obj_ssl_session_t);
self->base.type = type_in;

mbedtls_ssl_session_init(&self->session);
int ret = mbedtls_ssl_session_load(&self->session, bufinfo.buf, bufinfo.len);
if (ret != 0) {
mbedtls_raise_error(ret);

Check warning on line 289 in extmod/modtls_mbedtls.c

View check run for this annotation

Codecov / codecov/patch

extmod/modtls_mbedtls.c#L289

Added line #L289 was not covered by tests
}

return MP_OBJ_FROM_PTR(self);
}

static mp_obj_t ssl_session_serialize(mp_obj_t self_in) {
mp_obj_ssl_session_t *self = MP_OBJ_TO_PTR(self_in);
size_t len;
vstr_t vstr;
mbedtls_ssl_session_save(&self->session, NULL, 0, &len);
vstr_init_len(&vstr, len);
mbedtls_ssl_session_save(&self->session, (unsigned char *)vstr.buf, len, &len);
return mp_obj_new_bytes_from_vstr(&vstr);
}
static MP_DEFINE_CONST_FUN_OBJ_1(ssl_session_serialize_obj, ssl_session_serialize);

static mp_int_t ssl_session_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
if (flags != MP_BUFFER_READ) {
return 1;
}
mp_get_buffer_raise(ssl_session_serialize(self_in), bufinfo, flags);
return 0;
}

static const mp_rom_map_elem_t ssl_session_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_serialize), MP_ROM_PTR(&ssl_session_serialize_obj) },
};
static MP_DEFINE_CONST_DICT(ssl_session_locals_dict, ssl_session_locals_dict_table);

static MP_DEFINE_CONST_OBJ_TYPE(
ssl_session_type,
MP_QSTR_SSLSession,
MP_TYPE_FLAG_NONE,
make_new, ssl_session_make_new,
buffer, ssl_session_get_buffer,
locals_dict, &ssl_session_locals_dict
);

/******************************************************************************/
// SSLContext type.

Expand All @@ -279,6 +351,9 @@
mbedtls_x509_crt_init(&self->cacert);
mbedtls_x509_crt_init(&self->cert);
mbedtls_pk_init(&self->pkey);
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
mbedtls_ssl_ticket_init(&self->ticket);
#endif
self->ciphersuites = NULL;
self->handler = mp_const_none;
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
Expand Down Expand Up @@ -320,6 +395,14 @@
mbedtls_ssl_conf_dbg(&self->conf, mbedtls_debug, NULL);
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
ret = mbedtls_ssl_ticket_setup(&self->ticket, mbedtls_ctr_drbg_random, &self->ctr_drbg, MBEDTLS_CIPHER_AES_256_GCM, 86400);
if (ret != 0) {
mbedtls_raise_error(ret);

Check warning on line 401 in extmod/modtls_mbedtls.c

View check run for this annotation

Codecov / codecov/patch

extmod/modtls_mbedtls.c#L401

Added line #L401 was not covered by tests
}
mbedtls_ssl_conf_session_tickets_cb(&self->conf, mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, &self->ticket);
#endif

return MP_OBJ_FROM_PTR(self);
}

Expand Down Expand Up @@ -360,6 +443,9 @@
#if MICROPY_PY_SSL_FINALISER
static mp_obj_t ssl_context___del__(mp_obj_t self_in) {
mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(self_in);
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C)
mbedtls_ssl_ticket_free(&self->ticket);
#endif
mbedtls_pk_free(&self->pkey);
mbedtls_x509_crt_free(&self->cert);
mbedtls_x509_crt_free(&self->cacert);
Expand Down Expand Up @@ -468,11 +554,12 @@
static MP_DEFINE_CONST_FUN_OBJ_2(ssl_context_load_verify_locations_obj, ssl_context_load_verify_locations);

static mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname, ARG_session };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_do_handshake_on_connect, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_session, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
};

// Parse arguments.
Expand All @@ -483,7 +570,7 @@

// Create and return the new SSLSocket object.
return ssl_socket_make_new(self, sock, args[ARG_server_side].u_bool,
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj);
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj, args[ARG_session].u_obj);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_wrap_socket_obj, 2, ssl_context_wrap_socket);

Expand Down Expand Up @@ -580,7 +667,7 @@
#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) {
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname, mp_obj_t ssl_session) {

// Store the current SSL context.
store_active_context(ssl_context);
Expand Down Expand Up @@ -631,6 +718,14 @@
mp_raise_ValueError(MP_ERROR_TEXT("CERT_REQUIRED requires server_hostname"));
}

if (ssl_session != mp_const_none) {
mp_obj_ssl_session_t *session = MP_OBJ_TO_PTR(ssl_session);
ret = mbedtls_ssl_set_session(&o->ssl, &session->session);
if (ret != 0) {
goto cleanup;

Check warning on line 725 in extmod/modtls_mbedtls.c

View check run for this annotation

Codecov / codecov/patch

extmod/modtls_mbedtls.c#L725

Added line #L725 was not covered by tests
}
}

#ifdef MBEDTLS_SSL_PROTO_DTLS
mbedtls_ssl_set_timer_cb(&o->ssl, o, _mbedtls_timing_set_delay, _mbedtls_timing_get_delay);
#endif
Expand Down Expand Up @@ -841,6 +936,36 @@
return ret;
}

static void ssl_socket_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) {
// Load attribute.
if (attr == MP_QSTR_session) {
mp_obj_ssl_session_t *o = m_new_obj(mp_obj_ssl_session_t);
o->base.type = &ssl_session_type;
mbedtls_ssl_session_init(&o->session);
int ret = mbedtls_ssl_get_session(&self->ssl, &o->session);
if (ret != 0) {
mbedtls_raise_error(ret);

Check warning on line 949 in extmod/modtls_mbedtls.c

View check run for this annotation

Codecov / codecov/patch

extmod/modtls_mbedtls.c#L949

Added line #L949 was not covered by tests
}
dest[0] = MP_OBJ_FROM_PTR(o);
} else {
// Continue lookup in locals_dict.
dest[1] = MP_OBJ_SENTINEL;
}
} else if (dest[1] != MP_OBJ_NULL) {
// Store attribute.
if (attr == MP_QSTR_session) {
mp_obj_ssl_session_t *ssl_session = MP_OBJ_TO_PTR(dest[1]);
dest[0] = MP_OBJ_NULL;
int ret = mbedtls_ssl_set_session(&self->ssl, &ssl_session->session);
if (ret != 0) {
mbedtls_raise_error(ret);

Check warning on line 963 in extmod/modtls_mbedtls.c

View check run for this annotation

Codecov / codecov/patch

extmod/modtls_mbedtls.c#L963

Added line #L963 was not covered by tests
}
}
}
}

static const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
Expand Down Expand Up @@ -878,6 +1003,7 @@
MP_QSTR_SSLSocket,
MP_TYPE_FLAG_NONE,
protocol, &ssl_socket_stream_p,
attr, ssl_socket_attr,
locals_dict, &ssl_socket_locals_dict
);

Expand Down Expand Up @@ -940,6 +1066,7 @@

// Classes.
{ MP_ROM_QSTR(MP_QSTR_SSLContext), MP_ROM_PTR(&ssl_context_type) },
{ MP_ROM_QSTR(MP_QSTR_SSLSession), MP_ROM_PTR(&ssl_session_type) },

// Constants.
{ MP_ROM_QSTR(MP_QSTR_MBEDTLS_VERSION), MP_ROM_PTR(&mbedtls_version_obj)},
Expand Down
2 changes: 1 addition & 1 deletion lib/micropython-lib
Submodule micropython-lib updated 37 files
+2 −1 .github/workflows/ruff.yml
+2 −1 .pre-commit-config.yaml
+8 −8 micropython/aiorepl/aiorepl.py
+1 −1 micropython/bluetooth/aioble/examples/l2cap_file_client.py
+1 −1 micropython/bluetooth/aioble/examples/l2cap_file_server.py
+4 −8 micropython/drivers/codec/wm8960/wm8960.py
+2 −4 micropython/drivers/display/lcd160cr/lcd160cr.py
+1 −0 micropython/drivers/imu/lsm9ds1/lsm9ds1.py
+1 −2 micropython/drivers/radio/nrf24l01/nrf24l01.py
+1 −1 micropython/drivers/sensor/hts221/hts221.py
+1 −0 micropython/drivers/sensor/lps22h/lps22h.py
+8 −8 micropython/espflash/espflash.py
+1 −1 micropython/lora/examples/reliable_delivery/sender.py
+1 −1 micropython/lora/examples/reliable_delivery/sender_async.py
+3 −2 micropython/lora/lora-sx126x/lora/sx126x.py
+1 −1 micropython/lora/lora-sx126x/manifest.py
+0 −1 micropython/senml/examples/actuator.py
+0 −1 micropython/senml/examples/base.py
+0 −1 micropython/senml/examples/basic.py
+0 −1 micropython/senml/examples/basic2.py
+0 −1 micropython/senml/examples/basic_cbor.py
+0 −1 micropython/senml/examples/custom_record.py
+0 −1 micropython/senml/examples/gateway.py
+0 −1 micropython/senml/examples/gateway_actuators.py
+0 −1 micropython/senml/examples/supported_data_types.py
+0 −1 micropython/senml/senml/__init__.py
+0 −1 micropython/senml/senml/senml_pack.py
+0 −1 micropython/senml/senml/senml_record.py
+12 −0 micropython/utop/README.md
+6 −0 micropython/utop/manifest.py
+109 −0 micropython/utop/utop.py
+2 −1 pyproject.toml
+0 −1 python-ecosys/cbor2/cbor2/__init__.py
+0 −1 python-ecosys/cbor2/cbor2/_decoder.py
+0 −1 python-ecosys/cbor2/cbor2/_encoder.py
+0 −1 python-ecosys/cbor2/examples/cbor_test.py
+9 −1 python-stdlib/ssl/ssl.py
3 changes: 3 additions & 0 deletions ports/unix/mbedtls/mbedtls_config_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@

// Set mbedtls configuration
#define MBEDTLS_CIPHER_MODE_CTR // needed for MICROPY_PY_CRYPTOLIB_CTR
#define MBEDTLS_SSL_SESSION_TICKETS

// Enable mbedtls modules
#define MBEDTLS_GCM_C
#define MBEDTLS_SSL_TICKET_C
#define MBEDTLS_TIMING_C

#if defined(MICROPY_UNIX_COVERAGE)
Expand Down
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy