Thanks to visit codestin.com
Credit goes to github.com

Skip to content

extmod/mbedtls: Support Alternative Functions Implemented in Python. #15905

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

Merged
merged 6 commits into from
Oct 24, 2024
Merged
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
5 changes: 5 additions & 0 deletions extmod/extmod.mk
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SRC_EXTMOD_C += \
extmod/modsocket.c \
extmod/modtls_axtls.c \
extmod/modtls_mbedtls.c \
extmod/mbedtls/mbedtls_alt.c \
extmod/modtime.c \
extmod/moductypes.c \
extmod/modvfs.c \
Expand Down Expand Up @@ -242,6 +243,10 @@ MBEDTLS_CONFIG_FILE ?= \"mbedtls/mbedtls_config_port.h\"
GIT_SUBMODULES += $(MBEDTLS_DIR)
CFLAGS_EXTMOD += -DMBEDTLS_CONFIG_FILE=$(MBEDTLS_CONFIG_FILE)
CFLAGS_EXTMOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include
ifeq ($(MICROPY_PY_SSL_ECDSA_SIGN_ALT),1)
CFLAGS_EXTMOD += -DMICROPY_PY_SSL_ECDSA_SIGN_ALT=1
LDFLAGS_EXTMOD += -Wl,--wrap=mbedtls_ecdsa_write_signature
endif
SRC_THIRDPARTY_C += lib/mbedtls_errors/mp_mbedtls_errors.c
SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\
aes.c \
Expand Down
88 changes: 88 additions & 0 deletions extmod/mbedtls/mbedtls_alt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright The Mbed TLS Contributors
* Copyright (c) 2024 Damien P. George
*
* This file provides default fallback functions for use with alternate
* cryptography functions implemented in Python.
*/
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
#if defined(MBEDTLS_ECP_RESTARTABLE) || defined(MBEDTLS_ECDSA_DETERMINISTIC)
#error "MICROPY_PY_SSL_ECDSA_SIGN_ALT cannot be used with MBEDTLS_ECP_RESTARTABLE or MBEDTLS_ECDSA_DETERMINISTIC"
#endif

#include <string.h>
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#include "mbedtls/platform.h"
#include "mbedtls/ssl.h"
#include "mbedtls/error.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/asn1write.h"

extern int micropy_mbedtls_ecdsa_sign_alt(const mbedtls_mpi *d, const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t sig_size, size_t *slen);


// Compute and write signature
// See lib/mbedtls/library/ecdsa.c:688
//
// Note: To avoid duplicating a lot of code, MBEDTLS_ECDSA_SIGN_ALT is not defined,
// which allows the default mbedtls_ecdsa_sign to be used as a fallback function.
// However, mbedtls_ecdsa_sign cannot be wrapped because it is called internally
// within its object file, so we wrap mbedtls_ecdsa_read/write_signature instead.
int __wrap_mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx,
mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hlen,
unsigned char *sig, size_t sig_size, size_t *slen,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng) {

(void)md_alg;

if (f_rng == NULL) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

// Check if curve is supported for ECDSA.
if (!mbedtls_ecdsa_can_do(ctx->grp.id) || ctx->grp.N.p == NULL) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

// Try signing with the alternative function first.
int ret = micropy_mbedtls_ecdsa_sign_alt(&ctx->d, hash, hlen, sig, sig_size, slen);

// Fallback to the default mbedtls implementation if needed.
if (ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) {
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);

size_t len = 0;
unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = { 0 };
unsigned char *p = buf + sizeof(buf);

MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign(&ctx->grp, &r, &s, &ctx->d, hash, hlen, f_rng, p_rng));
MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_mpi(&p, buf, &s));
MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_mpi(&p, buf, &r));
MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

if (len > sig_size) {
ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
} else {
ret = 0;
*slen = len;
memcpy(sig, p, len);
}

cleanup:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
}

return ret;
}
#endif
89 changes: 89 additions & 0 deletions extmod/modtls_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
#else
#include "mbedtls/version.h"
#endif
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
#include "mbedtls/ecdsa.h"
#include "mbedtls/asn1.h"
#endif

