diff --git a/src/credentials/BUILD.gn b/src/credentials/BUILD.gn index f1472ce04483c9..b895a87557dbb9 100644 --- a/src/credentials/BUILD.gn +++ b/src/credentials/BUILD.gn @@ -27,6 +27,8 @@ static_library("credentials") { "CHIPOperationalCredentials.h", "DeviceAttestationCredsProvider.cpp", "DeviceAttestationCredsProvider.h", + "DeviceAttestation.h", + "DeviceAttestation.cpp", "GenerateChipX509Cert.cpp", "examples/DeviceAttestationCredsExample.cpp", "examples/DeviceAttestationCredsExample.h", diff --git a/src/credentials/DeviceAttestation.cpp b/src/credentials/DeviceAttestation.cpp new file mode 100644 index 00000000000000..eee3d23896fdb6 --- /dev/null +++ b/src/credentials/DeviceAttestation.cpp @@ -0,0 +1,146 @@ +#include "DeviceAttestation.h" +#include +#include + +namespace chip { +namespace Credentials { + +// TODO: vendor data needs fully qualitified IDs -- (vendor ID, profile number, tag #) + + +// context tag positions +enum { CERTIFICATE_DECLARATION = 1, + ATTESTATION_NONCE = 2, + TIMESTAMP = 3, + FIRMWARE_INFO = 4, + LAST_TAG = FIRMWARE_INFO +}; + +CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, + ByteSpan & certificationDeclaration, + ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, + std::vector & vendorReserved, + uint16_t & vendorId, uint16_t & profileNum) +{ +#if 0 + ByteSpan * element_array[] = { &certificationDeclaration, &attestationNonce, + nullptr, /* timestamp */ + &firmwareInfo, + }; +#endif + + uint32_t validArgumentCount = 0; + uint32_t currentDecodeTagId = 0; + bool argExists[4] = { false }; // only check the first 4 elements + CHIP_ERROR TLVError = CHIP_NO_ERROR; + TLV::TLVReader tlvReader; + TLV::TLVType containerType = TLV::kTLVType_Structure; + + tlvReader.Init(attestationElements.data(), static_cast(attestationElements.size())); + ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag)); + ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); + + while ((TLVError = tlvReader.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + uint64_t tag; + + tag = tlvReader.GetTag(); + + if (TLV::IsContextTag(tag)) + { + currentDecodeTagId = TLV::TagNumFromTag(tag); + if(0 == currentDecodeTagId) + continue; // ignore tag 0? or error? + if(currentDecodeTagId > LAST_TAG) + continue; // ignore tags too high? or error + if(true == argExists[currentDecodeTagId - 1]) + return CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + argExists[currentDecodeTagId - 1] = true; + validArgumentCount++; + + const uint8_t *data = nullptr; + // TODO: helper routine for cases 1, 3, 4 -- CHIP_ERROR getByteSpan(field &, tlvReader) + switch(currentDecodeTagId) { + case CERTIFICATE_DECLARATION: +// if(nullptr == certificationDeclaration) +// break; + VerifyOrReturnError(tlvReader.GetDataPtr(data) != CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + certificationDeclaration = ByteSpan(data, tlvReader.GetLength()); + break; + case ATTESTATION_NONCE: +// if(nullptr == attestationNonce) +// break; + VerifyOrReturnError(tlvReader.GetDataPtr(data) != CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + attestationNonce = ByteSpan(data, tlvReader.GetLength()); + break; + case TIMESTAMP: +// if(nullptr == timestamp) +// break; + VerifyOrReturnError(tlvReader.Get(timestamp) != CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + break; + case FIRMWARE_INFO: +// if(nullptr == firmwareInfo) +// break; + VerifyOrReturnError(tlvReader.GetDataPtr(data) != CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT); + firmwareInfo = ByteSpan(data, tlvReader.GetLength()); + break; + default: + // should never get here? Error? + return CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + } + } else if(TLV::IsProfileTag(tag)) { + // vendor information + } else { + // error + return CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + } + } + + return CHIP_NO_ERROR; +} + + +CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, + uint32_t timestamp, const ByteSpan & firmwareInfo, + std::vector &vendorReserved, + uint16_t vendorId, uint16_t profileNum, + MutableByteSpan & attestationElements ) +{ + TLV::TLVWriter tlvWriter; + TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; + + tlvWriter.Init(attestationElements.data(), static_cast(attestationElements.size())); + outerContainerType = TLV::kTLVType_NotSpecified; + ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag, TLV::kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp)); + if (!firmwareInfo.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo)); + } + + // TODO: this has to be changed +#if 0 + uint8_t tagNum = 5; + for(auto &vendorItem : vendorReserved) { + if(!vendorItem.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(tagNum), vendorItem)); + } + tagNum++; + } +#endif + + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Finalize()); + attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten()); + + return CHIP_NO_ERROR; +} + + +} // namespace Credentials + +} // namespace chip diff --git a/src/credentials/DeviceAttestation.h b/src/credentials/DeviceAttestation.h new file mode 100644 index 00000000000000..6a000231b01d3e --- /dev/null +++ b/src/credentials/DeviceAttestation.h @@ -0,0 +1,65 @@ +/* + * + * 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 + + +namespace chip { +namespace Credentials { + + /** + * @brief Take the attestation elements vector and return each component seperately. + * + * @param[in] attestionElements Buffer containg source of attestion + * @param[out] certificationDeclaration + * @param[out] attestationNonce + * @param[out] timestamp + * @param[out] firmwareInfo + * @param[out] vendorReserved elements + * @param[out] vendorId (from vendor reserved elements) + * @param[out] profileNum (from vendor reserved elements) + */ + CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration, + ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, + std::vector &vendorReserved, uint16_t & vendorId, uint16_t & profileNum ); + // uint16_t & vendorId, uint16_t & profileNum ); + + + /** + * @brief Take discrete components . + * + * @param[in] attestionElements Buffer containg source of attestion + * @param[out] certificationDeclaration + * @param[out] attestationNonce + * @param[out] timestamp + * @param[out] firmwareInfo + * @param[out] vendorReserved elements + * @param[out] vendorId (from vendor reserved elements) + * @param[out] profileNum (from vendor reserved elements) + */ + + CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, + uint32_t timestamp, const ByteSpan & firmwareInfo, + std::vector &vendorReserved, uint16_t vendorId, uint16_t profileNum, + MutableByteSpan & attestationElements); + +} // namespace Credentials +} // namespace chip + diff --git a/src/credentials/tests/BUILD.gn b/src/credentials/tests/BUILD.gn index aa26dba8c2b7d6..7c2d36dd5e7ab2 100644 --- a/src/credentials/tests/BUILD.gn +++ b/src/credentials/tests/BUILD.gn @@ -40,6 +40,7 @@ chip_test_suite("tests") { "TestChipCert.cpp", "TestChipOperationalCredentials.cpp", "TestDeviceAttestationCredentials.cpp", + "TestDeviceAttestationConstruction.cpp" ] cflags = [ "-Wconversion" ] diff --git a/src/credentials/tests/CHIPCert_test_vectors.cpp b/src/credentials/tests/CHIPCert_test_vectors.cpp index f5cbd4c61a1f22..6ee120a20256f3 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.cpp +++ b/src/credentials/tests/CHIPCert_test_vectors.cpp @@ -169,6 +169,43 @@ CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t ** certPubkey, uint return err; } +CHIP_ERROR GetTestCertAKID(uint8_t certType, ByteSpan & akid) +{ + CHIP_ERROR err; + +#define SELECT_CERT(NAME) \ + do \ + { \ + if (certType == TestCert::k##NAME) \ + { \ + akid = ByteSpan(sTestCert_##NAME##_AuthorityKeyId, sTestCert_##NAME##_AuthorityKeyId_Len); \ + ExitNow(err = CHIP_NO_ERROR); \ + } \ + } while (0) + + SELECT_CERT(Root01); + SELECT_CERT(Root02); + SELECT_CERT(ICA01); + SELECT_CERT(ICA02); + SELECT_CERT(ICA01_1); + SELECT_CERT(FWSign01); + SELECT_CERT(Node01_01); + SELECT_CERT(Node01_02); + SELECT_CERT(Node02_01); + SELECT_CERT(Node02_02); + SELECT_CERT(Node02_03); + SELECT_CERT(Node02_04); + SELECT_CERT(Node02_05); + SELECT_CERT(Node02_06); + SELECT_CERT(Node02_07); +#undef SELECT_CERT + + err = CHIP_ERROR_CA_CERT_NOT_FOUND; + +exit: + return err; +} + CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags certLoadFlags, BitFlags decodeFlags) { @@ -334,6 +371,12 @@ extern const uint8_t sTestCert_Root01_SubjectKeyId[] = { extern const uint8_t sTestCert_Root01_SubjectKeyId_Len = sizeof(sTestCert_Root01_SubjectKeyId); +extern const uint8_t sTestCert_Root01_AuthorityKeyId[] = { + 0x13, 0xAF, 0x81, 0xAB, 0x37, 0x37, 0x4B, 0x2E, 0xD2, 0xA9, 0x64, 0x9B, 0x12, 0xB7, 0xA3, 0xA4, 0x28, 0x7E, 0x15, 0x1D, +}; + +extern const uint8_t sTestCert_Root01_AuthorityKeyId_Len = sizeof(sTestCert_Root01_AuthorityKeyId); + /************** Test Root02 Certificate ************** Certificate: Data: @@ -463,6 +506,12 @@ extern const uint8_t sTestCert_Root02_SubjectKeyId[] = { extern const uint8_t sTestCert_Root02_SubjectKeyId_Len = sizeof(sTestCert_Root02_SubjectKeyId); +extern const uint8_t sTestCert_Root02_AuthorityKeyId[] = { + 0xB2, 0x1B, 0xEA, 0x40, 0xAB, 0xF2, 0xAB, 0xA9, 0x56, 0xF9, 0x82, 0xE1, 0xDA, 0xD2, 0xB6, 0x06, 0x92, 0x06, 0x90, 0xE0, +}; + +extern const uint8_t sTestCert_Root02_AuthorityKeyId_Len = sizeof(sTestCert_Root02_AuthorityKeyId); + /************** Test ICA01 Certificate ************** Certificate: Data: @@ -584,6 +633,12 @@ extern const uint8_t sTestCert_ICA01_SubjectKeyId[] = { extern const uint8_t sTestCert_ICA01_SubjectKeyId_Len = sizeof(sTestCert_ICA01_SubjectKeyId); +extern const uint8_t sTestCert_ICA01_AuthorityKeyId[] = { + 0x13, 0xAF, 0x81, 0xAB, 0x37, 0x37, 0x4B, 0x2E, 0xD2, 0xA9, 0x64, 0x9B, 0x12, 0xB7, 0xA3, 0xA4, 0x28, 0x7E, 0x15, 0x1D, +}; + +extern const uint8_t sTestCert_ICA01_AuthorityKeyId_Len = sizeof(sTestCert_ICA01_AuthorityKeyId); + /************** Test ICA02 Certificate ************** Certificate: Data: @@ -713,6 +768,12 @@ extern const uint8_t sTestCert_ICA02_SubjectKeyId[] = { extern const uint8_t sTestCert_ICA02_SubjectKeyId_Len = sizeof(sTestCert_ICA02_SubjectKeyId); +extern const uint8_t sTestCert_ICA02_AuthorityKeyId[] = { + 0xB2, 0x1B, 0xEA, 0x40, 0xAB, 0xF2, 0xAB, 0xA9, 0x56, 0xF9, 0x82, 0xE1, 0xDA, 0xD2, 0xB6, 0x06, 0x92, 0x06, 0x90, 0xE0, +}; + +extern const uint8_t sTestCert_ICA02_AuthorityKeyId_Len = sizeof(sTestCert_ICA02_AuthorityKeyId); + /************** Test ICA01_1 Certificate ************** Certificate: Data: @@ -834,6 +895,12 @@ extern const uint8_t sTestCert_ICA01_1_SubjectKeyId[] = { extern const uint8_t sTestCert_ICA01_1_SubjectKeyId_Len = sizeof(sTestCert_ICA01_1_SubjectKeyId); +extern const uint8_t sTestCert_ICA01_1_AuthorityKeyId[] = { + 0x13, 0xAF, 0x81, 0xAB, 0x37, 0x37, 0x4B, 0x2E, 0xD2, 0xA9, 0x64, 0x9B, 0x12, 0xB7, 0xA3, 0xA4, 0x28, 0x7E, 0x15, 0x1D, +}; + +extern const uint8_t sTestCert_ICA01_1_AuthorityKeyId_Len = sizeof(sTestCert_ICA01_1_AuthorityKeyId); + /************** Test FWSign01 Certificate ************** Certificate: Data: @@ -963,6 +1030,12 @@ extern const uint8_t sTestCert_FWSign01_SubjectKeyId[] = { extern const uint8_t sTestCert_FWSign01_SubjectKeyId_Len = sizeof(sTestCert_FWSign01_SubjectKeyId); +extern const uint8_t sTestCert_FWSign01_AuthorityKeyId[] = { + 0x93, 0x88, 0x3C, 0x64, 0x9F, 0xC1, 0x7E, 0xC1, 0x2A, 0x6A, 0x1D, 0x77, 0xCF, 0xB9, 0x97, 0x2A, 0x55, 0x9C, 0x1A, 0xD8, +}; + +extern const uint8_t sTestCert_FWSign01_AuthorityKeyId_Len = sizeof(sTestCert_FWSign01_AuthorityKeyId); + /************** Test Node01_01 Certificate ************** Certificate: Data: @@ -1093,6 +1166,12 @@ extern const uint8_t sTestCert_Node01_01_SubjectKeyId[] = { extern const uint8_t sTestCert_Node01_01_SubjectKeyId_Len = sizeof(sTestCert_Node01_01_SubjectKeyId); +extern const uint8_t sTestCert_Node01_01_AuthorityKeyId[] = { + 0x53, 0x52, 0xD7, 0x05, 0x9E, 0x9C, 0x15, 0xA5, 0x08, 0x90, 0x68, 0x62, 0x86, 0x48, 0x01, 0xA2, 0x9F, 0x1F, 0x41, 0xD3, +}; + +extern const uint8_t sTestCert_Node01_01_AuthorityKeyId_Len = sizeof(sTestCert_Node01_01_AuthorityKeyId); + /************** Test Node01_02 Certificate ************** Certificate: Data: @@ -1223,6 +1302,12 @@ extern const uint8_t sTestCert_Node01_02_SubjectKeyId[] = { extern const uint8_t sTestCert_Node01_02_SubjectKeyId_Len = sizeof(sTestCert_Node01_02_SubjectKeyId); +extern const uint8_t sTestCert_Node01_02_AuthorityKeyId[] = { + 0x13, 0xAF, 0x81, 0xAB, 0x37, 0x37, 0x4B, 0x2E, 0xD2, 0xA9, 0x64, 0x9B, 0x12, 0xB7, 0xA3, 0xA4, 0x28, 0x7E, 0x15, 0x1D, +}; + +extern const uint8_t sTestCert_Node01_02_AuthorityKeyId_Len = sizeof(sTestCert_Node01_02_AuthorityKeyId); + /************** Test Node02_01 Certificate ************** Certificate: Data: @@ -1355,6 +1440,12 @@ extern const uint8_t sTestCert_Node02_01_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_01_SubjectKeyId_Len = sizeof(sTestCert_Node02_01_SubjectKeyId); +extern const uint8_t sTestCert_Node02_01_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_01_AuthorityKeyId_Len = sizeof(sTestCert_Node02_01_AuthorityKeyId); + /************** Test Node02_02 Certificate ************** Certificate: Data: @@ -1490,6 +1581,12 @@ extern const uint8_t sTestCert_Node02_02_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_02_SubjectKeyId_Len = sizeof(sTestCert_Node02_02_SubjectKeyId); +extern const uint8_t sTestCert_Node02_02_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_02_AuthorityKeyId_Len = sizeof(sTestCert_Node02_02_AuthorityKeyId); + /************** Test Node02_03 Certificate ************** Certificate: Data: @@ -1626,6 +1723,12 @@ extern const uint8_t sTestCert_Node02_03_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_03_SubjectKeyId_Len = sizeof(sTestCert_Node02_03_SubjectKeyId); +extern const uint8_t sTestCert_Node02_03_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_03_AuthorityKeyId_Len = sizeof(sTestCert_Node02_03_AuthorityKeyId); + /************** Test Node02_04 Certificate ************** Certificate: Data: @@ -1762,6 +1865,12 @@ extern const uint8_t sTestCert_Node02_04_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_04_SubjectKeyId_Len = sizeof(sTestCert_Node02_04_SubjectKeyId); +extern const uint8_t sTestCert_Node02_04_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_04_AuthorityKeyId_Len = sizeof(sTestCert_Node02_04_AuthorityKeyId); + /************** Test Node02_05 Certificate ************** Certificate: Data: @@ -1900,6 +2009,12 @@ extern const uint8_t sTestCert_Node02_05_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_05_SubjectKeyId_Len = sizeof(sTestCert_Node02_05_SubjectKeyId); +extern const uint8_t sTestCert_Node02_05_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_05_AuthorityKeyId_Len = sizeof(sTestCert_Node02_05_AuthorityKeyId); + /************** Test Node02_06 Certificate ************** Certificate: Data: @@ -2045,6 +2160,12 @@ extern const uint8_t sTestCert_Node02_06_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_06_SubjectKeyId_Len = sizeof(sTestCert_Node02_06_SubjectKeyId); +extern const uint8_t sTestCert_Node02_06_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_06_AuthorityKeyId_Len = sizeof(sTestCert_Node02_06_AuthorityKeyId); + /************** Test Node02_07 Certificate ************** Certificate: Data: @@ -2190,5 +2311,11 @@ extern const uint8_t sTestCert_Node02_07_SubjectKeyId[] = { extern const uint8_t sTestCert_Node02_07_SubjectKeyId_Len = sizeof(sTestCert_Node02_07_SubjectKeyId); +extern const uint8_t sTestCert_Node02_07_AuthorityKeyId[] = { + 0xCF, 0x42, 0xBC, 0xF8, 0xDF, 0x48, 0x09, 0xD9, 0x26, 0x6F, 0x23, 0x15, 0x5A, 0x16, 0xB0, 0x7F, 0x04, 0xBB, 0x3D, 0x84, +}; + +extern const uint8_t sTestCert_Node02_07_AuthorityKeyId_Len = sizeof(sTestCert_Node02_07_AuthorityKeyId); + } // namespace TestCerts } // namespace chip diff --git a/src/credentials/tests/CHIPCert_test_vectors.h b/src/credentials/tests/CHIPCert_test_vectors.h index 438123f8574cb6..1eefcbf2624170 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.h +++ b/src/credentials/tests/CHIPCert_test_vectors.h @@ -71,6 +71,7 @@ enum class TestCertLoadFlags : uint8_t extern CHIP_ERROR GetTestCert(uint8_t certType, BitFlags certLoadFlags, ByteSpan & cert); extern const char * GetTestCertName(uint8_t certType); extern CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t ** certPubkey, uint32_t & certPubkeyLen); +extern CHIP_ERROR GetTestCertAKID(uint8_t certType, ByteSpan & akid); extern CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags certLoadFlags, BitFlags decodeFlags); @@ -89,6 +90,8 @@ extern const uint8_t sTestCert_Root01_PrivateKey[]; extern const uint8_t sTestCert_Root01_PrivateKey_Len; extern const uint8_t sTestCert_Root01_SubjectKeyId[]; extern const uint8_t sTestCert_Root01_SubjectKeyId_Len; +extern const uint8_t sTestCert_Root01_AuthorityKeyId[]; +extern const uint8_t sTestCert_Root01_AuthorityKeyId_Len; extern const uint8_t sTestCert_Root02_Chip[]; extern const uint32_t sTestCert_Root02_Chip_Len; @@ -100,6 +103,8 @@ extern const uint8_t sTestCert_Root02_PrivateKey[]; extern const uint8_t sTestCert_Root02_PrivateKey_Len; extern const uint8_t sTestCert_Root02_SubjectKeyId[]; extern const uint8_t sTestCert_Root02_SubjectKeyId_Len; +extern const uint8_t sTestCert_Root02_AuthorityKeyId[]; +extern const uint8_t sTestCert_Root02_AuthorityKeyId_Len; extern const uint8_t sTestCert_ICA01_Chip[]; extern const uint32_t sTestCert_ICA01_Chip_Len; @@ -111,6 +116,8 @@ extern const uint8_t sTestCert_ICA01_PrivateKey[]; extern const uint8_t sTestCert_ICA01_PrivateKey_Len; extern const uint8_t sTestCert_ICA01_SubjectKeyId[]; extern const uint8_t sTestCert_ICA01_SubjectKeyId_Len; +extern const uint8_t sTestCert_ICA01_AuthorityKeyId[]; +extern const uint8_t sTestCert_ICA01_AuthorityKeyId_Len; extern const uint8_t sTestCert_ICA02_Chip[]; extern const uint32_t sTestCert_ICA02_Chip_Len; @@ -122,6 +129,8 @@ extern const uint8_t sTestCert_ICA02_PrivateKey[]; extern const uint8_t sTestCert_ICA02_PrivateKey_Len; extern const uint8_t sTestCert_ICA02_SubjectKeyId[]; extern const uint8_t sTestCert_ICA02_SubjectKeyId_Len; +extern const uint8_t sTestCert_ICA02_AuthorityKeyId[]; +extern const uint8_t sTestCert_ICA02_AuthorityKeyId_Len; extern const uint8_t sTestCert_ICA01_1_Chip[]; extern const uint32_t sTestCert_ICA01_1_Chip_Len; @@ -133,6 +142,8 @@ extern const uint8_t sTestCert_ICA01_1_PrivateKey[]; extern const uint8_t sTestCert_ICA01_1_PrivateKey_Len; extern const uint8_t sTestCert_ICA01_1_SubjectKeyId[]; extern const uint8_t sTestCert_ICA01_1_SubjectKeyId_Len; +extern const uint8_t sTestCert_ICA01_1_AuthorityKeyId[]; +extern const uint8_t sTestCert_ICA01_1_AuthorityKeyId_Len; extern const uint8_t sTestCert_FWSign01_Chip[]; extern const uint32_t sTestCert_FWSign01_Chip_Len; @@ -144,6 +155,8 @@ extern const uint8_t sTestCert_FWSign01_PrivateKey[]; extern const uint8_t sTestCert_FWSign01_PrivateKey_Len; extern const uint8_t sTestCert_FWSign01_SubjectKeyId[]; extern const uint8_t sTestCert_FWSign01_SubjectKeyId_Len; +extern const uint8_t sTestCert_FWSign01_AuthorityKeyId[]; +extern const uint8_t sTestCert_FWSign01_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node01_01_Chip[]; extern const uint32_t sTestCert_Node01_01_Chip_Len; @@ -155,6 +168,8 @@ extern const uint8_t sTestCert_Node01_01_PrivateKey[]; extern const uint8_t sTestCert_Node01_01_PrivateKey_Len; extern const uint8_t sTestCert_Node01_01_SubjectKeyId[]; extern const uint8_t sTestCert_Node01_01_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node01_01_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node01_01_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node01_02_Chip[]; extern const uint32_t sTestCert_Node01_02_Chip_Len; @@ -166,6 +181,8 @@ extern const uint8_t sTestCert_Node01_02_PrivateKey[]; extern const uint8_t sTestCert_Node01_02_PrivateKey_Len; extern const uint8_t sTestCert_Node01_02_SubjectKeyId[]; extern const uint8_t sTestCert_Node01_02_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node01_02_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node01_02_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_01_Chip[]; extern const uint32_t sTestCert_Node02_01_Chip_Len; @@ -177,6 +194,8 @@ extern const uint8_t sTestCert_Node02_01_PrivateKey[]; extern const uint8_t sTestCert_Node02_01_PrivateKey_Len; extern const uint8_t sTestCert_Node02_01_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_01_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_01_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_01_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_02_Chip[]; extern const uint32_t sTestCert_Node02_02_Chip_Len; @@ -188,6 +207,8 @@ extern const uint8_t sTestCert_Node02_02_PrivateKey[]; extern const uint8_t sTestCert_Node02_02_PrivateKey_Len; extern const uint8_t sTestCert_Node02_02_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_02_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_02_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_02_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_03_Chip[]; extern const uint32_t sTestCert_Node02_03_Chip_Len; @@ -199,6 +220,8 @@ extern const uint8_t sTestCert_Node02_03_PrivateKey[]; extern const uint8_t sTestCert_Node02_03_PrivateKey_Len; extern const uint8_t sTestCert_Node02_03_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_03_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_03_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_03_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_04_Chip[]; extern const uint32_t sTestCert_Node02_04_Chip_Len; @@ -210,6 +233,8 @@ extern const uint8_t sTestCert_Node02_04_PrivateKey[]; extern const uint8_t sTestCert_Node02_04_PrivateKey_Len; extern const uint8_t sTestCert_Node02_04_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_04_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_04_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_04_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_05_Chip[]; extern const uint32_t sTestCert_Node02_05_Chip_Len; @@ -221,6 +246,8 @@ extern const uint8_t sTestCert_Node02_05_PrivateKey[]; extern const uint8_t sTestCert_Node02_05_PrivateKey_Len; extern const uint8_t sTestCert_Node02_05_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_05_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_05_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_05_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_06_Chip[]; extern const uint32_t sTestCert_Node02_06_Chip_Len; @@ -232,6 +259,8 @@ extern const uint8_t sTestCert_Node02_06_PrivateKey[]; extern const uint8_t sTestCert_Node02_06_PrivateKey_Len; extern const uint8_t sTestCert_Node02_06_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_06_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_06_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_06_AuthorityKeyId_Len; extern const uint8_t sTestCert_Node02_07_Chip[]; extern const uint32_t sTestCert_Node02_07_Chip_Len; @@ -243,6 +272,8 @@ extern const uint8_t sTestCert_Node02_07_PrivateKey[]; extern const uint8_t sTestCert_Node02_07_PrivateKey_Len; extern const uint8_t sTestCert_Node02_07_SubjectKeyId[]; extern const uint8_t sTestCert_Node02_07_SubjectKeyId_Len; +extern const uint8_t sTestCert_Node02_07_AuthorityKeyId[]; +extern const uint8_t sTestCert_Node02_07_AuthorityKeyId_Len; } // namespace TestCerts } // namespace chip diff --git a/src/credentials/tests/TestDeviceAttestationConstruction.cpp b/src/credentials/tests/TestDeviceAttestationConstruction.cpp new file mode 100644 index 00000000000000..970c0e9cbcac7c --- /dev/null +++ b/src/credentials/tests/TestDeviceAttestationConstruction.cpp @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * 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 + +#include +#include +#include +#include + +#include + +#include "support/ScopedBuffer.h" +#include "credentials/DeviceAttestation.h" + +using namespace chip; +using namespace chip::Credentials; + + +static void TestAttestationElements(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + 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 }; + uint8_t attestationElementsTestVector[] = { +#if 0 + 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, + 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, 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, 0x26, 0x03, 0xfd, 0xc6, 0x5b, 0x28, 0x30, 0x05, 0x17, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x31, 0x30, 0x07, 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 +#else + 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, 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, 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, 0x26, 0x03, 0xfd, 0xc6, 0x5b, 0x28, 0xd0, 0xf1, 0xff, + 0x3e, 0x00, 0x01, 0x00, 0x17, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31, 0xd0, 0xf1, 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 +#endif + }; + + attestationElementsLen = sizeof(certificationDeclaration) + sizeof(attestationNonce) + sizeof(timestamp) + + sizeof(vendorReserved1) + sizeof(vendorReserved3) + sizeof(uint64_t) * 5 ; + attestationElements.Alloc(attestationElementsLen); + NL_TEST_ASSERT(inSuite, attestationElements); + + { + uint16_t vendorId = 0xbeef; + uint16_t profileNum = 0xdead; + std::vector vendorReserved; + + MutableByteSpan attestationElementsSpan(attestationElements.Get(), attestationElementsLen); + err = ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(attestationNonce), + timestamp, ByteSpan(), vendorReserved, vendorId, profileNum, attestationElementsSpan); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + attestationElementsLen = attestationElementsSpan.size(); + } + + NL_TEST_ASSERT(inSuite, sizeof(attestationElementsTestVector) == attestationElementsLen); + NL_TEST_ASSERT(inSuite, + memcmp(attestationElements.Get(), attestationElementsTestVector, sizeof(attestationElementsTestVector)) == 0); + + ByteSpan certificationDeclarationSpan; + ByteSpan attestationNonceSpan; + uint32_t timestampDeconstructed; + ByteSpan firmwareInfoSpan; + std::vector vendorReserved; + uint16_t vendorId; + uint16_t vendorProfile; + + err = DeconstructAttestationElements(ByteSpan(attestationElementsTestVector), certificationDeclarationSpan, + attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, + vendorReserved, vendorId, vendorProfile); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + NL_TEST_ASSERT(inSuite, sizeof(certificationDeclaration) == certificationDeclarationSpan.size()); + NL_TEST_ASSERT(inSuite, + memcmp(certificationDeclarationSpan.data(), certificationDeclaration, sizeof(certificationDeclaration)) == 0); + + NL_TEST_ASSERT(inSuite, sizeof(attestationNonce) == attestationNonceSpan.size()); + NL_TEST_ASSERT(inSuite, memcmp(attestationNonceSpan.data(), attestationNonce, sizeof(attestationNonce)) == 0); + + NL_TEST_ASSERT(inSuite, timestamp == timestampDeconstructed); + + NL_TEST_ASSERT(inSuite, firmwareInfoSpan.empty()); +} + + + +/** + * Test Suite. It lists all the test functions. + */ +// clang-format off +static const nlTest sTests[] = { + NL_TEST_DEF("Test Device Attestation", TestAttestationElements), +// NL_TEST_DEF("Test Example Device Attestation Signature", TestDACProvidersExample_Signature), + NL_TEST_SENTINEL() +}; +// clang-format on + +/** + * Set up the test suite. + */ +int TestDeviceAttestation_Setup(void * inContext) +{ + CHIP_ERROR error = chip::Platform::MemoryInit(); + if (error != CHIP_NO_ERROR) + return FAILURE; + return SUCCESS; +} + +/** + * Tear down the test suite. + */ +int TestDeviceAttestation_Teardown(void * inContext) +{ + chip::Platform::MemoryShutdown(); + return SUCCESS; +} + +int TestDeviceAttestation() +{ + // clang-format off + nlTestSuite theSuite = + { + "Device Attestation", + &sTests[0], + TestDeviceAttestation_Setup, + TestDeviceAttestation_Teardown + }; + // clang-format on + nlTestRunner(&theSuite, nullptr); + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestDeviceAttestation); diff --git a/src/crypto/CHIPCryptoPAL.cpp b/src/crypto/CHIPCryptoPAL.cpp index eb55ac0231c546..79c6bb3021bc9f 100644 --- a/src/crypto/CHIPCryptoPAL.cpp +++ b/src/crypto/CHIPCryptoPAL.cpp @@ -21,6 +21,7 @@ */ #include "CHIPCryptoPAL.h" +#include #include #include #include @@ -654,5 +655,185 @@ CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_ return status; } +CHIP_ERROR P256Keypair::ECDSA_sign_attestation_data(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, + P256ECDSASignature & out_signature) +{ + Hash_SHA256_stream hashStream; + uint8_t md[kSHA256_Hash_Length]; + MutableByteSpan messageDigestSpan(md); + + ReturnErrorOnFailure(hashStream.Begin()); + ReturnErrorOnFailure(hashStream.AddData(attestationElements)); + ReturnErrorOnFailure(hashStream.AddData(attestationChallenge)); + ReturnErrorOnFailure(hashStream.Finish(messageDigestSpan)); + + ReturnErrorOnFailure(ECDSA_sign_hash(messageDigestSpan.data(), messageDigestSpan.size(), out_signature)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR P256PublicKey::ECDSA_validate_attestation_data(const ByteSpan & attestationElements, + const ByteSpan & attestationChallenge, + const P256ECDSASignature & out_signature) const +{ + Hash_SHA256_stream hashStream; + uint8_t md[kSHA256_Hash_Length]; + MutableByteSpan messageDigestSpan(md); + + ReturnErrorOnFailure(hashStream.Begin()); + ReturnErrorOnFailure(hashStream.AddData(attestationElements)); + ReturnErrorOnFailure(hashStream.AddData(attestationChallenge)); + ReturnErrorOnFailure(hashStream.Finish(messageDigestSpan)); + + ReturnErrorOnFailure(ECDSA_validate_hash_signature(messageDigestSpan.data(), messageDigestSpan.size(), out_signature)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, + uint32_t timestamp, const ByteSpan & firmwareInfo, const ByteSpan & vendorReserved5, + const ByteSpan & vendorReserved6, const ByteSpan & vendorReserved7, + const ByteSpan & vendorReserved8, MutableByteSpan & attestationElements) +{ + TLV::TLVWriter tlvWriter; + TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; + + tlvWriter.Init(attestationElements.data(), static_cast(attestationElements.size())); + outerContainerType = TLV::kTLVType_NotSpecified; + ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag, TLV::kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp)); + if (!firmwareInfo.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo)); + } + if (!vendorReserved5.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendorReserved5)); + } + if (!vendorReserved6.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(6), vendorReserved6)); + } + if (!vendorReserved7.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(7), vendorReserved7)); + } + if (!vendorReserved8.empty()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(8), vendorReserved8)); + } + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Finalize()); + attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration, + ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, + ByteSpan & vendorReserved5, ByteSpan & vendorReserved6, ByteSpan & vendorReserved7, + ByteSpan & vendorReserved8) +{ + ByteSpan * element_array[] = { &certificationDeclaration, &attestationNonce, nullptr, &firmwareInfo, + &vendorReserved5, &vendorReserved6, &vendorReserved7, &vendorReserved8 }; + + uint32_t validArgumentCount = 0; + uint32_t currentDecodeTagId = 0; + CHIP_ERROR TLVError = CHIP_NO_ERROR; + CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; + bool argExists[9]; + TLV::TLVReader tlvReader; + TLV::TLVType containerType = TLV::kTLVType_Structure; + + tlvReader.Init(attestationElements.data(), static_cast(attestationElements.size())); + ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag)); + ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); + + memset(argExists, 0, sizeof argExists); + + for (size_t i = 0; i < sizeof(element_array) / sizeof(*element_array); ++i) + { + if (element_array[i] != nullptr) + { + *element_array[i] = ByteSpan(); + } + } + + while ((TLVError = tlvReader.Next()) == CHIP_NO_ERROR) + { + // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. + // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. + if (!TLV::IsContextTag(tlvReader.GetTag())) + { + continue; + } + currentDecodeTagId = TLV::TagNumFromTag(tlvReader.GetTag()); + if (currentDecodeTagId < 9 && currentDecodeTagId > 0) + { + if (argExists[currentDecodeTagId]) + { + // Duplicate TLV tag + TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; + break; + } + else + { + argExists[currentDecodeTagId] = true; + validArgumentCount++; + } + } + switch (currentDecodeTagId) + { + case 1: + case 2: + case 4: + case 5: + case 6: + case 7: + case 8: { + const uint8_t * data = nullptr; + TLVUnpackError = tlvReader.GetDataPtr(data); + if (element_array[currentDecodeTagId - 1] != nullptr) + { + *element_array[currentDecodeTagId - 1] = ByteSpan(data, tlvReader.GetLength()); + } + } + break; + case 3: { + TLVUnpackError = tlvReader.Get(timestamp); + } + default: + // Unsupported tag, ignore it. + break; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + break; + } + } + + if (CHIP_END_OF_TLV == TLVError) + { + // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. + TLVError = CHIP_NO_ERROR; + } + + if (CHIP_NO_ERROR != TLVError) + { + return TLVError; + } + if (CHIP_NO_ERROR != TLVUnpackError) + { + return TLVUnpackError; + } + if (validArgumentCount > 8) + { + return CHIP_ERROR_INVALID_TLV_ELEMENT; + } + return CHIP_NO_ERROR; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 2a8b87bd4858db..93b432301705ea 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -170,6 +170,11 @@ class ECPKey virtual CHIP_ERROR ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, const Sig & signature) const = 0; virtual CHIP_ERROR ECDSA_validate_hash_signature(const uint8_t * hash, const size_t hash_length, const Sig & signature) const = 0; + +#if 1 + virtual CHIP_ERROR ECDSA_validate_attestation_data(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, + const Sig & out_signature) const = 0; +#endif }; template @@ -248,6 +253,9 @@ class P256PublicKey : public ECPKey CHIP_ERROR ECDSA_validate_hash_signature(const uint8_t * hash, size_t hash_length, const P256ECDSASignature & signature) const override; + CHIP_ERROR ECDSA_validate_attestation_data(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, + const P256ECDSASignature & out_signature) const override; + private: uint8_t bytes[kP256_PublicKey_Length]; }; @@ -286,6 +294,17 @@ class ECPKeypair **/ virtual CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, Sig & out_signature) = 0; + /** + * @brief A function to sign an attestation data blob using ECDSA + * @param attestationElements Span of the AttestationElements to be signed + * @param attestationChallenge Span of the AttestationChallenge to be signed + * @param out_signature Buffer that will hold the output signature. The signature consists of: 2 EC elements (r and s), + * in raw point form (see SEC1). + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + virtual CHIP_ERROR ECDSA_sign_attestation_data(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, + Sig & out_signature) = 0; + /** @brief A function to derive a shared secret using ECDH * @param remote_public_key Public key of remote peer with which we are trying to establish secure channel. remote_public_key is * ASN.1 DER encoded as padded big-endian field elements as described in SEC 1: Elliptic Curve Cryptography @@ -358,6 +377,17 @@ class P256Keypair : public ECPKeypair point form (see SEC1). + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR ECDSA_sign_attestation_data(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge, + P256ECDSASignature & out_signature) override; + /** * @brief A function to derive a shared secret using ECDH * @@ -1165,5 +1195,19 @@ CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t root CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey); +CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid); + +CHIP_ERROR ExtractVIDFromX509Cert(const ByteSpan & certificate, uint16_t & vid); + +CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce, + uint32_t timestamp, const ByteSpan & firmwareInfo, const ByteSpan & vendorReserved5, + const ByteSpan & vendorReserved6, const ByteSpan & vendorReserved7, + const ByteSpan & vendorReserved8, MutableByteSpan & attestationElements); + +CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration, + ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo, + ByteSpan & vendorReserved5, ByteSpan & vendorReserved6, ByteSpan & vendorReserved7, + ByteSpan & vendorReserved8); + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index 587981f9d657ae..1dcb09623afd82 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1665,5 +1666,60 @@ CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256P return err; } +CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + X509 * x509certificate = nullptr; + const unsigned char * pCertificate = certificate.data(); + const unsigned char ** ppCertificate = &pCertificate; + const ASN1_OCTET_STRING * akidString = nullptr; + + x509certificate = d2i_X509(NULL, ppCertificate, static_cast(certificate.size())); + VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY); + + akidString = X509_get0_authority_key_id(x509certificate); + + VerifyOrExit(akidString->length == static_cast(akid.size()), err = CHIP_ERROR_INVALID_MESSAGE_LENGTH); + + for (int i = 0; i < akidString->length; ++i) + { + akid.data()[i] = akidString->data[i]; + } + +exit: + X509_free(x509certificate); + + return err; +} + +CHIP_ERROR ExtractVIDFromX509Cert(const ByteSpan & certificate, uint16_t & vid) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + X509 * x509certificate = nullptr; + const unsigned char * pCertificate = certificate.data(); + const unsigned char ** ppCertificate = &pCertificate; + char * subj = nullptr; + char * vidSubj = nullptr; + static constexpr char vidNeedle[] = "1.3.6.1.4.1.37244.2.1="; + static constexpr size_t vidNeedleSize = sizeof(vidNeedle) - 1; + + x509certificate = d2i_X509(NULL, ppCertificate, static_cast(certificate.size())); + VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY); + + subj = X509_NAME_oneline(X509_get_subject_name(x509certificate), NULL, 0); + VerifyOrExit(subj != nullptr, err = CHIP_ERROR_NO_MEMORY); + + vidSubj = strstr(subj, vidNeedle); + VerifyOrExit(vidSubj != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE); + + vid = static_cast(strtol(vidSubj + vidNeedleSize, NULL, 16)); + +exit: + OPENSSL_free(subj); + X509_free(x509certificate); + + return err; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index 5cc29cb2400210..94516ee4db0fe4 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -1244,5 +1244,15 @@ CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256P return error; } +CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ExtractVIDFromX509Cert(const ByteSpan & certificate, uint16_t & vid) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index c63eb50fdf3908..af7c1edec76fae 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -1795,8 +1795,232 @@ static void TestPubkey_x509Extraction(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, memcmp(publicKey.ConstBytes(), certPubkey, certPubkeyLen) == 0); } } + +static void TestAKID_x509Extraction(nlTestSuite * inSuite, void * inContext) +{ + using namespace TestCerts; + + CHIP_ERROR err = CHIP_NO_ERROR; + uint8_t akidBuf[Credentials::kKeyIdentifierLength]; + MutableByteSpan akidOut(akidBuf); + + ByteSpan cert; + ByteSpan akidSpan; + + for (size_t i = 0; i < gNumTestCerts; i++) + { + uint8_t certType = gTestCerts[i]; + + err = GetTestCert(certType, TestCertLoadFlags::kDERForm, cert); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + err = GetTestCertAKID(certType, akidSpan); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = ExtractAKIDFromX509Cert(cert, akidOut); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, akidSpan.size() == akidOut.size() && memcmp(akidOut.data(), akidSpan.data(), akidSpan.size()) == 0); + } +} + +static void TestVID_x509Extraction(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint16_t vid; + /* + credentials/test/attestation/Chip-Test-DAC-FFF1-8000-000A-Cert.pem + -----BEGIN CERTIFICATE----- + MIIB6jCCAY+gAwIBAgIIBRpp5eeAND4wCgYIKoZIzj0EAwIwRjEYMBYGA1UEAwwP + TWF0dGVyIFRlc3QgUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQB + gqJ8AgIMBDgwMDAwIBcNMjEwNjI4MTQyMzQzWhgPOTk5OTEyMzEyMzU5NTlaMEsx + HTAbBgNVBAMMFE1hdHRlciBUZXN0IERBQyAwMDBBMRQwEgYKKwYBBAGConwCAQwE + RkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAwWTATBgcqhkjOPQIBBggqhkjOPQMB + BwNCAAR6hFivu5vNFeGa3NJm9mycL2B8dHR6NfgPN+EYEz+A8XYBEyePkfFaoPf4 + eTIJT+aftyhoqB4ml5s2izO1VDEDo2AwXjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB + /wQEAwIHgDAdBgNVHQ4EFgQU1a2yuIOOyAc8R3LcfoeX/rsjs64wHwYDVR0jBBgw + FoAUhPUd/57M2ik1lEhSDoXxKS2j7dcwCgYIKoZIzj0EAwIDSQAwRgIhAPL+Fnlk + P0xbynYuijQV7VEwBvzQUtpQbWLYvVFeN70IAiEAvi20eqszdReOEkmgeSCgrG6q + OS8H8W2E/ctS268o19k= + -----END CERTIFICATE----- + */ + uint16_t expectedVid = 0xFFF1; + static const uint8_t sDacCertificate[] = { + 0x30, 0x82, 0x01, 0xEA, 0x30, 0x82, 0x01, 0x8F, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x05, 0x1A, 0x69, 0xE5, 0xE7, + 0x80, 0x34, 0x3E, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x46, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x4D, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, + 0x50, 0x41, 0x49, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x01, 0x0C, + 0x04, 0x46, 0x46, 0x46, 0x31, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, + 0x02, 0x0C, 0x04, 0x38, 0x30, 0x30, 0x30, 0x30, 0x20, 0x17, 0x0D, 0x32, 0x31, 0x30, 0x36, 0x32, 0x38, 0x31, 0x34, 0x32, + 0x33, 0x34, 0x33, 0x5A, 0x18, 0x0F, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, + 0x5A, 0x30, 0x4B, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x14, 0x4D, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x41, 0x43, 0x20, 0x30, 0x30, 0x30, 0x41, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0A, + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x01, 0x0C, 0x04, 0x46, 0x46, 0x46, 0x31, 0x31, 0x14, 0x30, 0x12, + 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xA2, 0x7C, 0x02, 0x02, 0x0C, 0x04, 0x38, 0x30, 0x30, 0x30, 0x30, 0x59, + 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, + 0x07, 0x03, 0x42, 0x00, 0x04, 0x7A, 0x84, 0x58, 0xAF, 0xBB, 0x9B, 0xCD, 0x15, 0xE1, 0x9A, 0xDC, 0xD2, 0x66, 0xF6, 0x6C, + 0x9C, 0x2F, 0x60, 0x7C, 0x74, 0x74, 0x7A, 0x35, 0xF8, 0x0F, 0x37, 0xE1, 0x18, 0x13, 0x3F, 0x80, 0xF1, 0x76, 0x01, 0x13, + 0x27, 0x8F, 0x91, 0xF1, 0x5A, 0xA0, 0xF7, 0xF8, 0x79, 0x32, 0x09, 0x4F, 0xE6, 0x9F, 0xB7, 0x28, 0x68, 0xA8, 0x1E, 0x26, + 0x97, 0x9B, 0x36, 0x8B, 0x33, 0xB5, 0x54, 0x31, 0x03, 0xA3, 0x60, 0x30, 0x5E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, + 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, + 0x02, 0x07, 0x80, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xD5, 0xAD, 0xB2, 0xB8, 0x83, 0x8E, + 0xC8, 0x07, 0x3C, 0x47, 0x72, 0xDC, 0x7E, 0x87, 0x97, 0xFE, 0xBB, 0x23, 0xB3, 0xAE, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x84, 0xF5, 0x1D, 0xFF, 0x9E, 0xCC, 0xDA, 0x29, 0x35, 0x94, 0x48, 0x52, 0x0E, + 0x85, 0xF1, 0x29, 0x2D, 0xA3, 0xED, 0xD7, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, + 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xF2, 0xFE, 0x16, 0x79, 0x64, 0x3F, 0x4C, 0x5B, 0xCA, 0x76, 0x2E, 0x8A, 0x34, + 0x15, 0xED, 0x51, 0x30, 0x06, 0xFC, 0xD0, 0x52, 0xDA, 0x50, 0x6D, 0x62, 0xD8, 0xBD, 0x51, 0x5E, 0x37, 0xBD, 0x08, 0x02, + 0x21, 0x00, 0xBE, 0x2D, 0xB4, 0x7A, 0xAB, 0x33, 0x75, 0x17, 0x8E, 0x12, 0x49, 0xA0, 0x79, 0x20, 0xA0, 0xAC, 0x6E, 0xAA, + 0x39, 0x2F, 0x07, 0xF1, 0x6D, 0x84, 0xFD, 0xCB, 0x52, 0xDB, 0xAF, 0x28, 0xD7, 0xD9 + }; + ByteSpan cert(sDacCertificate); + + err = ExtractVIDFromX509Cert(cert, vid); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, vid == expectedVid); +} #endif // CHIP_CRYPTO_OPENSSL +static void TestAttestationElements_Construction(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + 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 }; + + 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, 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, 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, 0x26, 0x03, 0xfd, 0xc6, 0x5b, 0x28, 0x30, 0x05, 0x17, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x31, 0x30, 0x07, 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 + }; + + attestationElementsLen = sizeof(certificationDeclaration) + sizeof(attestationNonce) + sizeof(timestamp) + + sizeof(vendorReserved1) + sizeof(vendorReserved3) + sizeof(uint64_t) * 5; + attestationElements.Alloc(attestationElementsLen); + NL_TEST_ASSERT(inSuite, attestationElements); + + { + MutableByteSpan attestationElementsSpan(attestationElements.Get(), attestationElementsLen); + err = ConstructAttestationElements(ByteSpan(certificationDeclaration), ByteSpan(attestationNonce), timestamp, ByteSpan(), + ByteSpan(vendorReserved1), ByteSpan(), ByteSpan(vendorReserved3), ByteSpan(), + attestationElementsSpan); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + attestationElementsLen = attestationElementsSpan.size(); + } + + NL_TEST_ASSERT(inSuite, sizeof(attestationElementsTestVector) == attestationElementsLen); + NL_TEST_ASSERT(inSuite, + memcmp(attestationElements.Get(), attestationElementsTestVector, sizeof(attestationElementsTestVector)) == 0); + + ByteSpan certificationDeclarationSpan; + ByteSpan attestationNonceSpan; + uint32_t timestampDeconstructed; + ByteSpan firmwareInfoSpan; + ByteSpan vendorReserved1Span; + ByteSpan vendorReserved2Span; + ByteSpan vendorReserved3Span; + ByteSpan vendorReserved4Span; + err = DeconstructAttestationElements(ByteSpan(attestationElementsTestVector), certificationDeclarationSpan, + attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, vendorReserved1Span, + vendorReserved2Span, vendorReserved3Span, vendorReserved4Span); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + NL_TEST_ASSERT(inSuite, sizeof(certificationDeclaration) == certificationDeclarationSpan.size()); + NL_TEST_ASSERT(inSuite, + memcmp(certificationDeclarationSpan.data(), certificationDeclaration, sizeof(certificationDeclaration)) == 0); + + NL_TEST_ASSERT(inSuite, sizeof(attestationNonce) == attestationNonceSpan.size()); + NL_TEST_ASSERT(inSuite, memcmp(attestationNonceSpan.data(), attestationNonce, sizeof(attestationNonce)) == 0); + + NL_TEST_ASSERT(inSuite, timestamp == timestampDeconstructed); + + NL_TEST_ASSERT(inSuite, sizeof(vendorReserved1) == vendorReserved1Span.size()); + NL_TEST_ASSERT(inSuite, memcmp(vendorReserved1Span.data(), vendorReserved1, sizeof(vendorReserved1)) == 0); + + NL_TEST_ASSERT(inSuite, sizeof(vendorReserved3) == vendorReserved3Span.size()); + NL_TEST_ASSERT(inSuite, memcmp(vendorReserved3Span.data(), vendorReserved3, sizeof(vendorReserved3)) == 0); + + NL_TEST_ASSERT(inSuite, firmwareInfoSpan.empty()); + NL_TEST_ASSERT(inSuite, vendorReserved2Span.empty()); + NL_TEST_ASSERT(inSuite, vendorReserved4Span.empty()); +} + +static void TestAttestationElements_SigVer(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + uint8_t deviceAttestationPrivkey[] = { 0x38, 0xf3, 0xe0, 0xa1, 0xf1, 0x45, 0xba, 0x1b, 0xf3, 0xe4, 0x4b, + 0x55, 0x2d, 0xef, 0x65, 0x27, 0x3d, 0x1d, 0x8e, 0x27, 0x6a, 0xa3, + 0x14, 0xac, 0x74, 0x2e, 0xb1, 0x28, 0x93, 0x3b, 0xa6, 0x4b }; + uint8_t deviceAttestationPubkey[] = { 0x04, 0xce, 0x5c, 0xf8, 0xef, 0xb0, 0x5d, 0x4e, 0xee, 0x79, 0x0d, 0x0a, 0x71, + 0xd5, 0xc0, 0x11, 0xbb, 0x74, 0x72, 0x40, 0xdb, 0xa2, 0x14, 0x58, 0x84, 0x5d, + 0x33, 0xe3, 0x4b, 0x0a, 0xf6, 0x65, 0x16, 0x33, 0x06, 0x3a, 0x80, 0x4b, 0x2f, + 0xf8, 0x5d, 0xca, 0xb2, 0x01, 0x9a, 0x0a, 0xb6, 0xf5, 0x59, 0x57, 0x75, 0xfe, + 0x8d, 0x85, 0xfb, 0xd7, 0xa0, 0x7c, 0x8e, 0x83, 0x7d, 0xa4, 0xd5, 0xa8, 0xb9 }; + + 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, 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, 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, 0x26, 0x03, 0xfd, 0xc6, 0x5b, 0x28, 0x30, 0x05, 0x17, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x31, 0x30, 0x07, 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 attestationChallengeTestVector[] = { 0x7a, 0x49, 0x53, 0x05, 0xd0, 0x77, 0x79, 0xa4, + 0x94, 0xdd, 0x39, 0xa0, 0x85, 0x1b, 0x66, 0x0d }; + uint8_t attestationSignatureTestVector[] = { 0x79, 0x82, 0x53, 0x5d, 0x24, 0xcf, 0xe1, 0x4a, 0x71, 0xab, 0x04, 0x24, 0xcf, + 0x0b, 0xac, 0xf1, 0xe3, 0x45, 0x48, 0x7e, 0xd5, 0x0f, 0x1a, 0xc0, 0xbc, 0x25, + 0x9e, 0xcc, 0xfb, 0x39, 0x08, 0x1e, 0x9f, 0x1d, 0x35, 0x6f, 0xc0, 0x19, 0x0b, + 0x08, 0x86, 0x65, 0xb1, 0xce, 0xf1, 0xf2, 0xeb, 0xb8, 0x89, 0xb6, 0x86, 0x34, + 0x79, 0xef, 0x50, 0x8e, 0x2b, 0x19, 0x8a, 0xe4, 0x7b, 0x8a, 0xb5, 0xd6 }; + + P256SerializedKeypair serialized; + P256Keypair keypair; + P256ECDSASignature signature; + + err = serialized.SetLength(sizeof(deviceAttestationPrivkey) + sizeof(deviceAttestationPubkey)); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + memcpy(serialized, deviceAttestationPubkey, sizeof(deviceAttestationPubkey)); + memcpy(serialized + sizeof(deviceAttestationPubkey), deviceAttestationPrivkey, sizeof(deviceAttestationPrivkey)); + err = keypair.Deserialize(serialized); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = keypair.ECDSA_sign_attestation_data(ByteSpan(attestationElementsTestVector), ByteSpan(attestationChallengeTestVector), + signature); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + NL_TEST_ASSERT(inSuite, sizeof(attestationSignatureTestVector) == signature.Length()); + + err = keypair.Pubkey().ECDSA_validate_attestation_data(ByteSpan(attestationElementsTestVector), + ByteSpan(attestationChallengeTestVector), signature); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); +} + /** * Test Suite. It lists all the test functions. */ @@ -1857,9 +2081,13 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test Spake2+ against RFC test vectors", TestSPAKE2P_RFC), NL_TEST_DEF("Test compressed fabric identifier", TestCompressedFabricIdentifier), #if CHIP_CRYPTO_OPENSSL - NL_TEST_DEF("Test Pubkey Extraction from x509 Certificate", TestPubkey_x509Extraction), NL_TEST_DEF("Test x509 Certificate Extraction from PKCS7", TestX509_PKCS7Extraction), + NL_TEST_DEF("Test Pubkey Extraction from x509 Certificate", TestPubkey_x509Extraction), + NL_TEST_DEF("Test Authority Key Id Extraction from x509 Certificate", TestAKID_x509Extraction), + NL_TEST_DEF("Test Vendor ID Extraction from x509 Attestation Certificate", TestVID_x509Extraction), #endif // CHIP_CRYPTO_OPENSSL + NL_TEST_DEF("Test AttestationElements Construction", TestAttestationElements_Construction), + NL_TEST_DEF("Test AttestationElements signing and validation message using SHA256", TestAttestationElements_SigVer), NL_TEST_SENTINEL() };