Skip to content

Commit

Permalink
Additional Certificate Declaration payload validation changes
Browse files Browse the repository at this point in the history
  • Loading branch information
vijs committed Nov 19, 2021
1 parent 05ae943 commit d0f7bb1
Show file tree
Hide file tree
Showing 11 changed files with 399 additions and 144 deletions.
124 changes: 124 additions & 0 deletions src/credentials/CertificationDeclaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, Cer
TLVReader reader;
TLVType outerContainer1, outerContainer2;

VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);

reader.Init(encodedCertElements);

ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag));
Expand Down Expand Up @@ -174,6 +176,128 @@ CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements, Cer
return CHIP_NO_ERROR;
}

CHIP_ERROR CertificationElementsDecoder::DecodeCertificationElements(const ByteSpan & encodedCertElements)
{
CHIP_ERROR err;
TLVReader reader;
TLVType outerContainer1, outerContainer2;

VerifyOrReturnError(encodedCertElements.size() <= kMaxCMSSignedCDMessage, CHIP_ERROR_INVALID_ARGUMENT);

reader.Init(encodedCertElements);

ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag));

ReturnErrorOnFailure(reader.EnterContainer(outerContainer1));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_FormatVersion)));
ReturnErrorOnFailure(reader.Get(FormatVersion));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VendorId)));
ReturnErrorOnFailure(reader.Get(VendorId));

ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray)));
ReturnErrorOnFailure(reader.EnterContainer(outerContainer2));

ContainsPID = true;

ReturnErrorOnFailure(reader.ExitContainer(outerContainer2));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DeviceTypeId)));
ReturnErrorOnFailure(reader.Get(DeviceTypeId));

ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ContextTag(kTag_CertificateId)));
ReturnErrorOnFailure(reader.GetString(CertificateId, sizeof(CertificateId)));
VerifyOrReturnError(strlen(CertificateId) == kCertificateIdLength, CHIP_ERROR_INVALID_TLV_ELEMENT);

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityLevel)));
ReturnErrorOnFailure(reader.Get(SecurityLevel));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_SecurityInformation)));
ReturnErrorOnFailure(reader.Get(SecurityInformation));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_VersionNumber)));
ReturnErrorOnFailure(reader.Get(VersionNumber));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_CertificationType)));
ReturnErrorOnFailure(reader.Get(CertificationType));

DACOriginVIDandPIDPresent = false;

// If kTag_DACOriginVendorId present then kTag_DACOriginProductId must be present.
if ((err = reader.Next(ContextTag(kTag_DACOriginVendorId))) == CHIP_NO_ERROR)
{
ReturnErrorOnFailure(reader.Get(DACOriginVendorId));

ReturnErrorOnFailure(reader.Next(ContextTag(kTag_DACOriginProductId)));
ReturnErrorOnFailure(reader.Get(DACOriginProductId));

DACOriginVIDandPIDPresent = true;

err = reader.Next();
}
VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT || err == CHIP_NO_ERROR, err);

ReturnErrorOnFailure(reader.ExitContainer(outerContainer1));

ReturnErrorOnFailure(reader.VerifyEndOfContainer());

return CHIP_NO_ERROR;
}

bool CertificationElementsDecoder::IsProductIdIn(const ByteSpan & encodedCertElements, uint16_t productId)
{
VerifyOrReturnError(PrepareToReadProductIdList(encodedCertElements) == CHIP_NO_ERROR, false);

uint16_t cdProductId = 0;
CHIP_ERROR error = CHIP_NO_ERROR;

while ((error = GetNextProductId(cdProductId)) == CHIP_NO_ERROR)
{
if (productId == cdProductId)
{
return true;
}
}

return false;
}

CHIP_ERROR CertificationElementsDecoder::PrepareToReadProductIdList(const ByteSpan & encodedCertElements)
{
mIsInitialized = false;
mCertificationDeclarationData = encodedCertElements;

mReader.Init(mCertificationDeclarationData);
ReturnErrorOnFailure(mReader.Next(kTLVType_Structure, AnonymousTag));
ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType1));

// position to ProductId Array
CHIP_ERROR error = CHIP_NO_ERROR;
do
{
error = mReader.Next(kTLVType_Array, ContextTag(kTag_ProductIdArray));
// return error code if Next method returned different than CHIP_NO_ERROR.
// also return if different error code than CHIP_ERROR_WRONG_TLV_TYPE/CHIP_ERROR_UNEXPECTED_TLV_ELEMENT, which means that
// the expected type and tags do not match.
VerifyOrReturnError(
error == CHIP_NO_ERROR || error == CHIP_ERROR_WRONG_TLV_TYPE || error == CHIP_ERROR_UNEXPECTED_TLV_ELEMENT, error);
} while (error != CHIP_NO_ERROR);

ReturnErrorOnFailure(mReader.EnterContainer(mOuterContainerType2));

mIsInitialized = true;
return CHIP_NO_ERROR;
}