#define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)

Expand All @@ -68,6 +72,9 @@ typedef struct _mp_obj_ssl_context_t {
int authmode;
int *ciphersuites;
mp_obj_t handler;
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
mp_obj_t ecdsa_sign_callback;
#endif
} mp_obj_ssl_context_t;

// This corresponds to an SSLSocket object.
Expand Down Expand Up @@ -166,6 +173,13 @@ static NORETURN void mbedtls_raise_error(int err) {
#endif
}

// Stores the current SSLContext for use in mbedtls callbacks where the current state is not passed.
static inline void store_active_context(mp_obj_ssl_context_t *ssl_context) {
#if MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT
MP_STATE_THREAD(tls_ssl_context) = ssl_context;
#endif
}

static void ssl_check_async_handshake_failure(mp_obj_ssl_socket_t *sslsock, int *errcode) {
if (
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
Expand Down Expand Up @@ -241,6 +255,9 @@ static mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
mbedtls_pk_init(&self->pkey);
self->ciphersuites = NULL;
self->handler = mp_const_none;
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
self->ecdsa_sign_callback = mp_const_none;
#endif

#ifdef MBEDTLS_DEBUG_C
// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose
Expand Down Expand Up @@ -288,6 +305,10 @@ static void ssl_context_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[0] = MP_OBJ_NEW_SMALL_INT(self->authmode);
} else if (attr == MP_QSTR_verify_callback) {
dest[0] = self->handler;
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
} else if (attr == MP_QSTR_ecdsa_sign_callback) {
dest[0] = self->ecdsa_sign_callback;
#endif
} else {
// Continue lookup in locals_dict.
dest[1] = MP_OBJ_SENTINEL;
Expand All @@ -298,6 +319,11 @@ static void ssl_context_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
self->authmode = mp_obj_get_int(dest[1]);
dest[0] = MP_OBJ_NULL;
mbedtls_ssl_conf_authmode(&self->conf, self->authmode);
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
} else if (attr == MP_QSTR_ecdsa_sign_callback) {
dest[0] = MP_OBJ_NULL;
self->ecdsa_sign_callback = dest[1];
#endif
} else if (attr == MP_QSTR_verify_callback) {
dest[0] = MP_OBJ_NULL;
self->handler = dest[1];
Expand Down Expand Up @@ -497,6 +523,9 @@ static int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
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) {

// Store the current SSL context.
store_active_context(ssl_context);

// Verify the socket object has the full stream protocol
mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);

Expand Down Expand Up @@ -602,6 +631,9 @@ static mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
return MP_STREAM_ERROR;
}

// Store the current SSL context.
store_active_context(o->ssl_context);

int ret = mbedtls_ssl_read(&o->ssl, buf, size);
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
// end of stream
Expand Down Expand Up @@ -643,6 +675,9 @@ static mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
return MP_STREAM_ERROR;
}

// Store the current SSL context.
store_active_context(o->ssl_context);

