From 629234de82d658309d7f99c63677a5f616b706b9 Mon Sep 17 00:00:00 2001 From: Ricardo Casallas <77841255+rcasallas-silabs@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:41:27 -0500 Subject: [PATCH] Default Crypto PAL PSA copied into EFR32 with optimizations. (#157) --- .../silabs/efr32/CHIPCryptoPALPsaEfr32.cpp | 1655 +++-------------- 1 file changed, 218 insertions(+), 1437 deletions(-) diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index 76c3523d96..cef956681a 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2022-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. @@ -18,137 +18,36 @@ /** * @file * PSA Crypto API based implementation of CHIP crypto primitives - * with Silicon Labs SDK modifications */ -// The psa_driver_wrappers.h file that we're including here assumes that it has -// access to private struct members. Define this here in order to avoid -// compilation errors. -#define MBEDTLS_ALLOW_PRIVATE_ACCESS -#include #include +#include -#include - -// Include version header to get configuration information -#include - -#if !defined(MBEDTLS_PSA_CRYPTO_C) -#error "This implementation needs PSA Crypto" -#endif - -#if !defined(MBEDTLS_USE_PSA_CRYPTO) -#error "This implementation requires that PSA Crypto keys can be used for CSR generation" -#endif - -#include "psa/crypto.h" - -// Includes needed for SPAKE2+ ECP operations -#include -#include - -// Includes needed for certificate parsing -#if defined(MBEDTLS_X509_CRT_PARSE_C) -#include -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) -#include -#include -#include - -#if defined(MBEDTLS_ERROR_C) -#include -#endif // defined(MBEDTLS_ERROR_C) - +#include #include #include #include #include -#include #include #include #include #include +#include + +#include +#include +#include +#include + #include +#include namespace chip { namespace Crypto { -using chip::Platform::MemoryCalloc; -using chip::Platform::MemoryFree; - -#define MAX_ERROR_STR_LEN 128 -#define NUM_BYTES_IN_SHA256_HASH 32 - -// 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 - -#if (MBEDTLS_VERSION_NUMBER >= 0x03000000 && MBEDTLS_VERSION_NUMBER < 0x03010000) -#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) MBEDTLS_PRIVATE(x) -#else -#define CHIP_CRYPTO_PAL_PRIVATE_X509(x) x -#endif - namespace { -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 - } -} - -void _log_PSA_error(psa_status_t status) -{ - if (status != 0) - { - // Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise - ChipLogError(Crypto, "PSA error: %ld", status); - } -} - -/** - * @brief Compare two times - * - * @param t1 First time to compare - * @param t2 Second time to compare - * @return int 0 If both times are idential to the second, -1 if t1 < t2, 1 if t1 > t2. - */ -int TimeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) -{ - VerifyOrReturnValue(t1->year >= t2->year, -1); - VerifyOrReturnValue(t1->year <= t2->year, 1); - // Same year - VerifyOrReturnValue(t1->mon >= t2->mon, -1); - VerifyOrReturnValue(t1->mon <= t2->mon, 1); - // Same month - VerifyOrReturnValue(t1->day >= t2->day, -1); - VerifyOrReturnValue(t1->day <= t2->day, 1); - // Same day - VerifyOrReturnValue(t1->hour >= t2->hour, -1); - VerifyOrReturnValue(t1->hour <= t2->hour, 1); - // Same hour - VerifyOrReturnValue(t1->min >= t2->min, -1); - VerifyOrReturnValue(t1->min <= t2->min, 1); - // Same minute - VerifyOrReturnValue(t1->sec >= t2->sec, -1); - VerifyOrReturnValue(t1->sec <= t2->sec, 1); - // Same second - return 0; -} - bool IsBufferNonEmpty(const uint8_t * data, size_t data_length) { return data != nullptr && data_length > 0; @@ -185,8 +84,15 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c status = psa_aead_set_nonce(&operation, nonce, nonce_length); VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_aead_update_ad(&operation, aad, aad_length); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + if (aad_length != 0) + { + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + else + { + ChipLogDetail(Crypto, "AES_CCM_encrypt: Using aad == null path"); + } if (plaintext_length != 0) { @@ -264,170 +170,202 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) { - size_t output_length = 0; - - psa_crypto_init(); + size_t outLength = 0; - const psa_status_t result = - psa_hash_compute(PSA_ALG_SHA_256, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &output_length); + const psa_status_t status = + psa_hash_compute(PSA_ALG_SHA_256, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &outLength); - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; + return status == PSA_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR Hash_SHA1(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) { - size_t output_length = 0; + size_t outLength = 0; - psa_crypto_init(); + const psa_status_t status = + psa_hash_compute(PSA_ALG_SHA_1, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_1), &outLength); - const psa_status_t result = - psa_hash_compute(PSA_ALG_SHA_1, data, data_length, out_buffer, PSA_HASH_LENGTH(PSA_ALG_SHA_1), &output_length); - - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_1), CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; + return status == PSA_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(psa_hash_operation_t), - "kMAX_Hash_SHA256_Context_Size is too small for the size of underlying psa_hash_operation_t"); - -static inline psa_hash_operation_t * to_inner_hash_sha256_context(HashSHA256OpaqueContext * context) +static inline psa_hash_operation_t * toHashOperation(HashSHA256OpaqueContext * context) { return SafePointerCast(context); } -Hash_SHA256_stream::Hash_SHA256_stream(void) +static inline psa_hash_operation_t & toHashOperation(HashSHA256OpaqueContext & context) { - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - const psa_hash_operation_t initial_context = PSA_HASH_OPERATION_INIT; - memcpy(context, &initial_context, sizeof(psa_hash_operation_t)); + return *SafePointerCast(&context); } -Hash_SHA256_stream::~Hash_SHA256_stream(void) +Hash_SHA256_stream::Hash_SHA256_stream() { - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - psa_hash_abort(context); - Clear(); + toHashOperation(mContext) = PSA_HASH_OPERATION_INIT; } -CHIP_ERROR Hash_SHA256_stream::Begin(void) +Hash_SHA256_stream::~Hash_SHA256_stream() { - psa_crypto_init(); - - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - *context = PSA_HASH_OPERATION_INIT; - const psa_status_t result = psa_hash_setup(context, PSA_ALG_SHA_256); + Clear(); +} - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); +CHIP_ERROR Hash_SHA256_stream::Begin() +{ + toHashOperation(mContext) = PSA_HASH_OPERATION_INIT; + const psa_status_t status = psa_hash_setup(toHashOperation(&mContext), PSA_ALG_SHA_256); - return CHIP_NO_ERROR; + return status == PSA_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR Hash_SHA256_stream::AddData(const ByteSpan data) { - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - const psa_status_t result = psa_hash_update(context, Uint8::to_const_uchar(data.data()), data.size()); + const psa_status_t status = psa_hash_update(toHashOperation(&mContext), data.data(), data.size()); - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; + return status == PSA_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } CHIP_ERROR Hash_SHA256_stream::GetDigest(MutableByteSpan & out_buffer) { - CHIP_ERROR result = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - size_t output_length = 0; - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); + VerifyOrReturnError(out_buffer.size() >= PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_BUFFER_TOO_SMALL); - VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); - - // Clone the context first since calculating the digest finishes the operation - psa_hash_operation_t digest_context = PSA_HASH_OPERATION_INIT; - status = psa_hash_clone(context, &digest_context); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + size_t outLength; - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + status = psa_hash_clone(toHashOperation(&mContext), &operation); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - // Calculate digest on the cloned context - status = psa_hash_finish(&digest_context, Uint8::to_uchar(out_buffer.data()), out_buffer.size(), &output_length); + status = psa_hash_finish(&operation, out_buffer.data(), out_buffer.size(), &outLength); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + out_buffer.reduce_size(outLength); - VerifyOrExit(status == PSA_SUCCESS, result = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), result = CHIP_ERROR_INTERNAL); exit: - psa_hash_abort(&digest_context); - return result; + psa_hash_abort(&operation); + + return error; } CHIP_ERROR Hash_SHA256_stream::Finish(MutableByteSpan & out_buffer) { - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - size_t output_length = 0; + VerifyOrReturnError(out_buffer.size() >= PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_BUFFER_TOO_SMALL); - VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); - const psa_status_t status = psa_hash_finish(context, Uint8::to_uchar(out_buffer.data()), out_buffer.size(), &output_length); + size_t outLength; + const psa_status_t status = psa_hash_finish(toHashOperation(&mContext), out_buffer.data(), out_buffer.size(), &outLength); VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INTERNAL); + out_buffer.reduce_size(outLength); return CHIP_NO_ERROR; } -void Hash_SHA256_stream::Clear(void) +void Hash_SHA256_stream::Clear() { - psa_hash_operation_t * context = to_inner_hash_sha256_context(&mContext); - psa_hash_abort(context); + psa_hash_abort(toHashOperation(&mContext)); } -CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, - const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) +CHIP_ERROR FindFreeKeySlotInRange(psa_key_id_t & keyId, psa_key_id_t start, uint32_t range) { - VerifyOrReturnError(secret != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(secret_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t end = start + range; + + VerifyOrReturnError(start >= PSA_KEY_ID_USER_MIN && end - 1 <= PSA_KEY_ID_USER_MAX, CHIP_ERROR_INVALID_ARGUMENT); - // Salt is optional - if (salt_length > 0) + for (keyId = start; keyId < end; keyId++) { - VerifyOrReturnError(salt != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + psa_status_t status = psa_get_key_attributes(keyId, &attributes); + if (status == PSA_ERROR_INVALID_HANDLE) + { + return CHIP_NO_ERROR; + } + else if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } } + return CHIP_ERROR_NOT_FOUND; +} - VerifyOrReturnError(info_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(info != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); +CHIP_ERROR PsaKdf::Init(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); + psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); + + status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); + LogPsaError(status); + psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - psa_crypto_init(); + return InitOperation(mSecretKeyId, salt, info); +} - status = psa_key_derivation_setup(&operation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); +CHIP_ERROR PsaKdf::Init(const HkdfKeyHandle & hkdfKey, const ByteSpan & salt, const ByteSpan & info) +{ + return InitOperation(hkdfKey.As(), salt, info); +} - if (salt_length > 0) +CHIP_ERROR PsaKdf::InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info) +{ + psa_status_t status = psa_key_derivation_setup(&mOperation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + if (salt.size() > 0) { - status = - psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, Uint8::to_const_uchar(salt), salt_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); } - status = - psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SECRET, Uint8::to_const_uchar(secret), secret_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, hkdfKey); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO, Uint8::to_const_uchar(info), info_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_key_derivation_output_bytes(&operation, out_buffer, out_length); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); -exit: - psa_key_derivation_abort(&operation); + return CHIP_NO_ERROR; +} - return error; +void LogPsaError(psa_status_t status) +{ + if (status != PSA_SUCCESS) + { + ChipLogError(Crypto, "PSA error: %d", static_cast(status)); + } +} + +CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) +{ + psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); + LogPsaError(status); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) +{ + psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); + LogPsaError(status); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, + const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) +{ + VerifyOrReturnError(IsBufferNonEmpty(secret, secret_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(info, info_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(out_buffer, out_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(salt != nullptr || salt_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + + PsaKdf kdf; + + ReturnErrorOnFailure(kdf.Init(ByteSpan(secret, secret_length), ByteSpan(salt, salt_length), ByteSpan(info, info_length))); + + return kdf.DeriveBytes(MutableByteSpan(out_buffer, out_length)); } CHIP_ERROR HMAC_sha::HMAC_SHA256(const uint8_t * key, size_t key_length, const uint8_t * message, size_t message_length, @@ -476,10 +414,10 @@ CHIP_ERROR HMAC_sha::HMAC_SHA256(const Hmac128KeyHandle & key, const uint8_t * m return CHIP_NO_ERROR; } -CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t pass_length, const uint8_t * salt, size_t salt_length, +CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * pass, size_t pass_length, const uint8_t * salt, size_t salt_length, unsigned int iteration_count, uint32_t key_length, uint8_t * key) { - VerifyOrReturnError(IsBufferNonEmpty(password, pass_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(pass, pass_length), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(salt_length >= kSpake2p_Min_PBKDF_Salt_Length && salt_length <= kSpake2p_Max_PBKDF_Salt_Length, CHIP_ERROR_INVALID_ARGUMENT); @@ -497,7 +435,7 @@ CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t pass_le status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, iteration_count); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, password, pass_length); + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, pass, pass_length); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); status = psa_key_derivation_output_bytes(&operation, key, key_length); @@ -509,46 +447,25 @@ CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t pass_le return error; } -CHIP_ERROR add_entropy_source(entropy_source fn_source, void * p_source, size_t threshold) +CHIP_ERROR add_entropy_source(entropy_source /* fn_source */, void * /* p_source */, size_t /* threshold */) { - // PSA Crypto has its own entropy and doesn't support an override mechanism - (void) fn_source; - (void) p_source; - (void) threshold; - - return CHIP_NO_ERROR; + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } CHIP_ERROR DRBG_get_bytes(uint8_t * out_buffer, const size_t out_length) { - VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_length > 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(out_buffer, out_length), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); - const psa_status_t result = psa_generate_random(Uint8::to_uchar(out_buffer), out_length); - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + const psa_status_t status = psa_generate_random(out_buffer, out_length); - return CHIP_NO_ERROR; + return status == PSA_SUCCESS ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; } -// CryptoRNG's definition is needed to use the mbedTLS-backed SPAKE2+ and certificate operations 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; } -// Mapping function is used as part of the certificate operations -mbedtls_ecp_group_id MapECPGroupId(SupportedECPKeyTypes keyType) -{ - switch (keyType) - { - case SupportedECPKeyTypes::ECP256R1: - return MBEDTLS_ECP_DP_SECP256R1; - default: - return MBEDTLS_ECP_DP_NONE; - } -} - /******************************************************************************* * * WARNING: The default (base) implementation of P256Keypair is UNSAFE! @@ -572,22 +489,6 @@ mbedtls_ecp_group_id MapECPGroupId(SupportedECPKeyTypes keyType) * ******************************************************************************/ -typedef struct -{ - uint8_t privkey[32]; - size_t bitlen; -} psa_plaintext_ecp_keypair; - -static inline psa_plaintext_ecp_keypair * to_keypair(P256KeypairContext * context) -{ - return SafePointerCast(context); -} - -static inline const psa_plaintext_ecp_keypair * to_const_keypair(const P256KeypairContext * context) -{ - return SafePointerCast(context); -} - CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const { VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); @@ -669,44 +570,22 @@ CHIP_ERROR P256PublicKey::ECDSA_validate_hash_signature(const uint8_t * hash, co CHIP_ERROR P256Keypair::ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const { - // Todo: replace with driver call once key derivation through the driver wrapper has been figured out - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - mbedtls_svc_key_id_t key_id = 0; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); - - VerifyOrExit(mInitialized, error = CHIP_ERROR_UNINITIALIZED); - - // Step 1: import plaintext key as volatile for ECDH - psa_crypto_init(); - - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, keypair->bitlen); - psa_set_key_algorithm(&attr, PSA_ALG_ECDH); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE); - - status = psa_import_key(&attr, keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen), &key_id); - - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); - // Step 2: do key derivation - status = psa_raw_key_agreement(PSA_ALG_ECDH, key_id, Uint8::to_const_uchar(remote_public_key), remote_public_key.Length(), - out_secret.Bytes(), (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(), - &output_length); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); + const size_t outputSize = (out_secret.Length() == 0) ? out_secret.Capacity() : out_secret.Length(); + size_t outputLength; + status = psa_raw_key_agreement(PSA_ALG_ECDH, context.key_id, remote_public_key.ConstBytes(), remote_public_key.Length(), + out_secret.Bytes(), outputSize, &outputLength); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - SuccessOrExit(error = out_secret.SetLength(output_length)); + SuccessOrExit(error = out_secret.SetLength(outputLength)); exit: - _log_PSA_error(status); - // Step 3: destroy imported key - psa_reset_key_attributes(&attr); - if (key_id != 0) - { - psa_destroy_key(key_id); - } + LogPsaError(status); + return error; } @@ -788,38 +667,48 @@ CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) CHIP_ERROR P256Keypair::Serialize(P256SerializedKeypair & output) const { - CHIP_ERROR error = CHIP_NO_ERROR; - const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); - size_t len = output.Length() == 0 ? output.Capacity() : output.Length(); - Encoding::BufferWriter bbuf(output.Bytes(), len); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); + const size_t outputSize = output.Length() == 0 ? output.Capacity() : output.Length(); + Encoding::BufferWriter bbuf(output.Bytes(), outputSize); + uint8_t privateKey[kP256_PrivateKey_Length]; + size_t privateKeyLength = 0; - VerifyOrExit(mInitialized, error = CHIP_ERROR_UNINITIALIZED); + status = psa_export_key(context.key_id, privateKey, sizeof(privateKey), &privateKeyLength); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(privateKeyLength == kP256_PrivateKey_Length, error = CHIP_ERROR_INTERNAL); bbuf.Put(mPublicKey, mPublicKey.Length()); - - VerifyOrExit(bbuf.Available() == sizeof(keypair->privkey), error = CHIP_ERROR_INTERNAL); - - bbuf.Put(keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen)); + bbuf.Put(privateKey, privateKeyLength); VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - - output.SetLength(bbuf.Needed()); + error = output.SetLength(bbuf.Needed()); exit: + LogPsaError(status); + return error; } CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); - Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); + VerifyOrReturnError(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(input.Length() == mPublicKey.Length() + kP256_PrivateKey_Length, error = CHIP_ERROR_INVALID_ARGUMENT); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + PsaP256KeypairContext & context = ToPsaContext(mKeypair); + Encoding::BufferWriter bbuf(mPublicKey, mPublicKey.Length()); Clear(); - memcpy(keypair->privkey, input.ConstBytes() + mPublicKey.Length(), kP256_PrivateKey_Length); - keypair->bitlen = 256; + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE); + + status = psa_import_key(&attributes, input.ConstBytes() + mPublicKey.Length(), kP256_PrivateKey_Length, &context.key_id); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); bbuf.Put(input.ConstBytes(), mPublicKey.Length()); VerifyOrExit(bbuf.Fit(), error = CHIP_ERROR_NO_MEMORY); @@ -827,6 +716,8 @@ CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) mInitialized = true; exit: + LogPsaError(status); + return error; } @@ -834,8 +725,9 @@ void P256Keypair::Clear() { if (mInitialized) { - psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); - memset(keypair, 0, sizeof(psa_plaintext_ecp_keypair)); + PsaP256KeypairContext & context = ToPsaContext(mKeypair); + psa_destroy_key(context.key_id); + memset(&context, 0, sizeof(context)); mInitialized = false; } } @@ -847,71 +739,14 @@ P256Keypair::~P256Keypair() CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const { - MutableByteSpan csr(out_csr, csr_length); - CHIP_ERROR err = GenerateCertificateSigningRequest(this, csr); - csr_length = (CHIP_NO_ERROR == err) ? csr.size() : 0; - return err; -} - -CHIP_ERROR VerifyCertificateSigningRequest(const uint8_t * csr_buf, size_t csr_length, P256PublicKey & pubkey) -{ -#if defined(MBEDTLS_X509_CSR_PARSE_C) - ReturnErrorOnFailure(VerifyCertificateSigningRequestFormat(csr_buf, csr_length)); - - // TODO: For some embedded targets, mbedTLS library doesn't have mbedtls_x509_csr_parse_der, and mbedtls_x509_csr_parse_free. - // Taking a step back, embedded targets likely will not process CSR requests. Adding this action item to reevaluate - // this if there's a need for this processing for embedded targets. - CHIP_ERROR error = CHIP_NO_ERROR; - size_t pubkey_size = 0; - - mbedtls_ecp_keypair * keypair = nullptr; - - P256ECDSASignature signature; - MutableByteSpan out_raw_sig_span(signature.Bytes(), signature.Capacity()); - - mbedtls_x509_csr csr; - mbedtls_x509_csr_init(&csr); - - int result = mbedtls_x509_csr_parse_der(&csr, csr_buf, csr_length); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - // Verify the signature algorithm and public key type - VerifyOrExit(csr.CHIP_CRYPTO_PAL_PRIVATE(sig_md) == MBEDTLS_MD_SHA256, error = CHIP_ERROR_UNSUPPORTED_SIGNATURE_TYPE); - VerifyOrExit(csr.CHIP_CRYPTO_PAL_PRIVATE(sig_pk) == MBEDTLS_PK_ECDSA, error = CHIP_ERROR_WRONG_KEY_TYPE); - - keypair = mbedtls_pk_ec(csr.CHIP_CRYPTO_PAL_PRIVATE_X509(pk)); - - // Copy the public key from the CSR - result = mbedtls_ecp_point_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q), - MBEDTLS_ECP_PF_UNCOMPRESSED, &pubkey_size, Uint8::to_uchar(pubkey), pubkey.Length()); - - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(pubkey_size == pubkey.Length(), error = CHIP_ERROR_INTERNAL); - - // Convert DER signature to raw signature - error = EcdsaAsn1SignatureToRaw(kP256_FE_Length, - ByteSpan{ csr.CHIP_CRYPTO_PAL_PRIVATE(sig).CHIP_CRYPTO_PAL_PRIVATE_X509(p), - csr.CHIP_CRYPTO_PAL_PRIVATE(sig).CHIP_CRYPTO_PAL_PRIVATE_X509(len) }, - out_raw_sig_span); - - VerifyOrExit(error == CHIP_NO_ERROR, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(out_raw_sig_span.size() == (kP256_FE_Length * 2), error = CHIP_ERROR_INTERNAL); - signature.SetLength(out_raw_sig_span.size()); - - // Verify the signature using the public key - error = pubkey.ECDSA_validate_msg_signature(csr.CHIP_CRYPTO_PAL_PRIVATE_X509(cri).CHIP_CRYPTO_PAL_PRIVATE_X509(p), - csr.CHIP_CRYPTO_PAL_PRIVATE_X509(cri).CHIP_CRYPTO_PAL_PRIVATE_X509(len), signature); + VerifyOrReturnError(IsBufferNonEmpty(out_csr, csr_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); - SuccessOrExit(error); + MutableByteSpan csr(out_csr, csr_length); + ReturnErrorOnFailure(GenerateCertificateSigningRequest(this, csr)); + csr_length = csr.size(); -exit: - mbedtls_x509_csr_free(&csr); - _log_mbedTLS_error(result); - return error; -#else - ChipLogError(Crypto, "MBEDTLS_X509_CSR_PARSE_C is not enabled. CSR cannot be parsed"); - return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; -#endif + return CHIP_NO_ERROR; } typedef struct Spake2p_Context @@ -991,7 +826,6 @@ void Spake2p_P256_SHA256_HKDF_HMAC::Clear() VerifyOrReturn(state != CHIP_SPAKE2P_STATE::PREINIT); Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); - mbedtls_ecp_point_free(&context->M); mbedtls_ecp_point_free(&context->N); mbedtls_ecp_point_free(&context->X); @@ -1006,7 +840,6 @@ void Spake2p_P256_SHA256_HKDF_HMAC::Clear() mbedtls_mpi_free(&context->tempbn); mbedtls_ecp_group_free(&context->curve); - state = CHIP_SPAKE2P_STATE::PREINIT; } @@ -1341,44 +1174,39 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointCofactorMul(void * R) CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeL(uint8_t * Lout, size_t * L_len, const uint8_t * w1in, size_t w1in_len) { - CHIP_ERROR error = CHIP_NO_ERROR; - int result = 0; - Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + mbedtls_ecp_group curve; mbedtls_mpi w1_bn; mbedtls_ecp_point Ltemp; + mbedtls_ecp_group_init(&curve); mbedtls_mpi_init(&w1_bn); mbedtls_ecp_point_init(&Ltemp); + result = mbedtls_ecp_group_load(&curve, MBEDTLS_ECP_DP_SECP256R1); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + result = mbedtls_mpi_read_binary(&w1_bn, Uint8::to_const_uchar(w1in), w1in_len); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - result = mbedtls_mpi_mod_mpi(&w1_bn, &w1_bn, &context->curve.N); + result = mbedtls_mpi_mod_mpi(&w1_bn, &w1_bn, &curve.N); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); -#if defined(SEMAILBOX_PRESENT) - // Do the point multiplication using hardware acceleration via ECDH primitive - error = PointMul(&Ltemp, &context->curve.G, &w1_bn); - if (error != CHIP_NO_ERROR) - { - goto exit; - } -#else /* SEMAILBOX_PRESENT */ - result = mbedtls_ecp_mul(&context->curve, &Ltemp, &w1_bn, &context->curve.G, CryptoRNG, nullptr); + result = mbedtls_ecp_mul(&curve, &Ltemp, &w1_bn, &curve.G, CryptoRNG, nullptr); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); -#endif /* SEMAILBOX_PRESENT */ memset(Lout, 0, *L_len); - result = - mbedtls_ecp_point_write_binary(&context->curve, &Ltemp, MBEDTLS_ECP_PF_UNCOMPRESSED, L_len, Uint8::to_uchar(Lout), *L_len); + result = mbedtls_ecp_point_write_binary(&curve, &Ltemp, MBEDTLS_ECP_PF_UNCOMPRESSED, L_len, Uint8::to_uchar(Lout), *L_len); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); exit: _log_mbedTLS_error(result); mbedtls_ecp_point_free(&Ltemp); mbedtls_mpi_free(&w1_bn); + mbedtls_ecp_group_free(&curve); return error; } @@ -1395,1052 +1223,5 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointIsValid(void * R) return CHIP_NO_ERROR; } -constexpr uint8_t sOID_AttributeType_CommonName[] = { 0x55, 0x04, 0x03 }; -constexpr uint8_t sOID_AttributeType_MatterVendorId[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x01 }; -constexpr uint8_t sOID_AttributeType_MatterProductId[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x02 }; -constexpr uint8_t sOID_SigAlgo_ECDSAWithSHA256[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }; -constexpr uint8_t sOID_Extension_BasicConstraints[] = { 0x55, 0x1D, 0x13 }; -constexpr uint8_t sOID_Extension_KeyUsage[] = { 0x55, 0x1D, 0x0F }; -constexpr uint8_t sOID_Extension_SubjectKeyIdentifier[] = { 0x55, 0x1D, 0x0E }; -constexpr uint8_t sOID_Extension_AuthorityKeyIdentifier[] = { 0x55, 0x1D, 0x23 }; -constexpr uint8_t sOID_Extension_CRLDistributionPoint[] = { 0x55, 0x1D, 0x1F }; - -/** - * Compares an mbedtls_asn1_buf structure (oidBuf) to a reference OID represented as uint8_t array (oid). - */ -#define OID_CMP(oid, oidBuf) \ - ((MBEDTLS_ASN1_OID == (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(tag)) && \ - (sizeof(oid) == (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(len)) && \ - (memcmp((oid), (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(p), (oidBuf).CHIP_CRYPTO_PAL_PRIVATE_X509(len)) == 0)) - -CHIP_ERROR VerifyAttestationCertificateFormat(const ByteSpan & cert, AttestationCertType certType) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - int result = 0; - mbedtls_x509_crt mbed_cert; - unsigned char * p = nullptr; - const unsigned char * end = nullptr; - size_t len = 0; - bool extBasicPresent = false; - bool extKeyUsagePresent = false; - - VerifyOrReturnError(!cert.empty(), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbed_cert); - - result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(cert.data()), cert.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - // "version" value is 1 higher than the actual encoded value. - VerifyOrExit(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(version) - 1 == 2, error = CHIP_ERROR_INTERNAL); - - // Verify signature algorithms is ECDSA with SHA256. - VerifyOrExit(OID_CMP(sOID_SigAlgo_ECDSAWithSHA256, mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(sig_oid)), - error = CHIP_ERROR_INTERNAL); - - // Verify public key presence and format. - { - Crypto::P256PublicKey pubkey; - SuccessOrExit(error = ExtractPubkeyFromX509Cert(cert, pubkey)); - } - - p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - end = p + mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - while (p < end) - { - mbedtls_x509_buf extOID = { 0, 0, nullptr }; - int extCritical = 0; - - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - /* Get extension ID */ - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(tag) = MBEDTLS_ASN1_OID; - extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(len) = len; - extOID.CHIP_CRYPTO_PAL_PRIVATE_X509(p) = p; - p += len; - - /* Get optional critical */ - result = mbedtls_asn1_get_bool(&p, end, &extCritical); - VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_INTERNAL); - - /* Data should be octet string type */ - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - if (OID_CMP(sOID_Extension_BasicConstraints, extOID)) - { - int isCA = 0; - int pathLen = -1; - - VerifyOrExit(extCritical, error = CHIP_ERROR_INTERNAL); - extBasicPresent = true; - - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - if (len > 0) - { - unsigned char * seqStart = p; - result = mbedtls_asn1_get_bool(&p, end, &isCA); - VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_INTERNAL); - - // Check if pathLen is there by validating if the cursor didn't get to the end of - // of the internal SEQUENCE for the basic constraints encapsulation. - // Missing pathLen optional tag will leave pathLen == -1 for following checks. - bool hasPathLen = (p != (seqStart + len)); - if (hasPathLen) - { - // Extract pathLen value, making sure it's a valid format. - result = mbedtls_asn1_get_int(&p, end, &pathLen); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - } - } - - if (certType == AttestationCertType::kDAC) - { - VerifyOrExit(!isCA && pathLen == -1, error = CHIP_ERROR_INTERNAL); - } - else if (certType == AttestationCertType::kPAI) - { - VerifyOrExit(isCA && pathLen == 0, error = CHIP_ERROR_INTERNAL); - } - else - { - // For PAA, pathlen must be absent or equal to 1 (see Matter 1.1 spec 6.2.2.5) - VerifyOrExit(isCA && (pathLen == -1 || pathLen == 1), error = CHIP_ERROR_INTERNAL); - } - } - else if (OID_CMP(sOID_Extension_KeyUsage, extOID)) - { - mbedtls_x509_bitstring bs = { 0, 0, nullptr }; - unsigned int keyUsage = 0; - - VerifyOrExit(extCritical, error = CHIP_ERROR_INTERNAL); - extKeyUsagePresent = true; - - result = mbedtls_asn1_get_bitstring(&p, p + len, &bs); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - for (size_t i = 0; i < bs.CHIP_CRYPTO_PAL_PRIVATE_X509(len) && i < sizeof(unsigned int); i++) - { - keyUsage |= static_cast(bs.CHIP_CRYPTO_PAL_PRIVATE_X509(p)[i]) << (8 * i); - } - - if (certType == AttestationCertType::kDAC) - { - // SHALL only have the digitalSignature bit set. - VerifyOrExit(keyUsage == MBEDTLS_X509_KU_DIGITAL_SIGNATURE, error = CHIP_ERROR_INTERNAL); - } - else - { - bool keyCertSignFlag = keyUsage & MBEDTLS_X509_KU_KEY_CERT_SIGN; - bool crlSignFlag = keyUsage & MBEDTLS_X509_KU_CRL_SIGN; - bool otherFlags = - keyUsage & ~(MBEDTLS_X509_KU_CRL_SIGN | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_DIGITAL_SIGNATURE); - VerifyOrExit(keyCertSignFlag && crlSignFlag && !otherFlags, error = CHIP_ERROR_INTERNAL); - } - } - else - { - p += len; - } - } - - // Verify basic and key usage extensions are present. - VerifyOrExit(extBasicPresent && extKeyUsagePresent, error = CHIP_ERROR_INTERNAL); - - // Verify that SKID and AKID extensions are present. - { - uint8_t kidBuf[kSubjectKeyIdentifierLength]; - MutableByteSpan kid(kidBuf); - SuccessOrExit(error = ExtractSKIDFromX509Cert(cert, kid)); - if (certType == AttestationCertType::kDAC || certType == AttestationCertType::kPAI) - { - // Mandatory extension for DAC and PAI certs. - SuccessOrExit(error = ExtractAKIDFromX509Cert(cert, kid)); - } - } - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) cert; - (void) certType; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate, - size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen, - CertificateChainValidationResult & result) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - mbedtls_x509_crt certChain; - mbedtls_x509_crt rootCert; - mbedtls_x509_time leaf_valid_from; - mbedtls_x509_crt * cert = NULL; - int mbedResult; - uint32_t flags; - int compare_from = 0; - int compare_until = 0; - - result = CertificateChainValidationResult::kInternalFrameworkError; - - VerifyOrReturnError(rootCertificate != nullptr && rootCertificateLen != 0, - (result = CertificateChainValidationResult::kRootArgumentInvalid, CHIP_ERROR_INVALID_ARGUMENT)); - VerifyOrReturnError(leafCertificate != nullptr && leafCertificateLen != 0, - (result = CertificateChainValidationResult::kLeafArgumentInvalid, CHIP_ERROR_INVALID_ARGUMENT)); - - mbedtls_x509_crt_init(&certChain); - mbedtls_x509_crt_init(&rootCert); - - /* Start of chain */ - mbedResult = mbedtls_x509_crt_parse(&certChain, Uint8::to_const_uchar(leafCertificate), leafCertificateLen); - VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kLeafFormatInvalid, error = CHIP_ERROR_INTERNAL)); - leaf_valid_from = certChain.valid_from; - - /* Add the intermediate to the chain, if present */ - if (caCertificate != nullptr && caCertificateLen > 0) - { - mbedResult = mbedtls_x509_crt_parse(&certChain, Uint8::to_const_uchar(caCertificate), caCertificateLen); - VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kICAFormatInvalid, error = CHIP_ERROR_INTERNAL)); - } - - /* Parse the root cert */ - mbedResult = mbedtls_x509_crt_parse(&rootCert, Uint8::to_const_uchar(rootCertificate), rootCertificateLen); - VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kRootFormatInvalid, error = CHIP_ERROR_INTERNAL)); - - /* Validates that intermediate and root certificates are valid at the time of the leaf certificate's start time. */ - compare_from = TimeCompare(&leaf_valid_from, &rootCert.valid_from); - compare_until = TimeCompare(&leaf_valid_from, &rootCert.valid_to); - VerifyOrExit((compare_from >= 0) && (compare_until <= 0), - (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); - cert = certChain.next; - while (cert) - { - compare_from = TimeCompare(&leaf_valid_from, &cert->valid_from); - compare_until = TimeCompare(&leaf_valid_from, &cert->valid_to); - VerifyOrExit((compare_from >= 0) && (compare_until <= 0), - (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); - cert = cert->next; - } - - /* Verify the chain against the root */ - mbedResult = mbedtls_x509_crt_verify(&certChain, &rootCert, NULL, NULL, &flags, NULL, NULL); - - switch (mbedResult) - { - case 0: - VerifyOrExit(flags == 0, (result = CertificateChainValidationResult::kInternalFrameworkError, error = CHIP_ERROR_INTERNAL)); - result = CertificateChainValidationResult::kSuccess; - break; - case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - result = CertificateChainValidationResult::kChainInvalid; - error = CHIP_ERROR_CERT_NOT_TRUSTED; - break; - default: - result = CertificateChainValidationResult::kInternalFrameworkError; - error = CHIP_ERROR_INTERNAL; - break; - } - -exit: - _log_mbedTLS_error(mbedResult); - mbedtls_x509_crt_free(&certChain); - mbedtls_x509_crt_free(&rootCert); - -#else - (void) rootCertificate; - (void) rootCertificateLen; - (void) caCertificate; - (void) caCertificateLen; - (void) leafCertificate; - (void) leafCertificateLen; - (void) result; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -inline bool IsTimeGreaterThanEqual(const mbedtls_x509_time * const timeA, const mbedtls_x509_time * const timeB) -{ - - // checks if two values are different and if yes, then returns first > second. -#define RETURN_STRICTLY_GREATER_IF_DIFFERENT(component) \ - { \ - auto valueA = timeA->CHIP_CRYPTO_PAL_PRIVATE_X509(component); \ - auto valueB = timeB->CHIP_CRYPTO_PAL_PRIVATE_X509(component); \ - \ - if (valueA != valueB) \ - { \ - return valueA > valueB; \ - } \ - } - - RETURN_STRICTLY_GREATER_IF_DIFFERENT(year); - RETURN_STRICTLY_GREATER_IF_DIFFERENT(mon); - RETURN_STRICTLY_GREATER_IF_DIFFERENT(day); - RETURN_STRICTLY_GREATER_IF_DIFFERENT(hour); - RETURN_STRICTLY_GREATER_IF_DIFFERENT(min); - RETURN_STRICTLY_GREATER_IF_DIFFERENT(sec); - - // all above are equal - return true; -} - -CHIP_ERROR IsCertificateValidAtIssuance(const ByteSpan & referenceCertificate, const ByteSpan & toBeEvaluatedCertificate) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - mbedtls_x509_crt mbedReferenceCertificate; - mbedtls_x509_crt mbedToBeEvaluatedCertificate; - mbedtls_x509_time refNotBeforeTime; - mbedtls_x509_time tbeNotBeforeTime; - mbedtls_x509_time tbeNotAfterTime; - int result; - - VerifyOrReturnError(!referenceCertificate.empty() && !toBeEvaluatedCertificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbedReferenceCertificate); - mbedtls_x509_crt_init(&mbedToBeEvaluatedCertificate); - - result = mbedtls_x509_crt_parse(&mbedReferenceCertificate, Uint8::to_const_uchar(referenceCertificate.data()), - referenceCertificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - result = mbedtls_x509_crt_parse(&mbedToBeEvaluatedCertificate, Uint8::to_const_uchar(toBeEvaluatedCertificate.data()), - toBeEvaluatedCertificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - refNotBeforeTime = mbedReferenceCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from); - tbeNotBeforeTime = mbedToBeEvaluatedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from); - tbeNotAfterTime = mbedToBeEvaluatedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_to); - - // check if referenceCertificate is issued at or after tbeCertificate's notBefore timestamp - VerifyOrExit(IsTimeGreaterThanEqual(&refNotBeforeTime, &tbeNotBeforeTime), error = CHIP_ERROR_CERT_EXPIRED); - - // check if referenceCertificate is issued at or before tbeCertificate's notAfter timestamp - VerifyOrExit(IsTimeGreaterThanEqual(&tbeNotAfterTime, &refNotBeforeTime), error = CHIP_ERROR_CERT_EXPIRED); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbedReferenceCertificate); - mbedtls_x509_crt_free(&mbedToBeEvaluatedCertificate); - -#else - (void) referenceCertificate; - (void) toBeEvaluatedCertificate; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR IsCertificateValidAtCurrentTime(const ByteSpan & certificate) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - mbedtls_x509_crt mbedCertificate; - int result; - - VerifyOrReturnError(!certificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbedCertificate); - - result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - // check if certificate's notBefore timestamp is earlier than or equal to current time. - result = mbedtls_x509_time_is_past(&mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_from)); - VerifyOrExit(result == 1, error = CHIP_ERROR_CERT_EXPIRED); - - // check if certificate's notAfter timestamp is later than current time. - result = mbedtls_x509_time_is_future(&mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(valid_to)); - VerifyOrExit(result == 1, error = CHIP_ERROR_CERT_EXPIRED); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbedCertificate); - -#else - (void) certificate; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - mbedtls_x509_crt mbed_cert; - mbedtls_ecp_keypair * keypair = nullptr; - size_t pubkey_size = 0; - - mbedtls_x509_crt_init(&mbed_cert); - - int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - VerifyOrExit(mbedtls_pk_get_type(&(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(pk))) == MBEDTLS_PK_ECKEY, - error = CHIP_ERROR_INVALID_ARGUMENT); - - keypair = mbedtls_pk_ec(mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(pk)); - VerifyOrExit(keypair->CHIP_CRYPTO_PAL_PRIVATE(grp).id == MapECPGroupId(pubkey.Type()), error = CHIP_ERROR_INVALID_ARGUMENT); - // Copy the public key from the cert in raw point format - result = - mbedtls_ecp_point_write_binary(&keypair->CHIP_CRYPTO_PAL_PRIVATE(grp), &keypair->CHIP_CRYPTO_PAL_PRIVATE(Q), - MBEDTLS_ECP_PF_UNCOMPRESSED, &pubkey_size, Uint8::to_uchar(pubkey.Bytes()), pubkey.Length()); - - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(pubkey_size == pubkey.Length(), error = CHIP_ERROR_INTERNAL); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) pubkey; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -namespace { - -CHIP_ERROR ExtractKIDFromX509Cert(bool extractSKID, const ByteSpan & certificate, MutableByteSpan & kid) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; - mbedtls_x509_crt mbed_cert; - unsigned char * p = nullptr; - const unsigned char * end = nullptr; - size_t len = 0; - - mbedtls_x509_crt_init(&mbed_cert); - - int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - // TODO: The mbedTLS team is working on supporting SKID and AKID extensions processing. - // Once it is supported, this code should be updated. - - p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - end = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p) + - mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - while (p < end) - { - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - mbedtls_x509_buf extOID = { MBEDTLS_ASN1_OID, len, p }; - bool extractCurrentExtSKID = extractSKID && OID_CMP(sOID_Extension_SubjectKeyIdentifier, extOID); - bool extractCurrentExtAKID = !extractSKID && OID_CMP(sOID_Extension_AuthorityKeyIdentifier, extOID); - p += len; - - int is_critical = 0; - result = mbedtls_asn1_get_bool(&p, end, &is_critical); - VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_WRONG_CERT_TYPE); - - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - if (extractCurrentExtSKID || extractCurrentExtAKID) - { - if (extractCurrentExtSKID) - { - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - } - else - { - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - // Other optional fields, authorityCertIssuer and authorityCertSerialNumber, - // will be skipped if present. - } - VerifyOrExit(len == kSubjectKeyIdentifierLength, error = CHIP_ERROR_WRONG_CERT_TYPE); - VerifyOrExit(len <= kid.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(kid.data(), p, len); - if (kid.size() > len) - { - kid.reduce_size(len); - } - ExitNow(error = CHIP_NO_ERROR); - break; - } - p += len; - } - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) kid; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -} // namespace - -CHIP_ERROR ExtractSKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & skid) -{ - return ExtractKIDFromX509Cert(true, certificate, skid); -} - -CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid) -{ - return ExtractKIDFromX509Cert(false, certificate, akid); -} - -CHIP_ERROR ExtractCRLDistributionPointURIFromX509Cert(const ByteSpan & certificate, MutableCharSpan & cdpurl) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; - mbedtls_x509_crt mbed_cert; - unsigned char * p = nullptr; - const unsigned char * end = nullptr; - size_t len = 0; - size_t cdpExtCount = 0; - - VerifyOrReturnError(!certificate.empty() && CanCastTo(certificate.size()), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbed_cert); - - int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - end = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p) + - mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - while (p < end) - { - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - mbedtls_x509_buf extOID = { MBEDTLS_ASN1_OID, len, p }; - bool isCurrentExtCDP = OID_CMP(sOID_Extension_CRLDistributionPoint, extOID); - p += len; - - int is_critical = 0; - result = mbedtls_asn1_get_bool(&p, end, &is_critical); - VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_WRONG_CERT_TYPE); - - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - unsigned char * end_of_ext = p + len; - - if (isCurrentExtCDP) - { - // Only one CRL Distribution Point Extension is allowed. - cdpExtCount++; - VerifyOrExit(cdpExtCount <= 1, error = CHIP_ERROR_NOT_FOUND); - - // CRL Distribution Point Extension is encoded as a sequence of DistributionPoint: - // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint - // - // This implementation only supports a single DistributionPoint (sequence of size 1), - // which is verified by comparing (p + len == end_of_ext) - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - VerifyOrExit(p + len == end_of_ext, error = CHIP_ERROR_NOT_FOUND); - - // The DistributionPoint is a sequence of three optional elements: - // DistributionPoint ::= SEQUENCE { - // distributionPoint [0] DistributionPointName OPTIONAL, - // reasons [1] ReasonFlags OPTIONAL, - // cRLIssuer [2] GeneralNames OPTIONAL } - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - VerifyOrExit(p + len == end_of_ext, error = CHIP_ERROR_NOT_FOUND); - - // The DistributionPointName is: - // DistributionPointName ::= CHOICE { - // fullName [0] GeneralNames, - // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } - // - // The URI should be encoded in the fullName element. - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - - // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - - unsigned char * end_of_general_names = p + len; - - // The CDP URI is encoded as a uniformResourceIdentifier field of the GeneralName: - // GeneralName ::= CHOICE { - // otherName [0] OtherName, - // rfc822Name [1] IA5String, - // dNSName [2] IA5String, - // x400Address [3] ORAddress, - // directoryName [4] Name, - // ediPartyName [5] EDIPartyName, - // uniformResourceIdentifier [6] IA5String, - // iPAddress [7] OCTET STRING, - // registeredID [8] OBJECT IDENTIFIER } - result = - mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - - // Only single URI instance in the GeneralNames is supported - VerifyOrExit(p + len == end_of_general_names, error = CHIP_ERROR_NOT_FOUND); - - const char * urlptr = reinterpret_cast(p); - VerifyOrExit((len > strlen(kValidCDPURIHttpPrefix) && - strncmp(urlptr, kValidCDPURIHttpPrefix, strlen(kValidCDPURIHttpPrefix)) == 0) || - (len > strlen(kValidCDPURIHttpsPrefix) && - strncmp(urlptr, kValidCDPURIHttpsPrefix, strlen(kValidCDPURIHttpsPrefix)) == 0), - error = CHIP_ERROR_NOT_FOUND); - error = CopyCharSpanToMutableCharSpan(CharSpan(urlptr, len), cdpurl); - SuccessOrExit(error); - } - p = end_of_ext; - } - - VerifyOrExit(cdpExtCount == 1, error = CHIP_ERROR_NOT_FOUND); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) cdpurl; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR ExtractCDPExtensionCRLIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & crlIssuer) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; - mbedtls_x509_crt mbed_cert; - unsigned char * p = nullptr; - const unsigned char * end = nullptr; - size_t len = 0; - size_t cdpExtCount = 0; - - VerifyOrReturnError(!certificate.empty() && CanCastTo(certificate.size()), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbed_cert); - - int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - end = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(p) + - mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(v3_ext).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - while (p < end) - { - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - mbedtls_x509_buf extOID = { MBEDTLS_ASN1_OID, len, p }; - bool isCurrentExtCDP = OID_CMP(sOID_Extension_CRLDistributionPoint, extOID); - p += len; - - int is_critical = 0; - result = mbedtls_asn1_get_bool(&p, end, &is_critical); - VerifyOrExit(result == 0 || result == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = CHIP_ERROR_WRONG_CERT_TYPE); - - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); - VerifyOrExit(result == 0, error = CHIP_ERROR_WRONG_CERT_TYPE); - - unsigned char * end_of_ext = p + len; - - if (isCurrentExtCDP) - { - // Only one CRL Distribution Point Extension is allowed. - cdpExtCount++; - VerifyOrExit(cdpExtCount <= 1, error = CHIP_ERROR_NOT_FOUND); - - // CRL Distribution Point Extension is encoded as a sequence of DistributionPoint: - // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint - // - // This implementation only supports a single DistributionPoint (sequence of size 1), - // which is verified by comparing (p + len == end_of_ext) - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - VerifyOrExit(p + len == end_of_ext, error = CHIP_ERROR_NOT_FOUND); - - // The DistributionPoint is a sequence of three optional elements: - // DistributionPoint ::= SEQUENCE { - // distributionPoint [0] DistributionPointName OPTIONAL, - // reasons [1] ReasonFlags OPTIONAL, - // cRLIssuer [2] GeneralNames OPTIONAL } - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - VerifyOrExit(p + len == end_of_ext, error = CHIP_ERROR_NOT_FOUND); - - // If distributionPoint element presents, ignore it - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0); - if (result == 0) - { - p += len; - VerifyOrExit(p < end_of_ext, error = CHIP_ERROR_NOT_FOUND); - } - - // Check if cRLIssuer element present - result = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - - // The CRL Issuer is encoded as a directoryName field of the GeneralName: - // GeneralName ::= CHOICE { - // otherName [0] OtherName, - // rfc822Name [1] IA5String, - // dNSName [2] IA5String, - // x400Address [3] ORAddress, - // directoryName [4] Name, - // ediPartyName [5] EDIPartyName, - // uniformResourceIdentifier [6] IA5String, - // iPAddress [7] OCTET STRING, - // registeredID [8] OBJECT IDENTIFIER } - result = mbedtls_asn1_get_tag( - &p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_X509_SAN_DIRECTORY_NAME); - VerifyOrExit(result == 0, error = CHIP_ERROR_NOT_FOUND); - VerifyOrExit(p + len == end_of_ext, error = CHIP_ERROR_NOT_FOUND); - - error = CopySpanToMutableSpan(ByteSpan(p, len), crlIssuer); - SuccessOrExit(error); - } - p = end_of_ext; - } - - VerifyOrExit(cdpExtCount == 1, error = CHIP_ERROR_NOT_FOUND); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) crlIssuer; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - int result = 0; - uint8_t * p = nullptr; - size_t len = 0; - mbedtls_x509_crt mbed_cert; - - mbedtls_x509_crt_init(&mbed_cert); - - result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - - memcpy(serialNumber.data(), p, len); - serialNumber.reduce_size(len); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) serialNumber; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - mbedtls_x509_crt mbed_cert; - mbedtls_asn1_named_data * dnIterator = nullptr; - AttestationCertVidPid vidpidFromCN; - - mbedtls_x509_crt_init(&mbed_cert); - - int result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - for (dnIterator = &mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(subject); dnIterator != nullptr; - dnIterator = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(next)) - { - DNAttrType attrType = DNAttrType::kUnspecified; - if (OID_CMP(sOID_AttributeType_CommonName, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) - { - attrType = DNAttrType::kCommonName; - } - else if (OID_CMP(sOID_AttributeType_MatterVendorId, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) - { - attrType = DNAttrType::kMatterVID; - } - else if (OID_CMP(sOID_AttributeType_MatterProductId, dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(oid))) - { - attrType = DNAttrType::kMatterPID; - } - - size_t val_len = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(val).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - uint8_t * val_p = dnIterator->CHIP_CRYPTO_PAL_PRIVATE_X509(val).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - error = ExtractVIDPIDFromAttributeString(attrType, ByteSpan(val_p, val_len), vidpid, vidpidFromCN); - SuccessOrExit(error); - } - - // If Matter Attributes were not found use values extracted from the CN Attribute, - // which might be uninitialized as well. - if (!vidpid.Initialized()) - { - vidpid = vidpidFromCN; - } - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbed_cert); - -#else - (void) certificate; - (void) vidpid; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} - -namespace { -CHIP_ERROR ExtractRawDNFromX509Cert(bool extractSubject, const ByteSpan & certificate, MutableByteSpan & dn) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - CHIP_ERROR error = CHIP_NO_ERROR; - int result = 0; - uint8_t * p = nullptr; - size_t len = 0; - mbedtls_x509_crt mbedCertificate; - - ReturnErrorCodeIf(certificate.empty(), CHIP_ERROR_INVALID_ARGUMENT); - - mbedtls_x509_crt_init(&mbedCertificate); - result = mbedtls_x509_crt_parse(&mbedCertificate, Uint8::to_const_uchar(certificate.data()), certificate.size()); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - - if (extractSubject) - { - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(subject_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - } - else - { - len = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(len); - p = mbedCertificate.CHIP_CRYPTO_PAL_PRIVATE_X509(issuer_raw).CHIP_CRYPTO_PAL_PRIVATE_X509(p); - } - - VerifyOrExit(len <= dn.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL); - memcpy(dn.data(), p, len); - dn.reduce_size(len); - -exit: - _log_mbedTLS_error(result); - mbedtls_x509_crt_free(&mbedCertificate); - -#else - (void) certificate; - (void) dn; - CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) - - return error; -} -} // namespace - -CHIP_ERROR ExtractSubjectFromX509Cert(const ByteSpan & certificate, MutableByteSpan & subject) -{ - return ExtractRawDNFromX509Cert(true, certificate, subject); -} - -CHIP_ERROR ExtractIssuerFromX509Cert(const ByteSpan & certificate, MutableByteSpan & issuer) -{ - return ExtractRawDNFromX509Cert(false, certificate, issuer); -} - -CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, const ByteSpan * candidateCertificates, - size_t candidateCertificatesCount, ByteSpan & outCertificate) -{ -#if defined(MBEDTLS_X509_CRT_PARSE_C) - uint8_t referenceSubjectBuf[kMaxCertificateDistinguishedNameLength]; - uint8_t referenceSKIDBuf[kSubjectKeyIdentifierLength]; - MutableByteSpan referenceSubject(referenceSubjectBuf); - MutableByteSpan referenceSKID(referenceSKIDBuf); - - outCertificate = referenceCertificate; - - ReturnErrorCodeIf(candidateCertificates == nullptr || candidateCertificatesCount == 0, CHIP_NO_ERROR); - - ReturnErrorOnFailure(ExtractSubjectFromX509Cert(referenceCertificate, referenceSubject)); - ReturnErrorOnFailure(ExtractSKIDFromX509Cert(referenceCertificate, referenceSKID)); - - for (size_t i = 0; i < candidateCertificatesCount; i++) - { - const ByteSpan candidateCertificate = candidateCertificates[i]; - uint8_t candidateSubjectBuf[kMaxCertificateDistinguishedNameLength]; - uint8_t candidateSKIDBuf[kSubjectKeyIdentifierLength]; - MutableByteSpan candidateSubject(candidateSubjectBuf); - MutableByteSpan candidateSKID(candidateSKIDBuf); - - ReturnErrorOnFailure(ExtractSubjectFromX509Cert(candidateCertificate, candidateSubject)); - ReturnErrorOnFailure(ExtractSKIDFromX509Cert(candidateCertificate, candidateSKID)); - - if (referenceSKID.data_equal(candidateSKID) && referenceSubject.data_equal(candidateSubject)) - { - outCertificate = candidateCertificate; - return CHIP_NO_ERROR; - } - } - - return CHIP_NO_ERROR; -#else - (void) referenceCertificate; - (void) candidateCertificates; - (void) candidateCertificatesCount; - (void) outCertificate; - return CHIP_ERROR_NOT_IMPLEMENTED; -#endif // defined(MBEDTLS_X509_CRT_PARSE_C) -} - -void LogPsaError(psa_status_t status) -{ - if (status != PSA_SUCCESS) - { - ChipLogError(Crypto, "PSA error: %d", static_cast(status)); - } -} - -CHIP_ERROR PsaKdf::Init(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) -{ - psa_status_t status = PSA_SUCCESS; - psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); - psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); - - status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); - LogPsaError(status); - psa_reset_key_attributes(&attrs); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return InitOperation(mSecretKeyId, salt, info); -} - -CHIP_ERROR PsaKdf::Init(const HkdfKeyHandle & hkdfKey, const ByteSpan & salt, const ByteSpan & info) -{ - return InitOperation(hkdfKey.As(), salt, info); -} - -CHIP_ERROR PsaKdf::InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info) -{ - psa_status_t status = psa_key_derivation_setup(&mOperation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - if (salt.size() > 0) - { - status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - } - - status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, hkdfKey); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) -{ - psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); - LogPsaError(status); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) -{ - psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); - LogPsaError(status); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR FindFreeKeySlotInRange(psa_key_id_t & keyId, psa_key_id_t start, uint32_t range) -{ - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t end = start + range; - - VerifyOrReturnError(start >= PSA_KEY_ID_USER_MIN && end - 1 <= PSA_KEY_ID_USER_MAX, CHIP_ERROR_INVALID_ARGUMENT); - - for (keyId = start; keyId < end; keyId++) - { - psa_status_t status = psa_get_key_attributes(keyId, &attributes); - if (status == PSA_ERROR_INVALID_HANDLE) - { - return CHIP_NO_ERROR; - } - else if (status != PSA_SUCCESS) - { - return CHIP_ERROR_INTERNAL; - } - } - return CHIP_ERROR_NOT_FOUND; -} - } // namespace Crypto } // namespace chip