Skip to content

Commit

Permalink
Consolidate dac verification parameters into struct. (#15090)
Browse files Browse the repository at this point in the history
* Consolidate dac verification parameters into struct.

Per request in #14845, issue #14758

* make struct not use references.

* Fix up some naming.
  • Loading branch information
cecille authored and pull[bot] committed Nov 23, 2023
1 parent e3e5753 commit 03e60e3
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 83 deletions.
30 changes: 13 additions & 17 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,22 +1114,13 @@ void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * conte
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
}

CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const ByteSpan & attestationElements, const ByteSpan & signature,
const ByteSpan & attestationNonce, const ByteSpan & pai,
const ByteSpan & dac, VendorId remoteVendorId, uint16_t remoteProductId,
DeviceProxy * proxy)
CHIP_ERROR DeviceCommissioner::ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info)
{
VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(proxy != nullptr, CHIP_ERROR_INCORRECT_STATE);

DeviceAttestationVerifier * dac_verifier = GetDeviceAttestationVerifier();

// Retrieve attestation challenge
ByteSpan attestationChallenge =
proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge();

dac_verifier->VerifyAttestationInformation(attestationElements, attestationChallenge, signature, pai, dac, attestationNonce,
remoteVendorId, remoteProductId, &mDeviceAttestationInformationVerificationCallback);
dac_verifier->VerifyAttestationInformation(info, &mDeviceAttestationInformationVerificationCallback);

// TODO: Validate Firmware Information

Expand Down Expand Up @@ -1830,7 +1821,7 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
}
SendAttestationRequestCommand(proxy, params.GetAttestationNonce().Value());
break;
case CommissioningStage::kAttestationVerification:
case CommissioningStage::kAttestationVerification: {
ChipLogProgress(Controller, "Verifying attestation");
if (!params.GetAttestationElements().HasValue() || !params.GetAttestationSignature().HasValue() ||
!params.GetAttestationNonce().HasValue() || !params.GetDAC().HasValue() || !params.GetPAI().HasValue() ||
Expand All @@ -1840,16 +1831,21 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
return;
}
if (ValidateAttestationInfo(params.GetAttestationElements().Value(), params.GetAttestationSignature().Value(),
params.GetAttestationNonce().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value(),
proxy) != CHIP_NO_ERROR)

DeviceAttestationVerifier::AttestationInfo info(
params.GetAttestationElements().Value(),
proxy->GetSecureSession().Value()->AsSecureSession()->GetCryptoContext().GetAttestationChallenge(),
params.GetAttestationSignature().Value(), params.GetPAI().Value(), params.GetDAC().Value(),
params.GetAttestationNonce().Value(), params.GetRemoteVendorId().Value(), params.GetRemoteProductId().Value());

if (ValidateAttestationInfo(info) != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Error validating attestation information");
CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
return;
}
break;
}
break;
case CommissioningStage::kSendOpCertSigningRequest:
if (!params.GetCSRNonce().HasValue())
{
Expand Down
15 changes: 3 additions & 12 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,18 +574,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
* @brief
* This function validates the Attestation Information sent by the device.
*
* @param[in] attestationElements Attestation Elements TLV.
* @param[in] signature Attestation signature generated for all the above fields + Attestation Challenge.
* @param[in] attestationNonce Attestation nonce
* @param[in] pai PAI certificate
* @param[in] dac DAC certificates
* @param[in] remoteVendorId vendor ID read from the device Basic Information cluster
* @param[in] remoteProductId product ID read from the device Basic Information cluster
* @param[in] proxy device proxy that is being attested.
*/
CHIP_ERROR ValidateAttestationInfo(const ByteSpan & attestationElements, const ByteSpan & signature,
const ByteSpan & attestationNonce, const ByteSpan & pai, const ByteSpan & dac,
VendorId remoteVendorId, uint16_t remoteProductId, DeviceProxy * proxy);
* @param[in] info Structure contatining all the required information for validating the device attestation.
*/
CHIP_ERROR ValidateAttestationInfo(const Credentials::DeviceAttestationVerifier::AttestationInfo & info);

/**
* @brief
Expand Down
12 changes: 2 additions & 10 deletions src/credentials/DeviceAttestationVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,10 @@ namespace {
class UnimplementedDACVerifier : public DeviceAttestationVerifier
{
public:
void VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer, const ByteSpan & attestationChallengeBuffer,
const ByteSpan & attestationSignatureBuffer, const ByteSpan & paiDerBuffer,
const ByteSpan & dacDerBuffer, const ByteSpan & attestationNonce, VendorId vendorId,
uint16_t productId,
void VerifyAttestationInformation(const AttestationInfo & info,
Callback::Callback<OnAttestationInformationVerification> * onCompletion) override
{
(void) attestationInfoBuffer;
(void) attestationChallengeBuffer;
(void) attestationSignatureBuffer;
(void) paiDerBuffer;
(void) dacDerBuffer;
(void) attestationNonce;
(void) info;
(void) onCompletion;
}

Expand Down
34 changes: 23 additions & 11 deletions src/credentials/DeviceAttestationVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,23 +198,35 @@ class DeviceAttestationVerifier
DeviceAttestationVerifier(const DeviceAttestationVerifier &) = delete;
DeviceAttestationVerifier & operator=(const DeviceAttestationVerifier &) = delete;

struct AttestationInfo
{
AttestationInfo(const ByteSpan & attestationElements, const ByteSpan & attestationChallenge,
const ByteSpan & attestationSignature, const ByteSpan & paiDer, const ByteSpan & dacDer,
const ByteSpan & attestationNonce, VendorId remoteVendorId, uint16_t remoteProductId) :
attestationElementsBuffer(attestationElements),
attestationChallengeBuffer(attestationChallenge), attestationSignatureBuffer(attestationSignature),
paiDerBuffer(paiDer), dacDerBuffer(dacDer), attestationNonceBuffer(attestationNonce), vendorId(remoteVendorId),
productId(remoteProductId)
{}
const ByteSpan
attestationElementsBuffer; // Buffer containing attestation elements portion of Attestation Response (raw TLV)
const ByteSpan attestationChallengeBuffer; // Buffer containing the attestation challenge from the secure session
const ByteSpan attestationSignatureBuffer; // Buffer the signature portion of Attestation Response
const ByteSpan paiDerBuffer; // Buffer containing the PAI certificate from device in DER format.
const ByteSpan dacDerBuffer; // Buffer containing the DAC certificate from device in DER format.
const ByteSpan attestationNonceBuffer; // Buffer containing attestation nonce.
VendorId vendorId;
uint16_t productId;
};

/**
* @brief Verify an attestation information payload against a DAC/PAI chain.
*
* @param[in] attestationInfoBuffer Buffer containing attestation information portion of Attestation Response (raw TLV)
* @param[in] attestationChallengeBuffer Buffer containing the attestation challenge from the secure session
* @param[in] attestationSignatureBuffer Buffer the signature portion of Attestation Response
* @param[in] paiDerBuffer Buffer containing the PAI certificate from device in DER format.
* If length zero, there was no PAI certificate.
* @param[in] dacDerBuffer Buffer containing the DAC certificate from device in DER format.
* @param[in] attestationNonce Buffer containing attestation nonce.
* @param[in] attestationInfo All of the information required to verify the attestation.
* @param[in] onCompletion Callback handler to provide Attestation Information Verification result to the caller of
* VerifyAttestationInformation()
*/
virtual void VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer, const ByteSpan & attestationChallengeBuffer,
const ByteSpan & attestationSignatureBuffer, const ByteSpan & paiDerBuffer,
const ByteSpan & dacDerBuffer, const ByteSpan & attestationNonce, VendorId vendorId,
uint16_t productId,
virtual void VerifyAttestationInformation(const AttestationInfo & info,
Callback::Callback<OnAttestationInformationVerification> * onCompletion) = 0;

/**
Expand Down
59 changes: 28 additions & 31 deletions src/credentials/examples/DefaultDeviceAttestationVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,7 @@ class DefaultDACVerifier : public DeviceAttestationVerifier
public:
DefaultDACVerifier(const AttestationTrustStore * paaRootStore) : mAttestationTrustStore(paaRootStore) {}

void VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer, const ByteSpan & attestationChallengeBuffer,
const ByteSpan & attestationSignatureBuffer, const ByteSpan & paiDerBuffer,
const ByteSpan & dacDerBuffer, const ByteSpan & attestationNonce, VendorId vendorId,
uint16_t productId,
void VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info,
Callback::Callback<OnAttestationInformationVerification> * onCompletion) override;

AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer,
Expand All @@ -172,11 +169,7 @@ class DefaultDACVerifier : public DeviceAttestationVerifier
const AttestationTrustStore * mAttestationTrustStore;
};

void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestationInfoBuffer,
const ByteSpan & attestationChallengeBuffer,
const ByteSpan & attestationSignatureBuffer, const ByteSpan & paiDerBuffer,
const ByteSpan & dacDerBuffer, const ByteSpan & attestationNonce,
VendorId vendorId, uint16_t productId,
void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVerifier::AttestationInfo & info,
Callback::Callback<OnAttestationInformationVerification> * onCompletion)
{
AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess;
Expand All @@ -185,18 +178,19 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati
Platform::ScopedMemoryBuffer<uint8_t> paaCert;
MutableByteSpan paaDerBuffer;

VerifyOrExit(!attestationInfoBuffer.empty() && !attestationChallengeBuffer.empty() && !attestationSignatureBuffer.empty() &&
!paiDerBuffer.empty() && !dacDerBuffer.empty() && !attestationNonce.empty() && onCompletion != nullptr,
VerifyOrExit(!info.attestationElementsBuffer.empty() && !info.attestationChallengeBuffer.empty() &&
!info.attestationSignatureBuffer.empty() && !info.paiDerBuffer.empty() && !info.dacDerBuffer.empty() &&
!info.attestationNonceBuffer.empty() && onCompletion != nullptr,
attestationError = AttestationVerificationResult::kInvalidArgument);

// match DAC and PAI VIDs
{
uint16_t paiVid = VendorId::NotSpecified;
uint16_t dacVid = VendorId::NotSpecified;

VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, paiDerBuffer, paiVid) == CHIP_NO_ERROR,
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, info.paiDerBuffer, paiVid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, dacDerBuffer, dacVid) == CHIP_NO_ERROR,
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, info.dacDerBuffer, dacVid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kDacFormatInvalid);

VerifyOrExit(paiVid == dacVid, attestationError = AttestationVerificationResult::kDacVendorIdMismatch);
Expand All @@ -207,16 +201,16 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati
P256PublicKey remoteManufacturerPubkey;
P256ECDSASignature deviceSignature;

VerifyOrExit(ExtractPubkeyFromX509Cert(dacDerBuffer, remoteManufacturerPubkey) == CHIP_NO_ERROR,
VerifyOrExit(ExtractPubkeyFromX509Cert(info.dacDerBuffer, remoteManufacturerPubkey) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kDacFormatInvalid);

// Validate overall attestation signature on attestation information
// SetLength will fail if signature doesn't fit
VerifyOrExit(deviceSignature.SetLength(attestationSignatureBuffer.size()) == CHIP_NO_ERROR,
VerifyOrExit(deviceSignature.SetLength(info.attestationSignatureBuffer.size()) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kAttestationSignatureInvalidFormat);
memcpy(deviceSignature.Bytes(), attestationSignatureBuffer.data(), attestationSignatureBuffer.size());
VerifyOrExit(ValidateAttestationSignature(remoteManufacturerPubkey, attestationInfoBuffer, attestationChallengeBuffer,
deviceSignature) == CHIP_NO_ERROR,
memcpy(deviceSignature.Bytes(), info.attestationSignatureBuffer.data(), info.attestationSignatureBuffer.size());
VerifyOrExit(ValidateAttestationSignature(remoteManufacturerPubkey, info.attestationElementsBuffer,
info.attestationChallengeBuffer, deviceSignature) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kAttestationSignatureInvalid);
}

Expand All @@ -225,7 +219,7 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati
MutableByteSpan akid(akidBuf);
constexpr size_t paaCertAllocatedLen = kMaxDERCertLength;

VerifyOrExit(ExtractAKIDFromX509Cert(paiDerBuffer, akid) == CHIP_NO_ERROR,
VerifyOrExit(ExtractAKIDFromX509Cert(info.paiDerBuffer, akid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);

VerifyOrExit(paaCert.Alloc(paaCertAllocatedLen), attestationError = AttestationVerificationResult::kNoMemory);
Expand All @@ -236,19 +230,20 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati
}

#if !defined(CURRENT_TIME_NOT_IMPLEMENTED)
VerifyOrExit(IsCertificateValidAtCurrentTime(dacDerBuffer) == CHIP_NO_ERROR,
VerifyOrExit(IsCertificateValidAtCurrentTime(info.dacDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kDacExpired);
#endif

VerifyOrExit(IsCertificateValidAtIssuance(dacDerBuffer, paiDerBuffer) == CHIP_NO_ERROR,
VerifyOrExit(IsCertificateValidAtIssuance(info.dacDerBuffer, info.paiDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaiExpired);

VerifyOrExit(IsCertificateValidAtIssuance(dacDerBuffer, paaDerBuffer) == CHIP_NO_ERROR,
VerifyOrExit(IsCertificateValidAtIssuance(info.dacDerBuffer, paaDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaaExpired);

CertificateChainValidationResult chainValidationResult;
VerifyOrExit(ValidateCertificateChain(paaDerBuffer.data(), paaDerBuffer.size(), paiDerBuffer.data(), paiDerBuffer.size(),
dacDerBuffer.data(), dacDerBuffer.size(), chainValidationResult) == CHIP_NO_ERROR,
VerifyOrExit(ValidateCertificateChain(paaDerBuffer.data(), paaDerBuffer.size(), info.paiDerBuffer.data(),
info.paiDerBuffer.size(), info.dacDerBuffer.data(), info.dacDerBuffer.size(),
chainValidationResult) == CHIP_NO_ERROR,
attestationError = MapError(chainValidationResult));

// if PAA contains VID, see if matches with DAC's VID.
Expand All @@ -273,28 +268,30 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati
ByteSpan certificationDeclarationPayload;

DeviceInfoForAttestation deviceInfo{
.vendorId = vendorId,
.productId = productId,
.vendorId = info.vendorId,
.productId = info.productId,
.dacVendorId = dacVendorId,
.paiVendorId = dacVendorId,
};

VerifyOrExit(DeconstructAttestationElements(attestationInfoBuffer, certificationDeclarationSpan, attestationNonceSpan,
timestampDeconstructed, firmwareInfoSpan, vendorReserved) == CHIP_NO_ERROR,
VerifyOrExit(DeconstructAttestationElements(info.attestationElementsBuffer, certificationDeclarationSpan,
attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan,
vendorReserved) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kAttestationElementsMalformed);

// Verify that Nonce matches with what we sent
VerifyOrExit(attestationNonceSpan.data_equal(attestationNonce),
VerifyOrExit(attestationNonceSpan.data_equal(info.attestationNonceBuffer),
attestationError = AttestationVerificationResult::kAttestationNonceMismatch);

attestationError = ValidateCertificationDeclarationSignature(certificationDeclarationSpan, certificationDeclarationPayload);
VerifyOrExit(attestationError == AttestationVerificationResult::kSuccess, attestationError = attestationError);

VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kProductId, dacDerBuffer, deviceInfo.dacProductId) == CHIP_NO_ERROR,
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kProductId, info.dacDerBuffer, deviceInfo.dacProductId) ==
CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kDacFormatInvalid);
// If PID is missing from PAI, the next method call will return CHIP_ERROR_KEY_NOT_FOUND.
// Valid return values are then CHIP_NO_ERROR or CHIP_ERROR_KEY_NOT_FOUND.
error = ExtractDNAttributeFromX509Cert(MatterOid::kProductId, paiDerBuffer, deviceInfo.paiProductId);
error = ExtractDNAttributeFromX509Cert(MatterOid::kProductId, info.paiDerBuffer, deviceInfo.paiProductId);
VerifyOrExit(error == CHIP_NO_ERROR || error == CHIP_ERROR_KEY_NOT_FOUND,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);

Expand Down
Loading

0 comments on commit 03e60e3

Please sign in to comment.