CHIP_ERROR CertificationElementsDecoder::GetNextProductId(uint16_t & productId)
{
VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
ReturnErrorOnFailure(mReader.Next(AnonymousTag));
ReturnErrorOnFailure(mReader.Get(productId));
return CHIP_NO_ERROR;
}

namespace {

CHIP_ERROR EncodeEncapsulatedContent(const ByteSpan & cdContent, ASN1Writer & writer)
Expand Down
34 changes: 33 additions & 1 deletion src/credentials/CertificationDeclaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <crypto/CHIPCryptoPAL.h>
#include <lib/asn1/ASN1.h>
#include <lib/asn1/ASN1Macros.h>
#include <lib/core/CHIPTLV.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/Span.h>

Expand Down Expand Up @@ -62,6 +63,36 @@ struct CertificationElements
bool DACOriginVIDandPIDPresent;
};

class CertificationElementsDecoder
{
public:
uint16_t FormatVersion;
uint16_t VendorId;
bool ContainsPID;
uint32_t DeviceTypeId;
char CertificateId[kCertificateIdLength + 1];
uint8_t SecurityLevel;
uint16_t SecurityInformation;
uint16_t VersionNumber;
uint8_t CertificationType;
uint16_t DACOriginVendorId;
uint16_t DACOriginProductId;
bool DACOriginVIDandPIDPresent;

CHIP_ERROR DecodeCertificationElements(const ByteSpan & encodedCertElements);
bool IsProductIdIn(const ByteSpan & encodedCertElements, uint16_t productId);

private:
CHIP_ERROR PrepareToReadProductIdList(const ByteSpan & encodedCertElements);
CHIP_ERROR GetNextProductId(uint16_t & productId);

ByteSpan mCertificationDeclarationData;
bool mIsInitialized = false;
TLV::TLVReader mReader;
TLV::TLVType mOuterContainerType1 = TLV::kTLVType_Structure;
TLV::TLVType mOuterContainerType2 = TLV::kTLVType_Structure;
};

/**
* @brief Encode certification elements in TLV format.
*
Expand All @@ -70,7 +101,8 @@ struct CertificationElements
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR EncodeCertificationElements(const CertificationElements & certElements, MutableByteSpan & encodedCertElements);
CHIP_ERROR
EncodeCertificationElements(const CertificationElements & certElements, MutableByteSpan & encodedCertElements);

/**
* @brief Decode certification elements from TLV encoded structure.
Expand Down
11 changes: 3 additions & 8 deletions src/credentials/DeviceAttestationVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,12 @@ class UnimplementedDACVerifier : public DeviceAttestationVerifier
}

AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
const ByteSpan & firmwareInfo, uint16_t clusterVendorId,
uint16_t clusterProductId, uint16_t dacVendorId,
uint16_t dacProductId, uint16_t paiProductId) override
const ByteSpan & firmwareInfo,
DeviceInfoForAttestation deviceInfo) override
{
(void) certDeclBuffer;
(void) firmwareInfo;
(void) clusterVendorId;
(void) clusterProductId;
(void) dacVendorId;
(void) dacProductId;
(void) paiProductId;
(void) deviceInfo;
return AttestationVerificationResult::kNotImplemented;
}
};
Expand Down
26 changes: 18 additions & 8 deletions src/credentials/DeviceAttestationVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ enum CertificateType : uint8_t
kPAI = 2,
};

struct DeviceInfoForAttestation
{
// Vendor ID reported by device in Basic Information cluster
uint16_t vendorId = 0;
// Product ID reported by device in Basic Information cluster
uint16_t productId = 0;
// Vendor ID from DAC/PAI/PAA
uint16_t dacVendorId = 0;
// Product ID from DAC
uint16_t dacProductId = 0;
// Product ID from PAI cert (0 if absent)
uint16_t paiProductId = 0;
// Vendor ID from PAA cert (0 if absent)
uint16_t paaProductId = 0;
};

class DeviceAttestationVerifier
{
public:
Expand Down Expand Up @@ -125,20 +141,14 @@ class DeviceAttestationVerifier
*
* @param[in] certDeclBuffer A ByteSpan with the Certification Declaration content.
* @param[in] firmwareInfo A ByteSpan with the Firmware Information content.
* @param[in] clusterVendorId
* @param[in] clusterProductId
* @param[in] dacVendorId
* @param[in] dacProductId
* @param[in] paiProductId
* @param[in] deviceInfo
*
* @returns AttestationVerificationResult::kSuccess on success or another specific
* value from AttestationVerificationResult enum on failure.
*/
virtual AttestationVerificationResult ValidateCertificateDeclarationPayload(const ByteSpan & certDeclBuffer,
const ByteSpan & firmwareInfo,
uint16_t clusterVendorId, uint16_t clusterProductId,
uint16_t dacVendorId, uint16_t dacProductId,
uint16_t paiProductId) = 0;
DeviceInfoForAttestation deviceInfo) = 0;

// TODO: Validate Firmware Information

Expand Down
Loading

0 comments on commit d0f7bb1

Please sign in to comment.