diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp index 3af39b6c45e95d..633353b6ee7bd0 100644 --- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp +++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp @@ -552,10 +552,7 @@ bool emberAfOperationalCredentialsClusterAttestationRequestCallback(app::Command // TODO: retrieve vendor information to populate the fields below. uint32_t timestamp = 0; ByteSpan firmwareInfo; - ByteSpan * vendorReservedArray = nullptr; - size_t vendorReservedArraySize = 0; - uint16_t vendorId = 0; - uint16_t profileNum = 0; + Credentials::DeviceAttestationVendorReservedConstructor emptyVendorReserved(nullptr, 0); SuccessOrExit(err = dacProvider->GetCertificationDeclaration(certDeclSpan)); // TODO: Retrieve firmware Information @@ -565,8 +562,7 @@ bool emberAfOperationalCredentialsClusterAttestationRequestCallback(app::Command MutableByteSpan attestationElementsSpan(attestationElements.Get(), attestationElementsLen); SuccessOrExit(err = Credentials::ConstructAttestationElements(certDeclSpan, attestationNonce, timestamp, firmwareInfo, - vendorReservedArray, vendorReservedArraySize, vendorId, - profileNum, attestationElementsSpan)); + emptyVendorReserved, attestationElementsSpan)); attestationElementsLen = attestationElementsSpan.size(); } diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index fa9335993eac9c..c4790e9f3d0235 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -29,6 +29,7 @@ static_library("credentials") { "DeviceAttestationConstructor.h", "DeviceAttestationCredsProvider.cpp", "DeviceAttestationCredsProvider.h", + "DeviceAttestationVendorReserved.h", "DeviceAttestationVerifier.cpp", "DeviceAttestationVerifier.h", "GenerateChipX509Cert.cpp", diff --git a/src/credentials/DeviceAttestationConstructor.cpp b/src/credentials/DeviceAttestationConstructor.cpp index 447ff61a5a1576..eb206f2f56aa43 100644 --- a/src/credentials/DeviceAttestationConstructor.cpp +++ b/src/credentials/DeviceAttestationConstructor.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ #include "DeviceAttestationConstructor.h" +#include "DeviceAttestationVendorReserved.h" #include #include @@ -34,16 +35,40 @@ enum : uint32_t kFirmwareInfoTagId = 4, }; +// utility to determine number of Vendor Reserved elements in a bytespan +CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numOfElements) +{ + TLV::ContiguousBufferTLVReader tlvReader; + TLV::TLVType containerType = TLV::kTLVType_Structure; + + tlvReader.Init(attestationElements); + ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag)); + ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); + + size_t count = 0; + CHIP_ERROR error; + while ((error = tlvReader.Next()) == CHIP_NO_ERROR) + { + uint64_t tag = tlvReader.GetTag(); + if (TLV::IsProfileTag(tag)) + { + count++; + } + } + VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error); + + numOfElements = count; + return CHIP_NO_ERROR; +} + CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration, ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, - ByteSpan * vendorReservedArray, size_t & vendorReservedArraySize, uint16_t & vendorId, - uint16_t & profileNum) + DeviceAttestationVendorReservedDeconstructor & vendorReserved) { bool certificationDeclarationExists = false; bool attestationNonceExists = false; bool timestampExists = false; bool firmwareInfoExists = false; - size_t vendorReservedIdx = 0; uint32_t lastContextTagId = UINT32_MAX; TLV::ContiguousBufferTLVReader tlvReader; TLV::TLVType containerType = TLV::kTLVType_Structure; @@ -54,99 +79,65 @@ CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag)); ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); - CHIP_ERROR error = CHIP_NO_ERROR; + CHIP_ERROR error; - // TODO: per conversation with Tennessee, shold be two consecutive loops (rather than one big - // loop, since the contextTags come before the profileTags) + // process context tags first (should be in sorted order) while ((error = tlvReader.Next()) == CHIP_NO_ERROR) { TLV::Tag tag = tlvReader.GetTag(); - if (TLV::IsContextTag(tag)) - { - switch (TLV::TagNumFromTag(tag)) - { - case kCertificationDeclarationTagId: - VerifyOrReturnError(lastContextTagId == UINT32_MAX, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - VerifyOrReturnError(certificationDeclarationExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration)); - certificationDeclarationExists = true; - break; - case kAttestationNonceTagId: - VerifyOrReturnError(lastContextTagId == kCertificationDeclarationTagId, - CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - VerifyOrReturnError(attestationNonceExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce)); - attestationNonceExists = true; - break; - case kTimestampTagId: - VerifyOrReturnError(lastContextTagId == kAttestationNonceTagId, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - VerifyOrReturnError(timestampExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - ReturnErrorOnFailure(tlvReader.Get(timestamp)); - timestampExists = true; - break; - case kFirmwareInfoTagId: - VerifyOrReturnError(lastContextTagId == kTimestampTagId, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - VerifyOrReturnError(firmwareInfoExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo)); - firmwareInfoExists = true; - break; - default: - return CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; - } - - lastContextTagId = TLV::TagNumFromTag(tag); - } - else if (TLV::IsProfileTag(tag)) - { - // vendor fields - bool seenProfile = false; - uint16_t currentVendorId; - uint16_t currentProfileNum; - - currentVendorId = TLV::VendorIdFromTag(tag); - currentProfileNum = TLV::ProfileNumFromTag(tag); - if (!seenProfile) - { - seenProfile = true; - vendorId = currentVendorId; - profileNum = currentProfileNum; - } - else - { - // TODO: do not check for this - map vendorId and profileNum to each Vendor Reserved entry - // check that vendorId and profileNum match in every Vendor Reserved entry - VerifyOrReturnError(currentVendorId == vendorId && currentProfileNum == profileNum, - CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); - } - - ByteSpan vendorReservedEntry; - ReturnErrorOnFailure(tlvReader.GetByteView(vendorReservedEntry)); - VerifyOrReturnError(vendorReservedIdx < vendorReservedArraySize, CHIP_ERROR_NO_MEMORY); - vendorReservedArray[vendorReservedIdx++] = vendorReservedEntry; - } - else + if (!TLV::IsContextTag(tag)) + break; + + switch (TLV::TagNumFromTag(tag)) { + case kCertificationDeclarationTagId: + VerifyOrReturnError(lastContextTagId == UINT32_MAX, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + VerifyOrReturnError(certificationDeclarationExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration)); + certificationDeclarationExists = true; + break; + case kAttestationNonceTagId: + VerifyOrReturnError(lastContextTagId == kCertificationDeclarationTagId, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + VerifyOrReturnError(attestationNonceExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce)); + attestationNonceExists = true; + break; + case kTimestampTagId: + VerifyOrReturnError(lastContextTagId == kAttestationNonceTagId, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + VerifyOrReturnError(timestampExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + ReturnErrorOnFailure(tlvReader.Get(timestamp)); + timestampExists = true; + break; + case kFirmwareInfoTagId: + VerifyOrReturnError(lastContextTagId == kTimestampTagId, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + VerifyOrReturnError(firmwareInfoExists == false, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo)); + firmwareInfoExists = true; + break; + default: return CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; } + + lastContextTagId = TLV::TagNumFromTag(tag); } - vendorReservedArraySize = vendorReservedIdx; + VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error); - VerifyOrReturnError(error == CHIP_END_OF_TLV, error); - VerifyOrReturnError(lastContextTagId != UINT32_MAX, CHIP_ERROR_MISSING_TLV_ELEMENT); - VerifyOrReturnError(certificationDeclarationExists && attestationNonceExists && timestampExists, + VerifyOrReturnError(lastContextTagId == kTimestampTagId || lastContextTagId == kFirmwareInfoTagId, CHIP_ERROR_MISSING_TLV_ELEMENT); + size_t count = 0; + ReturnErrorOnFailure(CountVendorReservedElementsInDA(attestationElements, count)); + ReturnErrorOnFailure(vendorReserved.PrepareToReadVendorReservedElements(attestationElements, count)); return CHIP_NO_ERROR; } -// TODO: have independent vendorId and profileNum entries map to each vendor Reserved entry // Have a class for vendor reserved data, discussed in: // https://github.com/project-chip/connectedhomeip/issues/9825 CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, - uint32_t timestamp, const ByteSpan & firmwareInfo, ByteSpan * vendorReservedArray, - size_t vendorReservedArraySize, uint16_t vendorId, uint16_t profileNum, + uint32_t timestamp, const ByteSpan & firmwareInfo, + DeviceAttestationVendorReservedConstructor & vendorReserved, MutableByteSpan & attestationElements) { TLV::TLVWriter tlvWriter; @@ -154,10 +145,6 @@ CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaratio VerifyOrReturnError(!certificationDeclaration.empty() && !attestationNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(attestationNonce.size() == 32, CHIP_ERROR_INVALID_ARGUMENT); - if (vendorReservedArraySize != 0) - { - VerifyOrReturnError(vendorReservedArray != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - } tlvWriter.Init(attestationElements.data(), static_cast(attestationElements.size())); outerContainerType = TLV::kTLVType_NotSpecified; @@ -170,15 +157,11 @@ CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaratio ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo)); } - uint8_t vendorTagNum = 1; - for (size_t vendorReservedIdx = 0; vendorReservedIdx < vendorReservedArraySize; ++vendorReservedIdx) + const VendorReservedElement * element = vendorReserved.cbegin(); + while ((element = vendorReserved.Next()) != nullptr) { - if (!vendorReservedArray[vendorReservedIdx].empty()) - { - ReturnErrorOnFailure( - tlvWriter.Put(TLV::ProfileTag(vendorId, profileNum, vendorTagNum), vendorReservedArray[vendorReservedIdx])); - } - vendorTagNum++; + ReturnErrorOnFailure( + tlvWriter.Put(TLV::ProfileTag(element->vendorId, element->profileNum, element->tagNum), element->vendorReservedData)); } ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); diff --git a/src/credentials/DeviceAttestationConstructor.h b/src/credentials/DeviceAttestationConstructor.h index 5bde9560fd01e9..84ee02b5de38e7 100644 --- a/src/credentials/DeviceAttestationConstructor.h +++ b/src/credentials/DeviceAttestationConstructor.h @@ -16,11 +16,10 @@ */ #pragma once +#include #include #include -#include - namespace chip { namespace Credentials { @@ -34,15 +33,11 @@ namespace Credentials { * @param[out] timestamp * @param[out] firmwareInfo ByteSpan containing Firmware Information data if present within attestationElements. * Empty ByteSpan if not present in attestationElements. - * @param[out] vendorReservedArray - * @param[inout] vendorReservedArraySize - * @param[out] vendorId Vendor ID fetched from Attestation Elements data. - * @param[out] profileNum Profile Number fetched from Attestation Elements data. + * @param[out] VendorReserved Placeholder to for client to examine VendorReserved elements later */ CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration, ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, - ByteSpan * vendorReservedArray, size_t & vendorReservedArraySize, uint16_t & vendorId, - uint16_t & profileNum); + DeviceAttestationVendorReservedDeconstructor & vendorReserved); /** * @brief Take each component separately and form the Attestation Elements buffer. @@ -51,17 +46,23 @@ CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, * @param[in] attestationNonce Attestation Nonce - 32 octets required. * @param[in] timestamp Timestamp data in epoch time format. * @param[in] firmwareInfo Optional Firmware Information data - Can be empty. - * @param[in] vendorReservedArray Array of Vendor Reserved entries. - * @param[in] vendorReservedArraySize Number of Vendor Reserved entries present in the array. - * @param[in] vendorId Vendor ID to be written to Vendor Reserved entries' Qualified Tags - * @param[in] profileNum Profile Number to be written to Vendor Reserved entries' Qualified Tags + * @param[in] VendorReserved Prefilled-in vendor reserved elements to be put into DA elements. * @param[out] attestationElements Buffer used to write all AttestationElements data, formed with all the data fields above. * Provided buffer needs to be capable to handle all data fields + tags. */ CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, - uint32_t timestamp, const ByteSpan & firmwareInfo, ByteSpan * vendorReservedArray, - size_t vendorReservedArraySize, uint16_t vendorId, uint16_t profileNum, + uint32_t timestamp, const ByteSpan & firmwareInfo, + DeviceAttestationVendorReservedConstructor & vendorReserved, MutableByteSpan & attestationElements); +/*** + * @brief Count the number of VendorReservedElements in a DeviceAttestation blob + * + * @param[in] attestationElements ByeSpan conitaining source of Attestation Elements data + * @param[out] + * @returns CHIP_NO_ERROR on success + */ +CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numElements); + } // namespace Credentials } // namespace chip diff --git a/src/credentials/DeviceAttestationVendorReserved.h b/src/credentials/DeviceAttestationVendorReserved.h new file mode 100644 index 00000000000000..576ff2dfff3e22 --- /dev/null +++ b/src/credentials/DeviceAttestationVendorReserved.h @@ -0,0 +1,218 @@ +/* + * + * Copyright (c) 2021 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. + */ +#pragma once + +#include +#include +#include + +#include + +namespace chip { +namespace Credentials { + +struct VendorReservedElement +{ + uint16_t vendorId; + uint16_t profileNum; + uint32_t tagNum; + ByteSpan vendorReservedData; +}; + +// extract elements out of the device attestation bytespan +class DeviceAttestationVendorReservedDeconstructor +{ + +public: + DeviceAttestationVendorReservedDeconstructor() {} + + // read TLV until first profile tag + CHIP_ERROR PrepareToReadVendorReservedElements(const ByteSpan & attestationElements, size_t count) + { + mIsInitialized = false; + mNumVendorReservedData = count; + mAttestationData = attestationElements; + + mTlvReader.Init(mAttestationData); + ReturnErrorOnFailure(mTlvReader.Next(containerType, TLV::AnonymousTag)); + ReturnErrorOnFailure(mTlvReader.EnterContainer(containerType)); + + // position to first ProfileTag + while (true) + { + ReturnErrorOnFailure(mTlvReader.Next()); + if (!TLV::IsProfileTag(mTlvReader.GetTag())) + break; + } + // positioned to first context tag (vendor reserved data) + mIsInitialized = true; + return CHIP_NO_ERROR; + } + + size_t GetNumberOfElements() { return mNumVendorReservedData; } + + /** + * @brief Return next VendorReserved element. PrepareToReadVendorReservedElements must be called first. + * + * @param[out] element Next vendor Reserved element + * + * @returns CHIP_NO_ERROR on success + * CHIP_ERROR_INCORRECT_STATE if PrepareToReadVendorReservedElements hasn't been called first + * CHIP_END_OF_TLV if not further entries are present + */ + CHIP_ERROR GetNextVendorReservedElement(struct VendorReservedElement & element) + { + CHIP_ERROR err; + + VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE); + + while ((err = mTlvReader.Next()) == CHIP_NO_ERROR) + { + uint64_t tag = mTlvReader.GetTag(); + if (!TLV::IsProfileTag(tag)) + { + continue; + } + // tag is profile tag + element.vendorId = TLV::VendorIdFromTag(tag); + element.profileNum = TLV::ProfileNumFromTag(tag); + element.tagNum = TLV::TagNumFromTag(tag); + + return mTlvReader.GetByteView(element.vendorReservedData); + } + + return err; + } + +private: + size_t mNumVendorReservedData; // number of VendorReserved entries (could be 0) + ByteSpan mAttestationData; + bool mIsInitialized = false; + TLV::ContiguousBufferTLVReader mTlvReader; + TLV::TLVType containerType = TLV::kTLVType_Structure; +}; + +class DeviceAttestationVendorReservedConstructor +{ +public: + DeviceAttestationVendorReservedConstructor(struct VendorReservedElement * array, size_t size) : mElements(array), mMaxSize(size) + {} + + typedef const struct VendorReservedElement * const_iterator; + + const_iterator Next() + { + VerifyOrReturnError(mCurrentIndex < mNumEntriesUsed, nullptr); + return &mElements[mCurrentIndex++]; + } + + const_iterator cbegin() + { + // sort the array in place and return the head element. + do_sorting(); + mCurrentIndex = 0; + return mElements; + } + + CHIP_ERROR addVendorReservedElement(uint16_t vendorId, uint16_t profileNum, uint32_t tagNum, ByteSpan span) + { + if (mNumEntriesUsed == mMaxSize) + return CHIP_ERROR_NO_MEMORY; + + mElements[mNumEntriesUsed].tagNum = tagNum; + mElements[mNumEntriesUsed].profileNum = profileNum; + mElements[mNumEntriesUsed].vendorId = vendorId; + mElements[mNumEntriesUsed].vendorReservedData = span; + mNumEntriesUsed++; + return CHIP_NO_ERROR; + } + + size_t GetNumberOfElements() { return mNumEntriesUsed; } + +private: + /* + * Sort according to A.2.4 in the spec. + * Mark all sorted entries by setting used flag. + * Order is head to tail, sorted by next + * Executed when entries are about to be read + */ + void do_sorting() + { + size_t starting = 0; + + while (starting < mNumEntriesUsed) + { + uint32_t minVendor = UINT32_MAX; + + // find lowest vendorId + size_t i; + for (i = starting; i < mNumEntriesUsed; i++) + { + if (mElements[i].vendorId < minVendor) + { + minVendor = mElements[i].vendorId; + } + } + + uint32_t minProfile = UINT32_MAX; + // find lowest ProfileNum + for (i = starting; i < mNumEntriesUsed; i++) + { + if (mElements[i].vendorId == minVendor) + { + if (mElements[i].profileNum < minProfile) + minProfile = mElements[i].profileNum; + } + } + + // first lowest tagNum for this vendorId/profileNum + uint64_t minTagNum = UINT64_MAX; + size_t lowestIndex; + for (i = starting; i < mNumEntriesUsed; i++) + { + if (mElements[i].vendorId == minVendor && mElements[i].profileNum == minProfile) + { + if (mElements[i].tagNum < minTagNum) + { + minTagNum = mElements[i].tagNum; + lowestIndex = i; + } + } + } + + // lowestIndex is the element to move into elements[starting]. + if (lowestIndex != starting) + { + // + VendorReservedElement tmpElement; + + tmpElement = mElements[starting]; + mElements[starting] = mElements[lowestIndex]; + mElements[lowestIndex] = tmpElement; + } + starting++; + } + } + + VendorReservedElement * mElements; + size_t mMaxSize; // size of elements array + size_t mNumEntriesUsed = 0; // elements used + size_t mCurrentIndex; // iterating from [0...maxSize -1] +}; + +} // namespace Credentials +} // namespace chip diff --git a/src/credentials/examples/DeviceAttestationVerifierExample.cpp b/src/credentials/examples/DeviceAttestationVerifierExample.cpp index a2720012d628a6..43b42ed1fbc79a 100644 --- a/src/credentials/examples/DeviceAttestationVerifierExample.cpp +++ b/src/credentials/examples/DeviceAttestationVerifierExample.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -260,15 +261,10 @@ AttestationVerificationResult ExampleDACVerifier::VerifyAttestationInformation(c ByteSpan attestationNonceSpan; uint32_t timestampDeconstructed; ByteSpan firmwareInfoSpan; - // TODO: refactor once final vendor-specific data tags is handled. - ByteSpan vendorReservedDeconstructed[2]; - size_t vendorReservedDeconstructedSize = ArraySize(vendorReservedDeconstructed); - uint16_t vendorIdDeconstructed; - uint16_t profileNumDeconstructed; + DeviceAttestationVendorReservedDeconstructor vendorReserved; + VerifyOrReturnError(DeconstructAttestationElements(attestationInfoBuffer, certificationDeclarationSpan, attestationNonceSpan, - timestampDeconstructed, firmwareInfoSpan, vendorReservedDeconstructed, - vendorReservedDeconstructedSize, vendorIdDeconstructed, - profileNumDeconstructed) == CHIP_NO_ERROR, + timestampDeconstructed, firmwareInfoSpan, vendorReserved) == CHIP_NO_ERROR, AttestationVerificationResult::kAttestationElementsMalformed); // Verify that Nonce matches with what we sent diff --git a/src/credentials/tests/TestDeviceAttestationConstruction.cpp b/src/credentials/tests/TestDeviceAttestationConstruction.cpp index 3254de47d005c4..f75a183ce316b1 100644 --- a/src/credentials/tests/TestDeviceAttestationConstruction.cpp +++ b/src/credentials/tests/TestDeviceAttestationConstruction.cpp @@ -16,12 +16,14 @@ * limitations under the License. */ #include +#include #include #include #include #include #include +#include #include using namespace chip; @@ -33,54 +35,56 @@ static void TestAttestationElements_Roundtrip(nlTestSuite * inSuite, void * inCo chip::Platform::ScopedMemoryBuffer attestationElements; size_t attestationElementsLen; - uint8_t certificationDeclaration[] = { 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, - 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, - 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, - 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, - 0x28, 0x67, 0x02, 0xbd, 0x6b, 0xba, 0x48, 0xac, 0x7c, 0x83, 0x54, 0x9b, 0x68, 0x73, - 0x29, 0x47, 0x48, 0xb9, 0x51, 0xd5, 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, - 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, 0xae, 0xdf, 0x41, - 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa }; - uint8_t attestationNonce[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, - 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; - uint32_t timestamp = 677103357; - uint8_t vendorReserved1[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; - uint8_t vendorReserved3[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; - ByteSpan vendorReservedArray[] = { ByteSpan(vendorReserved1), ByteSpan(vendorReserved3) }; - uint16_t vendorId = 0xbeef; - uint16_t profileNum = 0xdead; + static constexpr uint8_t certificationDeclaration[] = { + 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, + 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, + 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, 0x28, + 0x67, 0x02, 0xbd, 0x6b, 0xba, 0x48, 0xac, 0x7c, 0x83, 0x54, 0x9b, 0x68, 0x73, 0x29, 0x47, 0x48, 0xb9, 0x51, 0xd5, + 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, + 0xae, 0xdf, 0x41, 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa + }; + static constexpr uint8_t attestationNonce[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, + 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, + 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; + static constexpr uint32_t timestamp = 677103357; + static constexpr uint8_t vendorReserved1[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; + static constexpr uint8_t vendorReserved3[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; + static constexpr uint16_t vendorId = 0xbeef; + static constexpr uint16_t profileNum = 0xdead; + VendorReservedElement vendorReservedArray[2]; + DeviceAttestationVendorReservedConstructor vendorReservedConstructor(vendorReservedArray, 2); attestationElementsLen = sizeof(certificationDeclaration) + sizeof(attestationNonce) + sizeof(timestamp) + sizeof(vendorReserved1) + sizeof(vendorReserved3) + sizeof(uint64_t) * 5; attestationElements.Alloc(attestationElementsLen); + vendorReservedConstructor.addVendorReservedElement(vendorId, profileNum, 1, ByteSpan(vendorReserved1)); + vendorReservedConstructor.addVendorReservedElement(vendorId, profileNum, 3, ByteSpan(vendorReserved3)); NL_TEST_ASSERT(inSuite, attestationElements); { MutableByteSpan attestationElementsSpan(attestationElements.Get(), attestationElementsLen); // Test wrong size nonce - err = ConstructAttestationElements( - ByteSpan(certificationDeclaration), ByteSpan(attestationNonce, sizeof(attestationNonce) - 1), timestamp, ByteSpan(), - vendorReservedArray, ArraySize(vendorReservedArray), vendorId, profileNum, attestationElementsSpan); + err = ConstructAttestationElements(ByteSpan(certificationDeclaration), + ByteSpan(attestationNonce, sizeof(attestationNonce) - 1), timestamp, ByteSpan(), + vendorReservedConstructor, attestationElementsSpan); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); // Test with missing mandatory TLV entries - err = ConstructAttestationElements(ByteSpan(), ByteSpan(attestationNonce), timestamp, ByteSpan(), vendorReservedArray, - ArraySize(vendorReservedArray), vendorId, profileNum, attestationElementsSpan); + err = ConstructAttestationElements(ByteSpan(), ByteSpan(attestationNonce), timestamp, ByteSpan(), vendorReservedConstructor, + attestationElementsSpan); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); // Test with missing mandatory TLV entries - err = - ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(), timestamp, ByteSpan(), vendorReservedArray, - ArraySize(vendorReservedArray), vendorId, profileNum, attestationElementsSpan); + err = ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(), timestamp, ByteSpan(), + vendorReservedConstructor, attestationElementsSpan); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT); // Test for success with entirely valid arguments err = ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(attestationNonce), timestamp, ByteSpan(), - vendorReservedArray, ArraySize(vendorReservedArray), vendorId, profileNum, - attestationElementsSpan); + vendorReservedConstructor, attestationElementsSpan); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); attestationElementsLen = attestationElementsSpan.size(); } @@ -89,28 +93,29 @@ static void TestAttestationElements_Roundtrip(nlTestSuite * inSuite, void * inCo ByteSpan attestationNonceSpan; uint32_t timestampDeconstructed; ByteSpan firmwareInfoSpan; - ByteSpan vendorReservedDeconstructed[2]; - size_t vendorReservedDeconstructedSize = ArraySize(vendorReservedDeconstructed); - uint16_t vendorIdDeconstructed; - uint16_t profileNumDeconstructed; + DeviceAttestationVendorReservedDeconstructor vendorReservedDeconstructor; err = DeconstructAttestationElements(ByteSpan(attestationElements.Get(), attestationElementsLen), certificationDeclarationSpan, - attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, vendorReservedDeconstructed, - vendorReservedDeconstructedSize, vendorIdDeconstructed, profileNumDeconstructed); + attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, vendorReservedDeconstructor); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, certificationDeclarationSpan.data_equal(ByteSpan(certificationDeclaration))); NL_TEST_ASSERT(inSuite, attestationNonceSpan.data_equal(ByteSpan(attestationNonce))); NL_TEST_ASSERT(inSuite, timestamp == timestampDeconstructed); NL_TEST_ASSERT(inSuite, firmwareInfoSpan.empty()); - NL_TEST_ASSERT(inSuite, ArraySize(vendorReservedArray) == ArraySize(vendorReservedDeconstructed)); - for (size_t i = 0; i < ArraySize(vendorReservedArray); ++i) + + NL_TEST_ASSERT(inSuite, vendorReservedConstructor.GetNumberOfElements() == vendorReservedDeconstructor.GetNumberOfElements()); + + const VendorReservedElement * constructionElement = vendorReservedConstructor.cbegin(); + VendorReservedElement deconstructionElement; + + while ((constructionElement = vendorReservedConstructor.Next()) != nullptr && + vendorReservedDeconstructor.GetNextVendorReservedElement(deconstructionElement) == CHIP_NO_ERROR) { - NL_TEST_ASSERT(inSuite, vendorReservedArray[i].data_equal(vendorReservedDeconstructed[i])); + NL_TEST_ASSERT(inSuite, constructionElement->vendorId == deconstructionElement.vendorId); + NL_TEST_ASSERT(inSuite, constructionElement->profileNum == deconstructionElement.profileNum); + NL_TEST_ASSERT(inSuite, constructionElement->vendorReservedData.data_equal(deconstructionElement.vendorReservedData)); } - NL_TEST_ASSERT(inSuite, vendorIdDeconstructed == vendorId); - NL_TEST_ASSERT(inSuite, profileNumDeconstructed == profileNum); } static void TestAttestationElements_Construction(nlTestSuite * inSuite, void * inContext) @@ -119,7 +124,7 @@ static void TestAttestationElements_Construction(nlTestSuite * inSuite, void * i Platform::ScopedMemoryBuffer attestationElements; size_t attestationElementsLen; - uint8_t attestationElementsTestVector[] = { + static constexpr uint8_t attestationElementsTestVector[] = { 0x15, 0x30, 0x01, 0x70, 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, @@ -133,24 +138,28 @@ static void TestAttestationElements_Construction(nlTestSuite * inSuite, void * i 0xff, 0x3e, 0x00, 0x03, 0x00, 0x18, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18 }; - uint8_t certificationDeclaration[] = { 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, - 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, - 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, - 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, - 0x28, 0x67, 0x02, 0xbd, 0x6b, 0xba, 0x48, 0xac, 0x7c, 0x83, 0x54, 0x9b, 0x68, 0x73, - 0x29, 0x47, 0x48, 0xb9, 0x51, 0xd5, 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, - 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, 0xae, 0xdf, 0x41, - 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa }; - uint8_t attestationNonce[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, - 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; - uint32_t timestamp = 677103357; - uint8_t vendorReserved1[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; - uint8_t vendorReserved3[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; - ByteSpan vendorReservedArray[] = { ByteSpan(vendorReserved1), ByteSpan(), ByteSpan(vendorReserved3) }; - uint16_t vendorId = 0xFFF1; - uint16_t profileNum = 0x003E; + static constexpr uint8_t certificationDeclaration[] = { + 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, + 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, + 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, 0x28, + 0x67, 0x02, 0xbd, 0x6b, 0xba, 0x48, 0xac, 0x7c, 0x83, 0x54, 0x9b, 0x68, 0x73, 0x29, 0x47, 0x48, 0xb9, 0x51, 0xd5, + 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, + 0xae, 0xdf, 0x41, 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa + }; + static constexpr uint8_t attestationNonce[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, + 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, + 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; + static constexpr uint32_t timestamp = 677103357; + static constexpr uint8_t vendorReserved1[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; + static constexpr uint8_t vendorReserved3[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; + static constexpr uint16_t vendorId = 0xFFF1; + static constexpr uint16_t profileNum = 0x003E; + VendorReservedElement vendorReservedArray[2]; + DeviceAttestationVendorReservedConstructor vendorReserved(vendorReservedArray, 2); + vendorReserved.addVendorReservedElement(vendorId, profileNum, 1, ByteSpan(vendorReserved1)); + vendorReserved.addVendorReservedElement(vendorId, profileNum, 3, ByteSpan(vendorReserved3)); attestationElementsLen = sizeof(certificationDeclaration) + sizeof(attestationNonce) + sizeof(timestamp) + sizeof(vendorReserved1) + sizeof(vendorReserved3) + sizeof(uint64_t) * 5; @@ -161,8 +170,7 @@ static void TestAttestationElements_Construction(nlTestSuite * inSuite, void * i MutableByteSpan attestationElementsSpan(attestationElements.Get(), attestationElementsLen); err = ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(attestationNonce), timestamp, ByteSpan(), - vendorReservedArray, ArraySize(vendorReservedArray), vendorId, profileNum, - attestationElementsSpan); + vendorReserved, attestationElementsSpan); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); attestationElementsLen = attestationElementsSpan.size(); @@ -174,7 +182,7 @@ static void TestAttestationElements_Deconstruction(nlTestSuite * inSuite, void * { CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t attestationElementsTestVector[] = { + static constexpr uint8_t attestationElementsTestVector[] = { 0x15, 0x30, 0x01, 0x70, 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, @@ -188,7 +196,7 @@ static void TestAttestationElements_Deconstruction(nlTestSuite * inSuite, void * 0xff, 0x3e, 0x00, 0x03, 0x00, 0x18, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18 }; - uint8_t certificationDeclarationTestVector[] = { + static constexpr uint8_t certificationDeclarationTestVector[] = { 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, 0x28, @@ -196,51 +204,107 @@ static void TestAttestationElements_Deconstruction(nlTestSuite * inSuite, void * 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, 0xae, 0xdf, 0x41, 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa }; - uint8_t attestationNonceTestVector[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, - 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, - 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; - uint32_t timestampTestVector = 677103357; - uint8_t vendorReserved1TestVector[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; - uint8_t vendorReserved3TestVector[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; - ByteSpan vendorReservedArrayTestVector[] = { ByteSpan(vendorReserved1TestVector), ByteSpan(vendorReserved3TestVector) }; - uint16_t vendorIdTestVector = 0xFFF1; - uint16_t profileNumTestVector = 0x003E; + static constexpr uint8_t attestationNonceTestVector[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, + 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, + 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; + static constexpr uint32_t timestampTestVector = 677103357; + static constexpr uint8_t vendorReserved1TestVector[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; + static constexpr uint8_t vendorReserved3TestVector[] = { + 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 + }; + static constexpr ByteSpan vendorReservedArrayTestVector[] = { ByteSpan(vendorReserved1TestVector), + ByteSpan(vendorReserved3TestVector) }; + static constexpr uint16_t vendorIdTestVector = 0xFFF1; + static constexpr uint16_t profileNumTestVector = 0x003E; ByteSpan certificationDeclarationDeconstructed; ByteSpan attestationNonceDeconstructed; uint32_t timestampDeconstructed; ByteSpan firmwareInfoDeconstructed; - ByteSpan vendorReservedDeconstructed[3]; - size_t vendorReservedDeconstructedSize = ArraySize(vendorReservedDeconstructed); - uint16_t vendorIdDeconstructed; - uint16_t profileNumDeconstructed; + DeviceAttestationVendorReservedDeconstructor vendorReserved; err = DeconstructAttestationElements(ByteSpan(attestationElementsTestVector), certificationDeclarationDeconstructed, attestationNonceDeconstructed, timestampDeconstructed, firmwareInfoDeconstructed, - vendorReservedDeconstructed, vendorReservedDeconstructedSize, vendorIdDeconstructed, - profileNumDeconstructed); + vendorReserved); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, certificationDeclarationDeconstructed.data_equal(ByteSpan(certificationDeclarationTestVector))); NL_TEST_ASSERT(inSuite, attestationNonceDeconstructed.data_equal(ByteSpan(attestationNonceTestVector))); NL_TEST_ASSERT(inSuite, timestampTestVector == timestampDeconstructed); NL_TEST_ASSERT(inSuite, firmwareInfoDeconstructed.empty()); - NL_TEST_ASSERT(inSuite, ArraySize(vendorReservedArrayTestVector) == vendorReservedDeconstructedSize); - for (size_t i = 0; i < ArraySize(vendorReservedArrayTestVector); ++i) + NL_TEST_ASSERT(inSuite, ArraySize(vendorReservedArrayTestVector) == vendorReserved.GetNumberOfElements()); + struct VendorReservedElement element; + + while (vendorReserved.GetNextVendorReservedElement(element) == CHIP_NO_ERROR) { - NL_TEST_ASSERT(inSuite, vendorReservedArrayTestVector[i].data_equal(vendorReservedDeconstructed[i])); + NL_TEST_ASSERT(inSuite, vendorIdTestVector == element.vendorId); + NL_TEST_ASSERT(inSuite, profileNumTestVector == element.profileNum); + switch (element.tagNum) + { + case 1: + NL_TEST_ASSERT(inSuite, element.vendorReservedData.data_equal(vendorReservedArrayTestVector[0])); + break; + case 3: + NL_TEST_ASSERT(inSuite, element.vendorReservedData.data_equal(vendorReservedArrayTestVector[1])); + break; + default: + NL_TEST_ASSERT(inSuite, 0); + break; + } } - NL_TEST_ASSERT(inSuite, vendorIdDeconstructed == vendorIdTestVector); - NL_TEST_ASSERT(inSuite, profileNumDeconstructed == profileNumTestVector); +} + +static void TestVendorReservedData(nlTestSuite * inSuite, void * inContext) +{ + + struct VendorReservedElement inputArray[] = { { 3000, 100, 10 }, { 2999, 99, 10 }, { 10, 20, 100 }, + { 100, 50, 200 }, { 3000, 100, 11 }, { 3000, 100, 9 } }; + + VendorReservedElement vendorReservedArray[6]; + DeviceAttestationVendorReservedConstructor vendorReserved(vendorReservedArray, 6); + size_t i; + uint8_t strings[6][50]; + for (i = 0; i < ArraySize(inputArray); i++) + { + snprintf(reinterpret_cast(strings[i]), sizeof(strings[i]), "Vendor Reserved Data #%d", + (int) i); // for debugging use + CHIP_ERROR err = + vendorReserved.addVendorReservedElement(inputArray[i].vendorId, inputArray[i].profileNum, inputArray[i].tagNum, + ByteSpan(strings[i], strlen(reinterpret_cast(strings[i])))); + + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + } + + // manually figure out the order these should be read out in when sorted + struct VendorReservedElement * desiredOrder[] = { + &inputArray[2], &inputArray[3], &inputArray[1], &inputArray[5], &inputArray[0], &inputArray[4], + }; + + const struct VendorReservedElement * element = vendorReserved.cbegin(); + NL_TEST_ASSERT(inSuite, element); + NL_TEST_ASSERT(inSuite, element = vendorReserved.Next()); + + for (i = 0; element && i < ArraySize(desiredOrder); element = vendorReserved.Next(), i++) + { + NL_TEST_ASSERT(inSuite, + element->vendorId == desiredOrder[i]->vendorId && element->profileNum == desiredOrder[i]->profileNum && + element->tagNum == desiredOrder[i]->tagNum); + } + NL_TEST_ASSERT(inSuite, i == ArraySize(desiredOrder)); // check if previous loop matched for every array entry. + + // add another element, it should fail + uint8_t testByteSpan[] = { 0x1, 0x2, 0x3 }; + CHIP_ERROR err = vendorReserved.addVendorReservedElement(5, 10, 20, ByteSpan(testByteSpan)); + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_NO_MEMORY); } static void TestAttestationElements_DeconstructionWithFirmwareInfo(nlTestSuite * inSuite, void * inContext) { CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t attestationElementsTestVectorWithFirmwareInfo[] = { + static constexpr uint8_t attestationElementsTestVectorWithFirmwareInfo[] = { 0x15, 0x30, 0x01, 0x70, 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, @@ -259,7 +323,7 @@ static void TestAttestationElements_DeconstructionWithFirmwareInfo(nlTestSuite * 0x00, 0x03, 0x00, 0x18, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18 }; - uint8_t certificationDeclarationTestVector[] = { + static constexpr uint8_t certificationDeclarationTestVector[] = { 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, 0x25, 0x01, 0x88, 0x99, 0x25, 0x02, 0xfe, 0xff, 0x25, 0x03, 0xd2, 0x04, 0x25, 0x04, 0x2e, 0x16, 0x24, 0x05, 0xaa, 0x25, 0x06, 0xde, 0xc0, 0x25, 0x07, 0x94, 0x26, 0x18, 0x58, 0x40, 0x96, 0x57, 0x2d, 0xd6, 0x3c, 0x03, 0x64, 0x0b, 0x28, @@ -267,58 +331,76 @@ static void TestAttestationElements_DeconstructionWithFirmwareInfo(nlTestSuite * 0xab, 0x66, 0x62, 0x2e, 0x9d, 0x26, 0x10, 0x41, 0xf8, 0x0e, 0x97, 0x49, 0xfe, 0xff, 0x78, 0x10, 0x02, 0x49, 0x67, 0xae, 0xdf, 0x41, 0x38, 0x36, 0x5b, 0x0a, 0x22, 0x57, 0x14, 0x9c, 0x9a, 0x12, 0x3e, 0x0d, 0x30, 0xaa }; - uint8_t attestationNonceTestVector[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, - 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, - 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; - uint32_t timestampTestVector = 677103357; - uint8_t firmwareInfoTestVector[] = { 0x30, 0x67, 0x80, 0x01, 0x05, 0xA1, 0x62, 0x30, 0x2F, 0xA0, 0x0B, 0x80, 0x09, 0x60, 0x86, - 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x81, 0x20, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, - 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, - 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x30, 0x2F, 0xA0, 0x0B, - 0x80, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x81, 0x20, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; - uint8_t vendorReserved1TestVector[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; - uint8_t vendorReserved3TestVector[] = { 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 }; - ByteSpan vendorReservedArrayTestVector[] = { ByteSpan(vendorReserved1TestVector), ByteSpan(vendorReserved3TestVector) }; - uint16_t vendorIdTestVector = 0xFFF1; - uint16_t profileNumTestVector = 0x003E; + static constexpr uint8_t attestationNonceTestVector[] = { 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, + 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, + 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2 }; + static constexpr uint32_t timestampTestVector = 677103357; + static constexpr uint8_t firmwareInfoTestVector[] = { + 0x30, 0x67, 0x80, 0x01, 0x05, 0xA1, 0x62, 0x30, 0x2F, 0xA0, 0x0B, 0x80, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x02, 0x01, 0x81, 0x20, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, + 0xEE, 0xFF, 0x30, 0x2F, 0xA0, 0x0B, 0x80, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x81, + 0x20, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F + }; + static constexpr uint8_t vendorReserved1TestVector[] = { 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31 }; + static constexpr uint8_t vendorReserved3TestVector[] = { + 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x64, 0x33, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65 + }; + static constexpr ByteSpan vendorReservedArrayTestVector[] = { ByteSpan(vendorReserved1TestVector), + ByteSpan(vendorReserved3TestVector) }; + static constexpr uint16_t vendorIdTestVector = 0xFFF1; + static constexpr uint16_t profileNumTestVector = 0x003E; ByteSpan certificationDeclarationDeconstructed; ByteSpan attestationNonceDeconstructed; uint32_t timestampDeconstructed; ByteSpan firmwareInfoDeconstructed; - ByteSpan vendorReservedDeconstructed[3]; - size_t vendorReservedDeconstructedSize = ArraySize(vendorReservedDeconstructed); - uint16_t vendorIdDeconstructed; - uint16_t profileNumDeconstructed; + + DeviceAttestationVendorReservedDeconstructor vendorReserved; err = DeconstructAttestationElements(ByteSpan(attestationElementsTestVectorWithFirmwareInfo), certificationDeclarationDeconstructed, attestationNonceDeconstructed, - timestampDeconstructed, firmwareInfoDeconstructed, vendorReservedDeconstructed, - vendorReservedDeconstructedSize, vendorIdDeconstructed, profileNumDeconstructed); + timestampDeconstructed, firmwareInfoDeconstructed, vendorReserved); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, certificationDeclarationDeconstructed.data_equal(ByteSpan(certificationDeclarationTestVector))); NL_TEST_ASSERT(inSuite, attestationNonceDeconstructed.data_equal(ByteSpan(attestationNonceTestVector))); NL_TEST_ASSERT(inSuite, timestampTestVector == timestampDeconstructed); NL_TEST_ASSERT(inSuite, firmwareInfoDeconstructed.data_equal(ByteSpan(firmwareInfoTestVector))); - NL_TEST_ASSERT(inSuite, ArraySize(vendorReservedArrayTestVector) == vendorReservedDeconstructedSize); - for (size_t i = 0; i < ArraySize(vendorReservedArrayTestVector); ++i) + NL_TEST_ASSERT(inSuite, ArraySize(vendorReservedArrayTestVector) == vendorReserved.GetNumberOfElements()); + struct VendorReservedElement element; + size_t elementsSeen = 0; + + while (vendorReserved.GetNextVendorReservedElement(element) == CHIP_NO_ERROR) { - NL_TEST_ASSERT(inSuite, vendorReservedArrayTestVector[i].data_equal(vendorReservedDeconstructed[i])); + NL_TEST_ASSERT(inSuite, vendorIdTestVector == element.vendorId); + NL_TEST_ASSERT(inSuite, profileNumTestVector == element.profileNum); + switch (element.tagNum) + { + case 1: + NL_TEST_ASSERT(inSuite, element.vendorReservedData.data_equal(vendorReservedArrayTestVector[0])); + elementsSeen++; + break; + case 3: + NL_TEST_ASSERT(inSuite, element.vendorReservedData.data_equal(vendorReservedArrayTestVector[1])); + elementsSeen++; + break; + default: + NL_TEST_ASSERT(inSuite, 0); + break; + } } - NL_TEST_ASSERT(inSuite, vendorIdDeconstructed == vendorIdTestVector); - NL_TEST_ASSERT(inSuite, profileNumDeconstructed == profileNumTestVector); + NL_TEST_ASSERT(inSuite, elementsSeen == ArraySize(vendorReservedArrayTestVector)); } static void TestAttestationElements_DeconstructionUnordered(nlTestSuite * inSuite, void * inContext) { CHIP_ERROR err = CHIP_NO_ERROR; - uint8_t attestationElementsUnorderedTestVector[] = { + static constexpr uint8_t attestationElementsUnorderedTestVector[] = { 0x15, 0x30, 0x02, 0x20, 0xe0, 0x42, 0x1b, 0x91, 0xc6, 0xfd, 0xcd, 0xb4, 0x0e, 0x2a, 0x4d, 0x2c, 0xf3, 0x1d, 0xb2, 0xb4, 0xe1, 0x8b, 0x41, 0x1b, 0x1d, 0x3a, 0xd4, 0xd1, 0x2a, 0x9d, 0x90, 0xaa, 0x8e, 0x52, 0xfa, 0xe2, 0x30, 0x01, 0x70, 0xd2, 0x84, 0x4b, 0xa2, 0x01, 0x26, 0x04, 0x46, 0x63, 0x73, 0x61, 0x63, 0x64, 0x30, 0xa0, 0x58, 0x1d, 0x15, @@ -337,15 +419,11 @@ static void TestAttestationElements_DeconstructionUnordered(nlTestSuite * inSuit ByteSpan attestationNonceDeconstructed; uint32_t timestampDeconstructed; ByteSpan firmwareInfoDeconstructed; - ByteSpan vendorReservedDeconstructed[3]; - size_t vendorReservedDeconstructedSize = ArraySize(vendorReservedDeconstructed); - uint16_t vendorIdDeconstructed; - uint16_t profileNumDeconstructed; + DeviceAttestationVendorReservedDeconstructor vendorReserved; err = DeconstructAttestationElements(ByteSpan(attestationElementsUnorderedTestVector), certificationDeclarationDeconstructed, attestationNonceDeconstructed, timestampDeconstructed, firmwareInfoDeconstructed, - vendorReservedDeconstructed, vendorReservedDeconstructedSize, vendorIdDeconstructed, - profileNumDeconstructed); + vendorReserved); NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); } @@ -357,6 +435,7 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test Device Attestation Elements Roundtrip", TestAttestationElements_Roundtrip), NL_TEST_DEF("Test Device Attestation Elements Construction", TestAttestationElements_Construction), NL_TEST_DEF("Test Device Attestation Elements Deconstruction", TestAttestationElements_Deconstruction), + NL_TEST_DEF("Test Vendor Reserved Data Ordering", TestVendorReservedData), NL_TEST_DEF("Test Device Attestation Elements Deconstruction with Firmware Information", TestAttestationElements_DeconstructionWithFirmwareInfo), NL_TEST_DEF("Test Device Attestation Elements Deconstruction - Corrupted/Out of Order TLV", TestAttestationElements_DeconstructionUnordered), NL_TEST_SENTINEL()