int ret = mbedtls_ssl_write(&o->ssl, buf, size);
if (ret >= 0) {
return ret;
Expand Down Expand Up @@ -680,6 +715,9 @@ static mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
mp_obj_t sock = self->sock;

if (request == MP_STREAM_CLOSE) {
// Clear the SSL context.
store_active_context(NULL);

if (sock == MP_OBJ_NULL) {
// Already closed socket, do nothing.
return 0;
Expand Down Expand Up @@ -767,6 +805,57 @@ static MP_DEFINE_CONST_OBJ_TYPE(
/******************************************************************************/
// ssl module.

#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
int micropy_mbedtls_ecdsa_sign_alt(const mbedtls_mpi *d, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t sig_size, size_t *slen) {
uint8_t key[256];

// Check if the current context has an alternative sign function.
mp_obj_ssl_context_t *ssl_ctx = MP_STATE_THREAD(tls_ssl_context);
if (ssl_ctx == NULL || ssl_ctx->ecdsa_sign_callback == mp_const_none) {
return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
}

size_t klen = mbedtls_mpi_size(d);
if (klen > sizeof(key)) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

// Convert the MPI private key (d) to a binary array
if (mbedtls_mpi_write_binary(d, key, klen) != 0) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

nlr_buf_t nlr;
mp_buffer_info_t sig_buf;
if (nlr_push(&nlr) == 0) {
mp_obj_t ret = mp_call_function_2(ssl_ctx->ecdsa_sign_callback,
mp_obj_new_bytearray_by_ref(klen, (void *)key),
mp_obj_new_bytearray_by_ref(hlen, (void *)hash));
if (ret == mp_const_none) {
// key couldn't be used by the alternative implementation.
nlr_pop();
return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
}
mp_get_buffer_raise(ret, &sig_buf, MP_BUFFER_READ);
nlr_pop();
} else {
// The alternative implementation failed to sign.
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}

// Check if the buffer fits.
if (sig_buf.len > sig_size) {
return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
}

// Copy ASN.1 signature to buffer.
*slen = sig_buf.len;
memcpy(sig, sig_buf.buf, sig_buf.len);
return 0;
}
#endif

static const mp_rom_map_elem_t mp_module_tls_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_tls) },

Expand Down
3 changes: 3 additions & 0 deletions ports/stm32/boards/ARDUINO_NICLA_VISION/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@

# RPC
require("msgpackrpc", library="arduino-lib")

# SE05x driver
require("se05x", library="arduino-lib")
1 change: 1 addition & 0 deletions ports/stm32/boards/ARDUINO_NICLA_VISION/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ MICROPY_BLUETOOTH_BTSTACK = 0
MICROPY_PY_LWIP = 1
MICROPY_PY_NETWORK_CYW43 = 1
MICROPY_PY_SSL = 1
MICROPY_PY_SSL_ECDSA_SIGN_ALT=1
MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
Expand Down
3 changes: 3 additions & 0 deletions ports/stm32/boards/ARDUINO_OPTA/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@
# Register external library
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")

# Opta modules.
require("opta", library="arduino-lib")

# RPC
require("msgpackrpc", library="arduino-lib")
7 changes: 6 additions & 1 deletion ports/stm32/boards/ARDUINO_PORTENTA_H7/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@
add_library("arduino-lib", "$(ARDUINO_LIB_DIR)")

# RPC
require("cmwx1", library="arduino-lib")
require("msgpackrpc", library="arduino-lib")

# Lora/CMWX1 driver
require("cmwx1", library="arduino-lib")

# SE05x driver
require("se05x", library="arduino-lib")
1 change: 1 addition & 0 deletions ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ MICROPY_BLUETOOTH_BTSTACK = 0
MICROPY_PY_LWIP = 1
MICROPY_PY_NETWORK_CYW43 = 1
MICROPY_PY_SSL = 1
MICROPY_PY_SSL_ECDSA_SIGN_ALT=1
MICROPY_SSL_MBEDTLS = 1
MICROPY_PY_OPENAMP = 1
MICROPY_PY_OPENAMP_REMOTEPROC = 1
Expand Down
5 changes: 5 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,11 @@ typedef double mp_float_t;
#define MICROPY_PY_SSL_FINALISER (MICROPY_ENABLE_FINALISER)
#endif

// Whether to add a root pointer for the current ssl object
#ifndef MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT
#define MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT (MICROPY_PY_SSL_ECDSA_SIGN_ALT)
#endif

// Whether to provide the "vfs" module
#ifndef MICROPY_PY_VFS
#define MICROPY_PY_VFS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES && MICROPY_VFS)
Expand Down
4 changes: 4 additions & 0 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ typedef struct _mp_state_thread_t {
bool prof_callback_is_executing;
struct _mp_code_state_t *current_code_state;
#endif

#if MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT
struct _mp_obj_ssl_context_t *tls_ssl_context;
#endif
} mp_state_thread_t;

// This structure combines the above 3 structures.
Expand Down
Loading