diff --git a/esphome/components/zigbee/zigbee_esp32.py b/esphome/components/zigbee/zigbee_esp32.py index 57fa3b2a00..9aae8d4557 100644 --- a/esphome/components/zigbee/zigbee_esp32.py +++ b/esphome/components/zigbee/zigbee_esp32.py @@ -10,6 +10,7 @@ from esphome.components.esp32 import ( add_idf_sdkconfig_option, add_partition, include_builtin_idf_component, + require_mbedtls_tls_extras, require_vfs_select, ) import esphome.config_validation as cv @@ -289,6 +290,12 @@ async def esp32_to_code(config: ConfigType) -> "MockObj": ref="2.0.4", ) + # Zigbee's crypto platform uses AES-CCM and deterministic ECDSA directly. + # Keep the esp32 component from trimming them out of mbedTLS. + require_mbedtls_tls_extras( + ("CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC") + ) + if CONF_WIFI in CORE.config: # zigbee_esp32.cpp uses esp_coexist.h when WiFi is present include_builtin_idf_component("esp_coex") diff --git a/tests/component_tests/esp32/config/tls_zigbee_c6.yaml b/tests/component_tests/esp32/config/tls_zigbee_c6.yaml new file mode 100644 index 0000000000..3f6904bd98 --- /dev/null +++ b/tests/component_tests/esp32/config/tls_zigbee_c6.yaml @@ -0,0 +1,11 @@ +esphome: + name: test + +esp32: + board: esp32-c6-devkitc-1 + framework: + type: esp-idf + +zigbee: + model: zigbee_test + power_source: MAINS_SINGLE_PHASE diff --git a/tests/component_tests/esp32/test_esp32.py b/tests/component_tests/esp32/test_esp32.py index 3ba819dee7..08f5dcc822 100644 --- a/tests/component_tests/esp32/test_esp32.py +++ b/tests/component_tests/esp32/test_esp32.py @@ -1488,7 +1488,7 @@ def test_mbedtls_tls_trim_sdkconfig( assert {sdkconfig.get(name) for name in MBEDTLS_TLS_EXTRA_OPTIONS} == {extras} -_OPENTHREAD_EXTRAS = {"CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC"} +_CCM_ECDSA_EXTRAS = {"CONFIG_MBEDTLS_CCM_C", "CONFIG_MBEDTLS_ECDSA_DETERMINISTIC"} def test_mbedtls_tls_openthread_keeps_only_what_it_uses( @@ -1500,7 +1500,19 @@ def test_mbedtls_tls_openthread_keeps_only_what_it_uses( 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) + assert sdkconfig.get(name) is (None if name in _CCM_ECDSA_EXTRAS else False) + + +def test_mbedtls_tls_zigbee_keeps_only_what_it_uses( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + """The Zigbee config keeps CCM and deterministic ECDSA; the rest is trimmed.""" + generate_main(component_config_path("tls_zigbee_c6.yaml")) + sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] + assert tuple(sdkconfig.get(name) for name in _TLS_SERVER_OPTIONS) == (True, False) + for name in MBEDTLS_TLS_EXTRA_OPTIONS: + assert sdkconfig.get(name) is (None if name in _CCM_ECDSA_EXTRAS else False) def test_mbedtls_tls_user_sdkconfig_wins( @@ -1529,7 +1541,16 @@ def test_mbedtls_tls_openthread_requires_server_and_extras( """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 + assert CORE.data[KEY_ESP32][KEY_MBEDTLS_TLS_EXTRAS_REQUIRED] == _CCM_ECDSA_EXTRAS + + +def test_mbedtls_tls_zigbee_requires_extras( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + """The Zigbee hooks mark the CCM/deterministic ECDSA as required.""" + generate_main(component_config_path("tls_zigbee_c6.yaml")) + assert CORE.data[KEY_ESP32][KEY_MBEDTLS_TLS_EXTRAS_REQUIRED] == _CCM_ECDSA_EXTRAS _VASPRINTF_STUB_FLAGS = {"-Wl,--wrap=vasprintf", "-Wl,--undefined=__wrap_vasprintf"}