From dcb650c5130ae1e9fa0f951fbdfc8630e9844471 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 29 Sep 2022 09:08:28 -0500 Subject: [PATCH] pico w: add ssl module Note: at this time, the ssl module on pico_w never verifies the server certificate. This means it does not actually provide a higher security level than regular socket / http protocols. --- locale/circuitpython.pot | 33 +- ports/espressif/common-hal/ssl/SSLSocket.c | 2 +- ports/raspberrypi/Makefile | 82 +++++ .../raspberry_pi_pico_w/mpconfigboard.mk | 3 +- ports/raspberrypi/common-hal/ssl/SSLContext.c | 52 +++ ports/raspberrypi/common-hal/ssl/SSLContext.h | 35 ++ ports/raspberrypi/common-hal/ssl/SSLSocket.c | 329 ++++++++++++++++++ ports/raspberrypi/common-hal/ssl/SSLSocket.h | 54 +++ ports/raspberrypi/common-hal/ssl/__init__.c | 32 ++ ports/raspberrypi/common-hal/ssl/__init__.h | 27 ++ ports/raspberrypi/mbedtls/mbedtls_config.h | 115 ++++++ ports/raspberrypi/mbedtls/mbedtls_port.c | 51 +++ py/circuitpy_mpconfig.h | 1 + py/circuitpy_mpconfig.mk | 4 + py/malloc.c | 93 +++++ py/misc.h | 7 + py/mpstate.h | 4 + shared-bindings/ssl/SSLSocket.h | 2 +- tools/ci_fetch_deps.py | 1 + 19 files changed, 905 insertions(+), 22 deletions(-) create mode 100644 ports/raspberrypi/common-hal/ssl/SSLContext.c create mode 100644 ports/raspberrypi/common-hal/ssl/SSLContext.h create mode 100644 ports/raspberrypi/common-hal/ssl/SSLSocket.c create mode 100644 ports/raspberrypi/common-hal/ssl/SSLSocket.h create mode 100644 ports/raspberrypi/common-hal/ssl/__init__.c create mode 100644 ports/raspberrypi/common-hal/ssl/__init__.h create mode 100644 ports/raspberrypi/mbedtls/mbedtls_config.h create mode 100644 ports/raspberrypi/mbedtls/mbedtls_port.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index ff943c9767..fd9e514754 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -152,14 +152,6 @@ msgstr "" msgid "%q must be >= %d" msgstr "" -#: py/argcheck.c -msgid "%q must be >= 0" -msgstr "" - -#: shared-bindings/vectorio/Circle.c shared-bindings/vectorio/Rectangle.c -msgid "%q must be >= 1" -msgstr "" - #: shared-bindings/analogbufio/BufferedIn.c #: shared-bindings/audiocore/RawSample.c msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" @@ -910,8 +902,7 @@ msgstr "" msgid "Error: Failure to bind" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c -#: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c +#: py/enum.c shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c #: shared-bindings/alarm/__init__.c shared-bindings/busio/SPI.c #: shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c @@ -1243,6 +1234,7 @@ msgid "Invalid size" msgstr "" #: ports/espressif/common-hal/ssl/SSLContext.c +#: ports/raspberrypi/common-hal/ssl/SSLSocket.c msgid "Invalid socket for TLS" msgstr "" @@ -1569,10 +1561,12 @@ msgid "Only 8 or 16 bit mono with " msgstr "" #: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c msgid "Only IPv4 addresses supported" msgstr "" #: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c msgid "Only IPv4 sockets supported" msgstr "" @@ -1642,6 +1636,7 @@ msgid "Out of memory" msgstr "" #: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c msgid "Out of sockets" msgstr "" @@ -1696,7 +1691,6 @@ msgid "Pin interrupt already in use" msgstr "" #: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -#: shared-bindings/digitalio/DigitalInOut.c msgid "Pin is input only" msgstr "" @@ -1916,6 +1910,7 @@ msgid "Slices not supported" msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" @@ -2341,10 +2336,6 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "address out of bounds" -msgstr "" - #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -2814,10 +2805,6 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination_length must be an int >= 0" -msgstr "" - #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3241,6 +3228,10 @@ msgstr "" msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" +#: ports/raspberrypi/common-hal/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -3267,6 +3258,10 @@ msgstr "" msgid "invalid hostname" msgstr "" +#: ports/raspberrypi/common-hal/ssl/SSLSocket.c +msgid "invalid key" +msgstr "" + #: py/compile.c msgid "invalid micropython decorator" msgstr "" diff --git a/ports/espressif/common-hal/ssl/SSLSocket.c b/ports/espressif/common-hal/ssl/SSLSocket.c index 281e356d77..d106e16894 100644 --- a/ports/espressif/common-hal/ssl/SSLSocket.c +++ b/ports/espressif/common-hal/ssl/SSLSocket.c @@ -158,7 +158,7 @@ mp_uint_t common_hal_ssl_sslsocket_send(ssl_sslsocket_obj_t *self, const uint8_t if (err == ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) { mp_raise_espidf_MemoryError(); - } else if (ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED) { + } else if (err == ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED) { mp_raise_OSError_msg_varg(translate("Failed SSL handshake")); } else { mp_raise_OSError_msg_varg(translate("Unhandled ESP TLS error %d %d %x %d"), esp_tls_code, flags, err, sent); diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 17c7eb477c..506b19a795 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -276,6 +276,88 @@ SRC_C += \ $(SRC_CYW43) \ $(SRC_LWIP) \ +ifeq ($(CIRCUITPY_SSL),1) +CFLAGS += -isystem $(TOP)/mbedtls/include +SRC_MBEDTLS := $(addprefix lib/mbedtls/library/, \ + aes.c \ + aesni.c \ + arc4.c \ + asn1parse.c \ + asn1write.c \ + base64.c \ + bignum.c \ + blowfish.c \ + camellia.c \ + ccm.c \ + certs.c \ + chacha20.c \ + chachapoly.c \ + cipher.c \ + cipher_wrap.c \ + cmac.c \ + ctr_drbg.c \ + debug.c \ + des.c \ + dhm.c \ + ecdh.c \ + ecdsa.c \ + ecjpake.c \ + ecp.c \ + ecp_curves.c \ + entropy.c \ + entropy_poll.c \ + gcm.c \ + havege.c \ + hmac_drbg.c \ + md2.c \ + md4.c \ + md5.c \ + md.c \ + md_wrap.c \ + oid.c \ + padlock.c \ + pem.c \ + pk.c \ + pkcs11.c \ + pkcs12.c \ + pkcs5.c \ + pkparse.c \ + pk_wrap.c \ + pkwrite.c \ + platform.c \ + platform_util.c \ + poly1305.c \ + ripemd160.c \ + rsa.c \ + rsa_internal.c \ + sha1.c \ + sha256.c \ + sha512.c \ + ssl_cache.c \ + ssl_ciphersuites.c \ + ssl_cli.c \ + ssl_cookie.c \ + ssl_srv.c \ + ssl_ticket.c \ + ssl_tls.c \ + timing.c \ + x509.c \ + x509_create.c \ + x509_crl.c \ + x509_crt.c \ + x509_csr.c \ + x509write_crt.c \ + x509write_csr.c \ + xtea.c \ + ) +SRC_C += $(SRC_MBEDTLS) mbedtls/mbedtls_port.c +CFLAGS += \ + -isystem $(TOP)/lib/mbedtls/include \ + -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"' \ + +$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS))): CFLAGS += -Wno-suggest-attribute=format +endif + SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) diff --git a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk index a8938b2623..15c4261f83 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk @@ -11,7 +11,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_CYW43 = 1 -CIRCUITPY_SSL = 0 +CIRCUITPY_SSL = 1 +CIRCUITPY_SSL_MBEDTLS = 1 CIRCUITPY_HASHLIB = 0 CIRCUITPY_WEB_WORKFLOW = 0 CIRCUITPY_MDNS = 0 diff --git a/ports/raspberrypi/common-hal/ssl/SSLContext.c b/ports/raspberrypi/common-hal/ssl/SSLContext.c new file mode 100644 index 0000000000..90f26a3830 --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/SSLContext.c @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/ssl/SSLContext.h" +#include "shared-bindings/ssl/SSLSocket.h" +#include "shared-bindings/socketpool/SocketPool.h" + +#include "py/runtime.h" +#include "py/stream.h" + +void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t *self) { +} + +void common_hal_ssl_sslcontext_load_verify_locations(ssl_sslcontext_obj_t *self, + const char *cadata) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_ssl_sslcontext_set_default_verify_paths(ssl_sslcontext_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_ssl_sslcontext_get_check_hostname(ssl_sslcontext_obj_t *self) { + return self->check_name; +} + +void common_hal_ssl_sslcontext_set_check_hostname(ssl_sslcontext_obj_t *self, bool value) { + self->check_name = value; +} diff --git a/ports/raspberrypi/common-hal/ssl/SSLContext.h b/ports/raspberrypi/common-hal/ssl/SSLContext.h new file mode 100644 index 0000000000..dc8caba089 --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/SSLContext.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + bool check_name; +} ssl_sslcontext_obj_t; diff --git a/ports/raspberrypi/common-hal/ssl/SSLSocket.c b/ports/raspberrypi/common-hal/ssl/SSLSocket.c new file mode 100644 index 0000000000..ab6ab04711 --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/SSLSocket.c @@ -0,0 +1,329 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Ltd. + * Copyright (c) 2019 Paul Sokolovsky + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/ssl/SSLSocket.h" +#include "shared-bindings/socketpool/Socket.h" +#include "shared-bindings/ssl/SSLContext.h" +#include "shared-bindings/socketpool/SocketPool.h" +#include "shared-bindings/socketpool/Socket.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "supervisor/shared/tick.h" + +#if defined(MBEDTLS_ERROR_C) +#include "../../lib/mbedtls_errors/mp_mbedtls_errors.c" +#endif + +#ifdef MBEDTLS_DEBUG_C +#include "mbedtls/debug.h" +STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { + (void)ctx; + (void)level; + mp_printf(&mp_plat_print, "DBG:%s:%04d: %s\n", file, line, str); +} +#define DEBUG(fmt, ...) mp_printf(&mp_plat_print, "DBG:%s:%04d: " fmt "\n", __FILE__, __LINE__,##__VA_ARGS__) +#else +#define DEBUG(...) do {} while (0) +#endif + +STATIC NORETURN void mbedtls_raise_error(int err) { + // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the + // underlying socket into negative codes to pass them through mbedtls. Here we turn them + // positive again so they get interpreted as the OSError they really are. The + // cut-off of -256 is a bit hacky, sigh. + if (err < 0 && err > -256) { + mp_raise_OSError(-err); + } + + #if defined(MBEDTLS_ERROR_C) + // Including mbedtls_strerror takes about 1.5KB due to the error strings. + // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror. + // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile. + + // Try to allocate memory for the message + #define ERR_STR_MAX 80 // mbedtls_strerror truncates if it doesn't fit + mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t); + byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX); + if (o_str == NULL || o_str_buf == NULL) { + mp_raise_OSError(err); + } + + // print the error message into the allocated buffer + mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX); + size_t len = strlen((char *)o_str_buf); + + // Put the exception object together + o_str->base.type = &mp_type_str; + o_str->data = o_str_buf; + o_str->len = len; + o_str->hash = qstr_compute_hash(o_str->data, o_str->len); + // raise + mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)}; + nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args)); + #else + // mbedtls is compiled without error strings so we simply return the err number + mp_raise_OSError(err); // err is typically a large negative number + #endif +} + +STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t *)ctx; + + // mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err); + mp_int_t out_sz = common_hal_socketpool_socket_send(sock, buf, len); + DEBUG("socket_send() -> %d", out_sz); + if (out_sz < 0) { + int err = -out_sz; + DEBUG("sock_stream->write() -> %d nonblocking? %d", out_sz, mp_is_nonblocking_error(err)); + if (mp_is_nonblocking_error(err)) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + return -err; // convert an MP_ERRNO to something mbedtls passes through as error + } else { + return out_sz; + } +} + +// _mbedtls_ssl_recv is called by mbedtls to receive bytes from the underlying socket +STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t *)ctx; + + mp_int_t out_sz = common_hal_socketpool_socket_recv_into(sock, buf, len); + DEBUG("socket_recv() -> %d", out_sz); + if (out_sz < 0) { + int err = -out_sz; + if (mp_is_nonblocking_error(err)) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + return -err; + } else { + return out_sz; + } +} + + + +ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t *self, + socketpool_socket_obj_t *socket, bool server_side, const char *server_hostname) { + + if (socket->type != SOCKETPOOL_SOCK_STREAM) { + mp_raise_RuntimeError(translate("Invalid socket for TLS")); + } + + ssl_sslsocket_obj_t *o = m_new_obj_with_finaliser(ssl_sslsocket_obj_t); + o->base.type = &ssl_sslsocket_type; + o->ssl_context = self; + o->sock = socket; + + mbedtls_ssl_init(&o->ssl); + mbedtls_ssl_config_init(&o->conf); + mbedtls_x509_crt_init(&o->cacert); + mbedtls_x509_crt_init(&o->cert); + mbedtls_pk_init(&o->pkey); + mbedtls_ctr_drbg_init(&o->ctr_drbg); + #ifdef MBEDTLS_DEBUG_C + // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose + mbedtls_debug_set_threshold(4); + #endif + + mbedtls_entropy_init(&o->entropy); + const byte seed[] = "upy"; + int ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); + if (ret != 0) { + goto cleanup; + } + + ret = mbedtls_ssl_config_defaults(&o->conf, + server_side ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + goto cleanup; + } + + // no certificate checking now + mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); + #ifdef MBEDTLS_DEBUG_C + mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); + #endif + + ret = mbedtls_ssl_setup(&o->ssl, &o->conf); + if (ret != 0) { + goto cleanup; + } + + if (server_hostname != NULL) { + ret = mbedtls_ssl_set_hostname(&o->ssl, server_hostname); + if (ret != 0) { + goto cleanup; + } + } + + mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); + + return o; +cleanup: + mbedtls_pk_free(&o->pkey); + mbedtls_x509_crt_free(&o->cert); + mbedtls_x509_crt_free(&o->cacert); + mbedtls_ssl_free(&o->ssl); + mbedtls_ssl_config_free(&o->conf); + mbedtls_ctr_drbg_free(&o->ctr_drbg); + mbedtls_entropy_free(&o->entropy); + + if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { + mp_raise_OSError(MP_ENOMEM); + } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid key")); + } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid cert")); + } else { + mbedtls_raise_error(ret); + } +} + +mp_uint_t common_hal_ssl_sslsocket_recv_into(ssl_sslsocket_obj_t *self, uint8_t *buf, uint32_t len) { + int ret = mbedtls_ssl_read(&self->ssl, buf, len); + DEBUG("recv_into mbedtls_ssl_read() -> %d\n", ret); + if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + DEBUG("returning %d\n", 0); + // end of stream + return 0; + } + if (ret >= 0) { + DEBUG("returning %d\n", ret); + return ret; + } + if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + ret = MP_EWOULDBLOCK; + } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + // If handshake is not finished, read attempt may end up in protocol + // wanting to write next handshake message. The same may happen with + // renegotation. + ret = MP_EWOULDBLOCK; + } + DEBUG("returning [error case] %d\n", -ret); + return -ret; +} + +mp_uint_t common_hal_ssl_sslsocket_send(ssl_sslsocket_obj_t *self, const uint8_t *buf, uint32_t len) { + int ret = mbedtls_ssl_write(&self->ssl, buf, len); + DEBUG("send mbedtls_ssl_write() -> %d\n", ret); + if (ret >= 0) { + DEBUG("returning %d\n", ret); + return ret; + } + if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + ret = MP_EWOULDBLOCK; + } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) { + // If handshake is not finished, write attempt may end up in protocol + // wanting to read next handshake message. The same may happen with + // renegotation. + ret = MP_EWOULDBLOCK; + } + DEBUG("returning [error case] %d\n", -ret); + return -ret; +} + +bool common_hal_ssl_sslsocket_bind(ssl_sslsocket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_ssl_sslsocket_close(ssl_sslsocket_obj_t *self) { + self->closed = true; + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); +} + +void common_hal_ssl_sslsocket_connect(ssl_sslsocket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { + common_hal_socketpool_socket_connect(self->sock, host, hostlen, port); + int ret; + while ((ret = mbedtls_ssl_handshake(&self->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + goto cleanup; + } + RUN_BACKGROUND_TASKS; + if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { + mp_handle_pending(true); + } + mp_hal_delay_ms(1); + } + + return; + +cleanup: + self->closed = true; + mbedtls_pk_free(&self->pkey); + mbedtls_x509_crt_free(&self->cert); + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + + if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { + mp_raise_OSError(MP_ENOMEM); + } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid key")); + } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid cert")); + } else { + mbedtls_raise_error(ret); + } +} + +bool common_hal_ssl_sslsocket_get_closed(ssl_sslsocket_obj_t *self) { + return self->closed; +} + +bool common_hal_ssl_sslsocket_get_connected(ssl_sslsocket_obj_t *self) { + return !self->closed; +} + +bool common_hal_ssl_sslsocket_listen(ssl_sslsocket_obj_t *self, int backlog) { + mp_raise_NotImplementedError(NULL); +} + +ssl_sslsocket_obj_t *common_hal_ssl_sslsocket_accept(ssl_sslsocket_obj_t *self, uint8_t *ip, uint32_t *port) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_ssl_sslsocket_settimeout(ssl_sslsocket_obj_t *self, uint32_t timeout_ms) { + self->sock->timeout = timeout_ms; +} diff --git a/ports/raspberrypi/common-hal/ssl/SSLSocket.h b/ports/raspberrypi/common-hal/ssl/SSLSocket.h new file mode 100644 index 0000000000..ad4f0f7092 --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/SSLSocket.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Lucian Copeland for Adafruit Industries + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +#include "common-hal/ssl/SSLContext.h" +#include "common-hal/socketpool/Socket.h" + +#include "mbedtls/platform.h" +#include "mbedtls/ssl.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/pk.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" + +typedef struct { + mp_obj_base_t base; + socketpool_socket_obj_t *sock; + ssl_sslcontext_obj_t *ssl_context; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt cacert; + mbedtls_x509_crt cert; + mbedtls_pk_context pkey; + bool closed; +} ssl_sslsocket_obj_t; diff --git a/ports/raspberrypi/common-hal/ssl/__init__.c b/ports/raspberrypi/common-hal/ssl/__init__.c new file mode 100644 index 0000000000..79cb360e85 --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/__init__.c @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/ssl/__init__.h" +#include "shared-bindings/ssl/SSLContext.h" + +void common_hal_ssl_create_default_context(ssl_sslcontext_obj_t *self) { +} diff --git a/ports/raspberrypi/common-hal/ssl/__init__.h b/ports/raspberrypi/common-hal/ssl/__init__.h new file mode 100644 index 0000000000..0bfe0789ec --- /dev/null +++ b/ports/raspberrypi/common-hal/ssl/__init__.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once diff --git a/ports/raspberrypi/mbedtls/mbedtls_config.h b/ports/raspberrypi/mbedtls/mbedtls_config.h new file mode 100644 index 0000000000..4fe4f8640e --- /dev/null +++ b/ports/raspberrypi/mbedtls/mbedtls_config.h @@ -0,0 +1,115 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_H +#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H + +// If you want to debug MBEDTLS uncomment the following and +// Pass 3 to mbedtls_debug_set_threshold in socket_new +// #define MBEDTLS_DEBUG_C + +// Set mbedtls configuration +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED +#define MBEDTLS_ENTROPY_HARDWARE_ALT +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_PROTO_TLS1_1 +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +// Use a smaller output buffer to reduce size of SSL context +#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384) +#define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN) +#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096) + +// Enable mbedtls modules +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_MD5_C +#define MBEDTLS_OID_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +// Memory allocation hooks +#include +#include +void *m_tracked_calloc(size_t nmemb, size_t size); +void m_tracked_free(void *ptr); +#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc +#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf + +// Time hook +#include +time_t rp2_rtctime_seconds(time_t *timer); +#define MBEDTLS_PLATFORM_TIME_MACRO rp2_rtctime_seconds + +#include "mbedtls/check_config.h" + +#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ diff --git a/ports/raspberrypi/mbedtls/mbedtls_port.c b/ports/raspberrypi/mbedtls/mbedtls_port.c new file mode 100644 index 0000000000..596d08ccd9 --- /dev/null +++ b/ports/raspberrypi/mbedtls/mbedtls_port.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#if CIRCUITPY_SSL_MBEDTLS + +#include "mbedtls_config.h" +#include "mbedtls/entropy_poll.h" + +#include "hardware/rtc.h" +#include "shared/timeutils/timeutils.h" +#include "shared-bindings/os/__init__.h" + +extern uint8_t rosc_random_u8(size_t cycles); + +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { + *olen = len; + common_hal_os_urandom(data, len); + return 0; +} + +time_t rp2_rtctime_seconds(time_t *timer) { + datetime_t t; + rtc_get_datetime(&t); + return timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.min, t.sec); +} + +#endif diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index e09c17d85e..6ae8275058 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -73,6 +73,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_ENABLE_DOC_STRING (0) #define MICROPY_ENABLE_FINALISER (1) #define MICROPY_ENABLE_GC (1) +#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_EPOCH_IS_1970 (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 96165997ce..2e7ac2e1d8 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -388,6 +388,10 @@ CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL) CIRCUITPY_SSL ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_SSL=$(CIRCUITPY_SSL) +CIRCUITPY_SSL_MBEDTLS ?= 0 +CFLAGS += -DCIRCUITPY_SSL_MBEDTLS=$(CIRCUITPY_SSL_MBEDTLS) + +# Currently always off. CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) diff --git a/py/malloc.c b/py/malloc.c index 5c09a2d283..7200285687 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -207,6 +207,99 @@ void m_free(void *ptr) { #endif } +#if MICROPY_TRACKED_ALLOC + +#define MICROPY_TRACKED_ALLOC_STORE_SIZE (!MICROPY_ENABLE_GC) + +typedef struct _m_tracked_node_t { + struct _m_tracked_node_t *prev; + struct _m_tracked_node_t *next; + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + uintptr_t size; + #endif + uint8_t data[]; +} m_tracked_node_t; + +#if MICROPY_DEBUG_VERBOSE +STATIC size_t m_tracked_count_links(size_t *nb) { + m_tracked_node_t *node = MP_STATE_VM(m_tracked_head); + size_t n = 0; + *nb = 0; + while (node != NULL) { + ++n; + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + *nb += node->size; + #else + *nb += gc_nbytes(node); + #endif + node = node->next; + } + return n; +} +#endif + +void *m_tracked_calloc(size_t nmemb, size_t size) { + m_tracked_node_t *node = m_malloc_maybe(sizeof(m_tracked_node_t) + nmemb * size, false); + if (node == NULL) { + return NULL; + } + #if MICROPY_DEBUG_VERBOSE + size_t nb; + size_t n = m_tracked_count_links(&nb); + DEBUG_printf("m_tracked_calloc(%u, %u) -> (%u;%u) %p\n", (int)nmemb, (int)size, (int)n, (int)nb, node); + #endif + if (MP_STATE_VM(m_tracked_head) != NULL) { + MP_STATE_VM(m_tracked_head)->prev = node; + } + node->prev = NULL; + node->next = MP_STATE_VM(m_tracked_head); + MP_STATE_VM(m_tracked_head) = node; + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + node->size = nmemb * size; + #endif + #if !MICROPY_GC_CONSERVATIVE_CLEAR + memset(&node->data[0], 0, nmemb * size); + #endif + return &node->data[0]; +} + +void m_tracked_free(void *ptr_in) { + if (ptr_in == NULL) { + return; + } + m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); + #if MICROPY_DEBUG_VERBOSE + size_t data_bytes; + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + data_bytes = node->size; + #else + data_bytes = gc_nbytes(node); + #endif + size_t nb; + size_t n = m_tracked_count_links(&nb); + DEBUG_printf("m_tracked_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)data_bytes, (int)n, (int)nb); + #endif + if (node->next != NULL) { + node->next->prev = node->prev; + } + if (node->prev != NULL) { + node->prev->next = node->next; + } else { + MP_STATE_VM(m_tracked_head) = node->next; + } + m_free(node + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + #if MICROPY_TRACKED_ALLOC_STORE_SIZE + , node->size + #else + , gc_nbytes(node) + #endif + #endif + ); +} + +#endif + #if MICROPY_MEM_STATS size_t m_get_total_bytes_allocated(void) { return MP_STATE_MEM(total_bytes_allocated); diff --git a/py/misc.h b/py/misc.h index 8f2d3a187a..1ced7c622e 100644 --- a/py/misc.h +++ b/py/misc.h @@ -112,6 +112,13 @@ void m_free(void *ptr); #endif NORETURN void m_malloc_fail(size_t num_bytes); +#if MICROPY_TRACKED_ALLOC +// These alloc/free functions track the pointers in a linked list so the GC does not reclaim +// them. They can be used by code that requires traditional C malloc/free semantics. +void *m_tracked_calloc(size_t nmemb, size_t size); +void m_tracked_free(void *ptr_in); +#endif + #if MICROPY_MEM_STATS size_t m_get_total_bytes_allocated(void); size_t m_get_current_bytes_allocated(void); diff --git a/py/mpstate.h b/py/mpstate.h index bfbc29d55a..cf1711b8ad 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -119,6 +119,10 @@ typedef struct _mp_state_vm_t { qstr_pool_t *last_pool; + #if MICROPY_TRACKED_ALLOC + struct _m_tracked_node_t *m_tracked_head; + #endif + // non-heap memory for creating a traceback if we can't allocate RAM mp_obj_traceback_t mp_emergency_traceback_obj; diff --git a/shared-bindings/ssl/SSLSocket.h b/shared-bindings/ssl/SSLSocket.h index d6519340d9..0c303e44c7 100644 --- a/shared-bindings/ssl/SSLSocket.h +++ b/shared-bindings/ssl/SSLSocket.h @@ -38,7 +38,7 @@ void common_hal_ssl_sslsocket_connect(ssl_sslsocket_obj_t *self, const char *hos bool common_hal_ssl_sslsocket_get_closed(ssl_sslsocket_obj_t *self); bool common_hal_ssl_sslsocket_get_connected(ssl_sslsocket_obj_t *self); bool common_hal_ssl_sslsocket_listen(ssl_sslsocket_obj_t *self, int backlog); -mp_uint_t common_hal_ssl_sslsocket_recv_into(ssl_sslsocket_obj_t *self, const uint8_t *buf, uint32_t len); +mp_uint_t common_hal_ssl_sslsocket_recv_into(ssl_sslsocket_obj_t *self, uint8_t *buf, uint32_t len); mp_uint_t common_hal_ssl_sslsocket_send(ssl_sslsocket_obj_t *self, const uint8_t *buf, uint32_t len); void common_hal_ssl_sslsocket_settimeout(ssl_sslsocket_obj_t *self, uint32_t timeout_ms); diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py index 55985ffe15..0b44f07402 100644 --- a/tools/ci_fetch_deps.py +++ b/tools/ci_fetch_deps.py @@ -32,6 +32,7 @@ port_deps = { "raspberrypi": [ "extmod/ulab/", "lib/adafruit_floppy/", + "lib/mbedtls/", "lib/mp3/", "lib/protomatter/", "lib/quirc/",