Skip to content

Commit

Permalink
[ESP32] Provision to use the ESP32H2 ECDSA Peripheral (#26655) (#26780)
Browse files Browse the repository at this point in the history
* 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



* 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 <commits@restyled.io>
Co-authored-by: Shu Chen <chenshu@espressif.com>
  • Loading branch information
3 people committed May 24, 2023
1 parent 82db976 commit 20daa6d
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 13 deletions.
3 changes: 3 additions & 0 deletions config/esp32/components/chip/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
13 changes: 13 additions & 0 deletions config/esp32/components/chip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
2 changes: 1 addition & 1 deletion config/esp32/components/chip/idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
8 changes: 8 additions & 0 deletions src/platform/ESP32/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -167,5 +168,12 @@ static_library("ESP32") {
]
}

if (chip_use_esp32_ecdsa_peripheral) {
sources += [
"ESP32CHIPCryptoPAL.cpp",
"ESP32CHIPCryptoPAL.h",
]
}

cflags = [ "-Wconversion" ]
}
147 changes: 147 additions & 0 deletions src/platform/ESP32/ESP32CHIPCryptoPAL.cpp
Original file line number Diff line number Diff line change
@@ -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 <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPSafeCasts.h>
#include <platform/ESP32/ESP32CHIPCryptoPAL.h>

#include <ecdsa/ecdsa_alt.h>
#include <mbedtls/bignum.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/ecp.h>
#include <mbedtls/error.h>

// 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<mbedtls_ecdsa_context *>(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<uint16_t>(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
43 changes: 43 additions & 0 deletions src/platform/ESP32/ESP32CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
@@ -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 <crypto/CHIPCryptoPAL.h>

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
69 changes: 57 additions & 12 deletions src/platform/ESP32/ESP32SecureCertDACProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#include <platform/ESP32/ESP32Config.h>
#include <platform/ESP32/ESP32SecureCertDACProvider.h>

#if CONFIG_USE_ESP32_ECDSA_PERIPHERAL
#include <platform/ESP32/ESP32CHIPCryptoPAL.h>
#endif // CONFIG_USE_ESP32_ECDSA_PERIPHERAL

#define TAG "dac_provider"

#if CONFIG_SEC_CERT_DAC_PROVIDER
Expand Down Expand Up @@ -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<const uint8_t *>(sc_keypair + kPrivKeyOffset), kDACPrivateKeySize),
ByteSpan(reinterpret_cast<const uint8_t *>(sc_keypair + kPubKeyOffset), kDACPublicKeySize), keypair);
VerifyOrReturnError(chipError == CHIP_NO_ERROR, chipError, esp_secure_cert_free_priv_key(sc_keypair));
Expand All @@ -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
Expand Down

0 comments on commit 20daa6d

Please sign in to comment.