diff --git a/config/nrfconnect/chip-module/Kconfig b/config/nrfconnect/chip-module/Kconfig index 6afd11cca2..8c2cd825d3 100644 --- a/config/nrfconnect/chip-module/Kconfig +++ b/config/nrfconnect/chip-module/Kconfig @@ -107,10 +107,6 @@ config CHIP_FACTORY_DATA bool "Factory data provider" select ZCBOR imply FPROTECT - imply MBEDTLS_X509_LIBRARY if CHIP_CRYPTO_PSA - imply MBEDTLS_X509_CRT_PARSE_C if CHIP_CRYPTO_PSA - imply MBEDTLS_PK_PARSE_C if CHIP_CRYPTO_PSA - imply MBEDTLS_TLS_LIBRARY if CHIP_CRYPTO_PSA help Enables the default nRF Connect factory data provider implementation that supports reading the factory data encoded in the CBOR format from the @@ -249,7 +245,7 @@ endif # CHIP_FACTORY_DATA_BUILD # See config/zephyr/Kconfig for full definition config CHIP_FACTORY_RESET_ERASE_NVS bool - default y + default y if !CHIP_CRYPTO_PSA # For now erasing whole NVS sector is not supported for PSA Crypto config CHIP_LOG_SIZE_OPTIMIZATION bool "Disable some detailed logs to decrease flash usage" @@ -284,4 +280,11 @@ config CHIP_ENABLE_READ_CLIENT This config can be disabled for device types that do not require Read Client functionality. Disabling this config can save flash and RAM space. +config CHIP_CRYPTO_PSA_ITS_NVM_OFFSET + hex "Specify the offset for Matter crypto keys in the ITS NVM space" + default 0x30000 + depends on CHIP_CRYPTO_PSA + help + Declared offset while using PSA key references. An example can override this definition based on implementation. + endif # CHIP diff --git a/src/platform/nrfconnect/CHIPPlatformConfig.h b/src/platform/nrfconnect/CHIPPlatformConfig.h index c8d67115f9..9d45a61f3f 100644 --- a/src/platform/nrfconnect/CHIPPlatformConfig.h +++ b/src/platform/nrfconnect/CHIPPlatformConfig.h @@ -54,6 +54,12 @@ #endif // CHIP_CONFIG_SHA256_CONTEXT_ALIGN #endif // CONFIG_CHIP_CRYPTO_PSA +#ifdef CONFIG_CHIP_CRYPTO_PSA +#ifndef CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE +#define CHIP_CONFIG_CRYPTO_PSA_KEY_ID_BASE CONFIG_CHIP_CRYPTO_PSA_ITS_NVM_OFFSET +#endif +#endif + // ==================== General Configuration Overrides ==================== #ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS diff --git a/src/platform/nrfconnect/FactoryDataParser.c b/src/platform/nrfconnect/FactoryDataParser.c index 610c78ab3e..85f9529836 100644 --- a/src/platform/nrfconnect/FactoryDataParser.c +++ b/src/platform/nrfconnect/FactoryDataParser.c @@ -17,13 +17,33 @@ #include "FactoryDataParser.h" +#include #include +#include #include #include +#define zcbor_tstr_put_lit_cast(state, string) zcbor_tstr_encode_ptr(state, (char *) string, sizeof(string) - 1) + #define MAX_FACTORY_DATA_NESTING_LEVEL 4 +static inline void updateSize(struct FactoryData * factoryData, const char * name, size_t len) +{ + if (factoryData) + { + if (name) + { + // Add name string length + 1, actual length of the entry and 1 Byte of CBOR item header. + factoryData->actualSize += strlen(name) + 1 + len + 1; + } + else + { + factoryData->actualSize += len + 1; + } + } +} + static inline bool uint16_decode(zcbor_state_t * states, uint16_t * value) { uint32_t u32; @@ -84,6 +104,87 @@ static bool DecodeEntry(zcbor_state_t * states, void * buffer, size_t bufferSize return res; } +bool SerializeFactoryData(uint8_t * factoryDataBuff, size_t factoryDataSize, const struct FactoryData * factoryData) +{ + zcbor_state_t cbor_state[2]; + zcbor_new_encode_state(cbor_state, MAX_FACTORY_DATA_NESTING_LEVEL, factoryDataBuff, factoryDataSize, 0); + + bool res = zcbor_map_start_encode(cbor_state, 1); + + res = res && zcbor_tstr_put_lit_cast(cbor_state, "version"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->version)); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "passcode"); + res = res && zcbor_uint32_put(cbor_state, factoryData->passcode); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "sn"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->sn.data, factoryData->sn.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "date"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->date.data, factoryData->date.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "hw_ver_str"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->hw_ver_str.data, factoryData->hw_ver_str.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "rd_uid"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->rd_uid.data, factoryData->rd_uid.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "dac_cert"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->dac_cert.data, factoryData->dac_cert.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "pai_cert"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->pai_cert.data, factoryData->pai_cert.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "spake2_it"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->spake2_it)); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "spake2_salt"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->spake2_salt.data, factoryData->spake2_salt.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "spake2_verifier"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->spake2_verifier.data, factoryData->spake2_verifier.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "vendor_name"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->vendor_name.data, factoryData->vendor_name.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "product_name"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->product_name.data, factoryData->product_name.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "part_number"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->part_number.data, factoryData->part_number.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "product_url"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->product_url.data, factoryData->product_url.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "product_label"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->product_label.data, factoryData->product_label.len); + res = res && zcbor_tstr_put_lit_cast(cbor_state, "enable_key"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->enable_key.data, factoryData->enable_key.len); + if (factoryData->hwVerPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "hw_ver"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->hw_ver)); + } + if (factoryData->vendorIdPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "vendor_id"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->vendor_id)); + } + if (factoryData->productIdPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "product_id"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->product_id)); + } + if (factoryData->discriminatorPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "discriminator"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->discriminator)); + } + if (factoryData->productFinishPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "product_finish"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->product_finish)); + } + if (factoryData->primaryColorPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "primary_color"); + res = res && zcbor_uint32_put(cbor_state, (uint32_t) (factoryData->primary_color)); + } + if (factoryData->userDataPresent) + { + res = res && zcbor_tstr_put_lit_cast(cbor_state, "user"); + res = res && zcbor_bstr_encode_ptr(cbor_state, factoryData->user.data, factoryData->user.len); + } + + res = res && zcbor_map_end_encode(cbor_state, 1); + return res; +} + bool FindUserDataEntry(struct FactoryData * factoryData, const char * entry, void * buffer, size_t bufferSize, size_t * outlen) { if ((!factoryData) || (!factoryData->user.data) || (!buffer) || (!outlen)) @@ -123,10 +224,16 @@ bool FindUserDataEntry(struct FactoryData * factoryData, const char * entry, voi bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData) { + if (!buffer || !factoryData || bufferSize == 0) + { + return false; + } + memset(factoryData, 0, sizeof(*factoryData)); ZCBOR_STATE_D(states, MAX_FACTORY_DATA_NESTING_LEVEL, buffer, bufferSize, 1); bool res = zcbor_map_start_decode(states); + updateSize(factoryData, NULL, 0); struct zcbor_string currentString; while (res) @@ -142,44 +249,56 @@ bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData if (strncmp("version", (const char *) currentString.value, currentString.len) == 0) { res = res && uint16_decode(states, &factoryData->version); + updateSize(factoryData, "version", sizeof(uint32_t)); } else if (strncmp("hw_ver", (const char *) currentString.value, currentString.len) == 0) { res = res && uint16_decode(states, &factoryData->hw_ver); factoryData->hwVerPresent = res; + updateSize(factoryData, "hw_ver", sizeof(uint32_t)); } else if (strncmp("spake2_it", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_uint32_decode(states, &factoryData->spake2_it); + updateSize(factoryData, "spake2_it", sizeof(uint32_t)); } else if (strncmp("vendor_id", (const char *) currentString.value, currentString.len) == 0) { res = res && uint16_decode(states, &factoryData->vendor_id); factoryData->vendorIdPresent = res; + updateSize(factoryData, "vendor_id", sizeof(uint32_t)); } else if (strncmp("product_id", (const char *) currentString.value, currentString.len) == 0) { res = res && uint16_decode(states, &factoryData->product_id); factoryData->productIdPresent = res; + updateSize(factoryData, "product_id", sizeof(uint32_t)); } else if (strncmp("discriminator", (const char *) currentString.value, currentString.len) == 0) { res = res && uint16_decode(states, &factoryData->discriminator); factoryData->discriminatorPresent = res; + updateSize(factoryData, "discriminator", sizeof(uint32_t)); } else if (strncmp("passcode", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_uint32_decode(states, &factoryData->passcode); + + updateSize(factoryData, "passcode", sizeof(uint32_t)); } else if (strncmp("sn", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->sn); + updateSize(factoryData, "sn", factoryData->sn.len); } else if (strncmp("date", (const char *) currentString.value, currentString.len) == 0) { // Date format is YYYY-MM-DD, so format needs to be validated and string parse to integer parts. struct zcbor_string date; res = res && zcbor_bstr_decode(states, &date); + updateSize(factoryData, "date", factoryData->date.len); + factoryData->date.data = (void *) date.value; + factoryData->date.len = date.len; if (date.len == 10 && isdigit(date.value[0]) && isdigit(date.value[1]) && isdigit(date.value[2]) && isdigit(date.value[3]) && date.value[4] == '-' && isdigit(date.value[5]) && isdigit(date.value[6]) && date.value[7] == '-' && isdigit(date.value[8]) && isdigit(date.value[9])) @@ -198,70 +317,88 @@ bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData else if (strncmp("hw_ver_str", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->hw_ver_str); + updateSize(factoryData, "hw_ver_str", factoryData->hw_ver_str.len); } else if (strncmp("rd_uid", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->rd_uid); + updateSize(factoryData, "rd_uid", factoryData->rd_uid.len); } else if (strncmp("dac_cert", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_cert); + updateSize(factoryData, "dac_cert", factoryData->dac_cert.len); } else if (strncmp("dac_key", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_priv_key); + updateSize(factoryData, "dac_key", factoryData->dac_priv_key.len); + factoryData->dacPrivateKeyPresent = true; } else if (strncmp("pai_cert", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->pai_cert); + updateSize(factoryData, "pai_cert", factoryData->pai_cert.len); } else if (strncmp("spake2_salt", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_salt); + updateSize(factoryData, "spake2_salt", factoryData->spake2_salt.len); } else if (strncmp("spake2_verifier", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_verifier); + updateSize(factoryData, "spake2_verifier", factoryData->spake2_verifier.len); } else if (strncmp("vendor_name", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->vendor_name); + updateSize(factoryData, "vendor_name", factoryData->vendor_name.len); } else if (strncmp("product_name", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_name); + updateSize(factoryData, "product_name", factoryData->product_name.len); } else if (strncmp("part_number", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->part_number); + updateSize(factoryData, "part_number", factoryData->part_number.len); } else if (strncmp("product_url", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_url); + updateSize(factoryData, "product_url", factoryData->product_url.len); } else if (strncmp("product_label", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_label); + updateSize(factoryData, "product_label", factoryData->product_label.len); } else if (strncmp("enable_key", (const char *) currentString.value, currentString.len) == 0) { res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->enable_key); + updateSize(factoryData, "enable_key", factoryData->enable_key.len); } else if (strncmp("product_finish", (const char *) currentString.value, currentString.len) == 0) { res = res && uint8_decode(states, &factoryData->product_finish); factoryData->productFinishPresent = res; + updateSize(factoryData, "product_finish", sizeof(uint32_t)); } else if (strncmp("primary_color", (const char *) currentString.value, currentString.len) == 0) { res = res && uint8_decode(states, &factoryData->primary_color); factoryData->primaryColorPresent = res; + updateSize(factoryData, "primary_color", sizeof(uint32_t)); } else if (strncmp("user", (const char *) currentString.value, currentString.len) == 0) { factoryData->user.data = (void *) states->payload; res = res && zcbor_any_skip(states, NULL); factoryData->user.len = (size_t) ((void *) states->payload - factoryData->user.data); + updateSize(factoryData, "user", factoryData->user.len); + factoryData->userDataPresent = true; } else { diff --git a/src/platform/nrfconnect/FactoryDataParser.h b/src/platform/nrfconnect/FactoryDataParser.h index 54be7b80b8..ab3ad12233 100644 --- a/src/platform/nrfconnect/FactoryDataParser.h +++ b/src/platform/nrfconnect/FactoryDataParser.h @@ -35,6 +35,7 @@ struct FactoryData { uint16_t version; struct FactoryDataString sn; + struct FactoryDataString date; uint16_t date_year; uint8_t date_month; uint8_t date_day; @@ -66,8 +67,24 @@ struct FactoryData bool discriminatorPresent; bool productFinishPresent; bool primaryColorPresent; + bool userDataPresent; + bool dacPrivateKeyPresent; + size_t actualSize; }; +/** + * @brief Serialize the new factory data set to binary CBOR format. + * + * Serialized data will not contain DAC private key + * + * @param factoryDataBuff buffer to store serialized factory data set + * @param factoryDataSize size of the output buffer + * @param factoryData reference pointer to the existing factory data set + * @return true if the factory data set was serialized successfully + * @return false if the error occurred, for example the output buffer size was to small. + */ +bool SerializeFactoryData(uint8_t * factoryDataBuff, size_t factoryDataSize, const struct FactoryData * factoryData); + /** * @brief Parses raw factory data into the factory data structure. * diff --git a/src/platform/nrfconnect/FactoryDataProvider.cpp b/src/platform/nrfconnect/FactoryDataProvider.cpp index caa1ad434f..4b994e56e0 100644 --- a/src/platform/nrfconnect/FactoryDataProvider.cpp +++ b/src/platform/nrfconnect/FactoryDataProvider.cpp @@ -24,7 +24,15 @@ #include #endif -#include +#include + +#ifdef CONFIG_CHIP_CRYPTO_PSA +#include +#include +#include + +static const struct device * const flash_dev = DEVICE_DT_GET_OR_NULL(DT_CHOSEN(zephyr_flash_controller)); +#endif namespace chip { namespace { @@ -59,21 +67,7 @@ CHIP_ERROR FactoryDataProvider::Init() uint8_t * factoryData = nullptr; size_t factoryDataSize; - CHIP_ERROR error = mFlashFactoryData.ProtectFactoryDataPartitionAgainstWrite(); - - // Protection against write for external storage is not supported. - if (error == CHIP_ERROR_NOT_IMPLEMENTED) - { - ChipLogProgress(DeviceLayer, "The device does not support hardware protection against write."); - error = CHIP_NO_ERROR; - } - else if (error != CHIP_NO_ERROR) - { - ChipLogError(DeviceLayer, "Failed to protect the factory data partition."); - return error; - } - - error = mFlashFactoryData.GetFactoryDataPartition(factoryData, factoryDataSize); + CHIP_ERROR error = mFlashFactoryData.GetFactoryDataPartition(factoryData, factoryDataSize); if (error != CHIP_NO_ERROR) { @@ -95,9 +89,90 @@ CHIP_ERROR FactoryDataProvider::Init() return CHIP_ERROR_VERSION_MISMATCH; } +#ifdef CONFIG_CHIP_CRYPTO_PSA + VerifyOrDie(MoveDACPrivateKeyToSecureStorage(factoryData, factoryDataSize) == CHIP_NO_ERROR); +#endif + + error = mFlashFactoryData.ProtectFactoryDataPartitionAgainstWrite(); + + // Protection against write for external storage is not supported. + if (error == CHIP_ERROR_NOT_IMPLEMENTED) + { + ChipLogProgress(DeviceLayer, "The device does not support hardware protection against write."); + error = CHIP_NO_ERROR; + } + else if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to protect the factory data partition."); + return error; + } + return CHIP_NO_ERROR; } +#ifdef CONFIG_CHIP_CRYPTO_PSA +template +CHIP_ERROR FactoryDataProvider::MoveDACPrivateKeyToSecureStorage(uint8_t * factoryDataPartition, + size_t factoryDataSize) +{ + + CHIP_ERROR err = CHIP_NO_ERROR; + void * factoryDataBuff = nullptr; + + // Check if factory data contains DAC private key + if (mFactoryData.dacPrivateKeyPresent) + { + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + // If there is the new DAC private key present in the factory data set and also there is + // the existing one in ITS NVM storage, then it is a security violation + // TODO: Consider other reactions to this violation: blocking the application, factory reset, etc. + if (psa_get_key_attributes(mDACPrivKeyId, &attributes) != PSA_SUCCESS) + { + ChipLogDetail(DeviceLayer, "Found DAC Private Key in factory data set. Copying to ITS..."); + + psa_reset_key_attributes(&attributes); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, kDACPrivateKeyLength * 8); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&attributes, mDACPrivKeyId); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE); + + VerifyOrExit(psa_import_key(&attributes, reinterpret_cast(mFactoryData.dac_priv_key.data), + kDACPrivateKeyLength, &mDACPrivKeyId) == PSA_SUCCESS, + err = CHIP_ERROR_INTERNAL); + } + + memset(mFactoryData.dac_priv_key.data, 0xff, mFactoryData.dac_priv_key.len); + mFactoryData.dacPrivateKeyPresent = false; + + // Allocate needed memory space to perform removal and moving DAC private key + size_t alignedSize = mFactoryData.actualSize + (sizeof(uint32_t) - (mFactoryData.actualSize % sizeof(uint32_t))); + factoryDataBuff = chip::DeviceLayer::Malloc::Calloc(alignedSize, sizeof(uint8_t)); + + if (!factoryDataBuff) + { + ChipLogError(DeviceLayer, "Could not allocate memory for removing DAC private key!"); + return CHIP_ERROR_NO_MEMORY; + } + + VerifyOrExit(SerializeFactoryData(reinterpret_cast(factoryDataBuff), mFactoryData.actualSize, &mFactoryData), + err = CHIP_ERROR_INTERNAL); + + // Replace the old factory data set with the new one. + VerifyOrExit(0 == flash_erase(flash_dev, PM_FACTORY_DATA_ADDRESS, factoryDataSize), err = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(0 == flash_write(flash_dev, PM_FACTORY_DATA_ADDRESS, factoryDataBuff, alignedSize), err = CHIP_ERROR_INTERNAL); + + VerifyOrExit(ParseFactoryData(factoryDataPartition, static_cast(factoryDataSize), &mFactoryData), + err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + } + +exit: + chip::DeviceLayer::Malloc::Free(factoryDataBuff); + return err; +} +#endif + template CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & outBuffer) { @@ -160,8 +235,18 @@ CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(c VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); ReturnErrorCodeIf(!mFactoryData.dac_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); - ReturnErrorCodeIf(!mFactoryData.dac_priv_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); +#ifdef CONFIG_CHIP_CRYPTO_PSA + size_t outputLen = 0; + + psa_status_t err = psa_sign_message(mDACPrivKeyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), messageToSign.data(), messageToSign.size(), + signature.Bytes(), signature.Capacity(), &outputLen); + + VerifyOrReturnError(!err, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(outputLen == chip::Crypto::kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(signature.SetLength(outputLen)); +#else + ReturnErrorCodeIf(!mFactoryData.dac_priv_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); // Extract public key from DAC cert. ByteSpan dacCertSpan{ reinterpret_cast(mFactoryData.dac_cert.data), mFactoryData.dac_cert.len }; chip::Crypto::P256PublicKey dacPublicKey; @@ -171,6 +256,7 @@ CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(c LoadKeypairFromRaw(ByteSpan(reinterpret_cast(mFactoryData.dac_priv_key.data), mFactoryData.dac_priv_key.len), ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature)); +#endif return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); } diff --git a/src/platform/nrfconnect/FactoryDataProvider.h b/src/platform/nrfconnect/FactoryDataProvider.h index 15dae3ab7e..04d8f5f90a 100644 --- a/src/platform/nrfconnect/FactoryDataProvider.h +++ b/src/platform/nrfconnect/FactoryDataProvider.h @@ -21,6 +21,10 @@ #include #include +#ifdef CONFIG_CHIP_CRYPTO_PSA +#include +#endif + #include #include #include @@ -109,6 +113,10 @@ class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentia { public: CHIP_ERROR Init(); +#ifdef CONFIG_CHIP_CRYPTO_PSA + CHIP_ERROR MoveDACPrivateKeyToSecureStorage(uint8_t * factoryDataPartition, size_t factoryDataSize); + CHIP_ERROR ImportDACPrivateKey(); +#endif // ===== Members functions that implement the DeviceAttestationCredentialsProvider CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & outBuffer) override; @@ -175,6 +183,9 @@ class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentia struct FactoryData mFactoryData; FlashFactoryData mFlashFactoryData; +#ifdef CONFIG_CHIP_CRYPTO_PSA + psa_key_id_t mDACPrivKeyId = static_cast(static_cast(chip::Crypto::KeyIdBase::Maximum) + 1); +#endif }; } // namespace DeviceLayer