mirror of
https://github.com/esphome/esphome.git
synced 2026-09-16 09:38:42 +00:00
[esp32] Trim mbedTLS to client-only defaults and stub vasprintf on the C6 (#19088)
This commit is contained in:
@@ -189,6 +189,13 @@ PSRAM_XIP_VARIANTS = {
|
||||
VARIANT_ESP32S31,
|
||||
}
|
||||
|
||||
# Variants whose ROM exports a full-format vsnprintf but no vasprintf
|
||||
# (esp32c6.rom.newlib-normal.ld). There, the newlib printf engine is only
|
||||
# linked because esp_http_client calls vasprintf; see vasprintf_stubs.cpp.
|
||||
# The other variants either export both (classic ESP32, nano-format only) or
|
||||
# neither, so the engine is already in the image and the wrap saves nothing.
|
||||
ROM_VSNPRINTF_WITHOUT_VASPRINTF_VARIANTS = {VARIANT_ESP32C6}
|
||||
|
||||
# NVS encryption (HMAC peripheral scheme) is only available on variants that
|
||||
# expose the HMAC peripheral (SOC_HMAC_SUPPORTED in soc_caps.h). The original
|
||||
# ESP32 and ESP32-C2 do not have it. New variants with an HMAC peripheral
|
||||
@@ -1732,6 +1739,8 @@ CONF_DISABLE_USB_SERIAL_JTAG_SECONDARY = "disable_usb_serial_jtag_secondary"
|
||||
CONF_DISABLE_DEV_NULL_VFS = "disable_dev_null_vfs"
|
||||
CONF_DISABLE_MBEDTLS_PEER_CERT = "disable_mbedtls_peer_cert"
|
||||
CONF_DISABLE_MBEDTLS_PKCS7 = "disable_mbedtls_pkcs7"
|
||||
CONF_DISABLE_MBEDTLS_TLS_SERVER = "disable_mbedtls_tls_server"
|
||||
CONF_DISABLE_MBEDTLS_TLS_EXTRAS = "disable_mbedtls_tls_extras"
|
||||
CONF_DISABLE_REGI2C_IN_IRAM = "disable_regi2c_in_iram"
|
||||
CONF_DISABLE_FATFS = "disable_fatfs"
|
||||
CONF_ADC_ONESHOT_IN_IRAM = "adc_oneshot_in_iram"
|
||||
@@ -1746,6 +1755,8 @@ KEY_VFS_TERMIOS_REQUIRED = "vfs_termios_required"
|
||||
KEY_USB_SERIAL_JTAG_SECONDARY_REQUIRED = "usb_serial_jtag_secondary_required"
|
||||
KEY_MBEDTLS_PEER_CERT_REQUIRED = "mbedtls_peer_cert_required"
|
||||
KEY_MBEDTLS_PKCS7_REQUIRED = "mbedtls_pkcs7_required"
|
||||
KEY_MBEDTLS_TLS_SERVER_REQUIRED = "mbedtls_tls_server_required"
|
||||
KEY_MBEDTLS_TLS_EXTRAS_REQUIRED = "mbedtls_tls_extras_required"
|
||||
KEY_FATFS_REQUIRED = "fatfs_required"
|
||||
KEY_MBEDTLS_SHA512_REQUIRED = "mbedtls_sha512_required"
|
||||
KEY_ADC_ONESHOT_IRAM_REQUIRED = "adc_oneshot_iram_required"
|
||||
@@ -1830,6 +1841,30 @@ def require_mbedtls_pkcs7() -> None:
|
||||
CORE.data[KEY_ESP32][KEY_MBEDTLS_PKCS7_REQUIRED] = True
|
||||
|
||||
|
||||
def require_mbedtls_tls_server() -> None:
|
||||
"""Mark that the mbedTLS server-side TLS/DTLS handshake is required.
|
||||
|
||||
Call this from components that accept TLS connections (OpenThread's DTLS
|
||||
commissioner does). This prevents CONFIG_MBEDTLS_TLS_CLIENT_ONLY from
|
||||
being selected.
|
||||
"""
|
||||
CORE.data[KEY_ESP32][KEY_MBEDTLS_TLS_SERVER_REQUIRED] = True
|
||||
|
||||
|
||||
def require_mbedtls_tls_extras(options: Iterable[str] | None = None) -> None:
|
||||
"""Mark TLS features disabled by ``disable_mbedtls_tls_extras`` as required.
|
||||
|
||||
``options`` names the entries of ``MBEDTLS_TLS_EXTRA_OPTIONS`` to keep;
|
||||
omit it to keep all of them. Call this from components that need AES-CCM,
|
||||
deterministic ECDSA signing, static RSA/ECDH key exchange, TLS
|
||||
renegotiation or session tickets, or that run a TLS client against
|
||||
servers ESPHome cannot vet (wpa_supplicant's EAP client). A user-supplied
|
||||
sdkconfig_options value is never overridden either.
|
||||
"""
|
||||
required = CORE.data[KEY_ESP32].setdefault(KEY_MBEDTLS_TLS_EXTRAS_REQUIRED, set())
|
||||
required.update(MBEDTLS_TLS_EXTRA_OPTIONS if options is None else options)
|
||||
|
||||
|
||||
def require_mbedtls_sha512() -> None:
|
||||
"""Mark that mbedTLS SHA-384/SHA-512 support is required by a component.
|
||||
|
||||
@@ -1987,6 +2022,8 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_DISABLE_DEV_NULL_VFS, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_MBEDTLS_PEER_CERT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_MBEDTLS_PKCS7, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_MBEDTLS_TLS_SERVER, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_MBEDTLS_TLS_EXTRAS, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_REGI2C_IN_IRAM, default=True): cv.boolean,
|
||||
cv.Optional(CONF_ADC_ONESHOT_IN_IRAM, default=False): cv.boolean,
|
||||
cv.Optional(CONF_DISABLE_FATFS, default=True): cv.boolean,
|
||||
@@ -2302,6 +2339,69 @@ async def _reconcile_certificate_bundle_sdkconfig() -> None:
|
||||
set_idf_sdkconfig_default("CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN", True)
|
||||
|
||||
|
||||
# TLS features an HTTPS/MQTT client talking to a modern server never
|
||||
# negotiates. Static RSA and static ECDH key exchange have no forward secrecy
|
||||
# and are gone in TLS 1.3, renegotiation is deprecated, esp-tls never enables
|
||||
# session tickets, AES-CCM ciphersuites are not offered by web servers, and
|
||||
# deterministic ECDSA only matters when signing with a private key. Together
|
||||
# they cost ~10 KB of flash whenever TLS is linked (http_request, mqtt).
|
||||
# wpa_supplicant's EAP client is a second TLS client that talks to RADIUS
|
||||
# servers ESPHome cannot vet, and a failed EAP handshake leaves the device
|
||||
# off the network, so the wifi component re-enables all of these when eap is
|
||||
# configured.
|
||||
# The EC public key parsing extras stay enabled: they decide whether a peer
|
||||
# certificate with a compressed point or explicit curve parameters parses,
|
||||
# which no component can know ahead of time.
|
||||
MBEDTLS_TLS_EXTRA_OPTIONS = (
|
||||
"CONFIG_MBEDTLS_KEY_EXCHANGE_RSA",
|
||||
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA",
|
||||
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA",
|
||||
"CONFIG_MBEDTLS_SSL_RENEGOTIATION",
|
||||
"CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS",
|
||||
"CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS",
|
||||
"CONFIG_MBEDTLS_CCM_C",
|
||||
"CONFIG_MBEDTLS_ECDSA_DETERMINISTIC",
|
||||
)
|
||||
|
||||
# Members of the mbedTLS "TLS Protocol Role" Kconfig choice. Setting one
|
||||
# member is only valid when the user has not already chosen another.
|
||||
MBEDTLS_TLS_ROLE_OPTIONS = (
|
||||
"CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT",
|
||||
"CONFIG_MBEDTLS_TLS_SERVER_ONLY",
|
||||
"CONFIG_MBEDTLS_TLS_CLIENT_ONLY",
|
||||
"CONFIG_MBEDTLS_TLS_DISABLED",
|
||||
)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _reconcile_mbedtls_tls_sdkconfig(
|
||||
disable_tls_server: bool, disable_tls_extras: bool
|
||||
) -> None:
|
||||
"""Trim mbedTLS to what a TLS client needs unless a component asked otherwise.
|
||||
|
||||
Runs at FINAL priority so every require_mbedtls_tls_server() and
|
||||
require_mbedtls_tls_extras() call has happened. Only the server-side
|
||||
handshake (~7 KB) is a separate option; nothing in ESPHome accepts TLS
|
||||
connections, but OpenThread's DTLS commissioner does. A user-supplied
|
||||
sdkconfig_options value always wins; for the TLS role choice, any member
|
||||
the user set leaves the whole choice alone so the pair cannot conflict.
|
||||
"""
|
||||
data = CORE.data[KEY_ESP32]
|
||||
sdkconfig = data[KEY_SDKCONFIG_OPTIONS]
|
||||
if (
|
||||
disable_tls_server
|
||||
and not data.get(KEY_MBEDTLS_TLS_SERVER_REQUIRED, False)
|
||||
and not any(option in sdkconfig for option in MBEDTLS_TLS_ROLE_OPTIONS)
|
||||
):
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_TLS_CLIENT_ONLY", True)
|
||||
add_idf_sdkconfig_option("CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT", False)
|
||||
if disable_tls_extras:
|
||||
required = data.get(KEY_MBEDTLS_TLS_EXTRAS_REQUIRED, set())
|
||||
for option in MBEDTLS_TLS_EXTRA_OPTIONS:
|
||||
if option not in required:
|
||||
set_idf_sdkconfig_default(option, False)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _reconcile_network_sdkconfig() -> None:
|
||||
"""Reconcile WiFi/Ethernet/Bluetooth/coexistence sdkconfig flags.
|
||||
@@ -2566,6 +2666,17 @@ async def to_code(config):
|
||||
else:
|
||||
for symbol in ("vprintf", "printf", "fprintf", "vfprintf"):
|
||||
cg.add_build_flag(f"-Wl,--wrap={symbol}")
|
||||
# esp_http_client calls vasprintf, which on the ESP32-C6 is the only
|
||||
# reference to newlib's full printf engine (~20 KB: _svfprintf_r,
|
||||
# _dtoa_r and their helpers); every other caller resolves to the
|
||||
# ROM. See vasprintf_stubs.cpp. The --undefined flag is needed
|
||||
# because libsrc.a is scanned before the IDF libraries that
|
||||
# reference the symbol, so the stub would otherwise never be pulled
|
||||
# from the archive.
|
||||
if variant in ROM_VSNPRINTF_WITHOUT_VASPRINTF_VARIANTS:
|
||||
cg.add_define("USE_ESP32_VASPRINTF_STUB")
|
||||
cg.add_build_flag("-Wl,--wrap=vasprintf")
|
||||
cg.add_build_flag("-Wl,--undefined=__wrap_vasprintf")
|
||||
else:
|
||||
cg.add_build_flag("-DUSE_ARDUINO")
|
||||
cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ARDUINO")
|
||||
@@ -2991,6 +3102,13 @@ async def to_code(config):
|
||||
# FINAL priority: runs after every require_certificate_bundle() call
|
||||
CORE.add_job(_reconcile_certificate_bundle_sdkconfig)
|
||||
|
||||
# FINAL priority: runs after every require_mbedtls_tls_*() call
|
||||
CORE.add_job(
|
||||
_reconcile_mbedtls_tls_sdkconfig,
|
||||
advanced[CONF_DISABLE_MBEDTLS_TLS_SERVER],
|
||||
advanced[CONF_DISABLE_MBEDTLS_TLS_EXTRAS],
|
||||
)
|
||||
|
||||
# FINAL: require_*() calls can come from to_code at or below this priority, so an
|
||||
# inline read would be iteration-order-dependent; reconcile once after every job ran.
|
||||
CORE.add_job(
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Linker wrap stub for vasprintf() on variants whose ROM exports a
|
||||
* full-format vsnprintf() but no vasprintf() (ESP32-C6, newlib only).
|
||||
*
|
||||
* On those chips every snprintf/vsnprintf call in the image resolves to
|
||||
* the ROM, so the newlib printf engine (_svfprintf_r, _dtoa_r and their
|
||||
* helpers, ~20 KB) is not linked at all until something references a
|
||||
* printf-family function the ROM lacks. esp_http_client does exactly that
|
||||
* through vasprintf() in its header and auth helpers, so adding
|
||||
* http_request to a build costs the whole engine on top of the HTTP and
|
||||
* TLS code itself.
|
||||
*
|
||||
* This stub reimplements vasprintf() on top of the ROM vsnprintf(), which
|
||||
* keeps the engine out of the image. It is only compiled in when codegen
|
||||
* defines USE_ESP32_VASPRINTF_STUB, which is gated on the variant's ROM
|
||||
* linker script and on the same newlib condition as printf_stubs.cpp.
|
||||
*/
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#if defined(USE_ESP_IDF) && defined(USE_ESP32_VASPRINTF_STUB)
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace esphome::esp32 {}
|
||||
|
||||
// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
|
||||
extern "C" {
|
||||
|
||||
int __wrap_vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
int len = vsnprintf(nullptr, 0, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
if (len < 0) {
|
||||
return len;
|
||||
}
|
||||
// vasprintf's contract is a malloc'd buffer the caller releases with free()
|
||||
char *buf = static_cast<char *>(malloc(static_cast<size_t>(len) + 1)); // NOLINT(cppcoreguidelines-no-malloc)
|
||||
if (buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
vsnprintf(buf, static_cast<size_t>(len) + 1, fmt, ap);
|
||||
*strp = buf;
|
||||
return len;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
|
||||
|
||||
#endif // USE_ESP_IDF && USE_ESP32_VASPRINTF_STUB
|
||||
@@ -13,6 +13,8 @@ from esphome.components.esp32 import (
|
||||
get_esp32_variant,
|
||||
include_builtin_idf_component,
|
||||
only_on_variant,
|
||||
require_mbedtls_tls_extras,
|
||||
require_mbedtls_tls_server,
|
||||
require_vfs_select,
|
||||
)
|
||||
from esphome.components.mdns import MDNSComponent, enable_mdns_storage
|
||||
@@ -109,6 +111,14 @@ def set_sdkconfig_options(config: ConfigType) -> None:
|
||||
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_ENABLED", True)
|
||||
|
||||
# OpenThread's DTLS commissioner is a TLS server, and its crypto platform
|
||||
# uses AES-CCM and deterministic ECDSA directly. Keep the esp32 component
|
||||
# from trimming them out of mbedTLS.
|
||||
require_mbedtls_tls_server()
|
||||
require_mbedtls_tls_extras(
|
||||
("CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC")
|
||||
)
|
||||
|
||||
if not config.get(CONF_TLV):
|
||||
if pan_id := config.get(CONF_PAN_ID):
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", pan_id)
|
||||
|
||||
@@ -12,6 +12,7 @@ from esphome.components.esp32 import (
|
||||
get_esp32_variant,
|
||||
only_on_variant,
|
||||
request_wifi,
|
||||
require_mbedtls_tls_extras,
|
||||
)
|
||||
from esphome.components.network import (
|
||||
add_use_address,
|
||||
@@ -658,6 +659,12 @@ async def to_code(config):
|
||||
# Disable Enterprise WiFi support if no EAP is configured
|
||||
if CORE.is_esp32:
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT", has_eap)
|
||||
if has_eap:
|
||||
# wpa_supplicant's EAP client negotiates with whatever the RADIUS
|
||||
# server offers, and a failed handshake leaves the device off the
|
||||
# network, so keep every mbedTLS client feature the esp32 platform
|
||||
# would otherwise trim.
|
||||
require_mbedtls_tls_extras()
|
||||
|
||||
# Only define USE_WIFI_MANUAL_IP if any AP uses manual IP
|
||||
if has_manual_ip:
|
||||
|
||||
@@ -298,6 +298,7 @@
|
||||
// ESP32-specific feature flags
|
||||
#ifdef USE_ESP32
|
||||
#define USE_ESP32_CRASH_HANDLER
|
||||
#define USE_ESP32_VASPRINTF_STUB
|
||||
#define USE_ESP32_INTERNAL_GPIO
|
||||
#define USE_MQTT_IDF_ENQUEUE
|
||||
#define USE_ESPHOME_TASK_LOG_BUFFER
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
password: "test_password"
|
||||
|
||||
http_request:
|
||||
verify_ssl: true
|
||||
@@ -0,0 +1,19 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
variant: esp32c6
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
network:
|
||||
enable_ipv6: true
|
||||
|
||||
openthread:
|
||||
channel: 13
|
||||
network_name: OpenThread-8f28
|
||||
network_key: 0xdfd34f0f05cad978ec4e32b0413038ff
|
||||
pan_id: 0x8f28
|
||||
ext_pan_id: 0xd63e8e3e495ebbc3
|
||||
pskc: 0xc23a76e98f1a6483639b1ac1271e2e27
|
||||
mesh_local_prefix: fd53:145f:ed22:ad81::/64
|
||||
@@ -0,0 +1,17 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
advanced:
|
||||
disable_mbedtls_tls_server: false
|
||||
disable_mbedtls_tls_extras: false
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
password: "test_password"
|
||||
|
||||
http_request:
|
||||
verify_ssl: true
|
||||
@@ -0,0 +1,17 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT: y
|
||||
CONFIG_MBEDTLS_CCM_C: y
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
password: "test_password"
|
||||
|
||||
http_request:
|
||||
verify_ssl: true
|
||||
@@ -0,0 +1,17 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
eap:
|
||||
identity: "user@example.org"
|
||||
username: "user"
|
||||
password: "secret"
|
||||
|
||||
http_request:
|
||||
verify_ssl: true
|
||||
@@ -0,0 +1,7 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
variant: esp32c6
|
||||
framework:
|
||||
type: esp-idf
|
||||
@@ -0,0 +1,9 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
variant: esp32c6
|
||||
framework:
|
||||
type: esp-idf
|
||||
advanced:
|
||||
enable_full_printf: true
|
||||
@@ -11,9 +11,12 @@ import pytest
|
||||
|
||||
from esphome.components.esp32 import (
|
||||
KEY_FATFS_REQUIRED,
|
||||
KEY_MBEDTLS_TLS_EXTRAS_REQUIRED,
|
||||
KEY_MBEDTLS_TLS_SERVER_REQUIRED,
|
||||
KEY_VFS_DIR_REQUIRED,
|
||||
KEY_VFS_SELECT_REQUIRED,
|
||||
KEY_VFS_TERMIOS_REQUIRED,
|
||||
MBEDTLS_TLS_EXTRA_OPTIONS,
|
||||
VARIANT_ESP32,
|
||||
VARIANTS,
|
||||
NetworkSdkconfigData,
|
||||
@@ -1339,3 +1342,99 @@ def test_esp32_s31_gpio_validation(
|
||||
with caplog.at_level("WARNING"):
|
||||
validate_supports(pin)
|
||||
assert "GPIO36 is a strapping PIN" in caplog.text
|
||||
|
||||
|
||||
_TLS_SERVER_OPTIONS = (
|
||||
"CONFIG_MBEDTLS_TLS_CLIENT_ONLY",
|
||||
"CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config_file", "server", "extras"),
|
||||
[
|
||||
pytest.param("mbedtls_tls_default.yaml", (True, False), False, id="default"),
|
||||
pytest.param("mbedtls_tls_opt_out.yaml", (None, None), None, id="opt_out"),
|
||||
pytest.param("mbedtls_tls_wifi_eap.yaml", (True, False), None, id="wifi_eap"),
|
||||
],
|
||||
)
|
||||
def test_mbedtls_tls_trim_sdkconfig(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
config_file: str,
|
||||
server: tuple[bool | None, bool | None],
|
||||
extras: bool | None,
|
||||
) -> None:
|
||||
"""Client-only TLS and the unused-feature trims apply unless opted out or required."""
|
||||
generate_main(component_config_path(config_file))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert tuple(sdkconfig.get(name) for name in _TLS_SERVER_OPTIONS) == server
|
||||
assert {sdkconfig.get(name) for name in MBEDTLS_TLS_EXTRA_OPTIONS} == {extras}
|
||||
|
||||
|
||||
_OPENTHREAD_EXTRAS = {"CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC"}
|
||||
|
||||
|
||||
def test_mbedtls_tls_openthread_keeps_only_what_it_uses(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""The OpenThread config keeps the DTLS server, CCM and deterministic ECDSA; the rest is trimmed."""
|
||||
generate_main(component_config_path("mbedtls_tls_openthread.yaml"))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert tuple(sdkconfig.get(name) for name in _TLS_SERVER_OPTIONS) == (None, None)
|
||||
for name in MBEDTLS_TLS_EXTRA_OPTIONS:
|
||||
assert sdkconfig.get(name) is (None if name in _OPENTHREAD_EXTRAS else False)
|
||||
|
||||
|
||||
def test_mbedtls_tls_user_sdkconfig_wins(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""A user-set TLS role member leaves the whole choice alone; other user values are kept."""
|
||||
generate_main(component_config_path("mbedtls_tls_user_sdkconfig.yaml"))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert sdkconfig.get("CONFIG_MBEDTLS_TLS_CLIENT_ONLY") is None
|
||||
role = sdkconfig["CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT"]
|
||||
assert isinstance(role, RawSdkconfigValue) and role.value == "y"
|
||||
ccm = sdkconfig["CONFIG_MBEDTLS_CCM_C"]
|
||||
assert isinstance(ccm, RawSdkconfigValue) and ccm.value == "y"
|
||||
assert {
|
||||
sdkconfig.get(name)
|
||||
for name in MBEDTLS_TLS_EXTRA_OPTIONS
|
||||
if name != "CONFIG_MBEDTLS_CCM_C"
|
||||
} == {False}
|
||||
|
||||
|
||||
def test_mbedtls_tls_openthread_requires_server_and_extras(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""The OpenThread hooks mark the DTLS server and CCM/deterministic ECDSA as required."""
|
||||
generate_main(component_config_path("mbedtls_tls_openthread.yaml"))
|
||||
assert CORE.data[KEY_ESP32][KEY_MBEDTLS_TLS_SERVER_REQUIRED] is True
|
||||
assert CORE.data[KEY_ESP32][KEY_MBEDTLS_TLS_EXTRAS_REQUIRED] == _OPENTHREAD_EXTRAS
|
||||
|
||||
|
||||
_VASPRINTF_STUB_FLAGS = {"-Wl,--wrap=vasprintf", "-Wl,--undefined=__wrap_vasprintf"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config_file", "expected"),
|
||||
[
|
||||
pytest.param("vasprintf_stub_c6.yaml", True, id="c6"),
|
||||
pytest.param("vasprintf_stub_c6_full_printf.yaml", False, id="c6_full_printf"),
|
||||
pytest.param("exclusion_reincludes.yaml", False, id="esp32"),
|
||||
],
|
||||
)
|
||||
def test_vasprintf_stub_only_on_rom_vsnprintf_variants(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
config_file: str,
|
||||
expected: bool,
|
||||
) -> None:
|
||||
"""The vasprintf wrap is emitted only where the ROM lacks vasprintf but has vsnprintf."""
|
||||
generate_main(component_config_path(config_file))
|
||||
assert (CORE.build_flags >= _VASPRINTF_STUB_FLAGS) is expected
|
||||
defines = {define.name for define in CORE.defines}
|
||||
assert ("USE_ESP32_VASPRINTF_STUB" in defines) is expected
|
||||
|
||||
@@ -17,6 +17,8 @@ esp32:
|
||||
disable_dev_null_vfs: true
|
||||
disable_mbedtls_peer_cert: true
|
||||
disable_mbedtls_pkcs7: true
|
||||
disable_mbedtls_tls_server: true
|
||||
disable_mbedtls_tls_extras: true
|
||||
disable_regi2c_in_iram: true
|
||||
disable_fatfs: true
|
||||
sram1_as_iram: true
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
substitutions:
|
||||
verify_ssl: "true"
|
||||
|
||||
<<: !include common.yaml
|
||||
Reference in New Issue
Block a user