blob: 764e3f6ac48300c650e5f1b8fa00e5e72706eb15 [file] [log] [blame]
/*
*
* Copyright (c) 2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fsl_adapter_flash.h"
#include <platform/nxp/k32w/k32w1/FactoryDataProviderImpl.h>
namespace chip {
namespace DeviceLayer {
#if !CHIP_USE_PLAIN_DAC_KEY
// SSS adds 24 bytes of metadata when creating the blob
static constexpr size_t kSssBlobMetadataLength = 24;
static constexpr size_t kPrivateKeyBlobLength = Crypto::kP256_PrivateKey_Length + kSssBlobMetadataLength;
#endif
FactoryDataProviderImpl::~FactoryDataProviderImpl()
{
#if !CHIP_USE_PLAIN_DAC_KEY
SSS_KEY_OBJ_FREE(&mContext);
#endif
}
CHIP_ERROR FactoryDataProviderImpl::Init()
{
CHIP_ERROR error = CHIP_NO_ERROR;
#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST && !CHIP_USE_PLAIN_DAC_KEY
SSS_RunApiTest();
#endif
error = Validate();
if (error != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Factory data init failed with: %s", ErrorStr(error));
}
#if !CHIP_USE_PLAIN_DAC_KEY
ReturnErrorOnFailure(SSS_InitContext());
ReturnErrorOnFailure(SSS_ConvertDacKey());
ReturnErrorOnFailure(SSS_ImportPrivateKeyBlob());
#endif
return error;
}
#if CHIP_USE_PLAIN_DAC_KEY
CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer)
{
CHIP_ERROR error = CHIP_NO_ERROR;
Crypto::P256ECDSASignature signature;
Crypto::P256Keypair keypair;
Crypto::P256SerializedKeypair serializedKeypair;
uint8_t keyBuf[Crypto::kP256_PrivateKey_Length];
MutableByteSpan dacPrivateKeySpan(keyBuf);
uint16_t keySize = 0;
VerifyOrExit(!outSignBuffer.empty(), error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(!messageToSign.empty(), error = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(outSignBuffer.size() >= signature.Capacity(), error = CHIP_ERROR_BUFFER_TOO_SMALL);
/* Get private key of DAC certificate from reserved section */
error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize);
SuccessOrExit(error);
dacPrivateKeySpan.reduce_size(keySize);
VerifyOrExit(keySize == Crypto::kP256_PrivateKey_Length, error = CHIP_ERROR_WRONG_KEY_TYPE);
/* Only the private key is used when signing */
error = serializedKeypair.SetLength(Crypto::kP256_PublicKey_Length + dacPrivateKeySpan.size());
SuccessOrExit(error);
memcpy(serializedKeypair.Bytes() + Crypto::kP256_PublicKey_Length, dacPrivateKeySpan.data(), dacPrivateKeySpan.size());
error = keypair.Deserialize(serializedKeypair);
SuccessOrExit(error);
error = keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature);
SuccessOrExit(error);
error = CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer);
exit:
/* Sanitize temporary buffer */
memset(keyBuf, 0, Crypto::kP256_PrivateKey_Length);
return error;
}
#else
CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer)
{
Crypto::P256ECDSASignature signature;
VerifyOrReturnError(IsSpanUsable(outSignBuffer), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(IsSpanUsable(messageToSign), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL);
VerifyOrReturnError(messageToSign.data() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(messageToSign.size() > 0, CHIP_ERROR_INVALID_ARGUMENT);
uint8_t digest[Crypto::kSHA256_Hash_Length];
memset(&digest[0], 0, sizeof(digest));
ReturnErrorOnFailure(Crypto::Hash_SHA256(messageToSign.data(), messageToSign.size(), digest));
ReturnErrorOnFailure(SSS_Sign(digest, signature));
return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer);
}
CHIP_ERROR FactoryDataProviderImpl::SSS_InitContext()
{
auto res = sss_sscp_key_object_init(&mContext, &g_keyStore);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
res = sss_sscp_key_object_allocate_handle(&mContext, 0x0u, kSSS_KeyPart_Private, kSSS_CipherType_EC_NIST_P,
Crypto::kP256_PrivateKey_Length, SSS_KEYPROP_OPERATION_ASYM);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR FactoryDataProviderImpl::SSS_ImportPrivateKeyBlob()
{
uint8_t blob[kPrivateKeyBlobLength] = { 0 };
uint16_t blobSize = 0;
ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, blob, kPrivateKeyBlobLength, blobSize));
auto res = sss_sscp_key_store_import_key(&g_keyStore, &mContext, blob, kPrivateKeyBlobLength, kPrivateKeyBlobLength * 8,
kSSS_blobType_ELKE_blob);
VerifyOrReturnError(res == kStatus_SSS_Success, CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
}
CHIP_ERROR FactoryDataProviderImpl::SSS_Sign(uint8_t * digest, Crypto::P256ECDSASignature & signature)
{
CHIP_ERROR error = CHIP_NO_ERROR;
size_t signatureSize = Crypto::kP256_ECDSA_Signature_Length_Raw;
sss_status_t res = kStatus_SSS_Fail;
sss_sscp_asymmetric_t asyc;
res = sss_sscp_asymmetric_context_init(&asyc, &g_sssSession, &mContext, kAlgorithm_SSS_ECDSA_SHA256, kMode_SSS_Sign);
VerifyOrExit(res == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL);
res = sss_sscp_asymmetric_sign_digest(&asyc, digest, Crypto::kP256_PrivateKey_Length, signature.Bytes(), &signatureSize);
VerifyOrExit(res == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL);
signature.SetLength(signatureSize);
exit:
sss_sscp_asymmetric_context_free(&asyc);
return error;
}
CHIP_ERROR FactoryDataProviderImpl::SSS_ConvertDacKey()
{
size_t blobSize = kPrivateKeyBlobLength;
size_t newSize = sizeof(FactoryDataProvider::Header) + mHeader.size + kSssBlobMetadataLength;
uint8_t blob[kPrivateKeyBlobLength] = { 0 };
uint8_t * data = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(newSize));
uint32_t offset = 0;
bool convNeeded = true;
VerifyOrReturnError(data != nullptr, CHIP_ERROR_INTERNAL);
ReturnErrorOnFailure(SSS_ExportBlob(blob, &blobSize, offset, convNeeded));
if (!convNeeded)
{
ChipLogError(DeviceLayer, "SSS: DAC private key already converted to blob");
chip::Platform::MemoryFree(data);
return CHIP_NO_ERROR;
}
ChipLogError(DeviceLayer, "SSS: extracted blob from DAC private key");
hal_flash_status_t status = HAL_FlashRead(kFactoryDataStart, newSize - kSssBlobMetadataLength, data);
VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL);
ChipLogError(DeviceLayer, "SSS: cached factory data in RAM");
ReturnErrorOnFailure(ReplaceWithBlob(data, blob, blobSize, offset));
ChipLogError(DeviceLayer, "SSS: replaced DAC private key with secured blob");
status = HAL_FlashEraseSector(kFactoryDataStart, kFactoryDataSize);
VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL);
status = HAL_FlashProgramUnaligned(kFactoryDataStart, newSize, data);
VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL);
ChipLogError(DeviceLayer, "SSS: updated factory data");
memset(data, 0, newSize);
chip::Platform::MemoryFree(data);
ChipLogError(DeviceLayer, "SSS: sanitized RAM cache");
ReturnErrorOnFailure(Validate());
return CHIP_NO_ERROR;
}
CHIP_ERROR FactoryDataProviderImpl::SSS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset, bool & isNeeded)
{
CHIP_ERROR error = CHIP_NO_ERROR;
auto res = kStatus_SSS_Success;
uint8_t keyBuf[kPrivateKeyBlobLength];
MutableByteSpan dacPrivateKeySpan(keyBuf);
uint16_t keySize = 0;
isNeeded = true;
error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize, &offset);
SuccessOrExit(error);
dacPrivateKeySpan.reduce_size(keySize);
if (keySize == kPrivateKeyBlobLength)
{
isNeeded = false;
return CHIP_NO_ERROR;
}
res = SSS_KEY_STORE_SET_KEY(&mContext, dacPrivateKeySpan.data(), Crypto::kP256_PrivateKey_Length, keySize * 8,
kSSS_KeyPart_Private);
VerifyOrExit(res == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL);
res = sss_sscp_key_store_export_key(&g_keyStore, &mContext, data, dataLen, kSSS_blobType_ELKE_blob);
VerifyOrExit(res == kStatus_SSS_Success, error = CHIP_ERROR_INTERNAL);
exit:
/* Sanitize temporary buffer */
memset(keyBuf, 0, Crypto::kP256_PrivateKey_Length);
return error;
}
CHIP_ERROR FactoryDataProviderImpl::ReplaceWithBlob(uint8_t * data, uint8_t * blob, size_t blobLen, uint32_t offset)
{
size_t newSize = mHeader.size + kSssBlobMetadataLength;
FactoryDataProvider::Header * header = reinterpret_cast<FactoryDataProvider::Header *>(data);
uint8_t * payload = data + sizeof(FactoryDataProvider::Header);
size_t subsequentDataOffset = offset + kValueOffset + Crypto::kP256_PrivateKey_Length;
memmove(payload + subsequentDataOffset + kSssBlobMetadataLength, payload + subsequentDataOffset,
mHeader.size - subsequentDataOffset);
header->size = newSize;
memcpy(payload + offset + kLengthOffset, (uint16_t *) &blobLen, sizeof(uint16_t));
memcpy(payload + offset + kValueOffset, blob, blobLen);
uint8_t hash[Crypto::kSHA256_Hash_Length] = { 0 };
ReturnErrorOnFailure(Crypto::Hash_SHA256(payload, header->size, hash));
memcpy(header->hash, hash, sizeof(header->hash));
return CHIP_NO_ERROR;
}
#if CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST
#define _assert(condition) \
if (!condition) \
{ \
ChipLogError(DeviceLayer, "Condition failed" #condition); \
while (1) \
; \
}
void FactoryDataProviderImpl::SSS_RunApiTest()
{
uint8_t privateKey[Crypto::kP256_PrivateKey_Length] = { 0x18, 0xfe, 0x9a, 0xd9, 0x30, 0xdd, 0x2f, 0x62, 0xbe, 0x99, 0x43,
0x93, 0xe8, 0xbe, 0x47, 0x28, 0x7f, 0xda, 0x5a, 0x71, 0x86, 0x1b,
0x0e, 0x3f, 0x91, 0x27, 0x52, 0xd0, 0xba, 0xa7, 0x40, 0x02 };
auto error = SSS_InitContext();
_assert((error == CHIP_NO_ERROR));
// Simulate factory data in RAM: create the header + dummy data + DAC private key entry + dummy data
uint8_t type = FactoryDataProvider::FactoryDataId::kDacPrivateKeyId;
uint8_t dummyType = FactoryDataProvider::FactoryDataId::kProductLabel;
uint16_t length = Crypto::kP256_PrivateKey_Length;
uint16_t dummyLength = 3;
uint32_t numberOfDummies = 10;
uint32_t dummySize = numberOfDummies * (sizeof(dummyType) + sizeof(dummyLength) + dummyLength);
uint32_t size =
sizeof(FactoryDataProvider::Header) + dummySize + sizeof(type) + sizeof(length) + kPrivateKeyBlobLength + dummySize;
uint8_t dummyData[3] = { 0xab };
uint8_t hash[Crypto::kSHA256_Hash_Length] = { 0 };
mHeader.hashId = FactoryDataProvider::kHashId;
mHeader.size = size - sizeof(FactoryDataProvider::Header);
mHeader.hash[0] = 0xde;
mHeader.hash[1] = 0xad;
mHeader.hash[2] = 0xbe;
mHeader.hash[3] = 0xef;
uint8_t * factoryData = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(size));
_assert((factoryData != nullptr));
uint8_t * entry = factoryData + sizeof(mHeader);
for (auto i = 0; i < numberOfDummies; i++)
{
memcpy(entry, (void *) &dummyType, sizeof(dummyType));
entry += sizeof(type);
memcpy(entry, (void *) &dummyLength, sizeof(dummyLength));
entry += sizeof(length);
memcpy(entry, dummyData, dummyLength);
entry += dummyLength;
}
memcpy(entry, (void *) &type, sizeof(type));
entry += sizeof(type);
memcpy(entry, (void *) &length, sizeof(length));
entry += sizeof(length);
memcpy(entry, privateKey, Crypto::kP256_PrivateKey_Length);
entry += Crypto::kP256_PrivateKey_Length;
for (auto i = 0; i < numberOfDummies; i++)
{
memcpy(entry, (void *) &dummyType, sizeof(dummyType));
entry += sizeof(type);
memcpy(entry, (void *) &dummyLength, sizeof(dummyLength));
entry += sizeof(length);
memcpy(entry, dummyData, dummyLength);
entry += dummyLength;
}
FactoryDataProvider::kFactoryDataPayloadStart = (uint32_t) factoryData + sizeof(FactoryDataProvider::Header);
uint8_t keyBuf[Crypto::kP256_PrivateKey_Length];
MutableByteSpan dacPrivateKeySpan(keyBuf);
uint16_t keySize = 0;
error = SearchForId(FactoryDataId::kCertDeclarationId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize);
_assert((error == CHIP_ERROR_NOT_FOUND));
error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize);
_assert((error == CHIP_NO_ERROR));
_assert((memcmp(dacPrivateKeySpan.data(), privateKey, Crypto::kP256_PrivateKey_Length) == 0));
size_t blobSize = kPrivateKeyBlobLength;
size_t newSize = sizeof(FactoryDataProvider::Header) + mHeader.size + kSssBlobMetadataLength;
uint8_t blob[kPrivateKeyBlobLength] = { 0 };
uint32_t offset = 0;
error = SSS_ExportBlob(blob, &blobSize, offset);
_assert((error == CHIP_NO_ERROR));
error = ReplaceWithBlob(factoryData, blob, blobSize, offset);
_assert((error == CHIP_NO_ERROR));
FactoryDataProvider::Header * header = reinterpret_cast<FactoryDataProvider::Header *>(factoryData);
_assert((header->size == (mHeader.size + kSssBlobMetadataLength)));
_assert((header->hash[0] != 0xde));
_assert((header->hash[1] != 0xad));
_assert((header->hash[2] != 0xbe));
_assert((header->hash[3] != 0xef));
memset(factoryData, 0, size);
chip::Platform::MemoryFree(factoryData);
FactoryDataProvider::kFactoryDataPayloadStart = FactoryDataProvider::kFactoryDataStart + sizeof(FactoryDataProvider::Header);
SSS_KEY_OBJ_FREE(&mContext);
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_SSS_API_TEST
#endif // CHIP_USE_PLAIN_DAC_KEY
} // namespace DeviceLayer
} // namespace chip