From fabfdcf6fe9e45b30014180c72d69c31c428323c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 5 Oct 2022 14:32:30 -0500 Subject: [PATCH] More ssl work --- ports/raspberrypi/Makefile | 11 +- ports/raspberrypi/common-hal/ssl/SSLContext.c | 13 +- ports/raspberrypi/common-hal/ssl/SSLContext.h | 6 +- ports/raspberrypi/common-hal/ssl/SSLSocket.c | 11 +- ports/raspberrypi/common-hal/ssl/__init__.c | 7 + ports/raspberrypi/common-hal/ssl/__init__.h | 2 + .../{esp_crt_bundle.c => crt_bundle.c} | 128 +++++++++--------- ports/raspberrypi/mbedtls/crt_bundle.h | 21 +++ ports/raspberrypi/supervisor/port.c | 8 ++ 9 files changed, 138 insertions(+), 69 deletions(-) rename ports/raspberrypi/mbedtls/{esp_crt_bundle.c => crt_bundle.c} (59%) create mode 100644 ports/raspberrypi/mbedtls/crt_bundle.h diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 506b19a795..bee6650577 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -350,12 +350,17 @@ SRC_MBEDTLS := $(addprefix lib/mbedtls/library/, \ x509write_csr.c \ xtea.c \ ) -SRC_C += $(SRC_MBEDTLS) mbedtls/mbedtls_port.c +SRC_C += $(SRC_MBEDTLS) mbedtls/mbedtls_port.c mbedtls/crt_bundle.c CFLAGS += \ -isystem $(TOP)/lib/mbedtls/include \ -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"' \ +$(BUILD)/x509_crt_bundle.S: $(TOP)/lib/certificates/nina-fw/data/roots.pem $(TOP)/tools/gen_crt_bundle.py + $(Q)$(PYTHON) $(TOP)/tools/gen_crt_bundle.py -i $< -o $@ --asm +OBJ_MBEDTLS := $(BUILD)/x509_crt_bundle.o $(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS))): CFLAGS += -Wno-suggest-attribute=format +else +OBJ_MBEDTLS := endif SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ @@ -396,9 +401,9 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/boot2_padded_checksummed.o -OBJ += $(OBJ_CYW43) +OBJ += $(OBJ_CYW43) $(OBJ_MBEDTLS) -$(BUILD)/boot2_padded_checksummed.o: $(BUILD)/boot2_padded_checksummed.S +$(BUILD)/%.o: $(BUILD)/%.S $(STEPECHO) "CC $<" $(Q)$(CC) $(CFLAGS) -c -o $@ $< diff --git a/ports/raspberrypi/common-hal/ssl/SSLContext.c b/ports/raspberrypi/common-hal/ssl/SSLContext.c index 90f26a3830..22d26b2da3 100644 --- a/ports/raspberrypi/common-hal/ssl/SSLContext.c +++ b/ports/raspberrypi/common-hal/ssl/SSLContext.c @@ -31,16 +31,27 @@ #include "py/runtime.h" #include "py/stream.h" +#include "mbedtls/crt_bundle.h" + void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t *self) { + common_hal_ssl_sslcontext_set_default_verify_paths(self); } void common_hal_ssl_sslcontext_load_verify_locations(ssl_sslcontext_obj_t *self, const char *cadata) { mp_raise_NotImplementedError(NULL); + + // self->crt_bundle_attach = NULL; + // self->use_global_ca_store = false; + // self->cacert_buf = (const unsigned char *)cadata; + // self->cacert_bytes = strlen(cadata) + 1; } void common_hal_ssl_sslcontext_set_default_verify_paths(ssl_sslcontext_obj_t *self) { - mp_raise_NotImplementedError(NULL); + self->crt_bundle_attach = crt_bundle_attach; + self->use_global_ca_store = true; + self->cacert_buf = NULL; + self->cacert_bytes = 0; } bool common_hal_ssl_sslcontext_get_check_hostname(ssl_sslcontext_obj_t *self) { diff --git a/ports/raspberrypi/common-hal/ssl/SSLContext.h b/ports/raspberrypi/common-hal/ssl/SSLContext.h index dc8caba089..33c683951b 100644 --- a/ports/raspberrypi/common-hal/ssl/SSLContext.h +++ b/ports/raspberrypi/common-hal/ssl/SSLContext.h @@ -28,8 +28,12 @@ #pragma once #include "py/obj.h" +#include "mbedtls/ssl.h" typedef struct { mp_obj_base_t base; - bool check_name; + bool check_name, use_global_ca_store; + const unsigned char *cacert_buf; + size_t cacert_bytes; + int (*crt_bundle_attach)(mbedtls_ssl_config *conf); } ssl_sslcontext_obj_t; diff --git a/ports/raspberrypi/common-hal/ssl/SSLSocket.c b/ports/raspberrypi/common-hal/ssl/SSLSocket.c index ab6ab04711..53434f8b92 100644 --- a/ports/raspberrypi/common-hal/ssl/SSLSocket.c +++ b/ports/raspberrypi/common-hal/ssl/SSLSocket.c @@ -171,8 +171,15 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t goto cleanup; } - // no certificate checking now - mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); + if (self->crt_bundle_attach != NULL) { + mp_printf(&mp_plat_print, "attaching bundle\n"); + mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + self->crt_bundle_attach(&o->conf); + // } else if(self->cacert_buf && self->cacert_bytes) { // TODO: user bundle + } else { + mp_printf(&mp_plat_print, "yolo\n"); + 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); diff --git a/ports/raspberrypi/common-hal/ssl/__init__.c b/ports/raspberrypi/common-hal/ssl/__init__.c index 79cb360e85..a59898b957 100644 --- a/ports/raspberrypi/common-hal/ssl/__init__.c +++ b/ports/raspberrypi/common-hal/ssl/__init__.c @@ -25,8 +25,15 @@ * THE SOFTWARE. */ +#include "common-hal/ssl/__init__.h" #include "shared-bindings/ssl/__init__.h" #include "shared-bindings/ssl/SSLContext.h" +#include "mbedtls/crt_bundle.h" void common_hal_ssl_create_default_context(ssl_sslcontext_obj_t *self) { + common_hal_ssl_sslcontext_construct(self); +} + +void ssl_reset(void) { + crt_bundle_detach(NULL); } diff --git a/ports/raspberrypi/common-hal/ssl/__init__.h b/ports/raspberrypi/common-hal/ssl/__init__.h index 0bfe0789ec..6f1757ee47 100644 --- a/ports/raspberrypi/common-hal/ssl/__init__.h +++ b/ports/raspberrypi/common-hal/ssl/__init__.h @@ -25,3 +25,5 @@ */ #pragma once + +void ssl_reset(void); diff --git a/ports/raspberrypi/mbedtls/esp_crt_bundle.c b/ports/raspberrypi/mbedtls/crt_bundle.c similarity index 59% rename from ports/raspberrypi/mbedtls/esp_crt_bundle.c rename to ports/raspberrypi/mbedtls/crt_bundle.c index 65e2fa925d..7fce35872b 100644 --- a/ports/raspberrypi/mbedtls/esp_crt_bundle.c +++ b/ports/raspberrypi/mbedtls/crt_bundle.c @@ -1,4 +1,5 @@ // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2022 Jeff Epler for Adafruit Industries // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,24 +13,35 @@ // See the License for the specific language governing permissions and // limitations under the License. +#define BUNDLE_MAX_CERTS (200) #include -#include -#include "esp_crt_bundle.h" -#include "esp_log.h" + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/crt_bundle.h" #define BUNDLE_HEADER_OFFSET 2 #define CRT_HEADER_OFFSET 4 -static const char *TAG = "esp-x509-crt-bundle"; - /* a dummy certificate so that * cacert_ptr passes non-NULL check during handshake */ static mbedtls_x509_crt s_dummy_crt; +#define TAG "x509-crt-bundle" -extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_bundle_start"); -extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end"); +#define LOGE(tag, fmt, ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__) +#if 0 +#define LOGI(tag, fmt, ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__) +#define LOGD(tag, fmt, ...) mp_printf(&mp_plat_print, tag ":" fmt "\n",##__VA_ARGS__) +#else +#define LOGI(tag, fmt, ...) do {} while (0) +#define LOGD(tag, fmt, ...) do {} while (0) +#endif + +extern const uint8_t x509_crt_imported_bundle_bin_start[] asm ("_binary_x509_crt_bundle_start"); +extern const uint8_t x509_crt_imported_bundle_bin_end[] asm ("_binary_x509_crt_bundle_end"); typedef struct crt_bundle_t { @@ -40,11 +52,10 @@ typedef struct crt_bundle_t { static crt_bundle_t s_crt_bundle; -static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len); +static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len); -static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len) -{ +static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len) { int ret = 0; mbedtls_x509_crt parent; const mbedtls_md_info_t *md_info; @@ -52,30 +63,30 @@ static int esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_k mbedtls_x509_crt_init(&parent); - if ( (ret = mbedtls_pk_parse_public_key(&parent.pk, pub_key_buf, pub_key_len) ) != 0) { - ESP_LOGE(TAG, "PK parse failed with error %X", ret); + if ((ret = mbedtls_pk_parse_public_key(&parent.pk, pub_key_buf, pub_key_len)) != 0) { + LOGE(TAG, "PK parse failed with error %X", ret); goto cleanup; } // Fast check to avoid expensive computations when not necessary if (!mbedtls_pk_can_do(&parent.pk, child->sig_pk)) { - ESP_LOGE(TAG, "Simple compare failed"); + LOGE(TAG, "Simple compare failed"); ret = -1; goto cleanup; } md_info = mbedtls_md_info_from_type(child->sig_md); - if ( (ret = mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash )) != 0 ) { - ESP_LOGE(TAG, "Internal mbedTLS error %X", ret); + if ((ret = mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash)) != 0) { + LOGE(TAG, "Internal mbedTLS error %X", ret); goto cleanup; } - if ( (ret = mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent.pk, - child->sig_md, hash, mbedtls_md_get_size( md_info ), - child->sig.p, child->sig.len )) != 0 ) { + if ((ret = mbedtls_pk_verify_ext(child->sig_pk, child->sig_opts, &parent.pk, + child->sig_md, hash, mbedtls_md_get_size(md_info), + child->sig.p, child->sig.len)) != 0) { - ESP_LOGE(TAG, "PK verify failed with error %X", ret); + LOGE(TAG, "PK verify failed with error %X", ret); goto cleanup; } cleanup: @@ -91,8 +102,7 @@ cleanup: * only verify the first untrusted link in the chain is signed by the * root certificate in the trusted bundle */ -int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_t *flags) -{ +static int crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { mbedtls_x509_crt *child = crt; /* It's OK for a trusted cert to have a weak signature hash alg. @@ -105,11 +115,11 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_ if (s_crt_bundle.crts == NULL) { - ESP_LOGE(TAG, "No certificates in bundle"); + LOGE(TAG, "No certificates in bundle"); return MBEDTLS_ERR_X509_FATAL_ERROR; } - ESP_LOGD(TAG, "%d certificates in bundle", s_crt_bundle.num_certs); + LOGD(TAG, "%d certificates in bundle", s_crt_bundle.num_certs); size_t name_len = 0; const uint8_t *crt_name; @@ -124,7 +134,7 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_ name_len = s_crt_bundle.crts[middle][0] << 8 | s_crt_bundle.crts[middle][1]; crt_name = s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET; - int cmp_res = memcmp(child->issuer_raw.p, crt_name, name_len ); + int cmp_res = memcmp(child->issuer_raw.p, crt_name, name_len); if (cmp_res == 0) { crt_found = true; break; @@ -139,16 +149,16 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_ int ret = MBEDTLS_ERR_X509_FATAL_ERROR; if (crt_found) { size_t key_len = s_crt_bundle.crts[middle][2] << 8 | s_crt_bundle.crts[middle][3]; - ret = esp_crt_check_signature(child, s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET + name_len, key_len); + ret = crt_check_signature(child, s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET + name_len, key_len); } if (ret == 0) { - ESP_LOGI(TAG, "Certificate validated"); + LOGI(TAG, "Certificate validated"); *flags = 0; return 0; } - ESP_LOGE(TAG, "Failed to verify certificate"); + LOGE(TAG, "Failed to verify certificate"); return MBEDTLS_ERR_X509_FATAL_ERROR; } @@ -156,25 +166,24 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_ /* Initialize the bundle into an array so we can do binary search for certs, the bundle generated by the python utility is already presorted by subject name */ -static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_size) -{ +static err_t crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_size) { if (bundle_size < BUNDLE_HEADER_OFFSET + CRT_HEADER_OFFSET) { - ESP_LOGE(TAG, "Invalid certificate bundle"); - return ESP_ERR_INVALID_ARG; + LOGE(TAG, "Invalid certificate bundle"); + return -MP_EINVAL; } uint16_t num_certs = (x509_bundle[0] << 8) | x509_bundle[1]; - if (num_certs > CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS) { - ESP_LOGE(TAG, "No. of certs in the certificate bundle = %d exceeds\n" - "Max allowed certificates in the certificate bundle = %d\n" - "Please update the menuconfig option with appropriate value", num_certs, CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS); - return ESP_ERR_INVALID_ARG; + if (num_certs > BUNDLE_MAX_CERTS) { + // No. of certs in the certificate bundle = %d exceeds\n" + // Max allowed certificates in the certificate bundle = %d\n" + // Please update the menuconfig option with appropriate value", num_certs, BUNDLE_MAX_CERTS + return -MP_E2BIG; } - const uint8_t **crts = calloc(num_certs, sizeof(x509_bundle)); + const uint8_t **crts = m_tracked_calloc(num_certs, sizeof(x509_bundle)); if (crts == NULL) { - ESP_LOGE(TAG, "Unable to allocate memory for bundle"); - return ESP_ERR_NO_MEM; + LOGE(TAG, "Unable to allocate memory for bundle"); + return -MP_ENOMEM; } const uint8_t *cur_crt; @@ -185,9 +194,9 @@ static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_s for (int i = 0; i < num_certs; i++) { crts[i] = cur_crt; if (cur_crt + CRT_HEADER_OFFSET > bundle_end) { - ESP_LOGE(TAG, "Invalid certificate bundle"); - free(crts); - return ESP_ERR_INVALID_ARG; + LOGE(TAG, "Invalid certificate bundle"); + m_tracked_free(crts); + return -MP_EINVAL; } size_t name_len = cur_crt[0] << 8 | cur_crt[1]; size_t key_len = cur_crt[2] << 8 | cur_crt[3]; @@ -195,57 +204,52 @@ static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_s } if (cur_crt > bundle_end) { - ESP_LOGE(TAG, "Invalid certificate bundle"); - free(crts); - return ESP_ERR_INVALID_ARG; + LOGE(TAG, "Invalid certificate bundle"); + m_tracked_free(crts); + return -MP_EINVAL; } /* The previous crt bundle is only updated when initialization of the * current crt_bundle is successful */ /* Free previous crt_bundle */ - free(s_crt_bundle.crts); + m_tracked_free(s_crt_bundle.crts); s_crt_bundle.num_certs = num_certs; s_crt_bundle.crts = crts; - return ESP_OK; + return 0; } -esp_err_t esp_crt_bundle_attach(void *conf) -{ - esp_err_t ret = ESP_OK; +int crt_bundle_attach(mbedtls_ssl_config *ssl_conf) { + int ret = 0; // If no bundle has been set by the user then use the bundle embedded in the binary if (s_crt_bundle.crts == NULL) { - ret = esp_crt_bundle_init(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start); + ret = crt_bundle_init(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start); } - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to attach bundle"); + if (ret != 0) { return ret; } - if (conf) { + if (ssl_conf) { /* point to a dummy certificate * This is only required so that the * cacert_ptr passes non-NULL check during handshake */ - mbedtls_ssl_config *ssl_conf = (mbedtls_ssl_config *)conf; mbedtls_x509_crt_init(&s_dummy_crt); mbedtls_ssl_conf_ca_chain(ssl_conf, &s_dummy_crt, NULL); - mbedtls_ssl_conf_verify(ssl_conf, esp_crt_verify_callback, NULL); + mbedtls_ssl_conf_verify(ssl_conf, crt_verify_callback, NULL); } return ret; } -void esp_crt_bundle_detach(mbedtls_ssl_config *conf) -{ - free(s_crt_bundle.crts); +void crt_bundle_detach(mbedtls_ssl_config *conf) { + m_tracked_free(s_crt_bundle.crts); s_crt_bundle.crts = NULL; if (conf) { mbedtls_ssl_conf_verify(conf, NULL, NULL); } } -esp_err_t esp_crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size) -{ - return esp_crt_bundle_init(x509_bundle, bundle_size); +int crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size) { + return crt_bundle_init(x509_bundle, bundle_size); } diff --git a/ports/raspberrypi/mbedtls/crt_bundle.h b/ports/raspberrypi/mbedtls/crt_bundle.h new file mode 100644 index 0000000000..b265ae4abe --- /dev/null +++ b/ports/raspberrypi/mbedtls/crt_bundle.h @@ -0,0 +1,21 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2022 Jeff Epler for Adafruit Industries +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "mbedtls/ssl.h" + +int crt_bundle_attach(mbedtls_ssl_config *conf); +void crt_bundle_detach(mbedtls_ssl_config *conf); +int crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size); diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 94e57c2028..781d2b11d2 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -41,6 +41,10 @@ #include "shared-bindings/rtc/__init__.h" #include "shared-bindings/pwmio/PWMOut.h" +#if CIRCUITPY_SSL +#include "common-hal/ssl/__init__.h" +#endif + #if CIRCUITPY_WIFI #include "common-hal/wifi/__init__.h" #endif @@ -179,6 +183,10 @@ void reset_port(void) { audio_dma_reset(); #endif + #if CIRCUITPY_SSL + ssl_reset(); + #endif + #if CIRCUITPY_WIFI wifi_reset(); #endif