| /* |
| * |
| * Copyright (c) 2024 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. |
| */ |
| |
| /* -------------------------------------------------------------------------- */ |
| /* Includes */ |
| /* -------------------------------------------------------------------------- */ |
| |
| #include "FactoryDataProviderImpl.h" |
| |
| /* mbedtls */ |
| #include "mbedtls/aes.h" |
| #include "mbedtls/sha256.h" |
| |
| /* -------------------------------------------------------------------------- */ |
| /* Private macros */ |
| /* -------------------------------------------------------------------------- */ |
| |
| #define HASH_ID 0xCE47BA5E |
| |
| /* -------------------------------------------------------------------------- */ |
| /* Class implementation */ |
| /* -------------------------------------------------------------------------- */ |
| |
| namespace chip { |
| namespace DeviceLayer { |
| |
| FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; |
| |
| CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, |
| uint32_t * contentAddr) |
| { |
| CHIP_ERROR err = CHIP_ERROR_NOT_FOUND; |
| uint8_t type = 0; |
| uint32_t index = 0; |
| uint8_t * factoryDataAddress = &mFactoryData.factoryDataBuffer[0]; |
| uint32_t factoryDataSize = sizeof(mFactoryData.factoryDataBuffer); |
| uint16_t currentLen = 0; |
| |
| while (index < factoryDataSize) |
| { |
| /* Read the type */ |
| memcpy((uint8_t *) &type, factoryDataAddress + index, sizeof(type)); |
| index += sizeof(type); |
| |
| /* Read the len */ |
| memcpy((uint8_t *) ¤tLen, factoryDataAddress + index, sizeof(currentLen)); |
| index += sizeof(currentLen); |
| |
| /* Check if the type gotten is the expected one */ |
| if (searchedType == type) |
| { |
| /* If pBuf is null it means that we only want to know if the Type has been found */ |
| if (pBuf != NULL) |
| { |
| /* If the buffer given is too small, fill only the available space */ |
| if (bufLength < currentLen) |
| { |
| currentLen = (uint16_t) bufLength; |
| } |
| memcpy((uint8_t *) pBuf, factoryDataAddress + index, currentLen); |
| } |
| length = (uint16_t) currentLen; |
| if (contentAddr != NULL) |
| { |
| *contentAddr = (uint32_t) factoryDataAddress + index; |
| } |
| err = CHIP_NO_ERROR; |
| break; |
| } |
| else if (type == 0) |
| { |
| /* No more type available , break the loop */ |
| break; |
| } |
| else |
| { |
| /* Jump to next data */ |
| index += currentLen; |
| } |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) |
| { |
| Crypto::P256ECDSASignature signature; |
| Crypto::P256Keypair keypair; |
| |
| VerifyOrReturnError(IsSpanUsable(outSignBuffer), CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(IsSpanUsable(digestToSign), CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); |
| |
| // In a non-exemplary implementation, the public key is not needed here. It is used here merely because |
| // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. |
| Crypto::P256PublicKey dacPublicKey; |
| uint16_t certificateSize = 0; |
| uint32_t certificateAddr; |
| ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, NULL, 0, certificateSize, &certificateAddr)); |
| MutableByteSpan dacCertSpan((uint8_t *) certificateAddr, certificateSize); |
| |
| /* Extract Public Key of DAC certificate from itself */ |
| ReturnErrorOnFailure(Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); |
| |
| /* Get private key of DAC certificate from reserved section */ |
| uint16_t keySize = 0; |
| uint32_t keyAddr; |
| ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, keySize, &keyAddr)); |
| MutableByteSpan dacPrivateKeySpan((uint8_t *) keyAddr, keySize); |
| |
| ReturnErrorOnFailure(LoadKeypairFromRaw(ByteSpan(dacPrivateKeySpan.data(), dacPrivateKeySpan.size()), |
| ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); |
| |
| ReturnErrorOnFailure(keypair.ECDSA_sign_msg(digestToSign.data(), digestToSign.size(), signature)); |
| |
| return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair) |
| { |
| Crypto::P256SerializedKeypair serialized_keypair; |
| ReturnErrorOnFailure(serialized_keypair.SetLength(privateKey.size() + publicKey.size())); |
| memcpy(serialized_keypair.Bytes(), publicKey.data(), publicKey.size()); |
| memcpy(serialized_keypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); |
| return keypair.Deserialize(serialized_keypair); |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::Init(void) |
| { |
| int ret; |
| CHIP_ERROR res; |
| const struct device * flashDevice; |
| uint8_t currentBlock[16]; |
| off_t factoryDataOffset = FIXED_PARTITION_OFFSET(factory_partition); |
| |
| flashDevice = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); |
| |
| /* Read the factory data header from flash */ |
| ret = flash_read(flashDevice, factoryDataOffset, (void *) &mFactoryData, sizeof(FactoryDataProviderImpl::Header)); |
| if (ret != 0) |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| /* Check ID is valid */ |
| if (mFactoryData.header.hashId != HASH_ID) |
| { |
| return CHIP_ERROR_NOT_FOUND; |
| } |
| |
| // TODO: add HASH compute + check |
| |
| factoryDataOffset += sizeof(FactoryDataProviderImpl::Header); |
| |
| /* Load the buffer into RAM by reading each 16 bytes blocks */ |
| for (int i = 0; (uint32_t) i < (mFactoryData.header.size / 16U); i++) |
| { |
| ret = flash_read(flashDevice, factoryDataOffset + i * 16, (void *) ¤tBlock[0], sizeof(currentBlock)); |
| if (ret != 0) |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| if (pAes128Key != NULL) |
| { |
| /* Decrypt data if a key has been set */ |
| res = ReadEncryptedData(&mFactoryData.factoryDataBuffer[i * 16], ¤tBlock[0]); |
| if (res != CHIP_NO_ERROR) |
| { |
| return res; |
| } |
| } |
| else |
| { |
| /* No key was set, copy the data as is */ |
| memcpy(&mFactoryData.factoryDataBuffer[i * 16], ¤tBlock[0], sizeof(currentBlock)); |
| } |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::SetAes128Key(const uint8_t * keyAes128) |
| { |
| CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; |
| if (keyAes128 != nullptr) |
| { |
| pAes128Key = keyAes128; |
| error = CHIP_NO_ERROR; |
| } |
| return error; |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::SetEncryptionMode(EncryptionMode mode) |
| { |
| CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; |
| |
| /* |
| * Currently the fwk_factory_data_provider module supports only ecb mode. |
| * Therefore return an error if encrypt mode is not ecb |
| */ |
| if (mode == encrypt_ecb) |
| { |
| encryptMode = mode; |
| error = CHIP_NO_ERROR; |
| } |
| return error; |
| } |
| |
| CHIP_ERROR FactoryDataProviderImpl::ReadEncryptedData(uint8_t * dest, uint8_t * source) |
| { |
| mbedtls_aes_context aesCtx; |
| |
| mbedtls_aes_init(&aesCtx); |
| |
| if (mbedtls_aes_setkey_dec(&aesCtx, pAes128Key, 128U) != 0) |
| { |
| return CHIP_ERROR_INTERNAL; |
| } |
| |
| if (mbedtls_aes_crypt_ecb(&aesCtx, MBEDTLS_AES_DECRYPT, source, dest) != 0) |
| { |
| return CHIP_ERROR_INTERNAL; |
| } |
| |
| mbedtls_aes_free(&aesCtx); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| } // namespace DeviceLayer |
| } // namespace chip |