From 1ea146841fabf04ceef62aa5788924d23ce58c21 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Tue, 23 May 2023 23:58:48 +0530 Subject: [PATCH] [ESP32] Provision to use the ESP32H2 ECDSA Peripheral (#26655) * Provision to use the ESP32H2 secure element * Restyled by clang-format * Select the depedent options if soc supports ecdsa peripheral and dac are stored in secure cert * Update src/platform/ESP32/ESP32SecureCertDACProvider.cpp Co-authored-by: Shu Chen * Make the config option visible * use CONFIG_USE_ECDSA_PERIPHERAL config option than SOC_ECDSA_SUPPORTED * guard the code which is not required when using ecdsa peripheral --------- Co-authored-by: Restyled.io Co-authored-by: Shu Chen --- config/esp32/components/chip/CMakeLists.txt | 3 + config/esp32/components/chip/Kconfig | 13 ++ .../esp32/components/chip/idf_component.yml | 2 +- src/platform/ESP32/BUILD.gn | 8 + src/platform/ESP32/ESP32CHIPCryptoPAL.cpp | 147 ++++++++++++++++++ src/platform/ESP32/ESP32CHIPCryptoPAL.h | 43 +++++ .../ESP32/ESP32SecureCertDACProvider.cpp | 69 ++++++-- 7 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 src/platform/ESP32/ESP32CHIPCryptoPAL.cpp create mode 100644 src/platform/ESP32/ESP32CHIPCryptoPAL.h diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt index 6f30e30e297e34..bf9dfe5565c606 100644 --- a/config/esp32/components/chip/CMakeLists.txt +++ b/config/esp32/components/chip/CMakeLists.txt @@ -238,6 +238,9 @@ if (CONFIG_SEC_CERT_DAC_PROVIDER) chip_gn_arg_append("chip_use_secure_cert_dac_provider" "true") endif() +if (CONFIG_USE_ESP32_ECDSA_PERIPHERAL) + chip_gn_arg_append("chip_use_esp32_ecdsa_peripheral" "true") +endif() set(args_gn_input "${CMAKE_CURRENT_BINARY_DIR}/args.gn.in") file(GENERATE OUTPUT "${args_gn_input}" CONTENT "${chip_gn_args}") diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index dc3b03b07ac555..732f0533a3d708 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -700,6 +700,19 @@ menu "CHIP Device Layer" Use ESP32 Secure Cert DAC Provider which is ESP32 DeviceAttestationCredentialsProvider implementation which reads attestation information from the esp_secure_cert partition + config USE_ESP32_ECDSA_PERIPHERAL + bool "Use ESP32 ECDSA Peripheral" + depends on SEC_CERT_DAC_PROVIDER && SOC_ECDSA_SUPPORTED + default y + select MBEDTLS_HARDWARE_ECDSA_SIGN + select ENABLE_ESP32_FACTORY_DATA_PROVIDER + select ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER + help + If DAC is being read from secure cert and SOC supports ECDSA signing using on-chip peripheral + then this option gets enabled. This option also selects few more that are required for commissioning + the device. + Also, please disable ESP_SECURE_CERT_DS_PERIPHERAL from the menuconfig when this option is disabled + endmenu diff --git a/config/esp32/components/chip/idf_component.yml b/config/esp32/components/chip/idf_component.yml index 30d77e8b2eb7c9..b9ce7591b88dd6 100644 --- a/config/esp32/components/chip/idf_component.yml +++ b/config/esp32/components/chip/idf_component.yml @@ -7,6 +7,6 @@ dependencies: - if: "target != esp32h2" espressif/esp_secure_cert_mgr: - version: "^2.2.1" + version: "^2.3.0" rules: - if: "idf_version >=4.3" diff --git a/src/platform/ESP32/BUILD.gn b/src/platform/ESP32/BUILD.gn index 66cf6279dfc6f8..233ced72e3c6fe 100644 --- a/src/platform/ESP32/BUILD.gn +++ b/src/platform/ESP32/BUILD.gn @@ -29,6 +29,7 @@ declare_args() { chip_bt_bluedroid_enabled = false chip_enable_ble_controller = false chip_use_secure_cert_dac_provider = false + chip_use_esp32_ecdsa_peripheral = false } defines = [ @@ -167,5 +168,12 @@ static_library("ESP32") { ] } + if (chip_use_esp32_ecdsa_peripheral) { + sources += [ + "ESP32CHIPCryptoPAL.cpp", + "ESP32CHIPCryptoPAL.h", + ] + } + cflags = [ "-Wconversion" ] } diff --git a/src/platform/ESP32/ESP32CHIPCryptoPAL.cpp b/src/platform/ESP32/ESP32CHIPCryptoPAL.cpp new file mode 100644 index 00000000000000..8efc2e56d3c154 --- /dev/null +++ b/src/platform/ESP32/ESP32CHIPCryptoPAL.cpp @@ -0,0 +1,147 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// In mbedTLS 3.0.0 direct access to structure fields was replaced with using MBEDTLS_PRIVATE macro. +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) +#define CHIP_CRYPTO_PAL_PRIVATE(x) MBEDTLS_PRIVATE(x) +#else +#define CHIP_CRYPTO_PAL_PRIVATE(x) x +#endif + +#define MAX_ERROR_STR_LEN 128 + +namespace { + +static int CryptoRNG(void * ctxt, uint8_t * out_buffer, size_t out_length) +{ + return (chip::Crypto::DRBG_get_bytes(out_buffer, out_length) == CHIP_NO_ERROR) ? 0 : 1; +} + +static inline mbedtls_ecdsa_context * to_ecdsa_ctx(chip::Crypto::P256KeypairContext * context) +{ + return chip::SafePointerCast(context); +} + +static void _log_mbedTLS_error(int error_code) +{ + if (error_code != 0) + { +#if defined(MBEDTLS_ERROR_C) + char error_str[MAX_ERROR_STR_LEN]; + mbedtls_strerror(error_code, error_str, sizeof(error_str)); + ChipLogError(Crypto, "mbedTLS error: %s", error_str); +#else + // Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise + ChipLogError(Crypto, "mbedTLS error: -0x%04X", -static_cast(error_code)); +#endif + } +} + +} // anonymous namespace + +namespace chip { +namespace Crypto { + +CHIP_ERROR ESP32P256Keypair::Initialize(ECPKeyTarget keyTarget, int efuseBlock) +{ + Clear(); + + CHIP_ERROR error = CHIP_NO_ERROR; + + mbedtls_ecdsa_context * ecdsa_ctx = to_ecdsa_ctx(&mKeypair); + mbedtls_ecdsa_init(ecdsa_ctx); + + int status = mbedtls_ecp_group_load(&ecdsa_ctx->MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); + VerifyOrExit(status == 0, error = CHIP_ERROR_INTERNAL); + + status = esp_ecdsa_privkey_load_mpi(&ecdsa_ctx->MBEDTLS_PRIVATE(d), efuseBlock); + VerifyOrExit(status == 0, error = CHIP_ERROR_INTERNAL); + + mInitialized = true; + ecdsa_ctx = nullptr; + return error; + +exit: + if (ecdsa_ctx) + { + mbedtls_ecdsa_free(ecdsa_ctx); + ecdsa_ctx = nullptr; + } + _log_mbedTLS_error(status); + return error; +} + +CHIP_ERROR ESP32P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const +{ + VerifyOrReturnError(mInitialized, CHIP_ERROR_WELL_UNINITIALIZED); + VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t digest[kSHA256_Hash_Length]; + memset(&digest[0], 0, sizeof(digest)); + ReturnErrorOnFailure(Hash_SHA256(msg, msg_length, &digest[0])); + +#if defined(MBEDTLS_ECDSA_C) + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + mbedtls_mpi r, s; + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + mbedtls_ecdsa_context * ecdsa_ctx = to_ecdsa_ctx(&mKeypair); + + result = mbedtls_ecdsa_sign(&ecdsa_ctx->CHIP_CRYPTO_PAL_PRIVATE(grp), &r, &s, &ecdsa_ctx->CHIP_CRYPTO_PAL_PRIVATE(d), + Uint8::to_const_uchar(digest), sizeof(digest), CryptoRNG, nullptr); + + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit((mbedtls_mpi_size(&r) <= kP256_FE_Length) && (mbedtls_mpi_size(&s) <= kP256_FE_Length), + error = CHIP_ERROR_INTERNAL); + + // Concatenate r and s to output. Sizes were checked above. + result = mbedtls_mpi_write_binary(&r, out_signature.Bytes() + 0u, kP256_FE_Length); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + result = mbedtls_mpi_write_binary(&s, out_signature.Bytes() + kP256_FE_Length, kP256_FE_Length); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + + VerifyOrExit(out_signature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, error = CHIP_ERROR_INTERNAL); + +exit: + ecdsa_ctx = nullptr; + mbedtls_mpi_free(&s); + mbedtls_mpi_free(&r); + _log_mbedTLS_error(result); + return error; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +} // namespace Crypto +} // namespace chip diff --git a/src/platform/ESP32/ESP32CHIPCryptoPAL.h b/src/platform/ESP32/ESP32CHIPCryptoPAL.h new file mode 100644 index 00000000000000..e6a0b77a64ad38 --- /dev/null +++ b/src/platform/ESP32/ESP32CHIPCryptoPAL.h @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This files overrides few APIs from mbedTLS based implementation of CHIP crypto primitives + * for using ECDSA peripheral on ESP32 chips. + */ +#pragma once + +#include + +namespace chip { +namespace Crypto { + +class ESP32P256Keypair : public P256Keypair +{ +public: + /** + * @brief Initialize the keypair with efuse block key + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Initialize(ECPKeyTarget keyTarget, int efuseBlock); + + CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const override; +}; + +} // namespace Crypto +} // namespace chip diff --git a/src/platform/ESP32/ESP32SecureCertDACProvider.cpp b/src/platform/ESP32/ESP32SecureCertDACProvider.cpp index 7c45caf5202d33..d31eaf02dbcebf 100644 --- a/src/platform/ESP32/ESP32SecureCertDACProvider.cpp +++ b/src/platform/ESP32/ESP32SecureCertDACProvider.cpp @@ -23,6 +23,10 @@ #include #include +#if CONFIG_USE_ESP32_ECDSA_PERIPHERAL +#include +#endif // CONFIG_USE_ESP32_ECDSA_PERIPHERAL + #define TAG "dac_provider" #if CONFIG_SEC_CERT_DAC_PROVIDER @@ -111,20 +115,62 @@ CHIP_ERROR ESP32SecureCertDACProvider ::GetProductAttestationIntermediateCert(Mu CHIP_ERROR ESP32SecureCertDACProvider ::SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) { + esp_err_t esp_err; + esp_secure_cert_key_type_t keyType; + + CHIP_ERROR chipError; Crypto::P256ECDSASignature signature; - Crypto::P256Keypair keypair; - char * sc_keypair = NULL; - uint32_t sc_keypair_len = 0; VerifyOrReturnError(IsSpanUsable(outSignBuffer), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(IsSpanUsable(messageToSign), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); - esp_err_t err = esp_secure_cert_get_priv_key(&sc_keypair, &sc_keypair_len); - if (err == ESP_OK && sc_keypair != NULL && sc_keypair_len != 0) + esp_err = esp_secure_cert_get_priv_key_type(&keyType); + VerifyOrReturnError(esp_err == ESP_OK, CHIP_ERROR_INCORRECT_STATE, + ESP_LOGE(TAG, "Failed to get the type of private key from secure cert partition, esp_err:%d", esp_err)); + + VerifyOrReturnError(keyType != ESP_SECURE_CERT_INVALID_KEY, CHIP_ERROR_INCORRECT_STATE, + ESP_LOGE(TAG, "Private key type in secure cert partition is invalid")); + + // This flow is for devices supporting ECDSA peripheral + if (keyType == ESP_SECURE_CERT_ECDSA_PERIPHERAL_KEY) + { +#if CONFIG_USE_ESP32_ECDSA_PERIPHERAL + Crypto::ESP32P256Keypair keypair; + uint8_t efuseBlockId; + + esp_err = esp_secure_cert_get_priv_key_efuse_id(&efuseBlockId); + VerifyOrReturnError(esp_err == ESP_OK, CHIP_ERROR_INVALID_KEY_ID, + ESP_LOGE(TAG, "Failed to get the private key efuse block id, esp_err:%d", esp_err)); + + ESP_LOGD(TAG, "efuse block id:%u", efuseBlockId); + + chipError = keypair.Initialize(chip::Crypto::ECPKeyTarget::ECDSA, efuseBlockId); + VerifyOrReturnError(chipError == CHIP_NO_ERROR, chipError, + ESP_LOGE(TAG, "Failed to initialize the keypair err:%" CHIP_ERROR_FORMAT, chipError.Format())); + + chipError = keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature); + VerifyOrReturnError( + chipError == CHIP_NO_ERROR, chipError, + ESP_LOGE(TAG, "Failed to sign with device attestation key, err:%" CHIP_ERROR_FORMAT, chipError.Format())); +#else + return CHIP_ERROR_INCORRECT_STATE; +#endif // CONFIG_USE_ESP32_ECDSA_PERIPHERAL + } + else // This flow is for devices which do not support ECDSA peripheral { - ESP_FAULT_ASSERT(err == ESP_OK && sc_keypair != NULL && sc_keypair_len != 0); - CHIP_ERROR chipError = +#if !CONFIG_USE_ESP32_ECDSA_PERIPHERAL + Crypto::P256Keypair keypair; + char * sc_keypair = NULL; + uint32_t sc_keypair_len = 0; + + esp_err = esp_secure_cert_get_priv_key(&sc_keypair, &sc_keypair_len); + VerifyOrReturnError(esp_err == ESP_OK && sc_keypair != NULL && sc_keypair_len != 0, CHIP_ERROR_INCORRECT_STATE, + ESP_LOGE(TAG, "esp_secure_cert_get_priv_key failed esp_err:%d", esp_err)); + + ESP_FAULT_ASSERT(esp_err == ESP_OK && sc_keypair != NULL && sc_keypair_len != 0); + + chipError = LoadKeypairFromRaw(ByteSpan(reinterpret_cast(sc_keypair + kPrivKeyOffset), kDACPrivateKeySize), ByteSpan(reinterpret_cast(sc_keypair + kPubKeyOffset), kDACPublicKeySize), keypair); VerifyOrReturnError(chipError == CHIP_NO_ERROR, chipError, esp_secure_cert_free_priv_key(sc_keypair)); @@ -133,12 +179,11 @@ CHIP_ERROR ESP32SecureCertDACProvider ::SignWithDeviceAttestationKey(const ByteS VerifyOrReturnError(chipError == CHIP_NO_ERROR, chipError, esp_secure_cert_free_priv_key(sc_keypair)); esp_secure_cert_free_priv_key(sc_keypair); - chipError = CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); - return chipError; +#else + return CHIP_ERROR_INCORRECT_STATE; +#endif // !CONFIG_USE_ESP32_ECDSA_PERIPHERAL } - - ESP_LOGE(TAG, "esp_secure_cert_get_priv_key failed err:%d", err); - return CHIP_ERROR_INCORRECT_STATE; + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); } } // namespace DeviceLayer