From e6dabbc398a2bfed2e528dec1b89e9f6f08aead4 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 8 Apr 2025 12:37:03 +0100 Subject: [PATCH 01/13] Update LwIP to 2.2.1 Fixes #2369 --- MODULE.bazel | 2 +- lib/lwip | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index d3afd78ff..93847f91d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -114,7 +114,7 @@ new_git_repository( new_git_repository( name = "lwip", build_file = "//src/rp2_common/pico_lwip:lwip.BUILD", - commit = "0a0452b2c39bdd91e252aef045c115f88f6ca773", # keep-in-sync-with-submodule: lib/lwip + commit = "77dcd25a72509eb83f72b033d219b1d40cd8eb95", # keep-in-sync-with-submodule: lib/lwip remote = "https://github.com/lwip-tcpip/lwip.git", ) diff --git a/lib/lwip b/lib/lwip index 0a0452b2c..77dcd25a7 160000 --- a/lib/lwip +++ b/lib/lwip @@ -1 +1 @@ -Subproject commit 0a0452b2c39bdd91e252aef045c115f88f6ca773 +Subproject commit 77dcd25a72509eb83f72b033d219b1d40cd8eb95 From 0081bf8da41086b3c70d3ae86ca68435a9be808c Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 8 Apr 2025 14:53:21 +0100 Subject: [PATCH 02/13] Update to mbedtls to 3.6.1 Fixes #2391 --- lib/mbedtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mbedtls b/lib/mbedtls index 5a764e555..107ea89da 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit 5a764e5555c64337ed17444410269ff21cb617b1 +Subproject commit 107ea89daaefb9867ea9121002fbbdf926780e98 From ccffe992fef71270d27707417c8b626e4827a6bb Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 8 Apr 2025 13:00:28 +0100 Subject: [PATCH 03/13] Add missing config docs for overriding libs Adds some docs for pico_mbedtls Documents the config for overriding the code in pico-sdk/libs --- docs/index.h | 1 + src/rp2_common/pico_btstack/CMakeLists.txt | 1 + src/rp2_common/pico_cyw43_driver/CMakeLists.txt | 1 + src/rp2_common/pico_lwip/CMakeLists.txt | 1 + src/rp2_common/pico_mbedtls/CMakeLists.txt | 1 + src/rp2_common/pico_mbedtls/doc.h | 11 +++++++++++ src/rp2_common/pico_mbedtls/pico_mbedtls.c | 2 +- src/rp2_common/tinyusb/CMakeLists.txt | 1 + 8 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/rp2_common/pico_mbedtls/doc.h diff --git a/docs/index.h b/docs/index.h index a4f88a431..be52f6a0d 100644 --- a/docs/index.h +++ b/docs/index.h @@ -80,6 +80,7 @@ * \defgroup tinyusb_device tinyusb_device * \defgroup tinyusb_host tinyusb_host * \endcond + * \cond pico_mbedtls \defgroup pico_mbedtls pico_mbedtls \endcond * @} * * \defgroup networking Networking Libraries diff --git a/src/rp2_common/pico_btstack/CMakeLists.txt b/src/rp2_common/pico_btstack/CMakeLists.txt index dcfcad4fe..7c277bd67 100644 --- a/src/rp2_common/pico_btstack/CMakeLists.txt +++ b/src/rp2_common/pico_btstack/CMakeLists.txt @@ -1,3 +1,4 @@ +# PICO_CMAKE_CONFIG: PICO_BTSTACK_PATH, Path to an alternative version of btstack overriding the version in pico-sdk/libs/btstack. Can be passed to cmake or set in your environment, type=string, group=pico_btstack if (DEFINED ENV{PICO_BTSTACK_PATH} AND (NOT PICO_BTSTACK_PATH)) set(PICO_BTSTACK_PATH $ENV{PICO_BTSTACK_PATH}) message("Using PICO_BTSTACK_PATH from environment ('${PICO_BTSTACK_PATH}')") diff --git a/src/rp2_common/pico_cyw43_driver/CMakeLists.txt b/src/rp2_common/pico_cyw43_driver/CMakeLists.txt index 289a22ab4..13ac2043c 100644 --- a/src/rp2_common/pico_cyw43_driver/CMakeLists.txt +++ b/src/rp2_common/pico_cyw43_driver/CMakeLists.txt @@ -1,3 +1,4 @@ +# PICO_CMAKE_CONFIG: PICO_CYW43_DRIVER_PATH, Path to an alternative version of cyw43-driver overriding the version in pico-sdk/libs/cyw43-driver, type=string, group=pico_cyw43_driver if (DEFINED ENV{PICO_CYW43_DRIVER_PATH} AND (NOT PICO_CYW43_DRIVER_PATH)) set(PICO_CYW43_DRIVER_PATH $ENV{PICO_CYW43_DRIVER_PATH}) message("Using PICO_CYW43_DRIVER_PATH from environment ('${PICO_CYW43_DRIVER_PATH}')") diff --git a/src/rp2_common/pico_lwip/CMakeLists.txt b/src/rp2_common/pico_lwip/CMakeLists.txt index e412f3727..e22b7e4f7 100644 --- a/src/rp2_common/pico_lwip/CMakeLists.txt +++ b/src/rp2_common/pico_lwip/CMakeLists.txt @@ -1,3 +1,4 @@ +# PICO_CMAKE_CONFIG: PICO_LWIP_PATH, Path to an alternative version of lwip overriding the version in pico-sdk/libs/lwip. Can be passed to cmake or set in your environment, type=string, group=pico_lwip if (DEFINED ENV{PICO_LWIP_PATH} AND (NOT PICO_LWIP_PATH)) set(PICO_LWIP_PATH $ENV{PICO_LWIP_PATH}) message("Using PICO_LWIP_PATH from environment ('${PICO_LWIP_PATH}')") diff --git a/src/rp2_common/pico_mbedtls/CMakeLists.txt b/src/rp2_common/pico_mbedtls/CMakeLists.txt index 13976d6fb..ce5595629 100644 --- a/src/rp2_common/pico_mbedtls/CMakeLists.txt +++ b/src/rp2_common/pico_mbedtls/CMakeLists.txt @@ -1,3 +1,4 @@ +# PICO_CMAKE_CONFIG: PICO_MBEDTLS_PATH, Path to an alternative version of mbedtls overriding the version in pico-sdk/libs/mbedtls. Can be passed to cmake or set in your environment, type=string, group=pico_mbedtls if (DEFINED ENV{PICO_MBEDTLS_PATH} AND (NOT PICO_MBEDTLS_PATH)) set(PICO_MBEDTLS_PATH $ENV{PICO_MBEDTLS_PATH}) message("Using PICO_MBEDTLS_PATH from environment ('${PICO_MBEDTLS_PATH}')") diff --git a/src/rp2_common/pico_mbedtls/doc.h b/src/rp2_common/pico_mbedtls/doc.h new file mode 100644 index 000000000..91591fc99 --- /dev/null +++ b/src/rp2_common/pico_mbedtls/doc.h @@ -0,0 +1,11 @@ +/** + * \defgroup pico_mbedtls pico_mbedtls + * \brief pico-sdk wrapper library for mbedtls + * the documentation for which is here. + * + * Builds mbedtls for pico-sdk and implements functions to take advantage of hardware support, if enabled in mbedtls_config.h + * + * * \c \b MBEDTLS_ENTROPY_HARDWARE_ALT, implementation of a hardware entropy collector that uses \ref get_rand_64 + * * \c \b MBEDTLS_SHA256_ALT, use SHA256 hardware acceleration. Only valid if LIB_PICO_SHA256 is defined (i.e. not available for rp2040) + * + */ diff --git a/src/rp2_common/pico_mbedtls/pico_mbedtls.c b/src/rp2_common/pico_mbedtls/pico_mbedtls.c index 853d97cdf..03a41da47 100644 --- a/src/rp2_common/pico_mbedtls/pico_mbedtls.c +++ b/src/rp2_common/pico_mbedtls/pico_mbedtls.c @@ -27,7 +27,7 @@ int mbedtls_hardware_poll(void *data __unused, unsigned char *output, size_t len #error SHA256 hardware acceleration not supported #endif -// PICO_CONFIG: PICO_MBEDTLS_SHA256_ALT_USE_DMA, Whether to use DMA for writing to hardware for the mbedtls SHA-256 hardware acceleration, type=int, default=1, group=pico_stdlib +// PICO_CONFIG: PICO_MBEDTLS_SHA256_ALT_USE_DMA, Whether to use DMA for writing to hardware for the mbedtls SHA-256 hardware acceleration, type=int, default=1, group=pico_mbedtls #ifndef PICO_MBEDTLS_SHA256_ALT_USE_DMA #define PICO_MBEDTLS_SHA256_ALT_USE_DMA 1 #endif diff --git a/src/rp2_common/tinyusb/CMakeLists.txt b/src/rp2_common/tinyusb/CMakeLists.txt index e305b36c0..88c79b8af 100644 --- a/src/rp2_common/tinyusb/CMakeLists.txt +++ b/src/rp2_common/tinyusb/CMakeLists.txt @@ -1,3 +1,4 @@ +# PICO_CMAKE_CONFIG: PICO_TINYUSB_PATH, Path to an alternative version of tinyusb overriding the version in pico-sdk/libs/tinyusb. Can be passed to cmake or set in your environment, type=string, group=tinyusb_device if (DEFINED ENV{PICO_TINYUSB_PATH} AND (NOT PICO_TINYUSB_PATH)) set(PICO_TINYUSB_PATH $ENV{PICO_TINYUSB_PATH}) message("Using PICO_TINYUSB_PATH from environment ('${PICO_TINYUSB_PATH}')") From e15c80dfdc3bf4b452363cd75976b4b94c5d94c0 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Thu, 16 Jan 2025 11:03:06 +0000 Subject: [PATCH 04/13] Support using a more recent version of mbedtls There are some build changes needed for the latest version of mbedtls. --- src/rp2_common/pico_mbedtls/CMakeLists.txt | 68 +++++++++++++++---- .../include/pico_mbedtls_config.h | 3 + 2 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 src/rp2_common/pico_mbedtls/include/pico_mbedtls_config.h diff --git a/src/rp2_common/pico_mbedtls/CMakeLists.txt b/src/rp2_common/pico_mbedtls/CMakeLists.txt index ce5595629..f1becc27f 100644 --- a/src/rp2_common/pico_mbedtls/CMakeLists.txt +++ b/src/rp2_common/pico_mbedtls/CMakeLists.txt @@ -16,16 +16,25 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) pico_register_common_scope_var(PICO_MBEDTLS_PATH) + # We use version 2.28.8. But this should build version 3.5.1 + if (NOT MBEDTLS_VERSION_MAJOR) + if (EXISTS ${PICO_MBEDTLS_PATH}/library/ssl_cli.c) + set(MBEDTLS_VERSION_MAJOR 2) + elseif (EXISTS ${PICO_MBEDTLS_PATH}/library/ssl_client.c) + set(MBEDTLS_VERSION_MAJOR 3) + else() + message(WARNING "Cannot determine the version of mbedtls") + endif() + endif() + set(src_crypto aes.c aesni.c - arc4.c aria.c asn1parse.c asn1write.c base64.c bignum.c - blowfish.c camellia.c ccm.c chacha20.c @@ -46,12 +55,9 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) entropy_poll.c error.c gcm.c - havege.c hkdf.c hmac_drbg.c md.c - md2.c - md4.c md5.c memory_buffer_alloc.c mps_reader.c @@ -73,7 +79,6 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) psa_crypto_aead.c psa_crypto_cipher.c psa_crypto_client.c - psa_crypto_driver_wrappers.c psa_crypto_ecp.c psa_crypto_hash.c psa_crypto_mac.c @@ -84,7 +89,6 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) psa_its_file.c ripemd160.c rsa.c - rsa_internal.c sha1.c sha256.c sha512.c @@ -92,15 +96,29 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) timing.c version.c version_features.c - xtea.c ) + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_crypto + arc4.c + blowfish.c + havege.c + md2.c + md4.c + psa_crypto_driver_wrappers.c + rsa_internal.c xtea.c + ) + elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) + list(APPEND src_crypto + bignum_core.c + rsa_alt_helpers.c + pk_ecc.c + ) + endif() list(TRANSFORM src_crypto PREPEND ${PICO_MBEDTLS_PATH}/library/) pico_add_library(pico_mbedtls_crypto NOFLAG) target_sources(pico_mbedtls_crypto INTERFACE ${src_crypto}) set(src_x509 - certs.c - pkcs11.c x509.c x509_create.c x509_crl.c @@ -109,6 +127,13 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) x509write_crt.c x509write_csr.c ) + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_x509 + certs.c + pkcs11.c + ) + endif() + list(TRANSFORM src_x509 PREPEND ${PICO_MBEDTLS_PATH}/library/) pico_add_library(pico_mbedtls_x509 NOFLAG) target_sources(pico_mbedtls_x509 INTERFACE ${src_x509}) @@ -118,14 +143,26 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) net_sockets.c ssl_cache.c ssl_ciphersuites.c - ssl_cli.c ssl_cookie.c ssl_msg.c - ssl_srv.c ssl_ticket.c ssl_tls.c ssl_tls13_keys.c ) + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_tls + ssl_cli.c + ssl_srv.c + ) + elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) + list(APPEND src_tls + ssl_client.c + ssl_debug_helpers_generated.c + ssl_tls12_client.c + ssl_tls12_server.c + ) + endif() + list(TRANSFORM src_tls PREPEND ${PICO_MBEDTLS_PATH}/library/) pico_add_library(pico_mbedtls_tls NOFLAG) target_sources(pico_mbedtls_tls INTERFACE ${src_tls}) @@ -135,7 +172,12 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) if (DEFINED PICO_MBEDTLS_CONFIG_FILE) target_compile_definitions(pico_mbedtls_headers INTERFACE MBEDTLS_CONFIG_FILE="${PICO_MBEDTLS_CONFIG_FILE}") else() - target_compile_definitions(pico_mbedtls_headers INTERFACE MBEDTLS_CONFIG_FILE="mbedtls_config.h") + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + target_compile_definitions(pico_mbedtls_headers INTERFACE MBEDTLS_CONFIG_FILE="mbedtls_config.h") + else() + # Avoid including mbedtls/include/mbedtls_config.h + target_compile_definitions(pico_mbedtls_headers INTERFACE MBEDTLS_CONFIG_FILE="pico_mbedtls_config.h") + endif() endif() if (TARGET pico_sha256) pico_mirrored_target_link_libraries(pico_mbedtls INTERFACE pico_sha256) diff --git a/src/rp2_common/pico_mbedtls/include/pico_mbedtls_config.h b/src/rp2_common/pico_mbedtls/include/pico_mbedtls_config.h new file mode 100644 index 000000000..6c86b8e7c --- /dev/null +++ b/src/rp2_common/pico_mbedtls/include/pico_mbedtls_config.h @@ -0,0 +1,3 @@ +// Latest versions of mbedtls include mbedtls/include/mbedtls_config.h and we used to set MBEDTLS_CONFIG_FILE=mbedtls_config.h +// To maintain compatibility with this and avoid including the mbedtls version of mbedtls_config.h we include pico_mbedtls_config.h first +#include "mbedtls_config.h" \ No newline at end of file From a33f2d376db0345d723ba625a05f69ef4c51a0d5 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 8 Apr 2025 16:00:32 +0100 Subject: [PATCH 05/13] Fix LwIP file altcp_tls_mbedtls.c altcp_tls_mbedtls.c is not compatible with mbedtls 3.x so use a patched version until this is resolved. Make sure MBEDTLS_VERSION_MAJOR is visible to LwIP. --- src/cmake/rp2_common.cmake | 2 +- src/rp2_common/pico_lwip/CMakeLists.txt | 17 +- src/rp2_common/pico_lwip/altcp_tls_mbedtls.c | 1399 ++++++++++++++++++ src/rp2_common/pico_mbedtls/CMakeLists.txt | 3 +- 4 files changed, 1418 insertions(+), 3 deletions(-) create mode 100644 src/rp2_common/pico_lwip/altcp_tls_mbedtls.c diff --git a/src/cmake/rp2_common.cmake b/src/cmake/rp2_common.cmake index 9e6f9f3fa..c02f9e2ca 100644 --- a/src/cmake/rp2_common.cmake +++ b/src/cmake/rp2_common.cmake @@ -127,9 +127,9 @@ if (NOT PICO_BARE_METAL) pico_add_subdirectory(rp2_common/pico_async_context) pico_add_subdirectory(rp2_common/pico_btstack) pico_add_subdirectory(rp2_common/pico_cyw43_driver) + pico_add_subdirectory(rp2_common/pico_mbedtls) pico_add_subdirectory(rp2_common/pico_lwip) pico_add_subdirectory(rp2_common/pico_cyw43_arch) - pico_add_subdirectory(rp2_common/pico_mbedtls) pico_add_subdirectory(rp2_common/pico_time_adapter) diff --git a/src/rp2_common/pico_lwip/CMakeLists.txt b/src/rp2_common/pico_lwip/CMakeLists.txt index e22b7e4f7..42dd1dfd7 100644 --- a/src/rp2_common/pico_lwip/CMakeLists.txt +++ b/src/rp2_common/pico_lwip/CMakeLists.txt @@ -235,14 +235,29 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH}) ${PICO_LWIP_PATH}/src/apps/tftp/tftp.c ) + # Mbed TLS files pico_add_library(pico_lwip_mbedtls NOFLAG) target_sources(pico_lwip_mbedtls INTERFACE - ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c ${PICO_LWIP_PATH}/src/apps/snmp/snmpv3_mbedtls.c ) + # altcp_tls_mbedtls.c is not compatible with mbedtls 3.x so use a patched version until this is resolved + # See https://savannah.nongnu.org/patch/index.php?10448 + if (MBEDTLS_VERSION_MAJOR AND MBEDTLS_VERSION_MAJOR GREATER_EQUAL 3) + target_sources(pico_lwip_mbedtls INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/altcp_tls_mbedtls.c + ) + target_include_directories(pico_lwip_mbedtls INTERFACE + ${PICO_LWIP_PATH}/src/apps/altcp_tls + ) + else() + target_sources(pico_lwip_mbedtls INTERFACE + ${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c + ) + endif() + # MQTT client files pico_add_library(pico_lwip_mqtt NOFLAG) target_sources(pico_lwip_mqtt INTERFACE diff --git a/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c b/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c new file mode 100644 index 000000000..adefa716a --- /dev/null +++ b/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c @@ -0,0 +1,1399 @@ +/** + * @file + * Application layered TCP/TLS connection API (to be used from TCPIP thread) + * + * This file provides a TLS layer using mbedTLS + * + * This version is currently compatible with the 2.x.x branch (current LTS). + */ + +/* + * Copyright (c) 2017 Simon Goldschmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + * Watch out: + * - 'sent' is always called with len==0 to the upper layer. This is because keeping + * track of the ratio of application data and TLS overhead would be too much. + * + * Mandatory security-related configuration: + * - ensure to add at least one strong entropy source to your mbedtls port (implement + * mbedtls_platform_entropy_poll or mbedtls_hardware_poll providing strong entropy) + * - define ALTCP_MBEDTLS_ENTROPY_PTR and ALTCP_MBEDTLS_ENTROPY_LEN to something providing + * GOOD custom entropy + * + * Missing things / @todo: + * - some unhandled/untested things might be caught by LWIP_ASSERTs... + */ + +#include "lwip/opt.h" +#include "lwip/sys.h" + +#if LWIP_ALTCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/apps/altcp_tls_mbedtls_opts.h" + +#if LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS + +#include "lwip/altcp.h" +#include "lwip/altcp_tls.h" +#include "lwip/priv/altcp_priv.h" + +#include "altcp_tls_mbedtls_structs.h" +#include "altcp_tls_mbedtls_mem.h" + +/* @todo: which includes are really needed? */ +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#if MBEDTLS_VERSION_MAJOR < 3 +#include "mbedtls/certs.h" +#endif +#include "mbedtls/x509.h" +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/platform.h" +#include "mbedtls/memory_buffer_alloc.h" +#include "mbedtls/ssl_cache.h" +#include "mbedtls/ssl_ticket.h" + +#if MBEDTLS_VERSION_MAJOR < 3 +#include "mbedtls/ssl_internal.h" /* to call mbedtls_flush_output after ERR_MEM */ +#else +int mbedtls_ssl_flush_output(mbedtls_ssl_context *ssl); +size_t mbedtls_ssl_get_output_max_frag_len(const mbedtls_ssl_context *ssl); +#endif + +#include + +#ifndef ALTCP_MBEDTLS_ENTROPY_PTR +#define ALTCP_MBEDTLS_ENTROPY_PTR NULL +#endif +#ifndef ALTCP_MBEDTLS_ENTROPY_LEN +#define ALTCP_MBEDTLS_ENTROPY_LEN 0 +#endif +#ifndef ALTCP_MBEDTLS_RNG_FN +#define ALTCP_MBEDTLS_RNG_FN mbedtls_entropy_func +#endif + +/* Variable prototype, the actual declaration is at the end of this file + since it contains pointers to static functions declared here */ +extern const struct altcp_functions altcp_mbedtls_functions; + +/** Our global mbedTLS configuration (server-specific, not connection-specific) */ +struct altcp_tls_config { + mbedtls_ssl_config conf; + mbedtls_x509_crt *cert; + mbedtls_pk_context *pkey; + u8_t cert_count; + u8_t cert_max; + u8_t pkey_count; + u8_t pkey_max; + mbedtls_x509_crt *ca; +#if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_USE_SESSION_CACHE + /** Inter-connection cache for fast connection startup */ + struct mbedtls_ssl_cache_context cache; +#endif +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && ALTCP_MBEDTLS_USE_SESSION_TICKETS + mbedtls_ssl_ticket_context ticket_ctx; +#endif +}; + +/** Entropy and random generator are shared by all mbedTLS configuration */ +struct altcp_tls_entropy_rng { + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + int ref; +}; +static struct altcp_tls_entropy_rng *altcp_tls_entropy_rng; + +static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err); +static err_t altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn); +static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state); +static err_t altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state); +static int altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size); + + +static void +altcp_mbedtls_flush_output(altcp_mbedtls_state_t* state) +{ + int flushed = mbedtls_ssl_flush_output(&state->ssl_context); + if (flushed) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_flush_output failed: %d\n", flushed)); + } +} + +/* callback functions from inner/lower connection: */ + +/** Accept callback from lower connection (i.e. TCP) + * Allocate one of our structures, assign it to the new connection's 'state' and + * call the new connection's 'accepted' callback. If that succeeds, we wait + * to receive connection setup handshake bytes from the client. + */ +static err_t +altcp_mbedtls_lower_accept(void *arg, struct altcp_pcb *accepted_conn, err_t err) +{ + struct altcp_pcb *listen_conn = (struct altcp_pcb *)arg; + if (listen_conn && listen_conn->state && listen_conn->accept) { + err_t setup_err; + altcp_mbedtls_state_t *listen_state = (altcp_mbedtls_state_t *)listen_conn->state; + /* create a new altcp_conn to pass to the next 'accept' callback */ + struct altcp_pcb *new_conn = altcp_alloc(); + if (new_conn == NULL) { + return ERR_MEM; + } + setup_err = altcp_mbedtls_setup(listen_state->conf, new_conn, accepted_conn); + if (setup_err != ERR_OK) { + altcp_free(new_conn); + return setup_err; + } + return listen_conn->accept(listen_conn->arg, new_conn, err); + } + return ERR_ARG; +} + +/** Connected callback from lower connection (i.e. TCP). + * Not really implemented/tested yet... + */ +static err_t +altcp_mbedtls_lower_connected(void *arg, struct altcp_pcb *inner_conn, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */ + if (conn && conn->state) { + altcp_mbedtls_state_t *state; + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + /* upper connected is called when handshake is done */ + if (err != ERR_OK) { + if (conn->connected) { + return conn->connected(conn->arg, conn, err); + } + } + state = (altcp_mbedtls_state_t *)conn->state; + /* ensure overhead value is valid before first write */ + state->overhead_bytes_adjust = 0; + return altcp_mbedtls_lower_recv_process(conn, state); + } + return ERR_VAL; +} + +/* Call recved for possibly more than an u16_t */ +static void +altcp_mbedtls_lower_recved(struct altcp_pcb *inner_conn, int recvd_cnt) +{ + while (recvd_cnt > 0) { + u16_t recvd_part = (u16_t)LWIP_MIN(recvd_cnt, 0xFFFF); + altcp_recved(inner_conn, recvd_part); + recvd_cnt -= recvd_part; + } +} + +/** Recv callback from lower connection (i.e. TCP) + * This one mainly differs between connection setup/handshake (data is fed into mbedTLS only) + * and application phase (data is decoded by mbedTLS and passed on to the application). + */ +static err_t +altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err) +{ + altcp_mbedtls_state_t *state; + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + + LWIP_ASSERT("no err expected", err == ERR_OK); + LWIP_UNUSED_ARG(err); + + if (!conn) { + /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */ + if (p != NULL) { + pbuf_free(p); + } + altcp_close(inner_conn); + return ERR_CLSD; + } + state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + if (!state) { + /* already closed */ + if (p != NULL) { + pbuf_free(p); + } + altcp_close(inner_conn); + return ERR_CLSD; + } + + /* handle NULL pbuf (inner connection closed) */ + if (p == NULL) { + /* remote host sent FIN, remember this (SSL state is destroyed + when both sides are closed only!) */ + if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) == + (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) { + /* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */ + if ((state->rx != NULL) || (state->rx_app != NULL)) { + state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED; + /* this is a normal close (FIN) but we have unprocessed data, so delay the FIN */ + altcp_mbedtls_handle_rx_appldata(conn, state); + return ERR_OK; + } + state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED; + if (conn->recv) { + return conn->recv(conn->arg, conn, NULL, ERR_OK); + } + } else { + /* before connection setup is done: call 'err' */ + if (conn->err) { + conn->err(conn->arg, ERR_ABRT); + } + altcp_close(conn); + } + return ERR_OK; + } + + /* If we come here, the connection is in good state (handshake phase or application data phase). + Queue up the pbuf for processing as handshake data or application data. */ + if (state->rx == NULL) { + state->rx = p; + } else { + LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF); + pbuf_cat(state->rx, p); + } + return altcp_mbedtls_lower_recv_process(conn, state); +} + +static err_t +altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) +{ + if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { + /* handle connection setup (handshake not done) */ + int ret = mbedtls_ssl_handshake(&state->ssl_context); + /* try to send data... */ + altcp_output(conn->inner_conn); + if (state->bio_bytes_read) { + /* acknowledge all bytes read */ + altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read); + state->bio_bytes_read = 0; + } + + if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + /* handshake not done, wait for more recv calls */ + LWIP_ASSERT("in this state, the rx chain should be empty", state->rx == NULL); + return ERR_OK; + } + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret)); + /* handshake failed, connection has to be closed */ + if (conn->err) { + conn->err(conn->arg, ERR_CLSD); + } + + if (altcp_close(conn) != ERR_OK) { + altcp_abort(conn); + } + return ERR_OK; + } + /* If we come here, handshake succeeded. */ + LWIP_ASSERT("state", state->bio_bytes_read == 0); + LWIP_ASSERT("state", state->bio_bytes_appl == 0); + state->flags |= ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE; + /* issue "connect" callback" to upper connection (this can only happen for active open) */ + if (conn->connected) { + err_t err; + err = conn->connected(conn->arg, conn, ERR_OK); + if (err != ERR_OK) { + return err; + } + } + if (state->rx == NULL) { + return ERR_OK; + } + } + /* handle application data */ + return altcp_mbedtls_handle_rx_appldata(conn, state); +} + +/* Pass queued decoded rx data to application */ +static err_t +altcp_mbedtls_pass_rx_data(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) +{ + err_t err; + struct pbuf *buf; + LWIP_ASSERT("conn != NULL", conn != NULL); + LWIP_ASSERT("state != NULL", state != NULL); + buf = state->rx_app; + if (buf) { + state->rx_app = NULL; + if (conn->recv) { + u16_t tot_len = buf->tot_len; + /* this needs to be increased first because the 'recved' call may come nested */ + state->rx_passed_unrecved += tot_len; + state->flags |= ALTCP_MBEDTLS_FLAGS_UPPER_CALLED; + err = conn->recv(conn->arg, conn, buf, ERR_OK); + if (err != ERR_OK) { + if (err == ERR_ABRT) { + return ERR_ABRT; + } + /* not received, leave the pbuf(s) queued (and decrease 'unrecved' again) */ + LWIP_ASSERT("state == conn->state", state == conn->state); + state->rx_app = buf; + state->rx_passed_unrecved -= tot_len; + LWIP_ASSERT("state->rx_passed_unrecved >= 0", state->rx_passed_unrecved >= 0); + if (state->rx_passed_unrecved < 0) { + state->rx_passed_unrecved = 0; + } + return err; + } + } else { + pbuf_free(buf); + } + } else if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) == + ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) { + state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED; + if (conn->recv) { + return conn->recv(conn->arg, conn, NULL, ERR_OK); + } + } + + /* application may have close the connection */ + if (conn->state != state) { + /* return error code to ensure altcp_mbedtls_handle_rx_appldata() exits the loop */ + return ERR_ARG; + } + return ERR_OK; +} + +/* Helper function that processes rx application data stored in rx pbuf chain */ +static err_t +altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) +{ + int ret; + LWIP_ASSERT("state != NULL", state != NULL); + if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { + /* handshake not done yet */ + return ERR_VAL; + } + do { + /* allocate a full-sized unchained PBUF_POOL: this is for RX! */ + struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL); + if (buf == NULL) { + /* We're short on pbufs, try again later from 'poll' or 'recv' callbacks. + @todo: close on excessive allocation failures or leave this up to upper conn? */ + return ERR_OK; + } + + /* decrypt application data, this pulls encrypted RX data off state->rx pbuf chain */ + ret = mbedtls_ssl_read(&state->ssl_context, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE); + if (ret < 0) { + if (ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT) { + /* client is initiating a new connection using the same source port -> close connection or make handshake */ + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("new connection on same source port\n")); + LWIP_ASSERT("TODO: new connection on same source port, close this connection", 0); + } else if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { + if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was closed gracefully\n")); + } else if (ret == MBEDTLS_ERR_NET_CONN_RESET) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("connection was reset by peer\n")); + } + pbuf_free(buf); + return ERR_OK; + } else { + pbuf_free(buf); + return ERR_OK; + } + pbuf_free(buf); + altcp_abort(conn); + return ERR_ABRT; + } else { + err_t err; + if (ret) { + LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE); + /* trim pool pbuf to actually decoded length */ + pbuf_realloc(buf, (u16_t)ret); + + state->bio_bytes_appl += ret; + if (mbedtls_ssl_get_bytes_avail(&state->ssl_context) == 0) { + /* Record is done, now we know the share between application and protocol bytes + and can adjust the RX window by the protocol bytes. + The rest is 'recved' by the application calling our 'recved' fn. */ + int overhead_bytes; + LWIP_ASSERT("bogus byte counts", state->bio_bytes_read > state->bio_bytes_appl); + overhead_bytes = state->bio_bytes_read - state->bio_bytes_appl; + altcp_mbedtls_lower_recved(conn->inner_conn, overhead_bytes); + state->bio_bytes_read = 0; + state->bio_bytes_appl = 0; + } + + if (state->rx_app == NULL) { + state->rx_app = buf; + } else { + pbuf_cat(state->rx_app, buf); + } + } else { + pbuf_free(buf); + buf = NULL; + } + err = altcp_mbedtls_pass_rx_data(conn, state); + if (err != ERR_OK) { + if (err == ERR_ABRT) { + /* recv callback needs to return this as the pcb is deallocated */ + return ERR_ABRT; + } + /* we hide all other errors as we retry feeding the pbuf to the app later */ + return ERR_OK; + } + } + } while (ret > 0); + return ERR_OK; +} + +/** Receive callback function called from mbedtls (set via mbedtls_ssl_set_bio) + * This function mainly copies data from pbufs and frees the pbufs after copying. + */ +static int +altcp_mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)ctx; + altcp_mbedtls_state_t *state; + struct pbuf *p; + u16_t ret; + u16_t copy_len; + err_t err; + + LWIP_UNUSED_ARG(err); /* for LWIP_NOASSERT */ + if ((conn == NULL) || (conn->state == NULL)) { + return MBEDTLS_ERR_NET_INVALID_CONTEXT; + } + state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("state != NULL", state != NULL); + p = state->rx; + + /* @todo: return MBEDTLS_ERR_NET_CONN_RESET/MBEDTLS_ERR_NET_RECV_FAILED? */ + + if ((p == NULL) || ((p->len == 0) && (p->next == NULL))) { + if (p) { + pbuf_free(p); + } + state->rx = NULL; + if ((state->flags & (ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED | ALTCP_MBEDTLS_FLAGS_RX_CLOSED)) == + ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED) { + /* close queued but not passed up yet */ + return 0; + } + return MBEDTLS_ERR_SSL_WANT_READ; + } + /* limit number of bytes again to copy from first pbuf in a chain only */ + copy_len = (u16_t)LWIP_MIN(len, p->len); + /* copy the data */ + ret = pbuf_copy_partial(p, buf, copy_len, 0); + LWIP_ASSERT("ret == copy_len", ret == copy_len); + /* hide the copied bytes from the pbuf */ + err = pbuf_remove_header(p, ret); + LWIP_ASSERT("error", err == ERR_OK); + if (p->len == 0) { + /* the first pbuf has been fully read, free it */ + state->rx = p->next; + p->next = NULL; + pbuf_free(p); + } + + state->bio_bytes_read += (int)ret; + return ret; +} + +/** Sent callback from lower connection (i.e. TCP) + * This only informs the upper layer the number of ACKed bytes. + * This now take care of TLS added bytes so application receive + * correct ACKed bytes. + */ +static err_t +altcp_mbedtls_lower_sent(void *arg, struct altcp_pcb *inner_conn, u16_t len) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */ + if (conn) { + int overhead; + u16_t app_len; + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("state", state != NULL); + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + /* calculate TLS overhead part to not send it to application */ + overhead = state->overhead_bytes_adjust + state->ssl_context.out_left; + if ((unsigned)overhead > len) { + overhead = len; + } + /* remove ACKed bytes from overhead adjust counter */ + state->overhead_bytes_adjust -= len; + /* try to send more if we failed before (may increase overhead adjust counter) */ + altcp_mbedtls_flush_output(state); + /* remove calculated overhead from ACKed bytes len */ + app_len = len - (u16_t)overhead; + /* update application write counter and inform application */ + if (app_len) { + state->overhead_bytes_adjust += app_len; + if (conn->sent) + return conn->sent(conn->arg, conn, app_len); + } + } + return ERR_OK; +} + +/** Poll callback from lower connection (i.e. TCP) + * Just pass this on to the application. + * @todo: retry sending? + */ +static err_t +altcp_mbedtls_lower_poll(void *arg, struct altcp_pcb *inner_conn) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + LWIP_UNUSED_ARG(inner_conn); /* for LWIP_NOASSERT */ + if (conn) { + LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); + /* check if there's unreceived rx data */ + if (conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + /* try to send more if we failed before */ + altcp_mbedtls_flush_output(state); + if (altcp_mbedtls_handle_rx_appldata(conn, state) == ERR_ABRT) { + return ERR_ABRT; + } + } + if (conn->poll) { + return conn->poll(conn->arg, conn); + } + } + return ERR_OK; +} + +static void +altcp_mbedtls_lower_err(void *arg, err_t err) +{ + struct altcp_pcb *conn = (struct altcp_pcb *)arg; + if (conn) { + conn->inner_conn = NULL; /* already freed */ + if (conn->err) { + conn->err(conn->arg, err); + } + altcp_free(conn); + } +} + +/* setup functions */ + +static void +altcp_mbedtls_remove_callbacks(struct altcp_pcb *inner_conn) +{ + altcp_arg(inner_conn, NULL); + altcp_recv(inner_conn, NULL); + altcp_sent(inner_conn, NULL); + altcp_err(inner_conn, NULL); + altcp_poll(inner_conn, NULL, inner_conn->pollinterval); +} + +static void +altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn) +{ + altcp_arg(inner_conn, conn); + altcp_recv(inner_conn, altcp_mbedtls_lower_recv); + altcp_sent(inner_conn, altcp_mbedtls_lower_sent); + altcp_err(inner_conn, altcp_mbedtls_lower_err); + /* tcp_poll is set when interval is set by application */ + /* listen is set totally different :-) */ +} + +static err_t +altcp_mbedtls_setup(void *conf, struct altcp_pcb *conn, struct altcp_pcb *inner_conn) +{ + int ret; + struct altcp_tls_config *config = (struct altcp_tls_config *)conf; + altcp_mbedtls_state_t *state; + if (!conf) { + return ERR_ARG; + } + LWIP_ASSERT("invalid inner_conn", conn != inner_conn); + + /* allocate mbedtls context */ + state = altcp_mbedtls_alloc(conf); + if (state == NULL) { + return ERR_MEM; + } + /* initialize mbedtls context: */ + mbedtls_ssl_init(&state->ssl_context); + ret = mbedtls_ssl_setup(&state->ssl_context, &config->conf); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_setup failed\n")); + /* @todo: convert 'ret' to err_t */ + altcp_mbedtls_free(conf, state); + return ERR_MEM; + } + /* tell mbedtls about our I/O functions */ + mbedtls_ssl_set_bio(&state->ssl_context, conn, altcp_mbedtls_bio_send, altcp_mbedtls_bio_recv, NULL); + + altcp_mbedtls_setup_callbacks(conn, inner_conn); + conn->inner_conn = inner_conn; + conn->fns = &altcp_mbedtls_functions; + conn->state = state; + return ERR_OK; +} + +struct altcp_pcb * +altcp_tls_wrap(struct altcp_tls_config *config, struct altcp_pcb *inner_pcb) +{ + struct altcp_pcb *ret; + if (inner_pcb == NULL) { + return NULL; + } + ret = altcp_alloc(); + if (ret != NULL) { + if (altcp_mbedtls_setup(config, ret, inner_pcb) != ERR_OK) { + altcp_free(ret); + return NULL; + } + } + return ret; +} + +void +altcp_tls_init_session(struct altcp_tls_session *session) +{ + if (session) + mbedtls_ssl_session_init(&session->data); +} + +err_t +altcp_tls_get_session(struct altcp_pcb *conn, struct altcp_tls_session *session) +{ + if (session && conn && conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + int ret = mbedtls_ssl_get_session(&state->ssl_context, &session->data); + return ret < 0 ? ERR_VAL : ERR_OK; + } + return ERR_ARG; +} + +err_t +altcp_tls_set_session(struct altcp_pcb *conn, struct altcp_tls_session *session) +{ + if (session && conn && conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + int ret = -1; + if (session->data.start) + ret = mbedtls_ssl_set_session(&state->ssl_context, &session->data); + return ret < 0 ? ERR_VAL : ERR_OK; + } + return ERR_ARG; +} + +void +altcp_tls_free_session(struct altcp_tls_session *session) +{ + if (session) + mbedtls_ssl_session_free(&session->data); +} + +void * +altcp_tls_context(struct altcp_pcb *conn) +{ + if (conn && conn->state) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + return &state->ssl_context; + } + return NULL; +} + +#if ALTCP_MBEDTLS_LIB_DEBUG != LWIP_DBG_OFF +static void +altcp_mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) +{ + LWIP_UNUSED_ARG(ctx); + LWIP_UNUSED_ARG(file); + LWIP_UNUSED_ARG(line); + LWIP_UNUSED_ARG(str); + + if (level >= ALTCP_MBEDTLS_LIB_DEBUG_LEVEL_MIN) { + LWIP_DEBUGF(ALTCP_MBEDTLS_LIB_DEBUG, ("%s:%04d: %s\n", file, line, str)); + } +} +#endif + +static err_t +altcp_mbedtls_ref_entropy(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (!altcp_tls_entropy_rng) { + altcp_tls_entropy_rng = (struct altcp_tls_entropy_rng *)altcp_mbedtls_alloc_config(sizeof(struct altcp_tls_entropy_rng)); + if (altcp_tls_entropy_rng) { + int ret; + altcp_tls_entropy_rng->ref = 1; + mbedtls_entropy_init(&altcp_tls_entropy_rng->entropy); + mbedtls_ctr_drbg_init(&altcp_tls_entropy_rng->ctr_drbg); + /* Seed the RNG, only once */ + ret = mbedtls_ctr_drbg_seed(&altcp_tls_entropy_rng->ctr_drbg, + ALTCP_MBEDTLS_RNG_FN, &altcp_tls_entropy_rng->entropy, + ALTCP_MBEDTLS_ENTROPY_PTR, ALTCP_MBEDTLS_ENTROPY_LEN); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ctr_drbg_seed failed: %d\n", ret)); + mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); + mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); + altcp_mbedtls_free_config(altcp_tls_entropy_rng); + altcp_tls_entropy_rng = NULL; + return ERR_ARG; + } + } else { + return ERR_MEM; + } + } else { + altcp_tls_entropy_rng->ref++; + } + return ERR_OK; +} + +static void +altcp_mbedtls_unref_entropy(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (altcp_tls_entropy_rng && altcp_tls_entropy_rng->ref) { + altcp_tls_entropy_rng->ref--; + } +} + +/** Create new TLS configuration + * ATTENTION: Server certificate and private key have to be added outside this function! + */ +static struct altcp_tls_config * +altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int have_ca) +{ + size_t sz; + int ret; + struct altcp_tls_config *conf; + mbedtls_x509_crt *mem; + +#if MBEDTLS_VERSION_MAJOR < 3 + if (TCP_WND < MBEDTLS_SSL_MAX_CONTENT_LEN) { +#else + if (TCP_WND < MBEDTLS_SSL_IN_CONTENT_LEN) { +#endif + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG|LWIP_DBG_LEVEL_SERIOUS, + ("altcp_tls: TCP_WND is smaller than the RX decrypion buffer, connection RX might stall!\n")); + } + + altcp_mbedtls_mem_init(); + + sz = sizeof(struct altcp_tls_config); + if (cert_count > 0) { + sz += (cert_count * sizeof(mbedtls_x509_crt)); + } + if (have_ca) { + sz += sizeof(mbedtls_x509_crt); + } + if (pkey_count > 0) { + sz += (pkey_count * sizeof(mbedtls_pk_context)); + } + + conf = (struct altcp_tls_config *)altcp_mbedtls_alloc_config(sz); + if (conf == NULL) { + return NULL; + } + conf->cert_max = cert_count; + mem = (mbedtls_x509_crt *)(conf + 1); + if (cert_count > 0) { + conf->cert = mem; + mem += cert_count; + } + if (have_ca) { + conf->ca = mem; + mem++; + } + conf->pkey_max = pkey_count; + if (pkey_count > 0) { + conf->pkey = (mbedtls_pk_context *)mem; + } + + mbedtls_ssl_config_init(&conf->conf); + + if (altcp_mbedtls_ref_entropy() != ERR_OK) { + altcp_mbedtls_free_config(conf); + return NULL; + } + + /* Setup ssl context (@todo: what's different for a client here? -> might better be done on listen/connect) */ + ret = mbedtls_ssl_config_defaults(&conf->conf, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_config_defaults failed: %d\n", ret)); + altcp_mbedtls_unref_entropy(); + altcp_mbedtls_free_config(conf); + return NULL; + } + mbedtls_ssl_conf_authmode(&conf->conf, ALTCP_MBEDTLS_AUTHMODE); + + mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &altcp_tls_entropy_rng->ctr_drbg); +#if ALTCP_MBEDTLS_LIB_DEBUG != LWIP_DBG_OFF + mbedtls_ssl_conf_dbg(&conf->conf, altcp_mbedtls_debug, stdout); +#endif +#if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_USE_SESSION_CACHE + mbedtls_ssl_conf_session_cache(&conf->conf, &conf->cache, mbedtls_ssl_cache_get, mbedtls_ssl_cache_set); + mbedtls_ssl_cache_set_timeout(&conf->cache, ALTCP_MBEDTLS_SESSION_CACHE_TIMEOUT_SECONDS); + mbedtls_ssl_cache_set_max_entries(&conf->cache, ALTCP_MBEDTLS_SESSION_CACHE_SIZE); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && ALTCP_MBEDTLS_USE_SESSION_TICKETS + mbedtls_ssl_ticket_init(&conf->ticket_ctx); + + ret = mbedtls_ssl_ticket_setup(&conf->ticket_ctx, mbedtls_ctr_drbg_random, &altcp_tls_entropy_rng->ctr_drbg, + ALTCP_MBEDTLS_SESSION_TICKET_CIPHER, ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS); + if (ret) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_ticket_setup failed: %d\n", ret)); + altcp_mbedtls_unref_entropy(); + altcp_mbedtls_free_config(conf); + return NULL; + } + + mbedtls_ssl_conf_session_tickets_cb(&conf->conf, mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, + &conf->ticket_ctx); +#endif + + return conf; +} + +struct altcp_tls_config *altcp_tls_create_config_server(u8_t cert_count) +{ + struct altcp_tls_config *conf = altcp_tls_create_config(1, cert_count, cert_count, 0); + if (conf == NULL) { + return NULL; + } + + mbedtls_ssl_conf_ca_chain(&conf->conf, NULL, NULL); + return conf; +} + +err_t altcp_tls_config_server_add_privkey_cert(struct altcp_tls_config *config, + const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len) +{ + int ret; + mbedtls_x509_crt *srvcert; + mbedtls_pk_context *pkey; + + if (config->cert_count >= config->cert_max) { + return ERR_MEM; + } + if (config->pkey_count >= config->pkey_max) { + return ERR_MEM; + } + + srvcert = config->cert + config->cert_count; + mbedtls_x509_crt_init(srvcert); + + pkey = config->pkey + config->pkey_count; + mbedtls_pk_init(pkey); + + /* Load the certificates and private key */ + ret = mbedtls_x509_crt_parse(srvcert, cert, cert_len); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse failed: %d\n", ret)); + return ERR_VAL; + } + +#if MBEDTLS_VERSION_MAJOR < 3 + ret = mbedtls_pk_parse_key(pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len); +#else + ret = mbedtls_pk_parse_key(pkey, (const unsigned char *) privkey, privkey_len, privkey_pass, privkey_pass_len, NULL, NULL); +#endif + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_public_key failed: %d\n", ret)); + mbedtls_x509_crt_free(srvcert); + return ERR_VAL; + } + + ret = mbedtls_ssl_conf_own_cert(&config->conf, srvcert, pkey); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d\n", ret)); + mbedtls_x509_crt_free(srvcert); + mbedtls_pk_free(pkey); + return ERR_VAL; + } + + config->cert_count++; + config->pkey_count++; + return ERR_OK; +} + +/** Create new TLS configuration + * This is a suboptimal version that gets the encrypted private key and its password, + * as well as the server certificate. + */ +struct altcp_tls_config * +altcp_tls_create_config_server_privkey_cert(const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len) +{ + struct altcp_tls_config *conf = altcp_tls_create_config_server(1); + if (conf == NULL) { + return NULL; + } + + if (altcp_tls_config_server_add_privkey_cert(conf, privkey, privkey_len, + privkey_pass, privkey_pass_len, cert, cert_len) != ERR_OK) { + altcp_tls_free_config(conf); + return NULL; + } + + return conf; +} + +static struct altcp_tls_config * +altcp_tls_create_config_client_common(const u8_t *ca, size_t ca_len, int is_2wayauth) +{ + int ret; + struct altcp_tls_config *conf = altcp_tls_create_config(0, (is_2wayauth) ? 1 : 0, (is_2wayauth) ? 1 : 0, ca != NULL); + if (conf == NULL) { + return NULL; + } + + /* Initialize the CA certificate if provided + * CA certificate is optional (to save memory) but recommended for production environment + * Without CA certificate, connection will be prone to man-in-the-middle attacks */ + if (ca) { + mbedtls_x509_crt_init(conf->ca); + ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); + return NULL; + } + + mbedtls_ssl_conf_ca_chain(&conf->conf, conf->ca, NULL); + } + return conf; +} + +struct altcp_tls_config * +altcp_tls_create_config_client(const u8_t *ca, size_t ca_len) +{ + return altcp_tls_create_config_client_common(ca, ca_len, 0); +} + +struct altcp_tls_config * +altcp_tls_create_config_client_2wayauth(const u8_t *ca, size_t ca_len, const u8_t *privkey, size_t privkey_len, + const u8_t *privkey_pass, size_t privkey_pass_len, + const u8_t *cert, size_t cert_len) +{ + int ret; + struct altcp_tls_config *conf; + + if (!cert || !privkey) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("altcp_tls_create_config_client_2wayauth: certificate and priv key required\n")); + return NULL; + } + + conf = altcp_tls_create_config_client_common(ca, ca_len, 1); + if (conf == NULL) { + return NULL; + } + + /* Initialize the client certificate and corresponding private key */ + mbedtls_x509_crt_init(conf->cert); + ret = mbedtls_x509_crt_parse(conf->cert, cert, cert_len); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse cert failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); + return NULL; + } + + mbedtls_pk_init(conf->pkey); +#if MBEDTLS_VERSION_MAJOR < 3 + ret = mbedtls_pk_parse_key(conf->pkey, privkey, privkey_len, privkey_pass, privkey_pass_len); +#else + ret = mbedtls_pk_parse_key(conf->pkey, privkey, privkey_len, privkey_pass, privkey_pass_len, NULL, NULL); +#endif + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_pk_parse_key failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); + return NULL; + } + + ret = mbedtls_ssl_conf_own_cert(&conf->conf, conf->cert, conf->pkey); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_own_cert failed: %d 0x%x\n", ret, -1*ret)); + altcp_tls_free_config(conf); + return NULL; + } + + return conf; +} + +int +altcp_tls_configure_alpn_protocols(struct altcp_tls_config *conf, const char **protos) +{ +#if defined(MBEDTLS_SSL_ALPN) + int ret = mbedtls_ssl_conf_alpn_protocols(&conf->conf, protos); + if (ret != 0) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_conf_alpn_protocols failed: %d\n", ret)); + } + + return ret; +#else + return -1; +#endif +} + +void +altcp_tls_free_config(struct altcp_tls_config *conf) +{ + if (conf->pkey) { + mbedtls_pk_free(conf->pkey); + } + if (conf->cert) { + mbedtls_x509_crt_free(conf->cert); + } + if (conf->ca) { + mbedtls_x509_crt_free(conf->ca); + } + mbedtls_ssl_config_free(&conf->conf); + altcp_mbedtls_free_config(conf); + altcp_mbedtls_unref_entropy(); +} + +void +altcp_tls_free_entropy(void) +{ + LWIP_ASSERT_CORE_LOCKED(); + + if (altcp_tls_entropy_rng && altcp_tls_entropy_rng->ref == 0) { + mbedtls_ctr_drbg_free(&altcp_tls_entropy_rng->ctr_drbg); + mbedtls_entropy_free(&altcp_tls_entropy_rng->entropy); + altcp_mbedtls_free_config(altcp_tls_entropy_rng); + altcp_tls_entropy_rng = NULL; + } +} + +/* "virtual" functions */ +static void +altcp_mbedtls_set_poll(struct altcp_pcb *conn, u8_t interval) +{ + if (conn != NULL) { + altcp_poll(conn->inner_conn, altcp_mbedtls_lower_poll, interval); + } +} + +static void +altcp_mbedtls_recved(struct altcp_pcb *conn, u16_t len) +{ + u16_t lower_recved; + altcp_mbedtls_state_t *state; + if (conn == NULL) { + return; + } + state = (altcp_mbedtls_state_t *)conn->state; + if (state == NULL) { + return; + } + if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { + return; + } + lower_recved = len; + if (lower_recved > state->rx_passed_unrecved) { + LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("bogus recved count (len > state->rx_passed_unrecved / %d / %d)\n", + len, state->rx_passed_unrecved)); + lower_recved = (u16_t)state->rx_passed_unrecved; + } + state->rx_passed_unrecved -= lower_recved; + + altcp_recved(conn->inner_conn, lower_recved); +} + +static err_t +altcp_mbedtls_connect(struct altcp_pcb *conn, const ip_addr_t *ipaddr, u16_t port, altcp_connected_fn connected) +{ + if (conn == NULL) { + return ERR_VAL; + } + conn->connected = connected; + return altcp_connect(conn->inner_conn, ipaddr, port, altcp_mbedtls_lower_connected); +} + +static struct altcp_pcb * +altcp_mbedtls_listen(struct altcp_pcb *conn, u8_t backlog, err_t *err) +{ + struct altcp_pcb *lpcb; + if (conn == NULL) { + return NULL; + } + lpcb = altcp_listen_with_backlog_and_err(conn->inner_conn, backlog, err); + if (lpcb != NULL) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + /* Free members of the ssl context (not used on listening pcb). This + includes freeing input/output buffers, so saves ~32KByte by default */ + mbedtls_ssl_free(&state->ssl_context); + + conn->inner_conn = lpcb; + altcp_accept(lpcb, altcp_mbedtls_lower_accept); + return conn; + } + return NULL; +} + +static void +altcp_mbedtls_abort(struct altcp_pcb *conn) +{ + if (conn != NULL) { + altcp_abort(conn->inner_conn); + } +} + +static err_t +altcp_mbedtls_close(struct altcp_pcb *conn) +{ + struct altcp_pcb *inner_conn; + if (conn == NULL) { + return ERR_VAL; + } + inner_conn = conn->inner_conn; + if (inner_conn) { + err_t err; + altcp_poll_fn oldpoll = inner_conn->poll; + altcp_mbedtls_remove_callbacks(conn->inner_conn); + err = altcp_close(conn->inner_conn); + if (err != ERR_OK) { + /* not closed, set up all callbacks again */ + altcp_mbedtls_setup_callbacks(conn, inner_conn); + /* poll callback is not included in the above */ + altcp_poll(inner_conn, oldpoll, inner_conn->pollinterval); + return err; + } + conn->inner_conn = NULL; + } + altcp_free(conn); + return ERR_OK; +} + +/** Allow caller of altcp_write() to limit to negotiated chunk size + * or remaining sndbuf space of inner_conn. + */ +static u16_t +altcp_mbedtls_sndbuf(struct altcp_pcb *conn) +{ + if (conn) { + altcp_mbedtls_state_t *state; + state = (altcp_mbedtls_state_t*)conn->state; + if (!state || !(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { + return 0; + } + if (conn->inner_conn) { + u16_t sndbuf = altcp_sndbuf(conn->inner_conn); + /* Take care of record header, IV, AuthTag */ + int ssl_expan = mbedtls_ssl_get_record_expansion(&state->ssl_context); + if (ssl_expan > 0) { + size_t ssl_added = (u16_t)LWIP_MIN(ssl_expan, 0xFFFF); + /* internal sndbuf smaller than our offset */ + if (ssl_added < sndbuf) { + size_t max_len = 0xFFFF; + size_t ret; +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + /* @todo: adjust ssl_added to real value related to negotiated cipher */ +#if MBEDTLS_VERSION_MAJOR < 3 + size_t max_frag_len = mbedtls_ssl_get_max_frag_len(&state->ssl_context); +#else + size_t max_frag_len = mbedtls_ssl_get_output_max_frag_len(&state->ssl_context); +#endif + max_len = LWIP_MIN(max_frag_len, max_len); +#endif + /* Adjust sndbuf of inner_conn with what added by SSL */ + ret = LWIP_MIN(sndbuf - ssl_added, max_len); + LWIP_ASSERT("sndbuf overflow", ret <= 0xFFFF); + return (u16_t)ret; + } + } + } + } + /* fallback: use sendbuf of the inner connection */ + return altcp_default_sndbuf(conn); +} + +/** Write data to a TLS connection. Calls into mbedTLS, which in turn calls into + * @ref altcp_mbedtls_bio_send() to send the encrypted data + */ +static err_t +altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) +{ + int ret; + altcp_mbedtls_state_t *state; + + LWIP_UNUSED_ARG(apiflags); + + if (conn == NULL) { + return ERR_VAL; + } + + state = (altcp_mbedtls_state_t *)conn->state; + if (state == NULL) { + /* @todo: which error? */ + return ERR_ARG; + } + if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { + /* @todo: which error? */ + return ERR_VAL; + } + + /* HACK: if there is something left to send, try to flush it and only + allow sending more if this succeeded (this is a hack because neither + returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */ + if (state->ssl_context.out_left) { + altcp_mbedtls_flush_output(state); + if (state->ssl_context.out_left) { + return ERR_MEM; + } + } + ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len); + /* try to send data... */ + altcp_output(conn->inner_conn); + if (ret >= 0) { + if (ret == len) { + /* update application sent counter */ + state->overhead_bytes_adjust -= ret; + return ERR_OK; + } else { + /* @todo/@fixme: assumption: either everything sent or error */ + LWIP_ASSERT("ret <= 0", 0); + return ERR_MEM; + } + } else { + if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { + /* @todo: convert error to err_t */ + return ERR_MEM; + } + LWIP_ASSERT("unhandled error", 0); + return ERR_VAL; + } +} + +/** Send callback function called from mbedtls (set via mbedtls_ssl_set_bio) + * This function is either called during handshake or when sending application + * data via @ref altcp_mbedtls_write (or altcp_write) + */ +static int +altcp_mbedtls_bio_send(void *ctx, const unsigned char *dataptr, size_t size) +{ + struct altcp_pcb *conn = (struct altcp_pcb *) ctx; + altcp_mbedtls_state_t *state; + int written = 0; + size_t size_left = size; + u8_t apiflags = TCP_WRITE_FLAG_COPY; + + LWIP_ASSERT("conn != NULL", conn != NULL); + if ((conn == NULL) || (conn->inner_conn == NULL)) { + return MBEDTLS_ERR_NET_INVALID_CONTEXT; + } + state = (altcp_mbedtls_state_t *)conn->state; + LWIP_ASSERT("state != NULL", state != NULL); + + while (size_left) { + u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF); + err_t err = altcp_write(conn->inner_conn, (const void *)dataptr, write_len, apiflags); + if (err == ERR_OK) { + written += write_len; + size_left -= write_len; + state->overhead_bytes_adjust += write_len; + } else if (err == ERR_MEM) { + if (written) { + return written; + } + return 0; /* MBEDTLS_ERR_SSL_WANT_WRITE; */ + } else { + LWIP_ASSERT("tls_write, tcp_write: err != ERR MEM", 0); + /* @todo: return MBEDTLS_ERR_NET_CONN_RESET or MBEDTLS_ERR_NET_SEND_FAILED */ + return MBEDTLS_ERR_NET_SEND_FAILED; + } + } + return written; +} + +static u16_t +altcp_mbedtls_mss(struct altcp_pcb *conn) +{ + if (conn == NULL) { + return 0; + } + /* @todo: LWIP_MIN(mss, mbedtls_ssl_get_max_frag_len()) ? */ + return altcp_mss(conn->inner_conn); +} + +static void +altcp_mbedtls_dealloc(struct altcp_pcb *conn) +{ + /* clean up and free tls state */ + if (conn) { + altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; + if (state) { + mbedtls_ssl_free(&state->ssl_context); + state->flags = 0; + if (state->rx) { + /* free leftover (unhandled) rx pbufs */ + pbuf_free(state->rx); + state->rx = NULL; + } + altcp_mbedtls_free(state->conf, state); + conn->state = NULL; + } + } +} + +const struct altcp_functions altcp_mbedtls_functions = { + altcp_mbedtls_set_poll, + altcp_mbedtls_recved, + altcp_default_bind, + altcp_mbedtls_connect, + altcp_mbedtls_listen, + altcp_mbedtls_abort, + altcp_mbedtls_close, + altcp_default_shutdown, + altcp_mbedtls_write, + altcp_default_output, + altcp_mbedtls_mss, + altcp_mbedtls_sndbuf, + altcp_default_sndqueuelen, + altcp_default_nagle_disable, + altcp_default_nagle_enable, + altcp_default_nagle_disabled, + altcp_default_setprio, + altcp_mbedtls_dealloc, + altcp_default_get_tcp_addrinfo, + altcp_default_get_ip, + altcp_default_get_port +#if LWIP_TCP_KEEPALIVE + , altcp_default_keepalive_disable + , altcp_default_keepalive_enable +#endif +#ifdef LWIP_DEBUG + , altcp_default_dbg_get_tcp_state +#endif +}; + +#endif /* LWIP_ALTCP_TLS && LWIP_ALTCP_TLS_MBEDTLS */ +#endif /* LWIP_ALTCP */ diff --git a/src/rp2_common/pico_mbedtls/CMakeLists.txt b/src/rp2_common/pico_mbedtls/CMakeLists.txt index f1becc27f..645497ed6 100644 --- a/src/rp2_common/pico_mbedtls/CMakeLists.txt +++ b/src/rp2_common/pico_mbedtls/CMakeLists.txt @@ -16,7 +16,7 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) pico_register_common_scope_var(PICO_MBEDTLS_PATH) - # We use version 2.28.8. But this should build version 3.5.1 + # Support version 2.28.8 or 3.6.2 if (NOT MBEDTLS_VERSION_MAJOR) if (EXISTS ${PICO_MBEDTLS_PATH}/library/ssl_cli.c) set(MBEDTLS_VERSION_MAJOR 2) @@ -25,6 +25,7 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) else() message(WARNING "Cannot determine the version of mbedtls") endif() + pico_register_common_scope_var(MBEDTLS_VERSION_MAJOR) endif() set(src_crypto From ba99b4d452b2a42ec624883dce144331a49201e6 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Tue, 8 Apr 2025 16:53:49 +0100 Subject: [PATCH 06/13] Update lib/cyw43-driver to 1.1.0 Fixes #2404 --- MODULE.bazel | 2 +- lib/cyw43-driver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 93847f91d..10223842f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -106,7 +106,7 @@ new_git_repository( new_git_repository( name = "cyw43-driver", build_file = "//src/rp2_common/pico_cyw43_driver:cyw43-driver.BUILD", - commit = "c1075d4bc440422cf2b2fd12c64a1f53f77660ee", # keep-in-sync-with-submodule: lib/cyw43-driver + commit = "dd7568229f3bf7a37737b9e1ef250c26efe75b23", # keep-in-sync-with-submodule: lib/cyw43-driver remote = "https://github.com/georgerobotics/cyw43-driver.git", ) diff --git a/lib/cyw43-driver b/lib/cyw43-driver index c1075d4bc..dd7568229 160000 --- a/lib/cyw43-driver +++ b/lib/cyw43-driver @@ -1 +1 @@ -Subproject commit c1075d4bc440422cf2b2fd12c64a1f53f77660ee +Subproject commit dd7568229f3bf7a37737b9e1ef250c26efe75b23 From 4bc43f3a4724deaa7b2a11e3bc6b834ae65e894f Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 16:28:53 +0100 Subject: [PATCH 07/13] Fix a couple of build warnings in altcp_tls_mbedtls.c --- src/rp2_common/pico_lwip/altcp_tls_mbedtls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c b/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c index adefa716a..669379db9 100644 --- a/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c +++ b/src/rp2_common/pico_lwip/altcp_tls_mbedtls.c @@ -429,7 +429,7 @@ altcp_mbedtls_handle_rx_appldata(struct altcp_pcb *conn, altcp_mbedtls_state_t * } else { err_t err; if (ret) { - LWIP_ASSERT("bogus receive length", ret <= PBUF_POOL_BUFSIZE); + LWIP_ASSERT("bogus receive length", ret <= (int)PBUF_POOL_BUFSIZE); /* trim pool pbuf to actually decoded length */ pbuf_realloc(buf, (u16_t)ret); @@ -1059,6 +1059,8 @@ altcp_tls_configure_alpn_protocols(struct altcp_tls_config *conf, const char **p return ret; #else + (void)conf; + (void)protos; return -1; #endif } From 9c265bc149fe9a995ec3407a9369bfceea18355b Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 16:57:37 +0100 Subject: [PATCH 08/13] Fix suppress_mbedtls_warnings It seems everything needs "no-cast-qual" due to mbedtls_get_unaligned_uint64. Move the source file lists into functions so they can be used in suppress_mbedtls_warnings to add -Wno-cast-qual to just mbedtls source files. --- src/rp2_common/pico_mbedtls/CMakeLists.txt | 303 +++++++++++---------- 1 file changed, 155 insertions(+), 148 deletions(-) diff --git a/src/rp2_common/pico_mbedtls/CMakeLists.txt b/src/rp2_common/pico_mbedtls/CMakeLists.txt index 645497ed6..d9b90a674 100644 --- a/src/rp2_common/pico_mbedtls/CMakeLists.txt +++ b/src/rp2_common/pico_mbedtls/CMakeLists.txt @@ -28,143 +28,156 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) pico_register_common_scope_var(MBEDTLS_VERSION_MAJOR) endif() - set(src_crypto - aes.c - aesni.c - aria.c - asn1parse.c - asn1write.c - base64.c - bignum.c - camellia.c - ccm.c - chacha20.c - chachapoly.c - cipher.c - cipher_wrap.c - constant_time.c - cmac.c - ctr_drbg.c - des.c - dhm.c - ecdh.c - ecdsa.c - ecjpake.c - ecp.c - ecp_curves.c - entropy.c - entropy_poll.c - error.c - gcm.c - hkdf.c - hmac_drbg.c - md.c - md5.c - memory_buffer_alloc.c - mps_reader.c - mps_trace.c - nist_kw.c - oid.c - padlock.c - pem.c - pk.c - pk_wrap.c - pkcs12.c - pkcs5.c - pkparse.c - pkwrite.c - platform.c - platform_util.c - poly1305.c - psa_crypto.c - psa_crypto_aead.c - psa_crypto_cipher.c - psa_crypto_client.c - psa_crypto_ecp.c - psa_crypto_hash.c - psa_crypto_mac.c - psa_crypto_rsa.c - psa_crypto_se.c - psa_crypto_slot_management.c - psa_crypto_storage.c - psa_its_file.c - ripemd160.c - rsa.c - sha1.c - sha256.c - sha512.c - threading.c - timing.c - version.c - version_features.c - ) - if (MBEDTLS_VERSION_MAJOR EQUAL 2) - list(APPEND src_crypto - arc4.c - blowfish.c - havege.c - md2.c - md4.c - psa_crypto_driver_wrappers.c - rsa_internal.c xtea.c + function(src_crypto_list) + set(src_crypto + aes.c + aesni.c + aria.c + asn1parse.c + asn1write.c + base64.c + bignum.c + camellia.c + ccm.c + chacha20.c + chachapoly.c + cipher.c + cipher_wrap.c + constant_time.c + cmac.c + ctr_drbg.c + des.c + dhm.c + ecdh.c + ecdsa.c + ecjpake.c + ecp.c + ecp_curves.c + entropy.c + entropy_poll.c + error.c + gcm.c + hkdf.c + hmac_drbg.c + md.c + md5.c + memory_buffer_alloc.c + mps_reader.c + mps_trace.c + nist_kw.c + oid.c + padlock.c + pem.c + pk.c + pk_wrap.c + pkcs12.c + pkcs5.c + pkparse.c + pkwrite.c + platform.c + platform_util.c + poly1305.c + psa_crypto.c + psa_crypto_aead.c + psa_crypto_cipher.c + psa_crypto_client.c + psa_crypto_ecp.c + psa_crypto_hash.c + psa_crypto_mac.c + psa_crypto_rsa.c + psa_crypto_se.c + psa_crypto_slot_management.c + psa_crypto_storage.c + psa_its_file.c + ripemd160.c + rsa.c + sha1.c + sha256.c + sha512.c + threading.c + timing.c + version.c + version_features.c ) - elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) - list(APPEND src_crypto - bignum_core.c - rsa_alt_helpers.c - pk_ecc.c - ) - endif() - list(TRANSFORM src_crypto PREPEND ${PICO_MBEDTLS_PATH}/library/) + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_crypto + arc4.c + blowfish.c + havege.c + md2.c + md4.c + psa_crypto_driver_wrappers.c + rsa_internal.c xtea.c + ) + elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) + list(APPEND src_crypto + bignum_core.c + rsa_alt_helpers.c + pk_ecc.c + ) + endif() + list(TRANSFORM src_crypto PREPEND ${PICO_MBEDTLS_PATH}/library/) + set(src_crypto ${src_crypto} PARENT_SCOPE) + endfunction() + + src_crypto_list() pico_add_library(pico_mbedtls_crypto NOFLAG) target_sources(pico_mbedtls_crypto INTERFACE ${src_crypto}) - set(src_x509 - x509.c - x509_create.c - x509_crl.c - x509_crt.c - x509_csr.c - x509write_crt.c - x509write_csr.c - ) - if (MBEDTLS_VERSION_MAJOR EQUAL 2) - list(APPEND src_x509 - certs.c - pkcs11.c + function(src_x509_list) + set(src_x509 + x509.c + x509_create.c + x509_crl.c + x509_crt.c + x509_csr.c + x509write_crt.c + x509write_csr.c ) - endif() + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_x509 + certs.c + pkcs11.c + ) + endif() + list(TRANSFORM src_x509 PREPEND ${PICO_MBEDTLS_PATH}/library/) + set(src_x509 ${src_x509} PARENT_SCOPE) + endfunction() - list(TRANSFORM src_x509 PREPEND ${PICO_MBEDTLS_PATH}/library/) + src_x509_list() pico_add_library(pico_mbedtls_x509 NOFLAG) target_sources(pico_mbedtls_x509 INTERFACE ${src_x509}) - set(src_tls - debug.c - net_sockets.c - ssl_cache.c - ssl_ciphersuites.c - ssl_cookie.c - ssl_msg.c - ssl_ticket.c - ssl_tls.c - ssl_tls13_keys.c - ) - if (MBEDTLS_VERSION_MAJOR EQUAL 2) - list(APPEND src_tls - ssl_cli.c - ssl_srv.c - ) - elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) - list(APPEND src_tls - ssl_client.c - ssl_debug_helpers_generated.c - ssl_tls12_client.c - ssl_tls12_server.c + function(src_tls_list) + set(src_tls + debug.c + net_sockets.c + ssl_cache.c + ssl_ciphersuites.c + ssl_cookie.c + ssl_msg.c + ssl_ticket.c + ssl_tls.c + ssl_tls13_keys.c ) - endif() + if (MBEDTLS_VERSION_MAJOR EQUAL 2) + list(APPEND src_tls + ssl_cli.c + ssl_srv.c + ) + elseif (MBEDTLS_VERSION_MAJOR EQUAL 3) + list(APPEND src_tls + ssl_client.c + ssl_debug_helpers_generated.c + ssl_tls12_client.c + ssl_tls12_server.c + ) + endif() + list(TRANSFORM src_tls PREPEND ${PICO_MBEDTLS_PATH}/library/) + set(src_tls ${src_tls} PARENT_SCOPE) + endfunction() - list(TRANSFORM src_tls PREPEND ${PICO_MBEDTLS_PATH}/library/) + src_tls_list() pico_add_library(pico_mbedtls_tls NOFLAG) target_sources(pico_mbedtls_tls INTERFACE ${src_tls}) @@ -187,32 +200,26 @@ if (EXISTS ${PICO_MBEDTLS_PATH}/${MBEDTLS_TEST_PATH}) target_include_directories(pico_mbedtls_headers SYSTEM INTERFACE ${PICO_MBEDTLS_PATH}/include/ ${PICO_MBEDTLS_PATH}/library/ ${CMAKE_CURRENT_LIST_DIR}/include/) function(suppress_mbedtls_warnings) + # It seems everything needs this due to mbedtls_get_unaligned_uint64 + src_crypto_list() + src_x509_list() + src_tls_list() + foreach(src_file IN LISTS src_crypto src_x509 src_tls) + set_source_files_properties( + ${src_file} + PROPERTIES + COMPILE_OPTIONS "-Wno-cast-qual" + ) + endforeach() + set_source_files_properties( - ${PICO_MBEDTLS_PATH}/library/ecdsa.c - ${PICO_MBEDTLS_PATH}/library/ecp.c - ${PICO_MBEDTLS_PATH}/library/ecp_curves.c - ${PICO_MBEDTLS_PATH}/library/pk_wrap.c - ${PICO_MBEDTLS_PATH}/library/pkparse.c - ${PICO_MBEDTLS_PATH}/library/ssl_cli.c - PROPERTIES - COMPILE_OPTIONS "-Wno-cast-qual" - ) - set_source_files_properties( - ${PICO_MBEDTLS_PATH}/library/psa_crypto_client.c - ${PICO_MBEDTLS_PATH}/library/psa_crypto_driver_wrappers.c - PROPERTIES - COMPILE_OPTIONS "-Wno-redundant-decls" - ) - set_source_files_properties( + ${PICO_MBEDTLS_PATH}/library/ssl_srvx.c ${PICO_MBEDTLS_PATH}/library/x509_crt.c - PROPERTIES - COMPILE_OPTIONS "-Wno-cast-qual;-Wno-null-dereference" - ) - set_source_files_properties( - ${PICO_MBEDTLS_PATH}/library/ssl_srv.c + ${PICO_MBEDTLS_PATH}/library/pk_ecc.c + ${PICO_MBEDTLS_PATH}/library/ssl_tls12_server.c ${PICO_MBEDTLS_PATH}/library/ssl_tls.c PROPERTIES - COMPILE_OPTIONS "-Wno-null-dereference" + COMPILE_OPTIONS "-Wno-cast-qual;-Wno-null-dereference" ) endfunction() From b6bb87bd7e0a86e66c1cdfc8ebbd6cff1b91ae03 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 17:00:25 +0100 Subject: [PATCH 09/13] Test mbedtls in kitchen sink --- src/rp2_common/pico_mbedtls/pico_mbedtls.c | 1 - test/kitchen_sink/lwipopts.h | 8 +++++++- test/kitchen_sink/mbedtls_config.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_mbedtls/pico_mbedtls.c b/src/rp2_common/pico_mbedtls/pico_mbedtls.c index 03a41da47..c7b61c077 100644 --- a/src/rp2_common/pico_mbedtls/pico_mbedtls.c +++ b/src/rp2_common/pico_mbedtls/pico_mbedtls.c @@ -8,7 +8,6 @@ #include "pico.h" #include "pico/rand.h" #include "mbedtls/sha256.h" -#include "common.h" /* Function to feed mbedtls entropy. */ int mbedtls_hardware_poll(void *data __unused, unsigned char *output, size_t len, size_t *olen) { diff --git a/test/kitchen_sink/lwipopts.h b/test/kitchen_sink/lwipopts.h index 58b704a1c..510a20449 100644 --- a/test/kitchen_sink/lwipopts.h +++ b/test/kitchen_sink/lwipopts.h @@ -11,4 +11,10 @@ #define LWIP_DNS 1 #define LWIP_SOCKET 0 #define LWIP_NETCONN 0 -#endif \ No newline at end of file + +// For testing mbedtls +#define LWIP_ALTCP 1 +#define LWIP_ALTCP_TLS 1 +#define LWIP_ALTCP_TLS_MBEDTLS 1 + +#endif diff --git a/test/kitchen_sink/mbedtls_config.h b/test/kitchen_sink/mbedtls_config.h index dae339567..4df2e168f 100644 --- a/test/kitchen_sink/mbedtls_config.h +++ b/test/kitchen_sink/mbedtls_config.h @@ -61,3 +61,4 @@ #define MBEDTLS_ECDSA_C #define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_PLATFORM_MS_TIME_ALT From 8a9bbfb307d9aae780ac1d7121d791d5a3c64e55 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 17:25:03 +0100 Subject: [PATCH 10/13] Add mbedtls to bazel Use it in kitchen_sink --- MODULE.bazel | 7 +++++++ bazel/config/BUILD.bazel | 6 ++++++ bazel/constraint/BUILD.bazel | 6 ++++++ bazel/util/transition.bzl | 2 ++ src/rp2_common/pico_lwip/lwip.BUILD | 16 ++++++++++++++-- src/rp2_common/pico_mbedtls/BUILD.bazel | 21 ++++++++++++++++++--- src/rp2_common/pico_mbedtls/mbedtls.BUILD | 23 +++++++++++++++++++++++ test/kitchen_sink/BUILD.bazel | 7 +++++++ tools/compare_build_systems.py | 1 + 9 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 src/rp2_common/pico_mbedtls/mbedtls.BUILD diff --git a/MODULE.bazel b/MODULE.bazel index 10223842f..1cc03bd1a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -118,6 +118,13 @@ new_git_repository( remote = "https://github.com/lwip-tcpip/lwip.git", ) +new_git_repository( + name = "mbedtls", + build_file = "//src/rp2_common/pico_mbedtls:mbedtls.BUILD", + commit = "107ea89daaefb9867ea9121002fbbdf926780e98", # keep-in-sync-with-submodule: lib/mbedtls + remote = "https://github.com/Mbed-TLS/mbedtls.git", +) + register_toolchains( "//bazel/toolchain:linux-aarch64-rp2040", "//bazel/toolchain:linux-aarch64-rp2350", diff --git a/bazel/config/BUILD.bazel b/bazel/config/BUILD.bazel index 3d75654eb..ac6dc387a 100644 --- a/bazel/config/BUILD.bazel +++ b/bazel/config/BUILD.bazel @@ -294,3 +294,9 @@ label_flag( name = "PICO_FREERTOS_LIB", build_setting_default = "//bazel:empty_cc_lib", ) + +# PICO_BAZEL_CONFIG: PICO_MBEDTL_CONFIG, [Bazel only] The cc_library that provides mbedtls_config.h, default=//bazel:empty_cc_lib, group=pico_mbedtls +label_flag( + name = "PICO_MBEDTLS_CONFIG", + build_setting_default = "//bazel:empty_cc_lib", +) diff --git a/bazel/constraint/BUILD.bazel b/bazel/constraint/BUILD.bazel index a4fe918b8..3ce282065 100644 --- a/bazel/constraint/BUILD.bazel +++ b/bazel/constraint/BUILD.bazel @@ -252,3 +252,9 @@ label_flag_matches( flag = "//bazel/config:PICO_FREERTOS_LIB", value = "//bazel:empty_cc_lib", ) + +label_flag_matches( + name = "pico_mbedtls_config_unset", + flag = "//bazel/config:PICO_MBEDTLS_CONFIG", + value = "//bazel:empty_cc_lib", +) diff --git a/bazel/util/transition.bzl b/bazel/util/transition.bzl index 67f0d616e..aa943d602 100644 --- a/bazel/util/transition.bzl +++ b/bazel/util/transition.bzl @@ -114,6 +114,7 @@ kitchen_sink_test_binary = declare_transtion( attrs = { "bt_stack_config": attr.label(mandatory = True), "lwip_config": attr.label(mandatory = True), + "mbedtls_config": attr.label(mandatory = True), "enable_ble": attr.bool(default = False), "enable_bt_classic": attr.bool(default = False), # This could be shared, but we don't in order to make it clearer that @@ -127,6 +128,7 @@ kitchen_sink_test_binary = declare_transtion( "@pico-sdk//bazel/config:PICO_LWIP_CONFIG": "lwip_config", "@pico-sdk//bazel/config:PICO_BT_ENABLE_BLE": "enable_ble", "@pico-sdk//bazel/config:PICO_BT_ENABLE_CLASSIC": "enable_bt_classic", + "@pico-sdk//bazel/config:PICO_MBEDTLS_CONFIG": "mbedtls_config", }, ) diff --git a/src/rp2_common/pico_lwip/lwip.BUILD b/src/rp2_common/pico_lwip/lwip.BUILD index c94b881c5..5958e274a 100644 --- a/src/rp2_common/pico_lwip/lwip.BUILD +++ b/src/rp2_common/pico_lwip/lwip.BUILD @@ -25,7 +25,15 @@ cc_library( deps = [ ":pico_lwip_headers", "@pico-sdk//bazel/config:PICO_LWIP_CONFIG", - ], + ] + # altcp_alloc.c *might* depend on mbedtls + + select({ + "@pico-sdk//bazel/constraint:pico_mbedtls_config_unset": [], + "//conditions:default": [ + "@pico-sdk//src/rp2_common/pico_mbedtls:pico_mbedtls_library", + ] + }) + , target_compatible_with = incompatible_with_config("@pico-sdk//bazel/constraint:pico_lwip_config_unset") ) @@ -142,7 +150,11 @@ cc_library( "src/apps/altcp_tls/altcp_tls_mbedtls_mem.c", "src/apps/snmp/snmpv3_mbedtls.c", ], - deps = [":pico_lwip_core"], + includes = ["src/apps/altcp_tls"], + deps = [ + ":pico_lwip_core", + "@pico-sdk//src/rp2_common/pico_mbedtls:pico_mbedtls_config" + ], ) cc_library( diff --git a/src/rp2_common/pico_mbedtls/BUILD.bazel b/src/rp2_common/pico_mbedtls/BUILD.bazel index c339941cd..843ae821e 100644 --- a/src/rp2_common/pico_mbedtls/BUILD.bazel +++ b/src/rp2_common/pico_mbedtls/BUILD.bazel @@ -2,6 +2,13 @@ load("//bazel:defs.bzl", "compatible_with_rp2") package(default_visibility = ["//visibility:public"]) +cc_library( + name = "pico_mbedtls_config", + includes = ["include"], + hdrs = ["include/pico_mbedtls_config.h"], + defines = ['MBEDTLS_CONFIG_FILE=\\"pico_mbedtls_config.h\\"'], +) + cc_library( name = "pico_mbedtls", srcs = ["pico_mbedtls.c"], @@ -9,9 +16,17 @@ cc_library( includes = ["include"], target_compatible_with = compatible_with_rp2(), deps = [ - "//bazel/config:PICO_MBEDTLS_LIB", + ":pico_mbedtls_library", + ":pico_mbedtls_config", "//src/rp2_common:pico_platform", "//src/rp2_common/pico_rand", - "//src/rp2_common/pico_sha256", - ], + ] + select({ + "//bazel/constraint:rp2350": [ "//src/rp2_common/pico_sha256" ], + "//conditions:default": [ ], + }), +) + +alias( + name = "pico_mbedtls_library", + actual = "@mbedtls//:pico_mbedtls_library", ) diff --git a/src/rp2_common/pico_mbedtls/mbedtls.BUILD b/src/rp2_common/pico_mbedtls/mbedtls.BUILD new file mode 100644 index 000000000..c8b856492 --- /dev/null +++ b/src/rp2_common/pico_mbedtls/mbedtls.BUILD @@ -0,0 +1,23 @@ +load("@pico-sdk//bazel:defs.bzl", "incompatible_with_config") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "pico_mbedtls_library", + srcs = glob( + ["library/*.c"], + exclude = ["*mbedtls.c"], + ), + hdrs = glob( + include = [ + "include/**/*.h", + "library/*.h", + ], + ), + includes = ["include"], + target_compatible_with = incompatible_with_config("@pico-sdk//bazel/constraint:pico_mbedtls_config_unset"), + deps = [ + "@pico-sdk//src/rp2_common/pico_mbedtls:pico_mbedtls_config", + "@pico-sdk//bazel/config:PICO_MBEDTLS_CONFIG", + ], +) diff --git a/test/kitchen_sink/BUILD.bazel b/test/kitchen_sink/BUILD.bazel index 1bd595c3e..d703ff320 100644 --- a/test/kitchen_sink/BUILD.bazel +++ b/test/kitchen_sink/BUILD.bazel @@ -110,6 +110,8 @@ cc_binary( ":kitchen_sink_common", "//src/rp2_common/pico_cyw43_arch:pico_cyw43_arch_lwip_poll", "//src/rp2_common/pico_btstack:pico_btstack", + "//src/rp2_common/pico_lwip:pico_lwip_mbedtls", + "//src/rp2_common/pico_mbedtls", ], ) @@ -121,6 +123,9 @@ cc_binary( deps = [ ":kitchen_sink_common", "//src/rp2_common/pico_cyw43_arch:pico_cyw43_arch_lwip_threadsafe_background", + "//src/rp2_common/pico_btstack:pico_btstack", + "//src/rp2_common/pico_lwip:pico_lwip_mbedtls", + "//src/rp2_common/pico_mbedtls", ], ) @@ -130,6 +135,7 @@ kitchen_sink_test_binary( src = ":kitchen_sink_lwip_poll_actual", bt_stack_config = ":btstack_config", lwip_config = ":lwip_config", + mbedtls_config = ":mbedtls_config", enable_ble = True, enable_bt_classic = True, target_compatible_with = compatible_with_rp2(), @@ -141,6 +147,7 @@ kitchen_sink_test_binary( src = ":kitchen_sink_lwip_background_actual", bt_stack_config = ":btstack_config", lwip_config = ":lwip_config", + mbedtls_config = ":mbedtls_config", enable_ble = True, enable_bt_classic = True, target_compatible_with = compatible_with_rp2(), diff --git a/tools/compare_build_systems.py b/tools/compare_build_systems.py index badeadee1..86dc615a1 100755 --- a/tools/compare_build_systems.py +++ b/tools/compare_build_systems.py @@ -135,6 +135,7 @@ # Bazel configuration for 3p deps. "PICO_BTSTACK_CONFIG", "PICO_LWIP_CONFIG", + "PICO_MBEDTLS_CONFIG", "PICO_FREERTOS_LIB", "PICO_MBEDTLS_LIB", # CMake has PICO_DEFAULT_CLIB, but it's not user-facing. From 438fda5d389bb1b8e54246346cba1e853fdbeb96 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 17:26:14 +0100 Subject: [PATCH 11/13] Use pico_lwip branch of altcp_tls_mbedtls.c Change for bazel build --- src/rp2_common/pico_lwip/BUILD.bazel | 5 +++-- src/rp2_common/pico_lwip/lwip.BUILD | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/rp2_common/pico_lwip/BUILD.bazel b/src/rp2_common/pico_lwip/BUILD.bazel index c98ff92a2..5af5e0b01 100644 --- a/src/rp2_common/pico_lwip/BUILD.bazel +++ b/src/rp2_common/pico_lwip/BUILD.bazel @@ -131,9 +131,10 @@ alias( actual = "@lwip//:pico_lwip_tftp", ) -alias( +cc_library( name = "pico_lwip_mbedtls", - actual = "@lwip//:pico_lwip_mbedtls", + srcs = ["altcp_tls_mbedtls.c"], + deps = ["@lwip//:pico_lwip_mbedtls"], ) alias( diff --git a/src/rp2_common/pico_lwip/lwip.BUILD b/src/rp2_common/pico_lwip/lwip.BUILD index 5958e274a..709720ab0 100644 --- a/src/rp2_common/pico_lwip/lwip.BUILD +++ b/src/rp2_common/pico_lwip/lwip.BUILD @@ -146,7 +146,9 @@ cc_library( cc_library( name = "pico_lwip_mbedtls", srcs = [ - "src/apps/altcp_tls/altcp_tls_mbedtls.c", + # This source file has issues with mbedtls 3.x + # See https://savannah.nongnu.org/patch/index.php?10448 + #"src/apps/altcp_tls/altcp_tls_mbedtls.c", "src/apps/altcp_tls/altcp_tls_mbedtls_mem.c", "src/apps/snmp/snmpv3_mbedtls.c", ], From b4bbac3fee3c997dede313ec28134f91d34cb927 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 17:28:58 +0100 Subject: [PATCH 12/13] Fix name of pico_lwip_mqtt in bazel build --- src/rp2_common/pico_lwip/BUILD.bazel | 4 ++-- src/rp2_common/pico_lwip/lwip.BUILD | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rp2_common/pico_lwip/BUILD.bazel b/src/rp2_common/pico_lwip/BUILD.bazel index 5af5e0b01..cc5de44c8 100644 --- a/src/rp2_common/pico_lwip/BUILD.bazel +++ b/src/rp2_common/pico_lwip/BUILD.bazel @@ -138,8 +138,8 @@ cc_library( ) alias( - name = "pico_lwip_mqttt", - actual = "@lwip//:pico_lwip_mqttt", + name = "pico_lwip_mqtt", + actual = "@lwip//:pico_lwip_mqtt", ) alias( diff --git a/src/rp2_common/pico_lwip/lwip.BUILD b/src/rp2_common/pico_lwip/lwip.BUILD index 709720ab0..c76d42dc7 100644 --- a/src/rp2_common/pico_lwip/lwip.BUILD +++ b/src/rp2_common/pico_lwip/lwip.BUILD @@ -160,7 +160,7 @@ cc_library( ) cc_library( - name = "pico_lwip_mqttt", + name = "pico_lwip_mqtt", srcs = ["src/apps/mqtt/mqtt.c"], deps = [":pico_lwip_core"], ) From b493ef0103c8f94c042d1eaa374fae7f754496c2 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Wed, 9 Apr 2025 17:38:34 +0100 Subject: [PATCH 13/13] mbedtls now has submodules Update github workflow to add "--recursive" to "git submodule update --init" --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 28ee68bd6..75ce8324e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v4 - name: Checkout submodules - run: git submodule update --init + run: git submodule update --init --recursive - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory