From f8fe24057df87a901c7559033cc5366b883c92b7 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 26 Jul 2022 04:28:02 +0100 Subject: [PATCH 01/20] extmod/modussl_mbedtls: Implement SSLContext. This implements ssl.ctx_init() and SSLContext methods: - get_ciphers() - set_ciphers() - load_cadata() - load_certchain() - wrap_socket() * ssl.MBEDTLS_VERSION * _SSLSocket.cipher() * extmod/ssl module with SSLContext CPython compliant. * SSLContext tests in multi_net and net_inet Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 435 +++++++++++++++++++++- extmod/ssl/__init__.py | 1 + extmod/ssl/manifest.py | 1 + extmod/ssl/ssl.py | 114 ++++++ ports/unix/variants/manifest.py | 3 + tests/multi_net/ssl_context_rsa.py | 160 ++++++++ tests/multi_net/ssl_context_rsa.py.exp | 4 + tests/net_inet/test_ssl_context_client.py | 104 ++++++ 8 files changed, 821 insertions(+), 1 deletion(-) create mode 100644 extmod/ssl/__init__.py create mode 100644 extmod/ssl/manifest.py create mode 100644 extmod/ssl/ssl.py create mode 100644 tests/multi_net/ssl_context_rsa.py create mode 100644 tests/multi_net/ssl_context_rsa.py.exp create mode 100644 tests/net_inet/test_ssl_context_client.py diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index e346f986f77f2..e044e8a04f045 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -45,6 +45,10 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/debug.h" #include "mbedtls/error.h" +// #if MICROPY_SSL_MBEDTLS_3 +// #include "mbedtls/build_info.h" +// #endif +#include "mbedtls/version.h" #define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR) @@ -63,6 +67,21 @@ typedef struct _mp_obj_ssl_socket_t { int last_error; // The last error code, if any } mp_obj_ssl_socket_t; + +typedef struct _mp_obj_ssl_context_t { + mp_obj_base_t base; + mp_obj_t sock; + 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; + int cipherid; +} mp_obj_ssl_context_t; + + struct ssl_args { mp_arg_val_t key; mp_arg_val_t cert; @@ -73,8 +92,17 @@ struct ssl_args { mp_arg_val_t do_handshake; }; -STATIC const mp_obj_type_t ssl_socket_type; +struct ctx_ws_args { + mp_arg_val_t server_side; + mp_arg_val_t server_hostname; + mp_arg_val_t cert_reqs; + mp_arg_val_t do_handshake; +}; + +STATIC const mp_obj_type_t ssl_socket_type; +STATIC const mp_obj_type_t ssl_context_type; +STATIC const MP_DEFINE_STR_OBJ(mbedtls_version_obj, MBEDTLS_VERSION_STRING_FULL); #ifdef MBEDTLS_DEBUG_C STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { (void)ctx; @@ -158,6 +186,396 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } } +// SSLContext +STATIC mp_obj_ssl_context_t *context_new() { + #if MICROPY_PY_USSL_FINALISER + mp_obj_ssl_context_t *ctxi = m_new_obj_with_finaliser(mp_obj_ssl_context_t); + #else + mp_obj_ssl_context_t *ctxi = m_new_obj(mp_obj_ssl_context_t); + #endif + ctxi->base.type = &ssl_context_type; + ctxi->cipherid = 0; + // o->sock = sock; + int ret; + + mbedtls_ssl_init(&ctxi->ssl); + mbedtls_ssl_config_init(&ctxi->conf); + mbedtls_x509_crt_init(&ctxi->cacert); + mbedtls_x509_crt_init(&ctxi->cert); + mbedtls_pk_init(&ctxi->pkey); + mbedtls_ctr_drbg_init(&ctxi->ctr_drbg); + #ifdef MBEDTLS_DEBUG_C + // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose + mbedtls_debug_set_threshold(3); + #endif + + mbedtls_entropy_init(&ctxi->entropy); + const byte seed[] = "upy"; + ret = mbedtls_ctr_drbg_seed(&ctxi->ctr_drbg, mbedtls_entropy_func, &ctxi->entropy, seed, sizeof(seed)); + if (ret != 0) { + goto cleanupctx; + } + + return ctxi; + + +cleanupctx: + + mbedtls_pk_free(&ctxi->pkey); + mbedtls_x509_crt_free(&ctxi->cert); + mbedtls_x509_crt_free(&ctxi->cacert); + mbedtls_ssl_free(&ctxi->ssl); + mbedtls_ssl_config_free(&ctxi->conf); + mbedtls_ctr_drbg_free(&ctxi->ctr_drbg); + mbedtls_entropy_free(&ctxi->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); + } + + + + +} + +STATIC void context_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<_SSLContext %p>", self); +} + +STATIC mp_obj_t mod_ssl_get_ciphers() { + mp_obj_t list = mp_obj_new_list(0, NULL); + const int *cipher_list = mbedtls_ssl_list_ciphersuites(); + // int len_cipher_list = sizeof(cipher_list); + + // for (int i = 0; i <= len_cipher_list; i++) + while (*cipher_list) { + const char *cipher_name = mbedtls_ssl_get_ciphersuite_name(*cipher_list); + mp_obj_list_append(list, + MP_OBJ_FROM_PTR(mp_obj_new_str(cipher_name, + strlen(cipher_name)))); + cipher_list++; + if (!*cipher_list) { + break; + } + + } + + return list; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ssl_get_ciphers_obj, mod_ssl_get_ciphers); + + +STATIC mp_obj_t mod_ssl_set_ciphers(mp_obj_t self_in, mp_obj_t ciphersuite) { + + mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(self_in); + + int ret = 0; + if (ciphersuite != mp_const_none) { + const char *ciphername = mp_obj_str_get_str(ciphersuite); + const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); + // const int ciphers[] = {id, 0}; + ctxi->cipherid = id; + if (id == 0) { + ret = MBEDTLS_ERR_SSL_BAD_CONFIG; + goto cleanupcipher; + } + + // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); + // ctxi->cipherid = id; + } + + return mp_const_none; + +cleanupcipher: + + mbedtls_raise_error(ret); + + +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_set_ciphers_obj, mod_ssl_set_ciphers); + + + +STATIC mp_obj_t mod_ssl_load_certchain(size_t n_args, const mp_obj_t *pos_args, + mp_map_t *kw_args) { + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + + mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(pos_args[0]); + // struct cert_chain_args args; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, + args); + int ret; + ret = 0; + if (args[0].u_obj != mp_const_none) { + size_t key_len; + const byte *key = (const byte *)mp_obj_str_get_data(args[0].u_obj, &key_len); + // len should include terminating null + ret = mbedtls_pk_parse_key(&ctxi->pkey, key, key_len + 1, NULL, 0); + if (ret != 0) { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors + goto cleanupcertchain; + } + + size_t cert_len; + const byte *cert = (const byte *)mp_obj_str_get_data(args[1].u_obj, &cert_len); + // len should include terminating null + ret = mbedtls_x509_crt_parse(&ctxi->cert, cert, cert_len + 1); + if (ret != 0) { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors + goto cleanupcertchain; + } + + ret = mbedtls_ssl_conf_own_cert(&ctxi->conf, &ctxi->cert, &ctxi->pkey); + if (ret != 0) { + goto cleanupcertchain; + } + } + + return mp_const_none; + +cleanupcertchain: + + mbedtls_ssl_config_free(&ctxi->conf); + mbedtls_pk_free(&ctxi->pkey); + mbedtls_x509_crt_free(&ctxi->cert); + + + 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); + } + + +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_load_certchain_obj, 1, mod_ssl_load_certchain); + + +STATIC mp_obj_t mod_ssl_load_cadata(mp_obj_t self_in, mp_obj_t cadata) { + mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(self_in); + int ret; + ret = 0; + if (cadata != mp_const_none) { + size_t cacert_len; + const byte *cacert = (const byte *)mp_obj_str_get_data(cadata, &cacert_len); + // len should include terminating null + ret = mbedtls_x509_crt_parse(&ctxi->cacert, cacert, cacert_len + 1); + if (ret != 0) { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors + goto cleanupcadata; + } + + mbedtls_ssl_conf_ca_chain(&ctxi->conf, &ctxi->cacert, NULL); + } + + return mp_const_none; + +cleanupcadata: + + mbedtls_x509_crt_free(&ctxi->cacert); + mbedtls_ssl_config_free(&ctxi->conf); + + + 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); + } + + +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_load_cadata_obj, mod_ssl_load_cadata); + + + + +STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct ctx_ws_args *args) { + // 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); + mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(self_in); + #if MICROPY_PY_USSL_FINALISER + mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); + #else + mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); + #endif + o->base.type = &ssl_socket_type; + o->sock = sock; + o->ssl = ctxi->ssl; + o->conf = ctxi->conf; + o->cacert = ctxi->cacert; + o->cert = ctxi->cert; + o->pkey = ctxi->pkey; + o->ctr_drbg = ctxi->ctr_drbg; + o->entropy = ctxi->entropy; + + int ret; + uint32_t flags = 0; + #ifdef MBEDTLS_DEBUG_C + // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose + mbedtls_debug_set_threshold(3); + #endif + + ret = mbedtls_ssl_config_defaults(&o->conf, + args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + goto cleanup; + } + // Ciphersuite Config + if (ctxi->cipherid != 0) { + const int ciphers[] = {ctxi->cipherid, 0}; + mbedtls_ssl_conf_ciphersuites(&o->conf, ciphers); + + } + + mbedtls_ssl_conf_authmode(&o->conf, args->cert_reqs.u_int); + 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 (args->server_hostname.u_obj != mp_const_none) { + const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); + ret = mbedtls_ssl_set_hostname(&o->ssl, sni); + if (ret != 0) { + goto cleanup; + } + } + + mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); + + + if (args->do_handshake.u_bool) { + while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + goto cleanup; + } + #ifdef MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK + #endif + } + } + + return o; + +cleanup: + + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + flags = mbedtls_ssl_get_verify_result(&o->ssl); + // ret = mbedtls_ssl_get_verify_result(&o->ssl); + + } + 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 if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + char xcbuf[512]; + ret = mbedtls_x509_crt_verify_info(xcbuf, sizeof(xcbuf), "\n", flags); + // The length of the string written (not including the terminated nul byte), + // or a negative err code. + if (ret > 0) { + mp_raise_ValueError(MP_ERROR_TEXT(xcbuf)); + } else { + mbedtls_raise_error(ret); + } + } else { + mbedtls_raise_error(ret); + } +} + +STATIC mp_obj_t mod_ssl_ctx_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO: Implement more args + static const mp_arg_t allowed_args[] = { + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MBEDTLS_SSL_VERIFY_NONE}}, + { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + + // TODO: Check that sock implements stream protocol + mp_obj_t self_in = pos_args[0]; + mp_obj_t sock = pos_args[1]; + + struct ctx_ws_args args; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); + + return MP_OBJ_FROM_PTR(ctx_socket(self_in, sock, &args)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_ctx_wrap_socket_obj, 1, mod_ssl_ctx_wrap_socket); + + +STATIC const mp_rom_map_elem_t ssl_context_locals_dict_table [] = { + { MP_ROM_QSTR(MP_QSTR_get_ciphers), MP_ROM_PTR(&mod_ssl_get_ciphers_obj)}, + { MP_ROM_QSTR(MP_QSTR_set_ciphers), MP_ROM_PTR(&mod_ssl_set_ciphers_obj)}, + { MP_ROM_QSTR(MP_QSTR_load_cadata), MP_ROM_PTR(&mod_ssl_load_cadata_obj)}, + { MP_ROM_QSTR(MP_QSTR_load_certchain), MP_ROM_PTR(&mod_ssl_load_certchain_obj)}, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_ctx_wrap_socket_obj)}, +}; + +STATIC MP_DEFINE_CONST_DICT(ssl_context_locals_dict, ssl_context_locals_dict_table); + +STATIC const mp_obj_type_t ssl_context_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_ssl_context, + .print = context_print, + .getiter = NULL, + .iternext = NULL, + .locals_dict = (void *)&ssl_context_locals_dict, +}; + + +STATIC mp_obj_t mod_ssl_ctx_init() { + // TODO: Implement class methods + return MP_OBJ_FROM_PTR(context_new()); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_ssl_ctx_init_obj, mod_ssl_ctx_init); + + STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { // Verify the socket object has the full stream protocol @@ -309,6 +727,18 @@ STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert); +STATIC mp_obj_t mod_ssl_cipher(mp_obj_t o_in) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + const char *cipher_suite = mbedtls_ssl_get_ciphersuite(&o->ssl); + const char *tls_version = mbedtls_ssl_get_version(&o->ssl); + mp_obj_t tuple[2] = {mp_obj_new_str(cipher_suite, strlen(cipher_suite)), + mp_obj_new_str(tls_version, strlen(tls_version))}; + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ssl_cipher_obj, mod_ssl_cipher); + + STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); @@ -453,6 +883,7 @@ STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, + { MP_ROM_QSTR(MP_QSTR_cipher), MP_ROM_PTR(&mod_ssl_cipher_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table); @@ -499,6 +930,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socke STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) }, { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, + { MP_ROM_QSTR(MP_QSTR_ctx_init), MP_ROM_PTR(&mod_ssl_ctx_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_MBEDTLS_VERSION), MP_ROM_PTR(&mbedtls_version_obj)}, { 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) }, diff --git a/extmod/ssl/__init__.py b/extmod/ssl/__init__.py new file mode 100644 index 0000000000000..2e2a2a42f3f52 --- /dev/null +++ b/extmod/ssl/__init__.py @@ -0,0 +1 @@ +from .ssl import * diff --git a/extmod/ssl/manifest.py b/extmod/ssl/manifest.py new file mode 100644 index 0000000000000..92893e58d14bb --- /dev/null +++ b/extmod/ssl/manifest.py @@ -0,0 +1 @@ +freeze(".", ("ssl.py",)) diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py new file mode 100644 index 0000000000000..d747b80f0b9fa --- /dev/null +++ b/extmod/ssl/ssl.py @@ -0,0 +1,114 @@ +from ussl import * +import ussl as _ussl + +# constants +PROTOCOL_TLS_CLIENT = const(0) +PROTOCOL_TLS_SERVER = const(1) + + +class SSLContext: + def __init__(self, protocol): + # protocol is PROTOCOL_TLS_CLIENT or PROTOCOL_TLS_SERVER + self._protocol = protocol + self._verify_mode = CERT_NONE + self._check_hostname = False + if protocol == PROTOCOL_TLS_CLIENT: + self.verify_mode = CERT_REQUIRED + self.check_hostname = True + self.key = None + self.cert = None + self.cadata = None + self.ctx = _ussl.ctx_init() + # PRE-ALLOCATE CONTEXT(key,cert) and SSL socket BUFFERS e.g. from (ussl) ? + # self.ssl_buffer_sock = _ussl.context_allocate_buffer() + # initiate context so we can get/set ciphers? : + # self._ctx = _ussl.context_init() + # + + @property + def protocol(self): + return self._protocol + + @property + def check_hostname(self): + return self._check_hostname + + @check_hostname.setter + def check_hostname(self, value): + assert type(value) == bool + + if value is True and not self.verify_mode: + self.verify_mode = CERT_REQUIRED + + self._check_hostname = value + + @property + def verify_mode(self): + return self._verify_mode + + @verify_mode.setter + def verify_mode(self, value): + assert value in (CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED) + if not self.check_hostname: + self._verify_mode = value + + def reset(self, server=True): + self.ctx = _ussl.ctx_init() + if server: + self.ctx.load_certchain(key=self.key, cert=self.cert) + else: + self.ctx.load_cadata(self.cadata) + + def load_cert_chain(self, certfile, keyfile=None): + # load certificate/key from a file, is possible to use memoryview to + # save RAM? + if isinstance(certfile, bytes): + self.cert = certfile + else: + with open(certfile, "rb") as cert: + self.cert = cert.read() + if keyfile: + if isinstance(keyfile, bytes): + self.key = keyfile + else: + with open(keyfile, "rb") as key: + self.key = key.read() + + self.ctx.load_certchain(key=self.key, cert=self.cert) + + def load_default_certs(self): + pass # not sure how/if implement this + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile: + with open(cafile, "rb") as ca_cert: + self.cadata = ca_cert.read() + if capath: + pass ## not implemented, it needs to concatenate multiple files + + if cadata: + self.cadata = cadata + + self.ctx.load_cadata(self.cadata) + + def get_ciphers(self): + return self.ctx.get_ciphers() + + def set_ciphers(self, ciphersuite): + return self.ctx.set_ciphers(ciphersuite) + + def wrap_socket( + self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None + ): + + if self.check_hostname and server_hostname is None: + raise ValueError("check_hostname requires server_hostname") + # to be substituted by e.g. _ussl._context_wrap_socket in modussl_mbedtls.c ?: + # _ussl._context_wrap_socket(*args, **kargs) + return self.ctx.wrap_socket( + sock, + server_side=server_side, + cert_reqs=self.verify_mode, + server_hostname=server_hostname, + do_handshake=do_handshake_on_connect, + ) diff --git a/ports/unix/variants/manifest.py b/ports/unix/variants/manifest.py index f8e8f250ac653..771a208f8c6b9 100644 --- a/ports/unix/variants/manifest.py +++ b/ports/unix/variants/manifest.py @@ -1 +1,4 @@ require("mip-cmdline") +require("mip") +module("ssl.py", base_path="$(MPY_DIR)/extmod/ssl", opt=3) + diff --git a/tests/multi_net/ssl_context_rsa.py b/tests/multi_net/ssl_context_rsa.py new file mode 100644 index 0000000000000..2de4d048e49ac --- /dev/null +++ b/tests/multi_net/ssl_context_rsa.py @@ -0,0 +1,160 @@ +# Simple test creating an SSL connection and transferring some data +# This test won't run under CPython because CPython doesn't have key/cert + +try: + import ubinascii as binascii, usocket as socket + import ssl +except ImportError: + print("SKIP") + raise SystemExit + +PORT = 8000 + + +# This self-signed key/cert pair is randomly generated and to be used for +# testing/demonstration only. You should always generate your own key/cert. + +# To generate a new self-signed key/cert pair with openssl do: +# $ openssl req -x509 -newkey rsa:4096 -keyout rsa_key.pem -out rsa_cert.pem +# -days 365 -nodes +# In this case CN is: esphome.local +# +# Convert them to DER format: +# $ openssl rsa -in rsa_key.pem -out rsa_key.der -outform DER +# $ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER +# +# Then convert to hex format, eg using binascii.hexlify(data). + +cert = binascii.unhexlify( + b"308205d7308203bfa003020102020900bc63b48a700c3d49300d06092a864886f70d01010b050030" + b"8181310b3009060355040613024155310c300a06035504080c03466f6f310c300a06035504070c03" + b"42617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03666f6f31" + b"16301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d010901160b" + b"666f6f406261722e636f6d301e170d3232303731323138303031335a170d32333037313231383030" + b"31335a308181310b3009060355040613024155310c300a06035504080c03466f6f310c300a060355" + b"04070c0342617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03" + b"666f6f3116301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d01" + b"0901160b666f6f406261722e636f6d30820222300d06092a864886f70d01010105000382020f0030" + b"82020a0282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444ab7d9ff66" + b"a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51abb515cb" + b"f60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925c855ab53" + b"7785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf19f59553" + b"349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207ea57c50e9" + b"2d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e572c56a4" + b"818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a9642489cb640a" + b"937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215f657b8f9" + b"f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c56447b404" + b"8c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb78284ede285" + b"0fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a48496c01" + b"6de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d055ea4692f" + b"eb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0dfc8a11e73" + b"0203010001a350304e301d0603551d0e04160414bc6048fe3cd278257e8b7c90dedbbce8369b20b8" + b"301f0603551d23041830168014bc6048fe3cd278257e8b7c90dedbbce8369b20b8300c0603551d13" + b"040530030101ff300d06092a864886f70d01010b0500038202010009238354b43379a3d2b56e928c" + b"ac8ea28e2c01cf8148e54c0bbd4055e2e57d578697d1e2c392f1fe3bc9211d4f27ed1be631e7547a" + b"6390d7f121a9e20a195fdda73f755188b16cf39714924a9686dd7cc749421335038c0640c2c6b15d" + b"f44d74d94a97285ee2a7b075ccc9d9d632e2a5906030cf59bde14ab10660b7cf47ec9d7ae2f35963" + b"454f76735a3dac12a4a4c907183e9ccf3e07d59484c182e67edc7c35ce15c7e1072fae8c9965a126" + b"1a1f31147d4af8d1ebf8ee7c142badfe67e31fb324a79a29bc94e89370b70d8cf7cd2b2aa427a49f" + b"77849891e7c4d5911f6fda52733a3c169b0188c2d9918f296dd8e234f8962f0db5e47c6159448045" + b"4e2d9a5850d4c696a0fb3b66534a4591c49dda8cc6f1b0008c625aa5e0091ecfbd51d9715c60b85e" + b"4e89d4a6cfabb2acdf81518eb61403b8f8767c5c00216f730e08f22959dff695a081cc726c4ab35a" + b"e3f6538a231f831a6e91206f3b691a94bdf95343ec02ef7aac42da2a70846cd5f13dd2955a5f1737" + b"a4c3c6c03b041d334c1dadd1e305f07c83b4b4e0509ec1d23e95f820290942eaaf8bea304cd5a505" + b"8fc0d4624ff1ffe1348e7bc54c756a12acb258eb5e7426fb062a82b88ec274c9c13b3eff8b010947" + b"62e166f490cd25b14e762db708785859a337d8fd0008fe602a90e2933cded3359e98ce3fbc041208" + b"66bd4d96d6b6f7f53def854d40021196b7a06b" +) + +key = binascii.unhexlify( + b"308209290201000282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444a" + b"b7d9ff66a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51" + b"abb515cbf60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925" + b"c855ab537785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf" + b"19f59553349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207e" + b"a57c50e92d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e" + b"572c56a4818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a96424" + b"89cb640a937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215" + b"f657b8f9f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c5" + b"6447b4048c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb782" + b"84ede2850fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a" + b"48496c016de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d05" + b"5ea4692feb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0df" + b"c8a11e73020301000102820201008efa0e8fe81c2e2cb6ed10152dfca4242750581d3e6b54f56524" + b"a6a2d2613cf2727efcec6cfddebd4c285f1148bc2a2936c28919cb0da502dea8c92fe2f9856bee61" + b"ac1aebdac838b5e66f7c7c799df07716f30ef362dbb5485884a180c8ce5539cb1db35699dce5f217" + b"27295d811f1ce7a115111c1823b5c90ce880f5352872a7a76282f6f1fd8a015136ab274c3d30783d" + b"eb6ad7096e33d826eafdf7c70398d5eab4d28f91cd3913c69c7a7ade9ef692b9f8292959be64dec4" + b"6ab2c291b41a6464004b5ddd4b93bfe41b37eedeef4ba2d16dcbb9c28b96f57fb96c20ed4a9471ff" + b"ae643b254f100f8c9702b5f67af6369e8d887f285e5d520c5aa5d3a79e5de96432e6d2e3dea68e58" + b"208c075fb119c6d3d4149b7e1247208d6b337c70272befc41d57f278618f1a82de337173346dc135" + b"4d80a7c9075af99dbb2a14733c06b71600c6677a6bb28c0e4fc63db622228047a2cb7474dc8141c3" + b"5f3a597c3e2bca9911d28eb9fd1a0c915e9f9c1cfd643d4fd8cac867f215380168ec37b8cfa28564" + b"e6288ab04a7d67ca44b4c8375214a7ffaa1e6be92c4b138fcfd6beaba251b31a50a6e2ef241c9554" + b"a1dc710b4acb63e749f5849e53d3f4915c6eb2a9a009bab04e932841ab34ae29eb000a08777d6399" + b"169c2dc3d7952df5bc2d06e90a32139c6a2793d3817e4feadac2ccac554d383a8d41569140c29168" + b"89220d3a5e410282010100fd603d18feef7aac61bda3b674a57ab38748bcde5c3efdba2279638f8e" + b"a413cc26b9dda0375c116a8798a295b2c283aaaad7cca0dbd9bb3322a9a815f6d0aa5fc4f9aff8fb" + b"da8ff914091ede7aefdb07a119c9b2e2b2bda776ac497060b8e88a82eb20c62f26f343566697726e" + b"71aa46fd4efad6f42fc8a478856324d72cbf5eb3918317162d6fc2cfd775969a2077759fa2c8220d" + b"acdc2ebb03ec39feed3f2b415449cbf40a7126bcf01d1068e3a45ec01181f2c68d7e05b4720bfe4a" + b"308e1648123c91214a5f8dfce58727c4cd9396a8b403b733a717449b2f1970db97a3b8467271ffa6" + b"e8c7cc9e2e1c0f789284ae9efe77eaac01131463c9c1329a1ba3530282010100d05ed6ab9b9fbdf7" + b"a0f5f91f68dc3bac5789332d6ece46103fb1ef109fc972fdc99edf3107a23d66d1cdfe6bdddfd1bb" + b"3952ccd10b5c20ad1b3e0aa6a51271ecf3a7ef2a65e029f5d77f238d1235b52a9dca3451c165d70a" + b"99cbaea5c610e5455979696db769191e7cf2db21f641959e4ba1c5c0aae260c724962b6ac2621d92" + b"e9df7adeb82b522d37b42cb454003bbe60d9915bf7737aeccf88c7ed1263a22f431a734e61fe7173" + b"a937ddf76ad2a79994c05238defc15f6846858e9edf27ae2a567c7c5c735ea5d2fbef65a2195bc05" + b"d82cbf06a477b29c84c92e8054c2bb25d8c6f19d43ef5fd1fce13c2cdbc361c39baec37b399200b3" + b"2d4a6798ba0b546102820101008e41492c4e7daff7368d1d6c64034067a94dca5461a0301e201add" + b"2e0d5ccb8cb435685bfa98e362572cf8236a10d191b187a568aee688b6c60050d1bc181d7fd57c86" + b"33195bf5b7576b637c6fb358dae8b52ccc15815affb99e334137dcb91a833475db2f4004164b5d20" + b"2c6c1bbf094a50dc7e70ec9f0ed067bb6944b1e7e3c897aaecfc53984add1c4ff5b525034cf3ca95" + b"e8a09aeba804f1c7e02be391b2bc641166c3e654eef5e72dba37d98f406f3fa520e41f2ea10f5574" + b"ac5984f75145378fefbfac1d07fff3f234fec698d55e746b1da18f6f7de24ec84ed7cb446d428820" + b"bef33c00693e6a0ef114b5d66e9fefa8ee059238df1ac37c87e7841ae7028201000721a7d139c34e" + b"da21cd295894db2cc3aa3f4cdc1a35bf1a2143f2bdabea56202f7d5b802f15b36a4875f76633b2cc" + b"57cf0f71691a2d6e04deb0d1e68031d06a5eb079b406c6944910b60e3e6ec81dca369a4c0e1c4363" + b"07bed9c4c171b4f453da4b187ba3d25a04bc1c07b9f2d6adcb3c256e4238d7049eec36a387c4dd5c" + b"cbc16b5fa62dc175cf8c5f83442cb7d153a3b6ee8daa3b6e929a4bc123f1042df1d6271a992d2b6b" + b"309d33074ac7822c304a72069e61ab590915e10862013dd24cdd825ec8fb17724cfc2c59fc1db825" + b"3641fece0ee9241b9dd5c198f0d575d0b7ebe26b3489b5b09edc3bcd366fd3110e83ce886c383d31" + b"feefe6e302cc2345210282010008f77a33d0081e9be3c1b1ac8b8e0eebb72df2eb69b95d2ed74935" + b"b9dab8e17023cc38465354023c5183b51a6a20288fbb2181172be1c2fdb8b444419454e5b37f7f3b" + b"df11e28cf4746b25534eb62f7e87bbbf28eda37024368b3897fbc661b40a93e04a183db9219c04a8" + b"7643edf5d8b5dbfe3d424e91d558d5e3e2fa02ce1984ee69fb8518470eee2e7db0e1df5ac4571f78" + b"a7a2529bc1fef5e32d46994869a8d8cc47869e174d84e7976be8ebb88f2ccb71a603a8bdb06af3eb" + b"2ddbd62082f40d7987e47f2e321eb5eb2a28fefab263409f89dc97ebc723a1b751418cdd3ea684ba" + b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c" +) + +# Server +def instance0(): + + multitest.globals(IP=multitest.get_network_ip()) + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1]) + s.listen(1) + multitest.next() + s2, _ = s.accept() + server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + server_ctx.load_cert_chain(cert, keyfile=key) + s2 = server_ctx.wrap_socket(s2, server_side=True) + print(s2.read(16)) + s2.write(b"server to client") + s2.close() + s.close() + + +# Client +def instance1(): + multitest.next() + s = socket.socket() + s.connect(socket.getaddrinfo(IP, PORT)[0][-1]) + client_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_ctx.load_verify_locations(cadata=cert) + s = client_ctx.wrap_socket(s, server_hostname="esphome.local") + s.write(b"client to server") + print(s.read(16)) + s.close() diff --git a/tests/multi_net/ssl_context_rsa.py.exp b/tests/multi_net/ssl_context_rsa.py.exp new file mode 100644 index 0000000000000..909c496d019e1 --- /dev/null +++ b/tests/multi_net/ssl_context_rsa.py.exp @@ -0,0 +1,4 @@ +--- instance0 --- +b'client to server' +--- instance1 --- +b'server to client' diff --git a/tests/net_inet/test_ssl_context_client.py b/tests/net_inet/test_ssl_context_client.py new file mode 100644 index 0000000000000..e01e8f926ba38 --- /dev/null +++ b/tests/net_inet/test_ssl_context_client.py @@ -0,0 +1,104 @@ +import socket +import ssl + +try: + import ubinascii as binascii +except: + import binascii +try: + import usocket as socket +except: + import socket + +# This certificate was obtained from micropython.org using openssl: +# $ openssl s_client -showcerts -connect micropython.org:443 /dev/null +# The certificate is from Let's Encrypt: +# 1 s:/C=US/O=Let's Encrypt/CN=R3 +# i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1 +# Validity +# Not Before: Sep 4 00:00:00 2020 GMT +# Not After : Sep 15 16:00:00 2025 GMT +# Copy PEM content to a file (certmpy.pem) and convert to DER e.g. +# $ openssl x509 -in certmpy.pem -out certmpy.der -outform DER +# Then convert to hex format, eg using binascii.hexlify(data). + +ca_cert_chain = binascii.unhexlify( + b"30820516308202fea003020102021100912b084acf0c18a753f6d62e25a75f5a300d06092a864886" + b"f70d01010b0500304f310b300906035504061302555331293027060355040a1320496e7465726e65" + b"742053656375726974792052657365617263682047726f7570311530130603550403130c49535247" + b"20526f6f74205831301e170d3230303930343030303030305a170d3235303931353136303030305a" + b"3032310b300906035504061302555331163014060355040a130d4c6574277320456e637279707431" + b"0b300906035504031302523330820122300d06092a864886f70d01010105000382010f003082010a" + b"0282010100bb021528ccf6a094d30f12ec8d5592c3f882f199a67a4288a75d26aab52bb9c54cb1af" + b"8e6bf975c8a3d70f4794145535578c9ea8a23919f5823c42a94e6ef53bc32edb8dc0b05cf35938e7" + b"edcf69f05a0b1bbec094242587fa3771b313e71cace19befdbe43b45524596a9c153ce34c852eeb5" + b"aeed8fde6070e2a554abb66d0e97a540346b2bd3bc66eb66347cfa6b8b8f572999f830175dba726f" + b"fb81c5add286583d17c7e709bbf12bf786dcc1da715dd446e3ccad25c188bc60677566b3f118f7a2" + b"5ce653ff3a88b647a5ff1318ea9809773f9d53f9cf01e5f5a6701714af63a4ff99b3939ddc53a706" + b"fe48851da169ae2575bb13cc5203f5ed51a18bdb150203010001a382010830820104300e0603551d" + b"0f0101ff040403020186301d0603551d250416301406082b0601050507030206082b060105050703" + b"0130120603551d130101ff040830060101ff020100301d0603551d0e04160414142eb317b75856cb" + b"ae500940e61faf9d8b14c2c6301f0603551d2304183016801479b459e67bb6e5e40173800888c81a" + b"58f6e99b6e303206082b0601050507010104263024302206082b060105050730028616687474703a" + b"2f2f78312e692e6c656e63722e6f72672f30270603551d1f0420301e301ca01aa018861668747470" + b"3a2f2f78312e632e6c656e63722e6f72672f30220603551d20041b30193008060667810c01020130" + b"0d060b2b0601040182df13010101300d06092a864886f70d01010b0500038202010085ca4e473ea3" + b"f7854485bcd56778b29863ad754d1e963d336572542d81a0eac3edf820bf5fccb77000b76e3bf65e" + b"94dee4209fa6ef8bb203e7a2b5163c91ceb4ed3902e77c258a47e6656e3f46f4d9f0ce942bee54ce" + b"12bc8c274bb8c1982fa2afcd71914a08b7c8b8237b042d08f908573e83d904330a472178098227c3" + b"2ac89bb9ce5cf264c8c0be79c04f8e6d440c5e92bb2ef78b10e1e81d4429db5920ed63b921f81226" + b"949357a01d6504c10a22ae100d4397a1181f7ee0e08637b55ab1bd30bf876e2b2aff214e1b05c3f5" + b"1897f05eacc3a5b86af02ebc3b33b9ee4bdeccfce4af840b863fc0554336f668e136176a8e99d1ff" + b"a540a734b7c0d063393539756ef2ba76c89302e9a94b6c17ce0c02d9bd81fb9fb768d40665b3823d" + b"7753f88e7903ad0a3107752a43d8559772c4290ef7c45d4ec8ae468430d7f2855f18a179bbe75e70" + b"8b07e18693c3b98fdc6171252aafdfed255052688b92dce5d6b5e3da7dd0876c842131ae82f5fbb9" + b"abc889173de14ce5380ef6bd2bbd968114ebd5db3d20a77e59d3e2f858f95bb848cdfe5c4f1629fe" + b"1e5523afc811b08dea7c9390172ffdaca20947463ff0e9b0b7ff284d6832d6675e1e69a393b8f59d" + b"8b2f0bd25243a66f3257654d3281df3853855d7e5d6629eab8dde495b5cdb5561242cdc44ec62538" + b"44506decce005518fee94964d44eca979cb45bc073a8abb847c2" +) + + +def main(use_stream=True): + + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + + # context.verify_mode = ssl.CERT_REQUIRED # enabled by default with + # PROTOCOL_TLS_CLIENT + + assert context.verify_mode == ssl.CERT_REQUIRED + + # context.check_hostname = True # enabled by default with + # PROTOCOL_TLS_CLIENT + # print(context.get_ciphers()) + + # context.load_verify_locations(cafile='certmpy.der') # not sure how to + # implement a external file + # in a testd + # context.ctx.set_ciphers('TLS-RSA-WITH-AES-256-CBC-SHA') + context.load_verify_locations(cadata=ca_cert_chain) + + context.load_default_certs() # not implemented in MicroPython just a mock, needed + # in CPython to load issuer CA too, + # otherwise verification fails. + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + addr = socket.getaddrinfo("micropython.org", 443)[0][-1] + + # CPython can wrap the socket even if not connected yet. + # ssl_sock = context.wrap_socket(s, server_hostname='micropython.org') + # ssl_sock.connect(addr) + + # MicroPython needs to connect first, CPython can do this too. + s.connect(addr) + # server_hostname must match CN (Common Name) in the certificate + # presented by the server + ssl_sock = context.wrap_socket(s, server_hostname="micropython.org") + ssl_sock.write(b"GET / HTTP/1.0\r\n\r\n") + print(ssl_sock.read(17)) + # print(ssl_sock.cipher()) + # print(ssl_sock.getpeercert(True)) + ssl_sock.close() + + +main() From 3ded4e2f3c4baa818b679da418ea8a55facfd693 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Fri, 19 Aug 2022 21:59:40 +0100 Subject: [PATCH 02/20] examples/network: Add http_server_ssl_context.py. Signed-off-by: Carlos Gil --- examples/network/http_server_ssl_context.py | 178 ++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 examples/network/http_server_ssl_context.py diff --git a/examples/network/http_server_ssl_context.py b/examples/network/http_server_ssl_context.py new file mode 100644 index 0000000000000..e92d6e6a6c813 --- /dev/null +++ b/examples/network/http_server_ssl_context.py @@ -0,0 +1,178 @@ +import ubinascii as binascii + +try: + import usocket as socket +except: + import socket +import ssl + + +# This self-signed key/cert pair is randomly generated and to be used for +# testing/demonstration only. You should always generate your own key/cert. + +cert = binascii.unhexlify( + b"308205d7308203bfa003020102020900bc63b48a700c3d49300d06092a864886f70d01010b050030" + b"8181310b3009060355040613024155310c300a06035504080c03466f6f310c300a06035504070c03" + b"42617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03666f6f31" + b"16301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d010901160b" + b"666f6f406261722e636f6d301e170d3232303731323138303031335a170d32333037313231383030" + b"31335a308181310b3009060355040613024155310c300a06035504080c03466f6f310c300a060355" + b"04070c0342617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03" + b"666f6f3116301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d01" + b"0901160b666f6f406261722e636f6d30820222300d06092a864886f70d01010105000382020f0030" + b"82020a0282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444ab7d9ff66" + b"a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51abb515cb" + b"f60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925c855ab53" + b"7785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf19f59553" + b"349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207ea57c50e9" + b"2d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e572c56a4" + b"818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a9642489cb640a" + b"937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215f657b8f9" + b"f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c56447b404" + b"8c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb78284ede285" + b"0fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a48496c01" + b"6de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d055ea4692f" + b"eb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0dfc8a11e73" + b"0203010001a350304e301d0603551d0e04160414bc6048fe3cd278257e8b7c90dedbbce8369b20b8" + b"301f0603551d23041830168014bc6048fe3cd278257e8b7c90dedbbce8369b20b8300c0603551d13" + b"040530030101ff300d06092a864886f70d01010b0500038202010009238354b43379a3d2b56e928c" + b"ac8ea28e2c01cf8148e54c0bbd4055e2e57d578697d1e2c392f1fe3bc9211d4f27ed1be631e7547a" + b"6390d7f121a9e20a195fdda73f755188b16cf39714924a9686dd7cc749421335038c0640c2c6b15d" + b"f44d74d94a97285ee2a7b075ccc9d9d632e2a5906030cf59bde14ab10660b7cf47ec9d7ae2f35963" + b"454f76735a3dac12a4a4c907183e9ccf3e07d59484c182e67edc7c35ce15c7e1072fae8c9965a126" + b"1a1f31147d4af8d1ebf8ee7c142badfe67e31fb324a79a29bc94e89370b70d8cf7cd2b2aa427a49f" + b"77849891e7c4d5911f6fda52733a3c169b0188c2d9918f296dd8e234f8962f0db5e47c6159448045" + b"4e2d9a5850d4c696a0fb3b66534a4591c49dda8cc6f1b0008c625aa5e0091ecfbd51d9715c60b85e" + b"4e89d4a6cfabb2acdf81518eb61403b8f8767c5c00216f730e08f22959dff695a081cc726c4ab35a" + b"e3f6538a231f831a6e91206f3b691a94bdf95343ec02ef7aac42da2a70846cd5f13dd2955a5f1737" + b"a4c3c6c03b041d334c1dadd1e305f07c83b4b4e0509ec1d23e95f820290942eaaf8bea304cd5a505" + b"8fc0d4624ff1ffe1348e7bc54c756a12acb258eb5e7426fb062a82b88ec274c9c13b3eff8b010947" + b"62e166f490cd25b14e762db708785859a337d8fd0008fe602a90e2933cded3359e98ce3fbc041208" + b"66bd4d96d6b6f7f53def854d40021196b7a06b" +) + +key = binascii.unhexlify( + b"308209290201000282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444a" + b"b7d9ff66a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51" + b"abb515cbf60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925" + b"c855ab537785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf" + b"19f59553349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207e" + b"a57c50e92d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e" + b"572c56a4818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a96424" + b"89cb640a937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215" + b"f657b8f9f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c5" + b"6447b4048c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb782" + b"84ede2850fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a" + b"48496c016de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d05" + b"5ea4692feb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0df" + b"c8a11e73020301000102820201008efa0e8fe81c2e2cb6ed10152dfca4242750581d3e6b54f56524" + b"a6a2d2613cf2727efcec6cfddebd4c285f1148bc2a2936c28919cb0da502dea8c92fe2f9856bee61" + b"ac1aebdac838b5e66f7c7c799df07716f30ef362dbb5485884a180c8ce5539cb1db35699dce5f217" + b"27295d811f1ce7a115111c1823b5c90ce880f5352872a7a76282f6f1fd8a015136ab274c3d30783d" + b"eb6ad7096e33d826eafdf7c70398d5eab4d28f91cd3913c69c7a7ade9ef692b9f8292959be64dec4" + b"6ab2c291b41a6464004b5ddd4b93bfe41b37eedeef4ba2d16dcbb9c28b96f57fb96c20ed4a9471ff" + b"ae643b254f100f8c9702b5f67af6369e8d887f285e5d520c5aa5d3a79e5de96432e6d2e3dea68e58" + b"208c075fb119c6d3d4149b7e1247208d6b337c70272befc41d57f278618f1a82de337173346dc135" + b"4d80a7c9075af99dbb2a14733c06b71600c6677a6bb28c0e4fc63db622228047a2cb7474dc8141c3" + b"5f3a597c3e2bca9911d28eb9fd1a0c915e9f9c1cfd643d4fd8cac867f215380168ec37b8cfa28564" + b"e6288ab04a7d67ca44b4c8375214a7ffaa1e6be92c4b138fcfd6beaba251b31a50a6e2ef241c9554" + b"a1dc710b4acb63e749f5849e53d3f4915c6eb2a9a009bab04e932841ab34ae29eb000a08777d6399" + b"169c2dc3d7952df5bc2d06e90a32139c6a2793d3817e4feadac2ccac554d383a8d41569140c29168" + b"89220d3a5e410282010100fd603d18feef7aac61bda3b674a57ab38748bcde5c3efdba2279638f8e" + b"a413cc26b9dda0375c116a8798a295b2c283aaaad7cca0dbd9bb3322a9a815f6d0aa5fc4f9aff8fb" + b"da8ff914091ede7aefdb07a119c9b2e2b2bda776ac497060b8e88a82eb20c62f26f343566697726e" + b"71aa46fd4efad6f42fc8a478856324d72cbf5eb3918317162d6fc2cfd775969a2077759fa2c8220d" + b"acdc2ebb03ec39feed3f2b415449cbf40a7126bcf01d1068e3a45ec01181f2c68d7e05b4720bfe4a" + b"308e1648123c91214a5f8dfce58727c4cd9396a8b403b733a717449b2f1970db97a3b8467271ffa6" + b"e8c7cc9e2e1c0f789284ae9efe77eaac01131463c9c1329a1ba3530282010100d05ed6ab9b9fbdf7" + b"a0f5f91f68dc3bac5789332d6ece46103fb1ef109fc972fdc99edf3107a23d66d1cdfe6bdddfd1bb" + b"3952ccd10b5c20ad1b3e0aa6a51271ecf3a7ef2a65e029f5d77f238d1235b52a9dca3451c165d70a" + b"99cbaea5c610e5455979696db769191e7cf2db21f641959e4ba1c5c0aae260c724962b6ac2621d92" + b"e9df7adeb82b522d37b42cb454003bbe60d9915bf7737aeccf88c7ed1263a22f431a734e61fe7173" + b"a937ddf76ad2a79994c05238defc15f6846858e9edf27ae2a567c7c5c735ea5d2fbef65a2195bc05" + b"d82cbf06a477b29c84c92e8054c2bb25d8c6f19d43ef5fd1fce13c2cdbc361c39baec37b399200b3" + b"2d4a6798ba0b546102820101008e41492c4e7daff7368d1d6c64034067a94dca5461a0301e201add" + b"2e0d5ccb8cb435685bfa98e362572cf8236a10d191b187a568aee688b6c60050d1bc181d7fd57c86" + b"33195bf5b7576b637c6fb358dae8b52ccc15815affb99e334137dcb91a833475db2f4004164b5d20" + b"2c6c1bbf094a50dc7e70ec9f0ed067bb6944b1e7e3c897aaecfc53984add1c4ff5b525034cf3ca95" + b"e8a09aeba804f1c7e02be391b2bc641166c3e654eef5e72dba37d98f406f3fa520e41f2ea10f5574" + b"ac5984f75145378fefbfac1d07fff3f234fec698d55e746b1da18f6f7de24ec84ed7cb446d428820" + b"bef33c00693e6a0ef114b5d66e9fefa8ee059238df1ac37c87e7841ae7028201000721a7d139c34e" + b"da21cd295894db2cc3aa3f4cdc1a35bf1a2143f2bdabea56202f7d5b802f15b36a4875f76633b2cc" + b"57cf0f71691a2d6e04deb0d1e68031d06a5eb079b406c6944910b60e3e6ec81dca369a4c0e1c4363" + b"07bed9c4c171b4f453da4b187ba3d25a04bc1c07b9f2d6adcb3c256e4238d7049eec36a387c4dd5c" + b"cbc16b5fa62dc175cf8c5f83442cb7d153a3b6ee8daa3b6e929a4bc123f1042df1d6271a992d2b6b" + b"309d33074ac7822c304a72069e61ab590915e10862013dd24cdd825ec8fb17724cfc2c59fc1db825" + b"3641fece0ee9241b9dd5c198f0d575d0b7ebe26b3489b5b09edc3bcd366fd3110e83ce886c383d31" + b"feefe6e302cc2345210282010008f77a33d0081e9be3c1b1ac8b8e0eebb72df2eb69b95d2ed74935" + b"b9dab8e17023cc38465354023c5183b51a6a20288fbb2181172be1c2fdb8b444419454e5b37f7f3b" + b"df11e28cf4746b25534eb62f7e87bbbf28eda37024368b3897fbc661b40a93e04a183db9219c04a8" + b"7643edf5d8b5dbfe3d424e91d558d5e3e2fa02ce1984ee69fb8518470eee2e7db0e1df5ac4571f78" + b"a7a2529bc1fef5e32d46994869a8d8cc47869e174d84e7976be8ebb88f2ccb71a603a8bdb06af3eb" + b"2ddbd62082f40d7987e47f2e321eb5eb2a28fefab263409f89dc97ebc723a1b751418cdd3ea684ba" + b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c" +) + + +CONTENT = b"""\ +HTTP/1.0 200 OK + +Hello #%d from MicroPython! +""" + + +def main(use_stream=True): + s = socket.socket() + + # Binding to all interfaces - server will be accessible to other hosts! + ai = socket.getaddrinfo("0.0.0.0", 8443) + print("Bind address info:", ai) + addr = ai[0][-1] + + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(addr) + s.listen(5) + print("Listening, connect your browser to https://:8443/") + + counter = 0 + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ctx.load_cert_chain(cert, key) + while True: + res = s.accept() + client_s = res[0] + client_addr = res[1] + print("Client address:", client_addr) + print("Client socket:", client_s) + # CPython uses key keyfile/certfile arguments, but MicroPython uses key/cert + client_s = ctx.wrap_socket(client_s, server_side=True) + print(client_s) + print("Request:") + if use_stream: + # Both CPython and MicroPython SSLSocket objects support read() and + # write() methods. + # Browsers are prone to terminate SSL connection abruptly if they + # see unknown certificate, etc. We must continue in such case - + # next request they issue will likely be more well-behaving and + # will succeed. + try: + req = client_s.readline() + print(req) + while True: + h = client_s.readline() + if h == b"" or h == b"\r\n": + break + print(h) + if req: + client_s.write(CONTENT % counter) + except Exception as e: + print("Exception serving request:", e) + else: + print(client_s.recv(4096)) + client_s.send(CONTENT % counter) + client_s.close() + ctx.reset() + counter += 1 + print() + + +main() From 0e381d426c766be1d037d571343e961e0cb40fbe Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Sun, 21 Aug 2022 04:07:12 +0100 Subject: [PATCH 03/20] extmod/modussl_mbedtls: Add time cert validation. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 19 ++++++++++++++++--- ports/esp32/boards/manifest.py | 1 + ports/esp32/boards/sdkconfig.base | 4 +++- ports/esp32/mbedtls/mbedtls_config.h | 3 +++ ports/esp32/mbedtls/mbedtls_port.c | 21 +++++++++++++++++++++ ports/esp32/mpconfigport.h | 1 + ports/unix/mbedtls/mbedtls_config.h | 6 ++++++ 7 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 ports/esp32/mbedtls/mbedtls_config.h create mode 100644 ports/esp32/mbedtls/mbedtls_port.c diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index e044e8a04f045..9822799bb5930 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -49,6 +49,10 @@ // #include "mbedtls/build_info.h" // #endif #include "mbedtls/version.h" +#ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT +#include "mbedtls/mbedtls_config.h" + +#endif #define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR) @@ -188,7 +192,7 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { // SSLContext STATIC mp_obj_ssl_context_t *context_new() { - #if MICROPY_PY_USSL_FINALISER + #if MICROPY_PY_SSL_FINALISER mp_obj_ssl_context_t *ctxi = m_new_obj_with_finaliser(mp_obj_ssl_context_t); #else mp_obj_ssl_context_t *ctxi = m_new_obj(mp_obj_ssl_context_t); @@ -208,7 +212,16 @@ STATIC mp_obj_ssl_context_t *context_new() { // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose mbedtls_debug_set_threshold(3); #endif - + #ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT + mbedtls_platform_set_time(platform_mbedtls_time); + #endif + // DEBUG MBEDTLS_PLATFORM + // time_t mbt; + // time_t mbtz; + // mbt = mbedtls_time(NULL); + // mbtz = platform_mbedtls_time(NULL); + // printf("secs mbt : %lu \n\n", mbt); + // printf("secs mbtz: %lu \n\n", mbtz); mbedtls_entropy_init(&ctxi->entropy); const byte seed[] = "upy"; ret = mbedtls_ctr_drbg_seed(&ctxi->ctr_drbg, mbedtls_entropy_func, &ctxi->entropy, seed, sizeof(seed)); @@ -418,7 +431,7 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c // 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); mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(self_in); - #if MICROPY_PY_USSL_FINALISER + #if MICROPY_PY_SSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py index 290d98c4e499c..919053d148cea 100644 --- a/ports/esp32/boards/manifest.py +++ b/ports/esp32/boards/manifest.py @@ -1,5 +1,6 @@ freeze("$(PORT_DIR)/modules") include("$(MPY_DIR)/extmod/asyncio") +include("$(MPY_DIR)/extmod/ssl") # Useful networking-related packages. require("bundle-networking") diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index c74a19c0cf2aa..278234fa1a8f6 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -48,7 +48,9 @@ CONFIG_LWIP_PPP_CHAP_SUPPORT=y # SSL # Use 4kiB output buffer instead of default 16kiB CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y - +CONFIG_MBEDTLS_HAVE_TIME_DATE=y +CONFIG_MBEDTLS_PLATFORM_TIME_ALT=y +CONFIG_MBEDTLS_HAVE_TIME=y # ULP coprocessor support # Only on: ESP32, ESP32S2, ESP32S3 CONFIG_ULP_COPROC_ENABLED=y diff --git a/ports/esp32/mbedtls/mbedtls_config.h b/ports/esp32/mbedtls/mbedtls_config.h new file mode 100644 index 0000000000000..92bcee0372f73 --- /dev/null +++ b/ports/esp32/mbedtls/mbedtls_config.h @@ -0,0 +1,3 @@ +// Time mbedtls_platform + +time_t platform_mbedtls_time(time_t *timer); diff --git a/ports/esp32/mbedtls/mbedtls_port.c b/ports/esp32/mbedtls/mbedtls_port.c new file mode 100644 index 0000000000000..7150f9bfdb714 --- /dev/null +++ b/ports/esp32/mbedtls/mbedtls_port.c @@ -0,0 +1,21 @@ +#include + +#ifdef MICROPY_SSL_MBEDTLS + +#include +#include +#include "shared/timeutils/timeutils.h" + +#ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT + +time_t platform_mbedtls_time(time_t *timer) { + // mbedtls_time requires time in seconds from EPOCH 1970 + + struct timeval tv; + gettimeofday(&tv, NULL); + + return tv.tv_sec + TIMEUTILS_SECONDS_1970_TO_2000; +} + +#endif +#endif diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b18681bb572df..556f6a4a7abe4 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -138,6 +138,7 @@ #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_SSL_FINALISER (1) #define MICROPY_PY_WEBSOCKET (1) +#define MICROPY_MBEDTLS_PLATFORM_TIME_ALT (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_ONEWIRE (1) #define MICROPY_PY_PLATFORM (1) diff --git a/ports/unix/mbedtls/mbedtls_config.h b/ports/unix/mbedtls/mbedtls_config.h index 629064abcf297..a786c8278b5c6 100644 --- a/ports/unix/mbedtls/mbedtls_config.h +++ b/ports/unix/mbedtls/mbedtls_config.h @@ -32,6 +32,12 @@ // Enable mbedtls modules #define MBEDTLS_HAVEGE_C #define MBEDTLS_TIMING_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 +#define MBEDTLS_HAVE_TIME_DATE + // Include common mbedtls configuration. #include "extmod/mbedtls/mbedtls_config_common.h" From 43249bf25c396862a0d5168a17f5cddeb2c0532e Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Sun, 21 Aug 2022 22:15:06 +0100 Subject: [PATCH 04/20] extmod/ssl: Enable backwards compatibility. This adds wrap_socket to extmod/ssl.py module to mantain backwards compatibility even after ussl.wrap_socket is deprecated. Signed-off-by: Carlos Gil --- extmod/ssl/ssl.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py index d747b80f0b9fa..2745e1959e8e2 100644 --- a/extmod/ssl/ssl.py +++ b/extmod/ssl/ssl.py @@ -5,6 +5,30 @@ PROTOCOL_TLS_CLIENT = const(0) PROTOCOL_TLS_SERVER = const(1) +# backwards compatibility even after C code is deprecated +def wrap_socket( + sock, + server_side=False, + key=None, + cert=None, + cert_reqs=CERT_NONE, + cadata=None, + server_hostname=None, + do_handshake=True, +): + ctx = _ussl.ctx_init() + if (key is not None) and (cert is not None): + ctx.load_certchain(key=key, cert=cert) + if cadata: + ctx.load_cadata(cadata) + return ctx.wrap_socket( + sock, + server_side=server_side, + cert_reqs=cert_reqs, + server_hostname=server_hostname, + do_handshake=do_handshake, + ) + class SSLContext: def __init__(self, protocol): From dad71ac949d8aa0efe7227c6ecc19ddec417fbcb Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Mon, 22 Aug 2022 17:39:12 +0100 Subject: [PATCH 05/20] extmod/modussl_mbedtls: Deprecate wrap_socket in C. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 175 +++------------------------------------- extmod/ssl/ssl.py | 8 +- 2 files changed, 18 insertions(+), 165 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 9822799bb5930..cfc51755f438f 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -46,9 +46,12 @@ #include "mbedtls/debug.h" #include "mbedtls/error.h" // #if MICROPY_SSL_MBEDTLS_3 -// #include "mbedtls/build_info.h" -// #endif +// +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#include "mbedtls/build_info.h" +#else #include "mbedtls/version.h" +#endif #ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT #include "mbedtls/mbedtls_config.h" @@ -338,7 +341,11 @@ STATIC mp_obj_t mod_ssl_load_certchain(size_t n_args, const mp_obj_t *pos_args, size_t key_len; const byte *key = (const byte *)mp_obj_str_get_data(args[0].u_obj, &key_len); // len should include terminating null + #if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&ctxi->pkey, key, key_len + 1, NULL, 0, mbedtls_ctr_drbg_random, &ctxi->ctr_drbg); + #else ret = mbedtls_pk_parse_key(&ctxi->pkey, key, key_len + 1, NULL, 0); + #endif if (ret != 0) { ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors goto cleanupcertchain; @@ -445,6 +452,8 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c o->pkey = ctxi->pkey; o->ctr_drbg = ctxi->ctr_drbg; o->entropy = ctxi->entropy; + o->poll_mask = 0; + o->last_error = 0; int ret; uint32_t flags = 0; @@ -588,145 +597,6 @@ STATIC mp_obj_t mod_ssl_ctx_init() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_ssl_ctx_init_obj, mod_ssl_ctx_init); - - -STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { - // 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); - - #if MICROPY_PY_SSL_FINALISER - mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); - #else - mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); - #endif - o->base.type = &ssl_socket_type; - o->sock = sock; - o->poll_mask = 0; - o->last_error = 0; - - int ret; - 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(3); - #endif - - mbedtls_entropy_init(&o->entropy); - const byte seed[] = "upy"; - 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, - args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if (ret != 0) { - goto cleanup; - } - - mbedtls_ssl_conf_authmode(&o->conf, args->cert_reqs.u_int); - 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 (args->server_hostname.u_obj != mp_const_none) { - const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); - ret = mbedtls_ssl_set_hostname(&o->ssl, sni); - if (ret != 0) { - goto cleanup; - } - } - - mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); - - if (args->key.u_obj != mp_const_none) { - size_t key_len; - const byte *key = (const byte *)mp_obj_str_get_data(args->key.u_obj, &key_len); - // len should include terminating null - #if MBEDTLS_VERSION_NUMBER >= 0x03000000 - ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0, mbedtls_ctr_drbg_random, &o->ctr_drbg); - #else - ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); - #endif - if (ret != 0) { - ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors - goto cleanup; - } - - size_t cert_len; - const byte *cert = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &cert_len); - // len should include terminating null - ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); - if (ret != 0) { - ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors - goto cleanup; - } - - ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); - if (ret != 0) { - goto cleanup; - } - } - - if (args->cadata.u_obj != mp_const_none) { - size_t cacert_len; - const byte *cacert = (const byte *)mp_obj_str_get_data(args->cadata.u_obj, &cacert_len); - // len should include terminating null - ret = mbedtls_x509_crt_parse(&o->cacert, cacert, cacert_len + 1); - if (ret != 0) { - ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors - goto cleanup; - } - - mbedtls_ssl_conf_ca_chain(&o->conf, &o->cacert, NULL); - } - - if (args->do_handshake.u_bool) { - while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - goto cleanup; - } - #ifdef MICROPY_EVENT_POLL_HOOK - MICROPY_EVENT_POLL_HOOK - #endif - } - } - - 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); - } -} - STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) { mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); if (!mp_obj_is_true(binary_form)) { @@ -917,32 +787,9 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &ssl_socket_locals_dict ); -STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // TODO: Implement more args - static const mp_arg_t allowed_args[] = { - { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MBEDTLS_SSL_VERIFY_NONE}}, - { MP_QSTR_cadata, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - }; - - // TODO: Check that sock implements stream protocol - mp_obj_t sock = pos_args[0]; - - struct ssl_args args; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); - - return MP_OBJ_FROM_PTR(socket_new(sock, &args)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) }, - { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, { MP_ROM_QSTR(MP_QSTR_ctx_init), MP_ROM_PTR(&mod_ssl_ctx_init_obj) }, { MP_ROM_QSTR(MP_QSTR_MBEDTLS_VERSION), MP_ROM_PTR(&mbedtls_version_obj)}, { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(MBEDTLS_SSL_VERIFY_NONE) }, diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py index 2745e1959e8e2..b3c48202cc5cc 100644 --- a/extmod/ssl/ssl.py +++ b/extmod/ssl/ssl.py @@ -15,9 +15,15 @@ def wrap_socket( cadata=None, server_hostname=None, do_handshake=True, + keyfile=None, + certfile=None, ): ctx = _ussl.ctx_init() - if (key is not None) and (cert is not None): + if keyfile: + key = keyfile + if certfile: + cert = certfile + if key is not None: # and (cert is not None): ctx.load_certchain(key=key, cert=cert) if cadata: ctx.load_cadata(cadata) From 76d16d116159e93495f8acd7ea7d04aab2a05529 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 13 Sep 2022 04:37:16 +0100 Subject: [PATCH 06/20] extmod/ssl: Enable reusability of SSLContext. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 54 ++++++++++++----------- extmod/ssl/manifest.py | 2 +- extmod/ssl/ssl.py | 33 +++++++++++--- tests/multi_net/ssl_data.py | 2 +- tests/net_inet/test_ssl_context_client.py | 4 +- 5 files changed, 60 insertions(+), 35 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index cfc51755f438f..174ec5afde2eb 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -85,7 +85,7 @@ typedef struct _mp_obj_ssl_context_t { mbedtls_x509_crt cacert; mbedtls_x509_crt cert; mbedtls_pk_context pkey; - int cipherid; + int cipherid []; } mp_obj_ssl_context_t; @@ -201,7 +201,7 @@ STATIC mp_obj_ssl_context_t *context_new() { mp_obj_ssl_context_t *ctxi = m_new_obj(mp_obj_ssl_context_t); #endif ctxi->base.type = &ssl_context_type; - ctxi->cipherid = 0; + ctxi->cipherid[0] = 0; // o->sock = sock; int ret; @@ -293,21 +293,27 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ssl_get_ciphers_obj, mod_ssl_get_ciphers); STATIC mp_obj_t mod_ssl_set_ciphers(mp_obj_t self_in, mp_obj_t ciphersuite) { mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *ciphers = MP_OBJ_TO_PTR(ciphersuite); int ret = 0; - if (ciphersuite != mp_const_none) { - const char *ciphername = mp_obj_str_get_str(ciphersuite); - const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); - // const int ciphers[] = {id, 0}; - ctxi->cipherid = id; - if (id == 0) { - ret = MBEDTLS_ERR_SSL_BAD_CONFIG; - goto cleanupcipher; - } - - // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); - // ctxi->cipherid = id; + for(int i = 0, n = ciphers->len; i < n; i++){ + + if (ciphers->items[i] != mp_const_none) { + const char *ciphername = mp_obj_str_get_str(ciphers->items[i]); + const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); + // const int ciphers[] = {id, 0}; + ctxi->cipherid[i] = id; + if (id == 0) { + ret = MBEDTLS_ERR_SSL_BAD_CONFIG; + goto cleanupcipher; + } + + // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); + // ctxi->cipherid = id; + } } + + ctxi->cipherid[ciphers->len+1] = 0; return mp_const_none; @@ -470,9 +476,8 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c goto cleanup; } // Ciphersuite Config - if (ctxi->cipherid != 0) { - const int ciphers[] = {ctxi->cipherid, 0}; - mbedtls_ssl_conf_ciphersuites(&o->conf, ciphers); + if (ctxi->cipherid[0] != 0) { + mbedtls_ssl_conf_ciphersuites(&o->conf, (const int *) ctxi->cipherid); } @@ -579,15 +584,14 @@ STATIC const mp_rom_map_elem_t ssl_context_locals_dict_table [] = { STATIC MP_DEFINE_CONST_DICT(ssl_context_locals_dict, ssl_context_locals_dict_table); -STATIC const mp_obj_type_t ssl_context_type = { - { &mp_type_type }, +STATIC MP_DEFINE_CONST_OBJ_TYPE( + ssl_context_type, // Save on qstr's, reuse same as for module - .name = MP_QSTR_ssl_context, - .print = context_print, - .getiter = NULL, - .iternext = NULL, - .locals_dict = (void *)&ssl_context_locals_dict, -}; + MP_QSTR_ssl_context, + MP_TYPE_FLAG_NONE, + print, context_print, + locals_dict, &ssl_context_locals_dict + ); STATIC mp_obj_t mod_ssl_ctx_init() { diff --git a/extmod/ssl/manifest.py b/extmod/ssl/manifest.py index 92893e58d14bb..93cd39576a589 100644 --- a/extmod/ssl/manifest.py +++ b/extmod/ssl/manifest.py @@ -1 +1 @@ -freeze(".", ("ssl.py",)) +module("ssl.py", opt=3) diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py index b3c48202cc5cc..1cae75920d8a9 100644 --- a/extmod/ssl/ssl.py +++ b/extmod/ssl/ssl.py @@ -17,6 +17,7 @@ def wrap_socket( do_handshake=True, keyfile=None, certfile=None, + ciphers="", ): ctx = _ussl.ctx_init() if keyfile: @@ -27,6 +28,8 @@ def wrap_socket( ctx.load_certchain(key=key, cert=cert) if cadata: ctx.load_cadata(cadata) + if ciphers: + ctx.set_ciphers(ciphers.split(":")) return ctx.wrap_socket( sock, server_side=server_side, @@ -48,7 +51,10 @@ def __init__(self, protocol): self.key = None self.cert = None self.cadata = None + self.ciphersuite = None self.ctx = _ussl.ctx_init() + self._reload_ctx = False + # PRE-ALLOCATE CONTEXT(key,cert) and SSL socket BUFFERS e.g. from (ussl) ? # self.ssl_buffer_sock = _ussl.context_allocate_buffer() # initiate context so we can get/set ciphers? : @@ -82,12 +88,21 @@ def verify_mode(self, value): if not self.check_hostname: self._verify_mode = value - def reset(self, server=True): - self.ctx = _ussl.ctx_init() + def _reset(self, server=True): + ctx = _ussl.ctx_init() if server: - self.ctx.load_certchain(key=self.key, cert=self.cert) + ctx.load_certchain(key=self.key, cert=self.cert) + if self.cadata: + ctx.load_cadata(self.cadata) else: - self.ctx.load_cadata(self.cadata) + if self.cadata: + ctx.load_cadata(self.cadata) + if self.key: + ctx.load_certchain(key=self.key, cert=self.cert) + + if self.ciphersuite: + ctx.set_ciphers(self.ciphersuite) + return ctx def load_cert_chain(self, certfile, keyfile=None): # load certificate/key from a file, is possible to use memoryview to @@ -125,7 +140,8 @@ def get_ciphers(self): return self.ctx.get_ciphers() def set_ciphers(self, ciphersuite): - return self.ctx.set_ciphers(ciphersuite) + self.ciphersuite = ciphersuite.split(":") + return self.ctx.set_ciphers(self.ciphersuite) def wrap_socket( self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None @@ -135,10 +151,15 @@ def wrap_socket( raise ValueError("check_hostname requires server_hostname") # to be substituted by e.g. _ussl._context_wrap_socket in modussl_mbedtls.c ?: # _ussl._context_wrap_socket(*args, **kargs) - return self.ctx.wrap_socket( + if self._reload_ctx: + self.ctx = self._reset(server=server_side) + + ssl_sock = self.ctx.wrap_socket( sock, server_side=server_side, cert_reqs=self.verify_mode, server_hostname=server_hostname, do_handshake=do_handshake_on_connect, ) + self._reload_ctx = True + return ssl_sock diff --git a/tests/multi_net/ssl_data.py b/tests/multi_net/ssl_data.py index a21c8c6589377..5295efe06945e 100644 --- a/tests/multi_net/ssl_data.py +++ b/tests/multi_net/ssl_data.py @@ -49,7 +49,7 @@ def instance0(): s.listen(1) multitest.next() s2, _ = s.accept() - s2 = ssl.wrap_socket(s2, server_side=True, key=key, cert=cert) + s2 = ssl.wrap_socket(s2, server_side=True, key=key, cert=cert, ciphers="TLS-RSA-WITH-AES-256-CBC-SHA256") print(s2.read(16)) s2.write(b"server to client") s2.close() diff --git a/tests/net_inet/test_ssl_context_client.py b/tests/net_inet/test_ssl_context_client.py index e01e8f926ba38..9c37071a088b5 100644 --- a/tests/net_inet/test_ssl_context_client.py +++ b/tests/net_inet/test_ssl_context_client.py @@ -70,12 +70,12 @@ def main(use_stream=True): # context.check_hostname = True # enabled by default with # PROTOCOL_TLS_CLIENT - # print(context.get_ciphers()) + #print(context.get_ciphers()) # context.load_verify_locations(cafile='certmpy.der') # not sure how to # implement a external file # in a testd - # context.ctx.set_ciphers('TLS-RSA-WITH-AES-256-CBC-SHA') + # context.set_ciphers('TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA') context.load_verify_locations(cadata=ca_cert_chain) context.load_default_certs() # not implemented in MicroPython just a mock, needed From 4c4f5a9bcbd457805968d2424fc9796b63595652 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 6 Oct 2022 21:18:53 +0100 Subject: [PATCH 07/20] extmod/ssl: Add ciphers kwarg to ssl.wrap_socket. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 36 +++++++++++------------ ports/unix/variants/manifest.py | 1 - tests/multi_net/ssl_data.py | 4 ++- tests/net_inet/test_ssl_context_client.py | 2 +- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 174ec5afde2eb..d861853593186 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -296,24 +296,24 @@ STATIC mp_obj_t mod_ssl_set_ciphers(mp_obj_t self_in, mp_obj_t ciphersuite) { mp_obj_list_t *ciphers = MP_OBJ_TO_PTR(ciphersuite); int ret = 0; - for(int i = 0, n = ciphers->len; i < n; i++){ - - if (ciphers->items[i] != mp_const_none) { - const char *ciphername = mp_obj_str_get_str(ciphers->items[i]); - const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); - // const int ciphers[] = {id, 0}; - ctxi->cipherid[i] = id; - if (id == 0) { - ret = MBEDTLS_ERR_SSL_BAD_CONFIG; - goto cleanupcipher; - } - - // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); - // ctxi->cipherid = id; - } + for (int i = 0, n = ciphers->len; i < n; i++) { + + if (ciphers->items[i] != mp_const_none) { + const char *ciphername = mp_obj_str_get_str(ciphers->items[i]); + const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); + // const int ciphers[] = {id, 0}; + ctxi->cipherid[i] = id; + if (id == 0) { + ret = MBEDTLS_ERR_SSL_BAD_CONFIG; + goto cleanupcipher; + } + + // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); + // ctxi->cipherid = id; + } } - - ctxi->cipherid[ciphers->len+1] = 0; + + ctxi->cipherid[ciphers->len + 1] = 0; return mp_const_none; @@ -477,7 +477,7 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c } // Ciphersuite Config if (ctxi->cipherid[0] != 0) { - mbedtls_ssl_conf_ciphersuites(&o->conf, (const int *) ctxi->cipherid); + mbedtls_ssl_conf_ciphersuites(&o->conf, (const int *)ctxi->cipherid); } diff --git a/ports/unix/variants/manifest.py b/ports/unix/variants/manifest.py index 771a208f8c6b9..4fbf291dadd2d 100644 --- a/ports/unix/variants/manifest.py +++ b/ports/unix/variants/manifest.py @@ -1,4 +1,3 @@ require("mip-cmdline") require("mip") module("ssl.py", base_path="$(MPY_DIR)/extmod/ssl", opt=3) - diff --git a/tests/multi_net/ssl_data.py b/tests/multi_net/ssl_data.py index 5295efe06945e..e581da6bc44ce 100644 --- a/tests/multi_net/ssl_data.py +++ b/tests/multi_net/ssl_data.py @@ -49,7 +49,9 @@ def instance0(): s.listen(1) multitest.next() s2, _ = s.accept() - s2 = ssl.wrap_socket(s2, server_side=True, key=key, cert=cert, ciphers="TLS-RSA-WITH-AES-256-CBC-SHA256") + s2 = ssl.wrap_socket( + s2, server_side=True, key=key, cert=cert, ciphers="TLS-RSA-WITH-AES-256-CBC-SHA256" + ) print(s2.read(16)) s2.write(b"server to client") s2.close() diff --git a/tests/net_inet/test_ssl_context_client.py b/tests/net_inet/test_ssl_context_client.py index 9c37071a088b5..d0b2fa227d4df 100644 --- a/tests/net_inet/test_ssl_context_client.py +++ b/tests/net_inet/test_ssl_context_client.py @@ -70,7 +70,7 @@ def main(use_stream=True): # context.check_hostname = True # enabled by default with # PROTOCOL_TLS_CLIENT - #print(context.get_ciphers()) + # print(context.get_ciphers()) # context.load_verify_locations(cafile='certmpy.der') # not sure how to # implement a external file From c0b199f2d7532a2d71901a3e3fd7450a3c5227a9 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Sun, 18 Dec 2022 20:36:32 +0000 Subject: [PATCH 08/20] extmod/uasyncio: Add ssl support with SSLContext. Signed-off-by: Carlos Gil --- extmod/asyncio/stream.py | 49 ++++- tests/multi_net/uasyncio_tls_server_client.py | 183 ++++++++++++++++++ .../uasyncio_tls_server_client.py.exp | 8 + .../net_inet/uasyncio_tls_open_connection.py | 87 +++++++++ .../uasyncio_tls_open_connection.py.exp | 5 + 5 files changed, 325 insertions(+), 7 deletions(-) create mode 100644 tests/multi_net/uasyncio_tls_server_client.py create mode 100644 tests/multi_net/uasyncio_tls_server_client.py.exp create mode 100644 tests/net_inet/uasyncio_tls_open_connection.py create mode 100644 tests/net_inet/uasyncio_tls_open_connection.py.exp diff --git a/extmod/asyncio/stream.py b/extmod/asyncio/stream.py index c47c48cf09823..e4d80a1ff9ddb 100644 --- a/extmod/asyncio/stream.py +++ b/extmod/asyncio/stream.py @@ -3,6 +3,11 @@ from . import core +try: + import ssl as _ssl +except: + _ssl = False + class Stream: def __init__(self, s, e={}): @@ -100,20 +105,40 @@ def drain(self): # Create a TCP stream connection to a remote host # # async -def open_connection(host, port): +async def open_connection(host, port, ssl=None, server_hostname=None): from errno import EINPROGRESS import socket ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking! s = socket.socket(ai[0], ai[1], ai[2]) - s.setblocking(False) - ss = Stream(s) + if not ssl: + s.setblocking(False) + ss = Stream(s) try: s.connect(ai[-1]) except OSError as er: if er.errno != EINPROGRESS: raise er - yield core._io_queue.queue_write(s) + if not ssl: + yield core._io_queue.queue_write(s) + # wrap with SSL, if requested + if ssl: + if not _ssl: + raise ValueError("SSL not supported") + if ssl is True: + ssl = _ssl.SSLContext(_ssl.PROTOCOL_TLS_CLIENT) + # spec says to use ssl.create_default_context() + else: + try: + assert isinstance(ssl, _ssl.SSLContext) + except: + raise ValueError("Invalid ssl param") + if not server_hostname: + server_hostname = host + s = ssl.wrap_socket(s, server_hostname=server_hostname) + s.setblocking(False) + yield core._io_queue.queue_write(s) + ss = Stream(s) return ss, ss @@ -132,7 +157,7 @@ def close(self): async def wait_closed(self): await self.task - async def _serve(self, s, cb): + async def _serve(self, s, cb, ssl): # Accept incoming connections while True: try: @@ -146,6 +171,16 @@ async def _serve(self, s, cb): except: # Ignore a failed accept continue + if s2: + if isinstance(ssl, _ssl.SSLContext): + s2.setblocking(True) + try: + s2 = ssl.wrap_socket(s2, server_side=True) + except OSError as e: + print(e) + s2.close() + ssl._reload_ctx = True + continue s2.setblocking(False) s2s = Stream(s2, {"peername": addr}) core.create_task(cb(s2s, s2s)) @@ -153,7 +188,7 @@ async def _serve(self, s, cb): # Helper function to start a TCP stream server, running as a new task # TODO could use an accept-callback on socket read activity instead of creating a task -async def start_server(cb, host, port, backlog=5): +async def start_server(cb, host, port, backlog=5, ssl=None): import socket # Create and bind server socket. @@ -166,7 +201,7 @@ async def start_server(cb, host, port, backlog=5): # Create and return server object and task. srv = Server() - srv.task = core.create_task(srv._serve(s, cb)) + srv.task = core.create_task(srv._serve(s, cb, ssl)) return srv diff --git a/tests/multi_net/uasyncio_tls_server_client.py b/tests/multi_net/uasyncio_tls_server_client.py new file mode 100644 index 0000000000000..f9cb1fa58d519 --- /dev/null +++ b/tests/multi_net/uasyncio_tls_server_client.py @@ -0,0 +1,183 @@ +# Test uasyncio TCP server and client using start_server() and open_connection() + +try: + import uasyncio as asyncio +except ImportError: + try: + import asyncio + except ImportError: + print("SKIP") + raise SystemExit +import ssl +import binascii + +PORT = 8000 + +# testing/demonstration only. You should always generate your own key/cert. + +# To generate a new self-signed key/cert pair with openssl do: +# $ openssl req -x509 -newkey rsa:4096 -keyout rsa_key.pem -out rsa_cert.pem +# -days 365 -nodes +# In this case CN is: esphome.local +# +# Convert them to DER format: +# $ openssl rsa -in rsa_key.pem -out rsa_key.der -outform DER +# $ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER +# +# Then convert to hex format, eg using binascii.hexlify(data). + +cert = binascii.unhexlify( + b"308205d7308203bfa003020102020900bc63b48a700c3d49300d06092a864886f70d01010b050030" + b"8181310b3009060355040613024155310c300a06035504080c03466f6f310c300a06035504070c03" + b"42617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03666f6f31" + b"16301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d010901160b" + b"666f6f406261722e636f6d301e170d3232303731323138303031335a170d32333037313231383030" + b"31335a308181310b3009060355040613024155310c300a06035504080c03466f6f310c300a060355" + b"04070c0342617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03" + b"666f6f3116301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d01" + b"0901160b666f6f406261722e636f6d30820222300d06092a864886f70d01010105000382020f0030" + b"82020a0282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444ab7d9ff66" + b"a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51abb515cb" + b"f60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925c855ab53" + b"7785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf19f59553" + b"349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207ea57c50e9" + b"2d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e572c56a4" + b"818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a9642489cb640a" + b"937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215f657b8f9" + b"f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c56447b404" + b"8c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb78284ede285" + b"0fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a48496c01" + b"6de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d055ea4692f" + b"eb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0dfc8a11e73" + b"0203010001a350304e301d0603551d0e04160414bc6048fe3cd278257e8b7c90dedbbce8369b20b8" + b"301f0603551d23041830168014bc6048fe3cd278257e8b7c90dedbbce8369b20b8300c0603551d13" + b"040530030101ff300d06092a864886f70d01010b0500038202010009238354b43379a3d2b56e928c" + b"ac8ea28e2c01cf8148e54c0bbd4055e2e57d578697d1e2c392f1fe3bc9211d4f27ed1be631e7547a" + b"6390d7f121a9e20a195fdda73f755188b16cf39714924a9686dd7cc749421335038c0640c2c6b15d" + b"f44d74d94a97285ee2a7b075ccc9d9d632e2a5906030cf59bde14ab10660b7cf47ec9d7ae2f35963" + b"454f76735a3dac12a4a4c907183e9ccf3e07d59484c182e67edc7c35ce15c7e1072fae8c9965a126" + b"1a1f31147d4af8d1ebf8ee7c142badfe67e31fb324a79a29bc94e89370b70d8cf7cd2b2aa427a49f" + b"77849891e7c4d5911f6fda52733a3c169b0188c2d9918f296dd8e234f8962f0db5e47c6159448045" + b"4e2d9a5850d4c696a0fb3b66534a4591c49dda8cc6f1b0008c625aa5e0091ecfbd51d9715c60b85e" + b"4e89d4a6cfabb2acdf81518eb61403b8f8767c5c00216f730e08f22959dff695a081cc726c4ab35a" + b"e3f6538a231f831a6e91206f3b691a94bdf95343ec02ef7aac42da2a70846cd5f13dd2955a5f1737" + b"a4c3c6c03b041d334c1dadd1e305f07c83b4b4e0509ec1d23e95f820290942eaaf8bea304cd5a505" + b"8fc0d4624ff1ffe1348e7bc54c756a12acb258eb5e7426fb062a82b88ec274c9c13b3eff8b010947" + b"62e166f490cd25b14e762db708785859a337d8fd0008fe602a90e2933cded3359e98ce3fbc041208" + b"66bd4d96d6b6f7f53def854d40021196b7a06b" +) + +key = binascii.unhexlify( + b"308209290201000282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444a" + b"b7d9ff66a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51" + b"abb515cbf60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925" + b"c855ab537785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf" + b"19f59553349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207e" + b"a57c50e92d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e" + b"572c56a4818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a96424" + b"89cb640a937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215" + b"f657b8f9f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c5" + b"6447b4048c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb782" + b"84ede2850fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a" + b"48496c016de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d05" + b"5ea4692feb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0df" + b"c8a11e73020301000102820201008efa0e8fe81c2e2cb6ed10152dfca4242750581d3e6b54f56524" + b"a6a2d2613cf2727efcec6cfddebd4c285f1148bc2a2936c28919cb0da502dea8c92fe2f9856bee61" + b"ac1aebdac838b5e66f7c7c799df07716f30ef362dbb5485884a180c8ce5539cb1db35699dce5f217" + b"27295d811f1ce7a115111c1823b5c90ce880f5352872a7a76282f6f1fd8a015136ab274c3d30783d" + b"eb6ad7096e33d826eafdf7c70398d5eab4d28f91cd3913c69c7a7ade9ef692b9f8292959be64dec4" + b"6ab2c291b41a6464004b5ddd4b93bfe41b37eedeef4ba2d16dcbb9c28b96f57fb96c20ed4a9471ff" + b"ae643b254f100f8c9702b5f67af6369e8d887f285e5d520c5aa5d3a79e5de96432e6d2e3dea68e58" + b"208c075fb119c6d3d4149b7e1247208d6b337c70272befc41d57f278618f1a82de337173346dc135" + b"4d80a7c9075af99dbb2a14733c06b71600c6677a6bb28c0e4fc63db622228047a2cb7474dc8141c3" + b"5f3a597c3e2bca9911d28eb9fd1a0c915e9f9c1cfd643d4fd8cac867f215380168ec37b8cfa28564" + b"e6288ab04a7d67ca44b4c8375214a7ffaa1e6be92c4b138fcfd6beaba251b31a50a6e2ef241c9554" + b"a1dc710b4acb63e749f5849e53d3f4915c6eb2a9a009bab04e932841ab34ae29eb000a08777d6399" + b"169c2dc3d7952df5bc2d06e90a32139c6a2793d3817e4feadac2ccac554d383a8d41569140c29168" + b"89220d3a5e410282010100fd603d18feef7aac61bda3b674a57ab38748bcde5c3efdba2279638f8e" + b"a413cc26b9dda0375c116a8798a295b2c283aaaad7cca0dbd9bb3322a9a815f6d0aa5fc4f9aff8fb" + b"da8ff914091ede7aefdb07a119c9b2e2b2bda776ac497060b8e88a82eb20c62f26f343566697726e" + b"71aa46fd4efad6f42fc8a478856324d72cbf5eb3918317162d6fc2cfd775969a2077759fa2c8220d" + b"acdc2ebb03ec39feed3f2b415449cbf40a7126bcf01d1068e3a45ec01181f2c68d7e05b4720bfe4a" + b"308e1648123c91214a5f8dfce58727c4cd9396a8b403b733a717449b2f1970db97a3b8467271ffa6" + b"e8c7cc9e2e1c0f789284ae9efe77eaac01131463c9c1329a1ba3530282010100d05ed6ab9b9fbdf7" + b"a0f5f91f68dc3bac5789332d6ece46103fb1ef109fc972fdc99edf3107a23d66d1cdfe6bdddfd1bb" + b"3952ccd10b5c20ad1b3e0aa6a51271ecf3a7ef2a65e029f5d77f238d1235b52a9dca3451c165d70a" + b"99cbaea5c610e5455979696db769191e7cf2db21f641959e4ba1c5c0aae260c724962b6ac2621d92" + b"e9df7adeb82b522d37b42cb454003bbe60d9915bf7737aeccf88c7ed1263a22f431a734e61fe7173" + b"a937ddf76ad2a79994c05238defc15f6846858e9edf27ae2a567c7c5c735ea5d2fbef65a2195bc05" + b"d82cbf06a477b29c84c92e8054c2bb25d8c6f19d43ef5fd1fce13c2cdbc361c39baec37b399200b3" + b"2d4a6798ba0b546102820101008e41492c4e7daff7368d1d6c64034067a94dca5461a0301e201add" + b"2e0d5ccb8cb435685bfa98e362572cf8236a10d191b187a568aee688b6c60050d1bc181d7fd57c86" + b"33195bf5b7576b637c6fb358dae8b52ccc15815affb99e334137dcb91a833475db2f4004164b5d20" + b"2c6c1bbf094a50dc7e70ec9f0ed067bb6944b1e7e3c897aaecfc53984add1c4ff5b525034cf3ca95" + b"e8a09aeba804f1c7e02be391b2bc641166c3e654eef5e72dba37d98f406f3fa520e41f2ea10f5574" + b"ac5984f75145378fefbfac1d07fff3f234fec698d55e746b1da18f6f7de24ec84ed7cb446d428820" + b"bef33c00693e6a0ef114b5d66e9fefa8ee059238df1ac37c87e7841ae7028201000721a7d139c34e" + b"da21cd295894db2cc3aa3f4cdc1a35bf1a2143f2bdabea56202f7d5b802f15b36a4875f76633b2cc" + b"57cf0f71691a2d6e04deb0d1e68031d06a5eb079b406c6944910b60e3e6ec81dca369a4c0e1c4363" + b"07bed9c4c171b4f453da4b187ba3d25a04bc1c07b9f2d6adcb3c256e4238d7049eec36a387c4dd5c" + b"cbc16b5fa62dc175cf8c5f83442cb7d153a3b6ee8daa3b6e929a4bc123f1042df1d6271a992d2b6b" + b"309d33074ac7822c304a72069e61ab590915e10862013dd24cdd825ec8fb17724cfc2c59fc1db825" + b"3641fece0ee9241b9dd5c198f0d575d0b7ebe26b3489b5b09edc3bcd366fd3110e83ce886c383d31" + b"feefe6e302cc2345210282010008f77a33d0081e9be3c1b1ac8b8e0eebb72df2eb69b95d2ed74935" + b"b9dab8e17023cc38465354023c5183b51a6a20288fbb2181172be1c2fdb8b444419454e5b37f7f3b" + b"df11e28cf4746b25534eb62f7e87bbbf28eda37024368b3897fbc661b40a93e04a183db9219c04a8" + b"7643edf5d8b5dbfe3d424e91d558d5e3e2fa02ce1984ee69fb8518470eee2e7db0e1df5ac4571f78" + b"a7a2529bc1fef5e32d46994869a8d8cc47869e174d84e7976be8ebb88f2ccb71a603a8bdb06af3eb" + b"2ddbd62082f40d7987e47f2e321eb5eb2a28fefab263409f89dc97ebc723a1b751418cdd3ea684ba" + b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c" +) + + +async def handle_connection(reader, writer): + # Test that peername exists (but don't check its value, it changes) + writer.get_extra_info("peername") + + data = await reader.read(100) + print("echo:", data) + writer.write(data) + await writer.drain() + + print("close") + writer.close() + await writer.wait_closed() + + print("done") + ev.set() + + +async def tcp_server(): + global ev + + server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + server_ctx.load_cert_chain(cert, keyfile=key) + ev = asyncio.Event() + server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT, ssl=server_ctx) + print("server running") + multitest.next() + async with server: + await asyncio.wait_for(ev.wait(), 10) + + +async def tcp_client(message): + client_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_ctx.load_verify_locations(cadata=cert) + reader, writer = await asyncio.open_connection( + IP, PORT, ssl=client_ctx, server_hostname="esphome.local" + ) + print("write:", message) + writer.write(message) + await writer.drain() + data = await reader.read(100) + print("read:", data) + + +def instance0(): + multitest.globals(IP=multitest.get_network_ip()) + asyncio.run(tcp_server()) + + +def instance1(): + multitest.next() + asyncio.run(tcp_client(b"client data")) diff --git a/tests/multi_net/uasyncio_tls_server_client.py.exp b/tests/multi_net/uasyncio_tls_server_client.py.exp new file mode 100644 index 0000000000000..6dc6a9bbc7e52 --- /dev/null +++ b/tests/multi_net/uasyncio_tls_server_client.py.exp @@ -0,0 +1,8 @@ +--- instance0 --- +server running +echo: b'client data' +close +done +--- instance1 --- +write: b'client data' +read: b'client data' diff --git a/tests/net_inet/uasyncio_tls_open_connection.py b/tests/net_inet/uasyncio_tls_open_connection.py new file mode 100644 index 0000000000000..f5e6a6dde10f7 --- /dev/null +++ b/tests/net_inet/uasyncio_tls_open_connection.py @@ -0,0 +1,87 @@ +# Test simple HTTPS request with uasyncio.open_connection() + +try: + import ubinascii as binascii + import uasyncio as asyncio +except ImportError: + try: + import asyncio + import binascii + except ImportError: + print("SKIP") + raise SystemExit + +import ssl + + +# This certificate was obtained from micropython.org using openssl: +# $ openssl s_client -showcerts -connect micropython.org:443 /dev/null +# The certificate is from Let's Encrypt: +# 1 s:/C=US/O=Let's Encrypt/CN=R3 +# i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1 +# Validity +# Not Before: Sep 4 00:00:00 2020 GMT +# Not After : Sep 15 16:00:00 2025 GMT +# Copy PEM content to a file (certmpy.pem) and convert to DER e.g. +# $ openssl x509 -in certmpy.pem -out certmpy.der -outform DER +# Then convert to hex format, eg using binascii.hexlify(data). + +ca_cert_chain = binascii.unhexlify( + b"30820516308202fea003020102021100912b084acf0c18a753f6d62e25a75f5a300d06092a864886" + b"f70d01010b0500304f310b300906035504061302555331293027060355040a1320496e7465726e65" + b"742053656375726974792052657365617263682047726f7570311530130603550403130c49535247" + b"20526f6f74205831301e170d3230303930343030303030305a170d3235303931353136303030305a" + b"3032310b300906035504061302555331163014060355040a130d4c6574277320456e637279707431" + b"0b300906035504031302523330820122300d06092a864886f70d01010105000382010f003082010a" + b"0282010100bb021528ccf6a094d30f12ec8d5592c3f882f199a67a4288a75d26aab52bb9c54cb1af" + b"8e6bf975c8a3d70f4794145535578c9ea8a23919f5823c42a94e6ef53bc32edb8dc0b05cf35938e7" + b"edcf69f05a0b1bbec094242587fa3771b313e71cace19befdbe43b45524596a9c153ce34c852eeb5" + b"aeed8fde6070e2a554abb66d0e97a540346b2bd3bc66eb66347cfa6b8b8f572999f830175dba726f" + b"fb81c5add286583d17c7e709bbf12bf786dcc1da715dd446e3ccad25c188bc60677566b3f118f7a2" + b"5ce653ff3a88b647a5ff1318ea9809773f9d53f9cf01e5f5a6701714af63a4ff99b3939ddc53a706" + b"fe48851da169ae2575bb13cc5203f5ed51a18bdb150203010001a382010830820104300e0603551d" + b"0f0101ff040403020186301d0603551d250416301406082b0601050507030206082b060105050703" + b"0130120603551d130101ff040830060101ff020100301d0603551d0e04160414142eb317b75856cb" + b"ae500940e61faf9d8b14c2c6301f0603551d2304183016801479b459e67bb6e5e40173800888c81a" + b"58f6e99b6e303206082b0601050507010104263024302206082b060105050730028616687474703a" + b"2f2f78312e692e6c656e63722e6f72672f30270603551d1f0420301e301ca01aa018861668747470" + b"3a2f2f78312e632e6c656e63722e6f72672f30220603551d20041b30193008060667810c01020130" + b"0d060b2b0601040182df13010101300d06092a864886f70d01010b0500038202010085ca4e473ea3" + b"f7854485bcd56778b29863ad754d1e963d336572542d81a0eac3edf820bf5fccb77000b76e3bf65e" + b"94dee4209fa6ef8bb203e7a2b5163c91ceb4ed3902e77c258a47e6656e3f46f4d9f0ce942bee54ce" + b"12bc8c274bb8c1982fa2afcd71914a08b7c8b8237b042d08f908573e83d904330a472178098227c3" + b"2ac89bb9ce5cf264c8c0be79c04f8e6d440c5e92bb2ef78b10e1e81d4429db5920ed63b921f81226" + b"949357a01d6504c10a22ae100d4397a1181f7ee0e08637b55ab1bd30bf876e2b2aff214e1b05c3f5" + b"1897f05eacc3a5b86af02ebc3b33b9ee4bdeccfce4af840b863fc0554336f668e136176a8e99d1ff" + b"a540a734b7c0d063393539756ef2ba76c89302e9a94b6c17ce0c02d9bd81fb9fb768d40665b3823d" + b"7753f88e7903ad0a3107752a43d8559772c4290ef7c45d4ec8ae468430d7f2855f18a179bbe75e70" + b"8b07e18693c3b98fdc6171252aafdfed255052688b92dce5d6b5e3da7dd0876c842131ae82f5fbb9" + b"abc889173de14ce5380ef6bd2bbd968114ebd5db3d20a77e59d3e2f858f95bb848cdfe5c4f1629fe" + b"1e5523afc811b08dea7c9390172ffdaca20947463ff0e9b0b7ff284d6832d6675e1e69a393b8f59d" + b"8b2f0bd25243a66f3257654d3281df3853855d7e5d6629eab8dde495b5cdb5561242cdc44ec62538" + b"44506decce005518fee94964d44eca979cb45bc073a8abb847c2" +) + +client_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +client_ctx.load_verify_locations(cadata=ca_cert_chain) +client_ctx.load_default_certs() + + +async def http_get(url, port, sslctx): + reader, writer = await asyncio.open_connection(url, port, ssl=sslctx) + + print("write GET") + writer.write(b"GET / HTTP/1.0\r\n\r\n") + await writer.drain() + + print("read response") + data = await reader.read(100) + print("read:", data.split(b"\r\n")[0]) + + print("close") + writer.close() + await writer.wait_closed() + print("done") + + +asyncio.run(http_get("micropython.org", 443, client_ctx)) diff --git a/tests/net_inet/uasyncio_tls_open_connection.py.exp b/tests/net_inet/uasyncio_tls_open_connection.py.exp new file mode 100644 index 0000000000000..c8dea365b5d53 --- /dev/null +++ b/tests/net_inet/uasyncio_tls_open_connection.py.exp @@ -0,0 +1,5 @@ +write GET +read response +read: b'HTTP/1.1 200 OK' +close +done From 04e445b670a5be27b98c9a8d5420797d584810f0 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 27 Dec 2022 19:08:38 +0000 Subject: [PATCH 09/20] ports/esp32: Enable MBEDTLS_PLATFORM_TIME_ALT. This enables MBEDTLS_PLATFORM_TIME_ALT which is needed for ssl certs datetime validation. This is due to esp32 using EPOCH 1/1/2000 to get current time in seconds which is not what mbedlts expects. MBEDTLS_PLATFORM_TIME_ALT gives the option to define an alternative function to get current time. Signed-off-by: Carlos Gil --- ports/esp32/Makefile | 1 + ports/esp32/esp32_common.cmake | 2 ++ ports/esp32/mbedtls/mbedtls_config.h | 1 + 3 files changed, 4 insertions(+) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 7c8c225dfb6e9..1936ea594b9d2 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -87,3 +87,4 @@ size-files: submodules: $(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules + diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index d55dd38134fb8..95c84a51f56a8 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -59,6 +59,8 @@ list(APPEND MICROPY_SOURCE_PORT mphalport.c fatfs_port.c help.c + modtime.c + mbedtls/mbedtls_port.c machine_bitstream.c machine_timer.c machine_pin.c diff --git a/ports/esp32/mbedtls/mbedtls_config.h b/ports/esp32/mbedtls/mbedtls_config.h index 92bcee0372f73..a9f63786d3e6c 100644 --- a/ports/esp32/mbedtls/mbedtls_config.h +++ b/ports/esp32/mbedtls/mbedtls_config.h @@ -1,3 +1,4 @@ // Time mbedtls_platform +#define MBEDTLS_HAVE_ASM time_t platform_mbedtls_time(time_t *timer); From 0787489403d13b19a2ab8d0be4fc269d6cac4595 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 27 Dec 2022 21:01:36 +0000 Subject: [PATCH 10/20] extmod/modussl_mbedtls.c: Fix old-style function definition. Signed-off-by: Carlosgg --- extmod/modssl_mbedtls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index d861853593186..0594bc9b11076 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -194,7 +194,7 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } // SSLContext -STATIC mp_obj_ssl_context_t *context_new() { +STATIC mp_obj_ssl_context_t *context_new(void) { #if MICROPY_PY_SSL_FINALISER mp_obj_ssl_context_t *ctxi = m_new_obj_with_finaliser(mp_obj_ssl_context_t); #else @@ -266,7 +266,7 @@ STATIC void context_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki mp_printf(print, "<_SSLContext %p>", self); } -STATIC mp_obj_t mod_ssl_get_ciphers() { +STATIC mp_obj_t mod_ssl_get_ciphers(mp_obj_t self_in) { mp_obj_t list = mp_obj_new_list(0, NULL); const int *cipher_list = mbedtls_ssl_list_ciphersuites(); // int len_cipher_list = sizeof(cipher_list); @@ -594,7 +594,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( ); -STATIC mp_obj_t mod_ssl_ctx_init() { +STATIC mp_obj_t mod_ssl_ctx_init(void) { // TODO: Implement class methods return MP_OBJ_FROM_PTR(context_new()); } From ff27008c9085e5713a6dd480a50ae95985135b45 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 27 Dec 2022 21:53:11 +0000 Subject: [PATCH 11/20] unix/coverage: Update ssl_poll.py test. Make ssl_poll.py use ssl module and add ssl.py module to unix coverage manifest.py Signed-off-by: Carlos Gil --- ports/unix/variants/coverage/manifest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/unix/variants/coverage/manifest.py b/ports/unix/variants/coverage/manifest.py index 7c3d9a6b64d69..c4ba1a5f84002 100644 --- a/ports/unix/variants/coverage/manifest.py +++ b/ports/unix/variants/coverage/manifest.py @@ -1,3 +1,4 @@ freeze_as_str("frzstr") freeze_as_mpy("frzmpy") freeze_mpy("$(MPY_DIR)/tests/frozen") +module("ssl.py", base_path="$(MPY_DIR)/extmod/ssl", opt=3) From f71b0f42e443aad71c7fe968630febf4a86e45a7 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Wed, 28 Dec 2022 16:04:53 +0000 Subject: [PATCH 12/20] rp2/PICO_W: Enable ssl module. Signed-off-by: Carlos Gil --- ports/rp2/boards/PICO_W/manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/rp2/boards/PICO_W/manifest.py b/ports/rp2/boards/PICO_W/manifest.py index 4e38f09cdee4f..bb6d76c6be1ea 100644 --- a/ports/rp2/boards/PICO_W/manifest.py +++ b/ports/rp2/boards/PICO_W/manifest.py @@ -1,5 +1,5 @@ include("$(PORT_DIR)/boards/manifest.py") - +include("$(MPY_DIR)/extmod/ssl") require("bundle-networking") # Bluetooth From 465bab7c560609ce03f498fa20064ec023cc4e24 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 29 Dec 2022 18:39:14 +0000 Subject: [PATCH 13/20] examples/network: Fix http_server_ssl_context.py. Signed-off-by: Carlos Gil --- examples/network/http_server_ssl_context.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/network/http_server_ssl_context.py b/examples/network/http_server_ssl_context.py index e92d6e6a6c813..88a123af031be 100644 --- a/examples/network/http_server_ssl_context.py +++ b/examples/network/http_server_ssl_context.py @@ -170,7 +170,6 @@ def main(use_stream=True): print(client_s.recv(4096)) client_s.send(CONTENT % counter) client_s.close() - ctx.reset() counter += 1 print() From 0aea890ae7fbc90e0fddb53509a7f892c9006341 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 29 Dec 2022 23:28:22 +0000 Subject: [PATCH 14/20] extmod/uasyncio: Fix settrace tests. Signed-off-by: Carlos Gil --- extmod/asyncio/stream.py | 2 +- tests/multi_net/uasyncio_tls_server_client.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/extmod/asyncio/stream.py b/extmod/asyncio/stream.py index e4d80a1ff9ddb..ceb28c0ae9c28 100644 --- a/extmod/asyncio/stream.py +++ b/extmod/asyncio/stream.py @@ -172,7 +172,7 @@ async def _serve(self, s, cb, ssl): # Ignore a failed accept continue if s2: - if isinstance(ssl, _ssl.SSLContext): + if _ssl and isinstance(ssl, _ssl.SSLContext): s2.setblocking(True) try: s2 = ssl.wrap_socket(s2, server_side=True) diff --git a/tests/multi_net/uasyncio_tls_server_client.py b/tests/multi_net/uasyncio_tls_server_client.py index f9cb1fa58d519..43a220f446a8c 100644 --- a/tests/multi_net/uasyncio_tls_server_client.py +++ b/tests/multi_net/uasyncio_tls_server_client.py @@ -2,13 +2,20 @@ try: import uasyncio as asyncio + except ImportError: try: import asyncio except ImportError: print("SKIP") raise SystemExit -import ssl + +try: + import ssl +except ImportError: + print("SKIP") + raise SystemExit + import binascii PORT = 8000 From 6933f263582e9afd46f54be60bcacba01182eba8 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 19 Jan 2023 00:54:05 +0000 Subject: [PATCH 15/20] extmod/modussl_mbedtls: Remove old comments. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 0594bc9b11076..1a9b1c1fbf628 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -36,7 +36,6 @@ #include "py/stream.h" #include "py/objstr.h" -// mbedtls_time_t #include "mbedtls/platform.h" #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" @@ -218,13 +217,6 @@ STATIC mp_obj_ssl_context_t *context_new(void) { #ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT mbedtls_platform_set_time(platform_mbedtls_time); #endif - // DEBUG MBEDTLS_PLATFORM - // time_t mbt; - // time_t mbtz; - // mbt = mbedtls_time(NULL); - // mbtz = platform_mbedtls_time(NULL); - // printf("secs mbt : %lu \n\n", mbt); - // printf("secs mbtz: %lu \n\n", mbtz); mbedtls_entropy_init(&ctxi->entropy); const byte seed[] = "upy"; ret = mbedtls_ctr_drbg_seed(&ctxi->ctr_drbg, mbedtls_entropy_func, &ctxi->entropy, seed, sizeof(seed)); @@ -269,9 +261,7 @@ STATIC void context_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki STATIC mp_obj_t mod_ssl_get_ciphers(mp_obj_t self_in) { mp_obj_t list = mp_obj_new_list(0, NULL); const int *cipher_list = mbedtls_ssl_list_ciphersuites(); - // int len_cipher_list = sizeof(cipher_list); - // for (int i = 0; i <= len_cipher_list; i++) while (*cipher_list) { const char *cipher_name = mbedtls_ssl_get_ciphersuite_name(*cipher_list); mp_obj_list_append(list, @@ -301,15 +291,12 @@ STATIC mp_obj_t mod_ssl_set_ciphers(mp_obj_t self_in, mp_obj_t ciphersuite) { if (ciphers->items[i] != mp_const_none) { const char *ciphername = mp_obj_str_get_str(ciphers->items[i]); const int id = mbedtls_ssl_get_ciphersuite_id(ciphername); - // const int ciphers[] = {id, 0}; ctxi->cipherid[i] = id; if (id == 0) { ret = MBEDTLS_ERR_SSL_BAD_CONFIG; goto cleanupcipher; } - // mbedtls_ssl_conf_ciphersuites(&ctxi->conf, ciphers); - // ctxi->cipherid = id; } } @@ -337,7 +324,6 @@ STATIC mp_obj_t mod_ssl_load_certchain(size_t n_args, const mp_obj_t *pos_args, }; mp_obj_ssl_context_t *ctxi = MP_OBJ_TO_PTR(pos_args[0]); - // struct cert_chain_args args; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -520,7 +506,6 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { flags = mbedtls_ssl_get_verify_result(&o->ssl); - // ret = mbedtls_ssl_get_verify_result(&o->ssl); } mbedtls_pk_free(&o->pkey); @@ -553,7 +538,6 @@ STATIC mp_obj_ssl_socket_t *ctx_socket(mp_obj_t self_in, mp_obj_t sock, struct c } STATIC mp_obj_t mod_ssl_ctx_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // TODO: Implement more args static const mp_arg_t allowed_args[] = { { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, @@ -561,7 +545,6 @@ STATIC mp_obj_t mod_ssl_ctx_wrap_socket(size_t n_args, const mp_obj_t *pos_args, { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; - // TODO: Check that sock implements stream protocol mp_obj_t self_in = pos_args[0]; mp_obj_t sock = pos_args[1]; @@ -595,7 +578,6 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE( STATIC mp_obj_t mod_ssl_ctx_init(void) { - // TODO: Implement class methods return MP_OBJ_FROM_PTR(context_new()); } From 3f88ffc6f590e7ee4107cddfcc6c38efea3ef89f Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Tue, 24 Jan 2023 01:14:50 +0000 Subject: [PATCH 16/20] extmod/ssl: Reuse context fix. Allow reuse context after handshake failure. Signed-off-by: Carlos Gil --- extmod/ssl/ssl.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py index 1cae75920d8a9..62699fc1a43a1 100644 --- a/extmod/ssl/ssl.py +++ b/extmod/ssl/ssl.py @@ -144,7 +144,11 @@ def set_ciphers(self, ciphersuite): return self.ctx.set_ciphers(self.ciphersuite) def wrap_socket( - self, sock, server_side=False, do_handshake_on_connect=True, server_hostname=None + self, + sock, + server_side=False, + do_handshake_on_connect=True, + server_hostname=None, ): if self.check_hostname and server_hostname is None: @@ -153,13 +157,16 @@ def wrap_socket( # _ussl._context_wrap_socket(*args, **kargs) if self._reload_ctx: self.ctx = self._reset(server=server_side) - - ssl_sock = self.ctx.wrap_socket( - sock, - server_side=server_side, - cert_reqs=self.verify_mode, - server_hostname=server_hostname, - do_handshake=do_handshake_on_connect, - ) - self._reload_ctx = True + try: + ssl_sock = self.ctx.wrap_socket( + sock, + server_side=server_side, + cert_reqs=self.verify_mode, + server_hostname=server_hostname, + do_handshake=do_handshake_on_connect, + ) + self._reload_ctx = True + except Exception as e: + self._reload_ctx = True + raise e return ssl_sock From 8ed1a3404b74721781f4f9f08599efd27f24ef7c Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 26 Jan 2023 04:42:34 +0000 Subject: [PATCH 17/20] extmod: Uasyncio-mbedtls fix stream async read. This fix async stream read methods in unix port. The reason is stream ssl sockets seem to behave different from plain stream sockets.The main difference is doing partial reads on ssl sockets will clear any write/read/close "event" flag even if there is still pending data to be read. So registering the ssl socket again in the poller will wait there until a new event or timeout. The fix is check first if the ssl socket has pending data and read/return it instead of registering in the poller to wait for an event. Signed-off-by: Carlos Gil --- extmod/asyncio/stream.py | 28 +++ extmod/modssl_mbedtls.c | 9 + .../uasyncio_tls_server_client_readline.py | 194 ++++++++++++++++++ ...uasyncio_tls_server_client_readline.py.exp | 10 + 4 files changed, 241 insertions(+) create mode 100644 tests/multi_net/uasyncio_tls_server_client_readline.py create mode 100644 tests/multi_net/uasyncio_tls_server_client_readline.py.exp diff --git a/extmod/asyncio/stream.py b/extmod/asyncio/stream.py index ceb28c0ae9c28..c6bfa0827a181 100644 --- a/extmod/asyncio/stream.py +++ b/extmod/asyncio/stream.py @@ -35,6 +35,15 @@ async def wait_closed(self): def read(self, n=-1): r = b"" while True: + if hasattr(self.s, "ssl_pending"): + if self.s.ssl_pending(): + r2 = self.s.read(n) + if r2 is not None: + if n >= 0: + return r2 + if not len(r2): + return r + r += r2 yield core._io_queue.queue_read(self.s) r2 = self.s.read(n) if r2 is not None: @@ -46,6 +55,9 @@ def read(self, n=-1): # async def readinto(self, buf): + if hasattr(self.s, "ssl_pending"): + if self.s.ssl_pending(): + return self.s.readinto(buf) yield core._io_queue.queue_read(self.s) return self.s.readinto(buf) @@ -53,6 +65,15 @@ def readinto(self, buf): def readexactly(self, n): r = b"" while n: + # prevent queueing if pending read in a ssl socket + if hasattr(self.s, "ssl_pending"): + if self.s.ssl_pending(): + r2 = self.s.read(n) + if r2 is not None: + if not len(r2): + raise EOFError + r += r2 + n -= len(r2) yield core._io_queue.queue_read(self.s) r2 = self.s.read(n) if r2 is not None: @@ -66,6 +87,13 @@ def readexactly(self, n): def readline(self): l = b"" while True: + # prevent queueing if pending read in a ssl socket + if hasattr(self.s, "ssl_pending"): + if self.s.ssl_pending(): + l2 = self.s.readline() + l += l2 + if not l2 or l[-1] == 10: + return l yield core._io_queue.queue_read(self.s) l2 = self.s.readline() # may do multiple reads but won't block l += l2 diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 1a9b1c1fbf628..2872fc3aac2f8 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -684,6 +684,14 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); +STATIC mp_obj_t socket_ssl_pending(mp_obj_t self_in) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in); + int check_pending = 0; + check_pending = mbedtls_ssl_check_pending(&o->ssl); + return mp_obj_new_int(check_pending); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_ssl_pending_obj, socket_ssl_pending); + STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in); mp_uint_t ret = 0; @@ -753,6 +761,7 @@ STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = { #endif { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) }, { MP_ROM_QSTR(MP_QSTR_cipher), MP_ROM_PTR(&mod_ssl_cipher_obj) }, + { MP_ROM_QSTR(MP_QSTR_ssl_pending), MP_ROM_PTR(&socket_ssl_pending_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table); diff --git a/tests/multi_net/uasyncio_tls_server_client_readline.py b/tests/multi_net/uasyncio_tls_server_client_readline.py new file mode 100644 index 0000000000000..b292ab583ecf7 --- /dev/null +++ b/tests/multi_net/uasyncio_tls_server_client_readline.py @@ -0,0 +1,194 @@ +# Test uasyncio TCP server and client using start_server() and open_connection() + +try: + import uasyncio as asyncio + +except ImportError: + try: + import asyncio + except ImportError: + print("SKIP") + raise SystemExit + +try: + import ssl +except ImportError: + print("SKIP") + raise SystemExit + +import binascii + +PORT = 8000 + +# testing/demonstration only. You should always generate your own key/cert. + +# To generate a new self-signed key/cert pair with openssl do: +# $ openssl req -x509 -newkey rsa:4096 -keyout rsa_key.pem -out rsa_cert.pem +# -days 365 -nodes +# In this case CN is: esphome.local +# +# Convert them to DER format: +# $ openssl rsa -in rsa_key.pem -out rsa_key.der -outform DER +# $ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER +# +# Then convert to hex format, eg using binascii.hexlify(data). + +cert = binascii.unhexlify( + b"308205d7308203bfa003020102020900bc63b48a700c3d49300d06092a864886f70d01010b050030" + b"8181310b3009060355040613024155310c300a06035504080c03466f6f310c300a06035504070c03" + b"42617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03666f6f31" + b"16301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d010901160b" + b"666f6f406261722e636f6d301e170d3232303731323138303031335a170d32333037313231383030" + b"31335a308181310b3009060355040613024155310c300a06035504080c03466f6f310c300a060355" + b"04070c0342617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03" + b"666f6f3116301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d01" + b"0901160b666f6f406261722e636f6d30820222300d06092a864886f70d01010105000382020f0030" + b"82020a0282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444ab7d9ff66" + b"a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51abb515cb" + b"f60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925c855ab53" + b"7785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf19f59553" + b"349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207ea57c50e9" + b"2d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e572c56a4" + b"818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a9642489cb640a" + b"937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215f657b8f9" + b"f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c56447b404" + b"8c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb78284ede285" + b"0fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a48496c01" + b"6de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d055ea4692f" + b"eb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0dfc8a11e73" + b"0203010001a350304e301d0603551d0e04160414bc6048fe3cd278257e8b7c90dedbbce8369b20b8" + b"301f0603551d23041830168014bc6048fe3cd278257e8b7c90dedbbce8369b20b8300c0603551d13" + b"040530030101ff300d06092a864886f70d01010b0500038202010009238354b43379a3d2b56e928c" + b"ac8ea28e2c01cf8148e54c0bbd4055e2e57d578697d1e2c392f1fe3bc9211d4f27ed1be631e7547a" + b"6390d7f121a9e20a195fdda73f755188b16cf39714924a9686dd7cc749421335038c0640c2c6b15d" + b"f44d74d94a97285ee2a7b075ccc9d9d632e2a5906030cf59bde14ab10660b7cf47ec9d7ae2f35963" + b"454f76735a3dac12a4a4c907183e9ccf3e07d59484c182e67edc7c35ce15c7e1072fae8c9965a126" + b"1a1f31147d4af8d1ebf8ee7c142badfe67e31fb324a79a29bc94e89370b70d8cf7cd2b2aa427a49f" + b"77849891e7c4d5911f6fda52733a3c169b0188c2d9918f296dd8e234f8962f0db5e47c6159448045" + b"4e2d9a5850d4c696a0fb3b66534a4591c49dda8cc6f1b0008c625aa5e0091ecfbd51d9715c60b85e" + b"4e89d4a6cfabb2acdf81518eb61403b8f8767c5c00216f730e08f22959dff695a081cc726c4ab35a" + b"e3f6538a231f831a6e91206f3b691a94bdf95343ec02ef7aac42da2a70846cd5f13dd2955a5f1737" + b"a4c3c6c03b041d334c1dadd1e305f07c83b4b4e0509ec1d23e95f820290942eaaf8bea304cd5a505" + b"8fc0d4624ff1ffe1348e7bc54c756a12acb258eb5e7426fb062a82b88ec274c9c13b3eff8b010947" + b"62e166f490cd25b14e762db708785859a337d8fd0008fe602a90e2933cded3359e98ce3fbc041208" + b"66bd4d96d6b6f7f53def854d40021196b7a06b" +) + +key = binascii.unhexlify( + b"308209290201000282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444a" + b"b7d9ff66a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51" + b"abb515cbf60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925" + b"c855ab537785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf" + b"19f59553349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207e" + b"a57c50e92d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e" + b"572c56a4818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a96424" + b"89cb640a937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215" + b"f657b8f9f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c5" + b"6447b4048c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb782" + b"84ede2850fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a" + b"48496c016de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d05" + b"5ea4692feb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0df" + b"c8a11e73020301000102820201008efa0e8fe81c2e2cb6ed10152dfca4242750581d3e6b54f56524" + b"a6a2d2613cf2727efcec6cfddebd4c285f1148bc2a2936c28919cb0da502dea8c92fe2f9856bee61" + b"ac1aebdac838b5e66f7c7c799df07716f30ef362dbb5485884a180c8ce5539cb1db35699dce5f217" + b"27295d811f1ce7a115111c1823b5c90ce880f5352872a7a76282f6f1fd8a015136ab274c3d30783d" + b"eb6ad7096e33d826eafdf7c70398d5eab4d28f91cd3913c69c7a7ade9ef692b9f8292959be64dec4" + b"6ab2c291b41a6464004b5ddd4b93bfe41b37eedeef4ba2d16dcbb9c28b96f57fb96c20ed4a9471ff" + b"ae643b254f100f8c9702b5f67af6369e8d887f285e5d520c5aa5d3a79e5de96432e6d2e3dea68e58" + b"208c075fb119c6d3d4149b7e1247208d6b337c70272befc41d57f278618f1a82de337173346dc135" + b"4d80a7c9075af99dbb2a14733c06b71600c6677a6bb28c0e4fc63db622228047a2cb7474dc8141c3" + b"5f3a597c3e2bca9911d28eb9fd1a0c915e9f9c1cfd643d4fd8cac867f215380168ec37b8cfa28564" + b"e6288ab04a7d67ca44b4c8375214a7ffaa1e6be92c4b138fcfd6beaba251b31a50a6e2ef241c9554" + b"a1dc710b4acb63e749f5849e53d3f4915c6eb2a9a009bab04e932841ab34ae29eb000a08777d6399" + b"169c2dc3d7952df5bc2d06e90a32139c6a2793d3817e4feadac2ccac554d383a8d41569140c29168" + b"89220d3a5e410282010100fd603d18feef7aac61bda3b674a57ab38748bcde5c3efdba2279638f8e" + b"a413cc26b9dda0375c116a8798a295b2c283aaaad7cca0dbd9bb3322a9a815f6d0aa5fc4f9aff8fb" + b"da8ff914091ede7aefdb07a119c9b2e2b2bda776ac497060b8e88a82eb20c62f26f343566697726e" + b"71aa46fd4efad6f42fc8a478856324d72cbf5eb3918317162d6fc2cfd775969a2077759fa2c8220d" + b"acdc2ebb03ec39feed3f2b415449cbf40a7126bcf01d1068e3a45ec01181f2c68d7e05b4720bfe4a" + b"308e1648123c91214a5f8dfce58727c4cd9396a8b403b733a717449b2f1970db97a3b8467271ffa6" + b"e8c7cc9e2e1c0f789284ae9efe77eaac01131463c9c1329a1ba3530282010100d05ed6ab9b9fbdf7" + b"a0f5f91f68dc3bac5789332d6ece46103fb1ef109fc972fdc99edf3107a23d66d1cdfe6bdddfd1bb" + b"3952ccd10b5c20ad1b3e0aa6a51271ecf3a7ef2a65e029f5d77f238d1235b52a9dca3451c165d70a" + b"99cbaea5c610e5455979696db769191e7cf2db21f641959e4ba1c5c0aae260c724962b6ac2621d92" + b"e9df7adeb82b522d37b42cb454003bbe60d9915bf7737aeccf88c7ed1263a22f431a734e61fe7173" + b"a937ddf76ad2a79994c05238defc15f6846858e9edf27ae2a567c7c5c735ea5d2fbef65a2195bc05" + b"d82cbf06a477b29c84c92e8054c2bb25d8c6f19d43ef5fd1fce13c2cdbc361c39baec37b399200b3" + b"2d4a6798ba0b546102820101008e41492c4e7daff7368d1d6c64034067a94dca5461a0301e201add" + b"2e0d5ccb8cb435685bfa98e362572cf8236a10d191b187a568aee688b6c60050d1bc181d7fd57c86" + b"33195bf5b7576b637c6fb358dae8b52ccc15815affb99e334137dcb91a833475db2f4004164b5d20" + b"2c6c1bbf094a50dc7e70ec9f0ed067bb6944b1e7e3c897aaecfc53984add1c4ff5b525034cf3ca95" + b"e8a09aeba804f1c7e02be391b2bc641166c3e654eef5e72dba37d98f406f3fa520e41f2ea10f5574" + b"ac5984f75145378fefbfac1d07fff3f234fec698d55e746b1da18f6f7de24ec84ed7cb446d428820" + b"bef33c00693e6a0ef114b5d66e9fefa8ee059238df1ac37c87e7841ae7028201000721a7d139c34e" + b"da21cd295894db2cc3aa3f4cdc1a35bf1a2143f2bdabea56202f7d5b802f15b36a4875f76633b2cc" + b"57cf0f71691a2d6e04deb0d1e68031d06a5eb079b406c6944910b60e3e6ec81dca369a4c0e1c4363" + b"07bed9c4c171b4f453da4b187ba3d25a04bc1c07b9f2d6adcb3c256e4238d7049eec36a387c4dd5c" + b"cbc16b5fa62dc175cf8c5f83442cb7d153a3b6ee8daa3b6e929a4bc123f1042df1d6271a992d2b6b" + b"309d33074ac7822c304a72069e61ab590915e10862013dd24cdd825ec8fb17724cfc2c59fc1db825" + b"3641fece0ee9241b9dd5c198f0d575d0b7ebe26b3489b5b09edc3bcd366fd3110e83ce886c383d31" + b"feefe6e302cc2345210282010008f77a33d0081e9be3c1b1ac8b8e0eebb72df2eb69b95d2ed74935" + b"b9dab8e17023cc38465354023c5183b51a6a20288fbb2181172be1c2fdb8b444419454e5b37f7f3b" + b"df11e28cf4746b25534eb62f7e87bbbf28eda37024368b3897fbc661b40a93e04a183db9219c04a8" + b"7643edf5d8b5dbfe3d424e91d558d5e3e2fa02ce1984ee69fb8518470eee2e7db0e1df5ac4571f78" + b"a7a2529bc1fef5e32d46994869a8d8cc47869e174d84e7976be8ebb88f2ccb71a603a8bdb06af3eb" + b"2ddbd62082f40d7987e47f2e321eb5eb2a28fefab263409f89dc97ebc723a1b751418cdd3ea684ba" + b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c" +) + + +async def handle_connection(reader, writer): + # Test that peername exists (but don't check its value, it changes) + writer.get_extra_info("peername") + + data = await reader.readline() + print("echo:", data) + data2 = await reader.readline() + print("echo:", data2) + writer.write(data + data2) + await writer.drain() + + print("close") + writer.close() + await writer.wait_closed() + + print("done") + ev.set() + + +async def tcp_server(): + global ev + + server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + server_ctx.load_cert_chain(cert, keyfile=key) + ev = asyncio.Event() + server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT, ssl=server_ctx) + print("server running") + multitest.next() + async with server: + await asyncio.wait_for(ev.wait(), 10) + + +async def tcp_client(message): + client_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_ctx.load_verify_locations(cadata=cert) + reader, writer = await asyncio.open_connection( + IP, PORT, ssl=client_ctx, server_hostname="esphome.local" + ) + print("write:", message) + writer.write(message) + await writer.drain() + data = await reader.readline() + print("read:", data) + data2 = await reader.readline() + print("read:", data2) + + +def instance0(): + multitest.globals(IP=multitest.get_network_ip()) + asyncio.run(tcp_server()) + + +def instance1(): + multitest.next() + asyncio.run(tcp_client(b"client data\nclient data2\n")) diff --git a/tests/multi_net/uasyncio_tls_server_client_readline.py.exp b/tests/multi_net/uasyncio_tls_server_client_readline.py.exp new file mode 100644 index 0000000000000..4c93c5729aa76 --- /dev/null +++ b/tests/multi_net/uasyncio_tls_server_client_readline.py.exp @@ -0,0 +1,10 @@ +--- instance0 --- +server running +echo: b'client data\n' +echo: b'client data2\n' +close +done +--- instance1 --- +write: b'client data\nclient data2\n' +read: b'client data\n' +read: b'client data2\n' From 558892fd673a322c23d9e0eef3ea9ed7bf213d6f Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Fri, 24 Feb 2023 00:11:56 +0000 Subject: [PATCH 18/20] extmod/uasyncio: Fix readline if returns None. Reading from a stream ssl socket too soon will return `None` so this avoids adding the bytes buffer with None raising `TypeError`. Signed-off-by: Carlos Gil --- extmod/asyncio/stream.py | 16 +++- extmod/ssl/ssl.py | 2 +- tests/multi_net/ssl_context_rsa.py | 2 +- tests/net_inet/test_ssl_context_client.py | 1 - .../uasyncio_tls_open_connection_readline.py | 93 +++++++++++++++++++ 5 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 tests/net_inet/uasyncio_tls_open_connection_readline.py diff --git a/extmod/asyncio/stream.py b/extmod/asyncio/stream.py index c6bfa0827a181..04f149ac8fde5 100644 --- a/extmod/asyncio/stream.py +++ b/extmod/asyncio/stream.py @@ -2,6 +2,7 @@ # MIT license; Copyright (c) 2019-2020 Damien P. George from . import core +import sys try: import ssl as _ssl @@ -91,12 +92,18 @@ def readline(self): if hasattr(self.s, "ssl_pending"): if self.s.ssl_pending(): l2 = self.s.readline() - l += l2 + if l2: + l += l2 + if l2 is None: + continue if not l2 or l[-1] == 10: return l yield core._io_queue.queue_read(self.s) l2 = self.s.readline() # may do multiple reads but won't block - l += l2 + if l2: + l += l2 + if l2 is None: + continue if not l2 or l[-1] == 10: # \n (check l in case l2 is str) return l @@ -204,10 +211,9 @@ async def _serve(self, s, cb, ssl): s2.setblocking(True) try: s2 = ssl.wrap_socket(s2, server_side=True) - except OSError as e: - print(e) + except Exception as e: + sys.print_exception(e) s2.close() - ssl._reload_ctx = True continue s2.setblocking(False) s2s = Stream(s2, {"peername": addr}) diff --git a/extmod/ssl/ssl.py b/extmod/ssl/ssl.py index 62699fc1a43a1..86bda756dcab7 100644 --- a/extmod/ssl/ssl.py +++ b/extmod/ssl/ssl.py @@ -5,6 +5,7 @@ PROTOCOL_TLS_CLIENT = const(0) PROTOCOL_TLS_SERVER = const(1) + # backwards compatibility even after C code is deprecated def wrap_socket( sock, @@ -150,7 +151,6 @@ def wrap_socket( do_handshake_on_connect=True, server_hostname=None, ): - if self.check_hostname and server_hostname is None: raise ValueError("check_hostname requires server_hostname") # to be substituted by e.g. _ussl._context_wrap_socket in modussl_mbedtls.c ?: diff --git a/tests/multi_net/ssl_context_rsa.py b/tests/multi_net/ssl_context_rsa.py index 2de4d048e49ac..712016f6a3290 100644 --- a/tests/multi_net/ssl_context_rsa.py +++ b/tests/multi_net/ssl_context_rsa.py @@ -128,9 +128,9 @@ b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c" ) + # Server def instance0(): - multitest.globals(IP=multitest.get_network_ip()) s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) diff --git a/tests/net_inet/test_ssl_context_client.py b/tests/net_inet/test_ssl_context_client.py index d0b2fa227d4df..33c2a2d39b7fa 100644 --- a/tests/net_inet/test_ssl_context_client.py +++ b/tests/net_inet/test_ssl_context_client.py @@ -60,7 +60,6 @@ def main(use_stream=True): - context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # context.verify_mode = ssl.CERT_REQUIRED # enabled by default with diff --git a/tests/net_inet/uasyncio_tls_open_connection_readline.py b/tests/net_inet/uasyncio_tls_open_connection_readline.py new file mode 100644 index 0000000000000..3fb38604fbfaa --- /dev/null +++ b/tests/net_inet/uasyncio_tls_open_connection_readline.py @@ -0,0 +1,93 @@ +# Test simple HTTPS request with uasyncio.open_connection() + +try: + import ubinascii as binascii + import uasyncio as asyncio +except ImportError: + try: + import asyncio + import binascii + except ImportError: + print("SKIP") + raise SystemExit + +import ssl + + +# This certificate was obtained from micropython.org using openssl: +# $ openssl s_client -showcerts -connect micropython.org:443 /dev/null +# The certificate is from Let's Encrypt: +# 1 s:/C=US/O=Let's Encrypt/CN=R3 +# i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1 +# Validity +# Not Before: Sep 4 00:00:00 2020 GMT +# Not After : Sep 15 16:00:00 2025 GMT +# Copy PEM content to a file (certmpy.pem) and convert to DER e.g. +# $ openssl x509 -in certmpy.pem -out certmpy.der -outform DER +# Then convert to hex format, eg using binascii.hexlify(data). + +ca_cert_chain = binascii.unhexlify( + b"30820516308202fea003020102021100912b084acf0c18a753f6d62e25a75f5a300d06092a864886" + b"f70d01010b0500304f310b300906035504061302555331293027060355040a1320496e7465726e65" + b"742053656375726974792052657365617263682047726f7570311530130603550403130c49535247" + b"20526f6f74205831301e170d3230303930343030303030305a170d3235303931353136303030305a" + b"3032310b300906035504061302555331163014060355040a130d4c6574277320456e637279707431" + b"0b300906035504031302523330820122300d06092a864886f70d01010105000382010f003082010a" + b"0282010100bb021528ccf6a094d30f12ec8d5592c3f882f199a67a4288a75d26aab52bb9c54cb1af" + b"8e6bf975c8a3d70f4794145535578c9ea8a23919f5823c42a94e6ef53bc32edb8dc0b05cf35938e7" + b"edcf69f05a0b1bbec094242587fa3771b313e71cace19befdbe43b45524596a9c153ce34c852eeb5" + b"aeed8fde6070e2a554abb66d0e97a540346b2bd3bc66eb66347cfa6b8b8f572999f830175dba726f" + b"fb81c5add286583d17c7e709bbf12bf786dcc1da715dd446e3ccad25c188bc60677566b3f118f7a2" + b"5ce653ff3a88b647a5ff1318ea9809773f9d53f9cf01e5f5a6701714af63a4ff99b3939ddc53a706" + b"fe48851da169ae2575bb13cc5203f5ed51a18bdb150203010001a382010830820104300e0603551d" + b"0f0101ff040403020186301d0603551d250416301406082b0601050507030206082b060105050703" + b"0130120603551d130101ff040830060101ff020100301d0603551d0e04160414142eb317b75856cb" + b"ae500940e61faf9d8b14c2c6301f0603551d2304183016801479b459e67bb6e5e40173800888c81a" + b"58f6e99b6e303206082b0601050507010104263024302206082b060105050730028616687474703a" + b"2f2f78312e692e6c656e63722e6f72672f30270603551d1f0420301e301ca01aa018861668747470" + b"3a2f2f78312e632e6c656e63722e6f72672f30220603551d20041b30193008060667810c01020130" + b"0d060b2b0601040182df13010101300d06092a864886f70d01010b0500038202010085ca4e473ea3" + b"f7854485bcd56778b29863ad754d1e963d336572542d81a0eac3edf820bf5fccb77000b76e3bf65e" + b"94dee4209fa6ef8bb203e7a2b5163c91ceb4ed3902e77c258a47e6656e3f46f4d9f0ce942bee54ce" + b"12bc8c274bb8c1982fa2afcd71914a08b7c8b8237b042d08f908573e83d904330a472178098227c3" + b"2ac89bb9ce5cf264c8c0be79c04f8e6d440c5e92bb2ef78b10e1e81d4429db5920ed63b921f81226" + b"949357a01d6504c10a22ae100d4397a1181f7ee0e08637b55ab1bd30bf876e2b2aff214e1b05c3f5" + b"1897f05eacc3a5b86af02ebc3b33b9ee4bdeccfce4af840b863fc0554336f668e136176a8e99d1ff" + b"a540a734b7c0d063393539756ef2ba76c89302e9a94b6c17ce0c02d9bd81fb9fb768d40665b3823d" + b"7753f88e7903ad0a3107752a43d8559772c4290ef7c45d4ec8ae468430d7f2855f18a179bbe75e70" + b"8b07e18693c3b98fdc6171252aafdfed255052688b92dce5d6b5e3da7dd0876c842131ae82f5fbb9" + b"abc889173de14ce5380ef6bd2bbd968114ebd5db3d20a77e59d3e2f858f95bb848cdfe5c4f1629fe" + b"1e5523afc811b08dea7c9390172ffdaca20947463ff0e9b0b7ff284d6832d6675e1e69a393b8f59d" + b"8b2f0bd25243a66f3257654d3281df3853855d7e5d6629eab8dde495b5cdb5561242cdc44ec62538" + b"44506decce005518fee94964d44eca979cb45bc073a8abb847c2" +) + +client_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +client_ctx.load_verify_locations(cadata=ca_cert_chain) +client_ctx.load_default_certs() + + +async def http_get(url, port, sslctx): + reader, writer = await asyncio.open_connection(url, port, ssl=sslctx) + + print("write GET") + writer.write(b"GET / HTTP/1.0\r\n\r\n") + await writer.drain() + + print("read response") + # await asyncio.sleep(1) + while True: + data = await reader.readline() + # avoid printing datetime which makes the test fail + if b"GMT" not in data: + print("read:", data) + if not data: + break + + print("close") + writer.close() + await writer.wait_closed() + print("done") + + +asyncio.run(http_get("micropython.org", 443, client_ctx)) From deffb44c1936fec385f0a6f53787b99af225d670 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Thu, 8 Jun 2023 18:06:42 +0100 Subject: [PATCH 19/20] tests: Rename imports. Signed-off-by: Carlos Gil --- tests/multi_net/ssl_context_rsa.py | 3 ++- tests/net_inet/test_ssl_context_client.py | 10 +--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/multi_net/ssl_context_rsa.py b/tests/multi_net/ssl_context_rsa.py index 712016f6a3290..1f484e1bb28d4 100644 --- a/tests/multi_net/ssl_context_rsa.py +++ b/tests/multi_net/ssl_context_rsa.py @@ -2,7 +2,8 @@ # This test won't run under CPython because CPython doesn't have key/cert try: - import ubinascii as binascii, usocket as socket + import binascii + import socket import ssl except ImportError: print("SKIP") diff --git a/tests/net_inet/test_ssl_context_client.py b/tests/net_inet/test_ssl_context_client.py index 33c2a2d39b7fa..d8e4e61b34769 100644 --- a/tests/net_inet/test_ssl_context_client.py +++ b/tests/net_inet/test_ssl_context_client.py @@ -1,14 +1,6 @@ import socket import ssl - -try: - import ubinascii as binascii -except: - import binascii -try: - import usocket as socket -except: - import socket +import binascii # This certificate was obtained from micropython.org using openssl: # $ openssl s_client -showcerts -connect micropython.org:443 /dev/null From 3d071ff2b3a4137daba05cfad77b1b114abfa5b8 Mon Sep 17 00:00:00 2001 From: Carlosgg Date: Sat, 24 Jun 2023 00:58:56 +0100 Subject: [PATCH 20/20] esp32/mbedtls: Datetime cert validation in idfv5. Signed-off-by: Carlos Gil --- extmod/modssl_mbedtls.c | 1 + ports/esp32/mbedtls/mbedtls_port.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c index 2872fc3aac2f8..9e0364680a9b7 100644 --- a/extmod/modssl_mbedtls.c +++ b/extmod/modssl_mbedtls.c @@ -48,6 +48,7 @@ // #if MBEDTLS_VERSION_NUMBER >= 0x03000000 #include "mbedtls/build_info.h" +#include "mbedtls/platform_time.h" #else #include "mbedtls/version.h" #endif diff --git a/ports/esp32/mbedtls/mbedtls_port.c b/ports/esp32/mbedtls/mbedtls_port.c index 7150f9bfdb714..2d807d1c172ae 100644 --- a/ports/esp32/mbedtls/mbedtls_port.c +++ b/ports/esp32/mbedtls/mbedtls_port.c @@ -6,8 +6,11 @@ #include #include "shared/timeutils/timeutils.h" + #ifdef MICROPY_MBEDTLS_PLATFORM_TIME_ALT +#include "mbedtls/platform_time.h" + time_t platform_mbedtls_time(time_t *timer) { // mbedtls_time requires time in seconds from EPOCH 1970