diff --git a/examples/platform/silabs/FreeRTOSConfig.h b/examples/platform/silabs/FreeRTOSConfig.h index 24a1408a47..462f923aff 100644 --- a/examples/platform/silabs/FreeRTOSConfig.h +++ b/examples/platform/silabs/FreeRTOSConfig.h @@ -203,7 +203,10 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ #define configENABLE_FPU 1 #define configENABLE_MPU 0 /* FreeRTOS Secure Side Only and TrustZone Security Extension */ +#ifndef configRUN_FREERTOS_SECURE_ONLY +// prevent redefinition with Series 3 #define configRUN_FREERTOS_SECURE_ONLY 1 +#endif #define configENABLE_TRUSTZONE 0 /* FreeRTOS MPU specific definitions. */ #define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS (0) diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index 6f82c93c19..235e8e2f43 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -38,6 +38,18 @@ assert( chip_crypto == "platform", "Please select a valid crypto implementation: mbedtls, psa, openssl, boringssl, platform") +if (chip_crypto_keystore == "") { + if (chip_crypto == "psa") { + chip_crypto_keystore = "psa" + } else { + chip_crypto_keystore = "raw" + } +} + +assert(chip_crypto_keystore == "psa" || chip_crypto_keystore == "raw" || + chip_crypto_keystore == "app", + "Please select a valid crypto keystore: psa, raw, app") + buildconfig_header("crypto_buildconfig") { header = "CryptoBuildConfig.h" header_dir = "crypto" @@ -47,11 +59,17 @@ buildconfig_header("crypto_buildconfig") { chip_crypto_openssl = chip_crypto == "openssl" chip_crypto_boringssl = chip_crypto == "boringssl" chip_crypto_platform = chip_crypto == "platform" + chip_crypto_keystore_psa = chip_crypto_keystore == "psa" + chip_crypto_keystore_raw = chip_crypto_keystore == "raw" + chip_crypto_keystore_app = chip_crypto_keystore == "app" defines = [ "CHIP_CRYPTO_MBEDTLS=${chip_crypto_mbedtls}", "CHIP_CRYPTO_PSA=${chip_crypto_psa}", "CHIP_CRYPTO_PSA_SPAKE2P=${chip_crypto_psa_spake2p}", + "CHIP_CRYPTO_KEYSTORE_PSA=${chip_crypto_keystore_psa}", + "CHIP_CRYPTO_KEYSTORE_RAW=${chip_crypto_keystore_raw}", + "CHIP_CRYPTO_KEYSTORE_APP=${chip_crypto_keystore_app}", "CHIP_CRYPTO_OPENSSL=${chip_crypto_openssl}", "CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}", "CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}", @@ -144,18 +162,20 @@ static_library("crypto") { "RandUtils.h", ] - if (chip_crypto == "psa") { + if (chip_crypto_keystore == "psa") { sources += [ "PSAOperationalKeystore.cpp", "PSAOperationalKeystore.h", "PSASessionKeystore.cpp", "PSASessionKeystore.h", ] - } else { + } else if (chip_crypto_keystore == "raw") { sources += [ "RawKeySessionKeystore.cpp", "RawKeySessionKeystore.h", ] + } else { + # Keystore provided by app } if (chip_crypto_psa_spake2p) { diff --git a/src/crypto/DefaultSessionKeystore.h b/src/crypto/DefaultSessionKeystore.h index 8fa6121af5..227455b113 100644 --- a/src/crypto/DefaultSessionKeystore.h +++ b/src/crypto/DefaultSessionKeystore.h @@ -21,9 +21,9 @@ #include #endif -#if CHIP_CRYPTO_PSA +#if CHIP_CRYPTO_KEYSTORE_PSA #include -#else +#elif CHIP_CRYPTO_KEYSTORE_RAW #include #endif @@ -34,9 +34,9 @@ namespace Crypto { // when the PSA crypto backend is used, AES encryption/decryption function assume that the input // key handle carries a key reference instead of raw key material, so PSASessionKeystore must be // used instead of RawKeySessionKeystore to initialize the key handle. -#if CHIP_CRYPTO_PSA +#if CHIP_CRYPTO_KEYSTORE_PSA using DefaultSessionKeystore = PSASessionKeystore; -#else +#elif CHIP_CRYPTO_KEYSTORE_RAW using DefaultSessionKeystore = RawKeySessionKeystore; #endif diff --git a/src/crypto/crypto.gni b/src/crypto/crypto.gni index 96f506033b..2630af95b2 100644 --- a/src/crypto/crypto.gni +++ b/src/crypto/crypto.gni @@ -22,6 +22,10 @@ declare_args() { # Use PSA Spake2+ implementation. Only used if chip_crypto == "psa" chip_crypto_psa_spake2p = false + + # Crypto storage: psa, raw, app. + # app: includes zero new files and disables the unit tests for the keystore. + chip_crypto_keystore = "" } assert( diff --git a/src/crypto/tests/TestChipCryptoPAL.cpp b/src/crypto/tests/TestChipCryptoPAL.cpp index 2d1f5c0612..4dd5182e78 100644 --- a/src/crypto/tests/TestChipCryptoPAL.cpp +++ b/src/crypto/tests/TestChipCryptoPAL.cpp @@ -210,6 +210,7 @@ const AesCtrTestEntry theAesCtrTestVector[] = { } }; +#if !(CHIP_CRYPTO_KEYSTORE_APP) struct TestAesKey { public: @@ -245,6 +246,7 @@ struct TestHmacKey DefaultSessionKeystore keystore; Hmac128KeyHandle key; }; +#endif static void TestAES_CTR_128_Encrypt(const AesCtrTestEntry * vector) { @@ -964,6 +966,7 @@ TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_RawKey) EXPECT_EQ(numOfTestsExecuted, numOfTestCases); } +#if !(CHIP_CRYPTO_KEYSTORE_APP) TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_KeyHandle) { HeapChecker heapChecker; @@ -994,6 +997,7 @@ TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_KeyHandle) } EXPECT_EQ(numOfTestsExecuted, numOfTestCases); } +#endif TEST_F(TestChipCryptoPAL, TestHKDF_SHA256) { @@ -1870,7 +1874,6 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) size_t Pverifier_len = sizeof(Pverifier); uint8_t Vverifier[kMAX_Hash_Length]; size_t Vverifier_len = sizeof(Vverifier); - DefaultSessionKeystore keystore; int numOfTestVectors = ArraySize(rfc_tvs); int numOfTestsRan = 0; @@ -1967,7 +1970,9 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) error = Verifier.KeyConfirm(Pverifier, Pverifier_len); EXPECT_EQ(error, CHIP_NO_ERROR); +#if !(CHIP_CRYPTO_KEYSTORE_APP) // Import HKDF key from the test vector to the keystore + DefaultSessionKeystore keystore; HkdfKeyHandle vectorKe; error = keystore.CreateKey(ByteSpan(vector->Ke, vector->Ke_len), vectorKe); EXPECT_EQ(error, CHIP_NO_ERROR); @@ -1988,7 +1993,7 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) keystore.DestroyKey(vectorKe); keystore.DestroyKey(PKe); keystore.DestroyKey(VKe); - +#endif numOfTestsRan += 1; } EXPECT_GT(numOfTestsRan, 0); diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index 6989e3a2c6..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,613 +18,454 @@ /** * @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 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" - -// Go straight for the driver wrappers for speed on plaintext keys -extern "C" { -#include "psa_crypto_core.h" -#include "psa_crypto_driver_wrappers.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 + #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 - -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 - } -} +namespace { -static void _log_PSA_error(psa_status_t status) +bool IsBufferNonEmpty(const uint8_t * data, size_t data_length) { - if (status != 0) - { - // Error codes defined in 16-bit negative hex numbers. Ease lookup by printing likewise - ChipLogError(Crypto, "PSA error: %ld", status); - } + return data != nullptr && data_length > 0; } -static bool _isValidTagLength(size_t tag_length) +bool IsValidTag(const uint8_t * tag, size_t tag_length) { - if (tag_length == 8 || tag_length == 12 || tag_length == 16) - { - return true; - } - return false; + return tag != nullptr && (tag_length == 8 || tag_length == 12 || tag_length == 16); } -/** - * @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. - */ -static 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; -} +} // namespace CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; - - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_uchar(ciphertext) + plaintext_length != Uint8::to_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, plaintext_length + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } + VerifyOrReturnError(IsBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || plaintext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t out_length; + size_t tag_out_length; - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Symmetric128BitsKeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + status = psa_aead_encrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_driver_wrapper_aead_encrypt(&attr, key.As(), sizeof(Symmetric128BitsKeyByteArray), - PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), - nonce_length, Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), - plaintext_length, allocated_buffer ? buffer : ciphertext, - plaintext_length + tag_length, &output_length); + status = psa_aead_set_lengths(&operation, aad_length, plaintext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == plaintext_length + tag_length, error = CHIP_ERROR_INTERNAL); + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (aad_length != 0) { - memcpy(Uint8::to_uchar(ciphertext), buffer, plaintext_length); - memcpy(Uint8::to_uchar(tag), buffer + plaintext_length, tag_length); - memset(buffer, 0, plaintext_length + tag_length); + 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"); } -exit: - if (allocated_buffer) + if (plaintext_length != 0) { - MemoryFree(buffer); + status = psa_aead_update(&operation, plaintext, plaintext_length, ciphertext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, plaintext_length), &out_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + ciphertext += out_length; + + status = psa_aead_finish(&operation, ciphertext, PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &out_length, tag, + tag_length, &tag_out_length); } - psa_reset_key_attributes(&attr); - return error; + else + { + status = psa_aead_finish(&operation, nullptr, 0, &out_length, tag, tag_length, &tag_out_length); + } + VerifyOrReturnError(status == PSA_SUCCESS && tag_length == tag_out_length, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } -CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, +CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; - - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_const_uchar(ciphertext) + ciphertext_len != Uint8::to_const_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, ciphertext_len + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } + VerifyOrReturnError(IsBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || ciphertext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t outLength; - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Symmetric128BitsKeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DECRYPT); + status = psa_aead_decrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) - { - memcpy(buffer, ciphertext, ciphertext_len); - memcpy(buffer + ciphertext_len, tag, tag_length); - } + status = psa_aead_set_lengths(&operation, aad_length, ciphertext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = - psa_driver_wrapper_aead_decrypt(&attr, key.As(), sizeof(Symmetric128BitsKeyByteArray), - PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), - nonce_length, Uint8::to_const_uchar(aad), aad_len, allocated_buffer ? buffer : ciphertext, - ciphertext_len + tag_length, plaintext, ciphertext_len, &output_length); + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (aad_length != 0) { - memset(buffer, 0, ciphertext_len + tag_length); + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + else + { + ChipLogDetail(Crypto, "AES_CCM_decrypt: Using aad == null path"); } - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == ciphertext_len, error = CHIP_ERROR_INTERNAL); -exit: - if (allocated_buffer) + if (ciphertext_length != 0) + { + status = psa_aead_update(&operation, ciphertext, ciphertext_length, plaintext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, ciphertext_length), &outLength); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + plaintext += outLength; + + status = psa_aead_verify(&operation, plaintext, PSA_AEAD_VERIFY_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &outLength, tag, + tag_length); + } + else { - MemoryFree(buffer); + status = psa_aead_verify(&operation, nullptr, 0, &outLength, tag, tag_length); } - psa_reset_key_attributes(&attr); - return error; + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } 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(); - - 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); + size_t outLength = 0; - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INTERNAL); + 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); - 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; - - psa_crypto_init(); + size_t outLength = 0; - 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); + 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); - 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()); - - VerifyOrReturnError(result == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + const psa_status_t status = psa_hash_update(toHashOperation(&mContext), data.data(), data.size()); - 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() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(out_buffer.size() >= PSA_HASH_LENGTH(PSA_ALG_SHA_256), 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); - psa_crypto_init(); + status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); + LogPsaError(status); + psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_key_derivation_setup(&operation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - VerifyOrExit(status == PSA_SUCCESS, error = 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_length > 0) + 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, uint8_t * out_buffer, size_t out_length) { - VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(key_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(message != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(message_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_length >= kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; - size_t output_length = 0; + VerifyOrReturnError(IsBufferNonEmpty(key, key_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(message, message_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr && out_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + const psa_algorithm_t algorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t keyId = 0; - psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); - psa_set_key_bits(&attr, key_length * 8); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attrs, PSA_KEY_TYPE_HMAC); + psa_set_key_algorithm(&attrs, algorithm); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_SIGN_HASH); - status = psa_driver_wrapper_mac_compute(&attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_HMAC(PSA_ALG_SHA_256), - Uint8::to_const_uchar(message), message_length, out_buffer, out_length, &output_length); + status = psa_import_key(&attrs, key, key_length, &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_mac_compute(keyId, algorithm, message, message_length, out_buffer, out_length, &out_length); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + exit: - psa_mac_abort(&operation); - psa_reset_key_attributes(&attr); - return error; + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attrs); + + return CHIP_NO_ERROR; } CHIP_ERROR HMAC_sha::HMAC_SHA256(const Hmac128KeyHandle & key, const uint8_t * message, size_t message_length, uint8_t * out_buffer, size_t out_length) { - return HMAC_SHA256(key.As(), sizeof(Symmetric128BitsKeyByteArray), message, message_length, - out_buffer, out_length); -} + VerifyOrReturnError(IsBufferNonEmpty(message, message_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr && out_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INVALID_ARGUMENT); -CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t plen, const uint8_t * salt, size_t slen, - unsigned int iteration_count, uint32_t key_length, uint8_t * output) -{ - // TODO: replace inlined algorithm with usage of the PSA key derivation API once implemented - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - - // Align these buffers on the native data size to speed up the XOR - static const size_t hash_size_in_native = - ((PSA_HASH_LENGTH(PSA_ALG_SHA_256) + sizeof(unsigned int) - 1) / sizeof(unsigned int)); - static_assert(hash_size_in_native * sizeof(unsigned int) >= PSA_HASH_LENGTH(PSA_ALG_SHA_256)); - - unsigned int md1_buffer[hash_size_in_native]; - unsigned int work_buffer[hash_size_in_native]; - uint8_t * md1 = (uint8_t *) md1_buffer; - uint8_t * work = (uint8_t *) work_buffer; - - size_t use_len; - unsigned char * out_p = output; - uint8_t * U1 = (uint8_t *) MemoryCalloc(1, slen + 4); - - VerifyOrExit(U1 != nullptr, error = CHIP_ERROR_NO_MEMORY); - VerifyOrExit(password != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(plen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(salt != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(slen >= kSpake2p_Min_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(slen <= kSpake2p_Max_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(output != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - - psa_crypto_init(); - - psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); - psa_set_key_bits(&attr, plen * 8); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); - - // Start with initializing the salt + counter - memcpy(U1, salt, slen); - U1[slen] = 0; - U1[slen + 1] = 0; - U1[slen + 2] = 0; - U1[slen + 3] = 1; - - // Loop until we have generated the requested key length - while (key_length) - { - // U1 ends up in work - status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), U1, slen + 4, work, - PSA_HASH_LENGTH(PSA_ALG_SHA_256), &output_length); + const psa_algorithm_t algorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256); + psa_status_t status = PSA_SUCCESS; - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + status = psa_mac_compute(key.As(), algorithm, message, message_length, out_buffer, out_length, &out_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - memcpy(md1, work, PSA_HASH_LENGTH(PSA_ALG_SHA_256)); + return CHIP_NO_ERROR; +} - for (size_t i = 1; i < iteration_count; i++) - { - // U2 ends up in md1 - // +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(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); - status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), md1, sizeof(md1_buffer), - md1, sizeof(md1_buffer), &output_length); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - // U1 xor U2 - // - for (size_t j = 0; j < hash_size_in_native; j++) - { - work_buffer[j] ^= md1_buffer[j]; - } - } + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, salt, salt_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - use_len = (key_length < PSA_HASH_LENGTH(PSA_ALG_SHA_256)) ? key_length : PSA_HASH_LENGTH(PSA_ALG_SHA_256); - memcpy(out_p, work, use_len); + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, iteration_count); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - key_length -= (uint32_t) use_len; - out_p += use_len; + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, pass, pass_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - for (size_t i = 4; i > 0; i--) - { - if (++U1[slen + i - 1] != 0) - { - break; - } - } - } + status = psa_key_derivation_output_bytes(&operation, key, key_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); exit: - MemoryFree(U1); - psa_reset_key_attributes(&attr); + psa_key_derivation_abort(&operation); + 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! @@ -648,80 +489,52 @@ 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 { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - 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); - VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); - - psa_crypto_init(); + VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); + VerifyOrReturnError(IsBufferNonEmpty(msg, msg_length), CHIP_ERROR_INVALID_ARGUMENT); - 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_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + size_t outputLen = 0; + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); - // use imported key to sign a message - status = - psa_driver_wrapper_sign_message(&attr, keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen), PSA_ALG_ECDSA(PSA_ALG_SHA_256), - msg, msg_length, out_signature.Bytes(), out_signature.Capacity(), &output_length); + status = psa_sign_message(context.key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_length, out_signature.Bytes(), + out_signature.Capacity(), &outputLen); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(out_signature.SetLength(output_length) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(outputLen == kP256_ECDSA_Signature_Length_Raw, error = CHIP_ERROR_INTERNAL); + error = out_signature.SetLength(outputLen); exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); - + LogPsaError(status); return error; } CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, const P256ECDSASignature & signature) const { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + VerifyOrReturnError(IsBufferNonEmpty(msg, msg_length), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_id_t keyId = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_crypto_init(); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - - // use imported key to verify a message - status = psa_driver_wrapper_verify_message(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, - msg_length, signature.ConstBytes(), signature.Length()); + status = psa_import_key(&attributes, ConstBytes(), Length(), &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_verify_message(keyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_length, signature.ConstBytes(), signature.Length()); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); + exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attributes); return error; } @@ -729,73 +542,50 @@ CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, cons CHIP_ERROR P256PublicKey::ECDSA_validate_hash_signature(const uint8_t * hash, const size_t hash_length, const P256ECDSASignature & signature) const { - VerifyOrReturnError(hash != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(hash != nullptr && hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(signature.Length() == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INVALID_ARGUMENT); - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - - // Step 1: import public key as volatile - psa_crypto_init(); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_id_t keyId = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - // use imported key to verify a hash - status = psa_driver_wrapper_verify_hash(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, - hash_length, signature.ConstBytes(), signature.Length()); + status = psa_import_key(&attributes, ConstBytes(), Length(), &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_verify_hash(keyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, hash_length, signature.ConstBytes(), signature.Length()); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); + exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attributes); + return error; } 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); + VerifyOrReturnError(mInitialized, 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); - - // 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; } @@ -832,84 +622,93 @@ bool IsBufferContentEqualConstantTime(const void * a, const void * b, size_t n) CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); - size_t output_length; + VerifyOrReturnError(!mInitialized, CHIP_ERROR_INCORRECT_STATE); - if (mInitialized) - { - return CHIP_ERROR_INCORRECT_STATE; - } - - // Step 1: Generate a volatile new key - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - psa_crypto_init(); + 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); + size_t publicKeyLength = 0; - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_algorithm(&attr, PSA_ALG_ECDH); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + // Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1 + 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); - status = psa_driver_wrapper_generate_key(&attr, keypair->privkey, sizeof(keypair->privkey), &output_length); + if (key_target == ECPKeyTarget::ECDH) + { + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + } + else if (key_target == ECPKeyTarget::ECDSA) + { + 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); + } + else + { + ExitNow(error = CHIP_ERROR_UNKNOWN_KEY_TYPE); + } + status = psa_generate_key(&attributes, &context.key_id); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == kP256_PrivateKey_Length, error = CHIP_ERROR_INTERNAL); - - keypair->bitlen = 256; - - // Step 2: Export the public key into the pubkey member - status = psa_driver_wrapper_export_public_key(&attr, keypair->privkey, sizeof(keypair->privkey), Uint8::to_uchar(mPublicKey), - mPublicKey.Length(), &output_length); + status = psa_export_public_key(context.key_id, mPublicKey.Bytes(), mPublicKey.Length(), &publicKeyLength); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(publicKeyLength == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + + mInitialized = true; exit: - _log_PSA_error(status); - if (error == CHIP_NO_ERROR) - { - mInitialized = true; - } - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_reset_key_attributes(&attributes); return error; } 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); @@ -917,6 +716,8 @@ CHIP_ERROR P256Keypair::Deserialize(P256SerializedKeypair & input) mInitialized = true; exit: + LogPsaError(status); + return error; } @@ -924,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; } } @@ -937,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); + VerifyOrReturnError(IsBufferNonEmpty(out_csr, csr_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); - // 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); - - 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 @@ -1081,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); @@ -1096,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; } @@ -1215,20 +958,43 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointWrite(const void * R, uint8_t * o return CHIP_NO_ERROR; } -extern "C" { -#include "em_device.h" -} - #if defined(SEMAILBOX_PRESENT) // Add inlined optimisation which can use the SE to do point multiplication operations using // the ECDH primitive as a proxy for scalar multiplication. extern "C" { #include "sl_se_manager.h" #include "sl_se_manager_key_derivation.h" -#include "sl_se_manager_util.h" -#include "sli_se_driver_key_management.h" -#include "sli_se_manager_internal.h" } + +/** Pad size to word alignment + * Copied from: + * ${simplicity_sdk}/platform/security/sl_component/sl_psa_driver/inc/sli_se_driver_key_management.h + * @param size + * Unsigend integer type. + * @returns the number of padding bytes required + */ +#define sli_se_word_align(size) ((size + 3) & ~3) + +/** + * @brief + * Set the key desc to a plaintext key type pointing to data. + * Copied from: + * ${simplicity_sdk}/platform/security/sl_component/sl_psa_driver/inc/sli_se_driver_key_management.h + * @param[out] key_desc + * The SE manager key struct representing a key + * @param[in] data + * Buffer containing the key + * @param[in] data_length + * Length of the buffer + */ +static inline void key_descriptor_set_plaintext(sl_se_key_descriptor_t * key_desc, const uint8_t * data, size_t data_length) +{ + key_desc->storage.method = SL_SE_KEY_STORAGE_EXTERNAL_PLAINTEXT; + key_desc->storage.location.buffer.pointer = (uint8_t *) data; + // TODO: Improve SE manager alignment requirements + key_desc->storage.location.buffer.size = sli_se_word_align(data_length); +} + #endif /* SEMAILBOX_PRESENT */ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, const void * fe1) @@ -1276,17 +1042,17 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, co // Set private key to scalar priv_desc.type = SL_SE_KEY_TYPE_ECC_P256; priv_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PRIVATE_KEY; - sli_se_key_descriptor_set_plaintext(&priv_desc, scalar, sizeof(scalar)); + key_descriptor_set_plaintext(&priv_desc, scalar, sizeof(scalar)); // Set public key to point pub_desc.type = SL_SE_KEY_TYPE_ECC_P256; pub_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PUBLIC_KEY; - sli_se_key_descriptor_set_plaintext(&pub_desc, point, sizeof(point)); + key_descriptor_set_plaintext(&pub_desc, point, sizeof(point)); // Set output to point shared_desc.type = SL_SE_KEY_TYPE_SYMMETRIC; shared_desc.size = sizeof(point); - sli_se_key_descriptor_set_plaintext(&shared_desc, point, sizeof(point)); + key_descriptor_set_plaintext(&shared_desc, point, sizeof(point)); // Re-init SE command context. sl_status = sl_se_init_command_context(&cmd_ctx); @@ -1408,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; } @@ -1462,962 +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) -} - } // namespace Crypto } // namespace chip diff --git a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp index 9528c5b779..f7096d666f 100644 --- a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp @@ -281,8 +281,13 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) osDelay(100); // sl-temp: delay for uart print before verifyImage #endif // _SILICON_LABS_32B_SERIES_3 && CHIP_PROGRESS_LOGGING LockRadioProcessing(); +#if defined(SL_TRUSTZONE_NONSECURE) + WRAP_BL_DFU_CALL(err = bootloader_verifyImage(mSlotId)) +#else WRAP_BL_DFU_CALL(err = bootloader_verifyImage(mSlotId, NULL)) +#endif UnlockRadioProcessing(); + if (err != SL_BOOTLOADER_OK) { ChipLogError(SoftwareUpdate, "bootloader_verifyImage() error: %ld", err); diff --git a/src/platform/silabs/efr32/args.gni b/src/platform/silabs/efr32/args.gni index 501661866a..95b7519474 100644 --- a/src/platform/silabs/efr32/args.gni +++ b/src/platform/silabs/efr32/args.gni @@ -29,6 +29,7 @@ openthread_external_mbedtls = mbedtls_target # default to platform crypto implementation but allow commandline override if (chip_crypto == "") { chip_crypto = "platform" + chip_crypto_keystore = "psa" } chip_device_platform = "efr32" diff --git a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp index 361dfa93a4..bc221ead6a 100644 --- a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp +++ b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp @@ -126,7 +126,9 @@ CHIP_ERROR SilabsPlatform::Init(void) CHIP_ERROR SilabsPlatform::FlashInit() { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_Init(); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status; @@ -140,7 +142,9 @@ CHIP_ERROR SilabsPlatform::FlashInit() CHIP_ERROR SilabsPlatform::FlashErasePage(uint32_t addr) { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_ErasePage((uint32_t *) addr); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status; @@ -158,7 +162,9 @@ CHIP_ERROR SilabsPlatform::FlashErasePage(uint32_t addr) CHIP_ERROR SilabsPlatform::FlashWritePage(uint32_t addr, const uint8_t * data, size_t size) { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_WriteWord((uint32_t *) addr, data, size); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status;