Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate dac verification parameters into struct. #15090

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1133,22 +1133,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 @@ -1849,7 +1840,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 @@ -1859,16 +1850,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 @@ -575,18 +575,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 & attestationElementsBuffer, const ByteSpan & attestationChallengeBuffer,
const ByteSpan & attestationSignatureBuffer, const ByteSpan & paiDerBuffer, const ByteSpan & dacDerBuffer,
const ByteSpan & attestationNonce, VendorId vendorId, uint16_t productId) :
mAttestationElementsBuffer(attestationElementsBuffer),
mAttestationChallengeBuffer(attestationChallengeBuffer), mAttestationSignatureBuffer(attestationSignatureBuffer),
mPaiDerBuffer(paiDerBuffer), mDacDerBuffer(dacDerBuffer), mAttestationNonce(attestationNonce), mVendorId(vendorId),
mProductId(productId)
{}
const ByteSpan &
mAttestationElementsBuffer; // Buffer containing attestation elements portion of Attestation Response (raw TLV)
const ByteSpan & mAttestationChallengeBuffer; // Buffer containing the attestation challenge from the secure session
const ByteSpan & mAttestationSignatureBuffer; // Buffer the signature portion of Attestation Response
const ByteSpan & mPaiDerBuffer; // Buffer containing the PAI certificate from device in DER format.
cecille marked this conversation as resolved.
Show resolved Hide resolved
const ByteSpan & mDacDerBuffer; // Buffer containing the DAC certificate from device in DER format.
const ByteSpan & mAttestationNonce; // Buffer containing attestation nonce.
cecille marked this conversation as resolved.
Show resolved Hide resolved
VendorId mVendorId;
uint16_t mProductId;
};

/**
* @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.mAttestationElementsBuffer.empty() && !info.mAttestationChallengeBuffer.empty() &&
!info.mAttestationSignatureBuffer.empty() && !info.mPaiDerBuffer.empty() && !info.mDacDerBuffer.empty() &&
!info.mAttestationNonce.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.mPaiDerBuffer, paiVid) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, dacDerBuffer, dacVid) == CHIP_NO_ERROR,
VerifyOrExit(ExtractDNAttributeFromX509Cert(MatterOid::kVendorId, info.mDacDerBuffer, 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.mDacDerBuffer, 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.mAttestationSignatureBuffer.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.mAttestationSignatureBuffer.data(), info.mAttestationSignatureBuffer.size());
VerifyOrExit(ValidateAttestationSignature(remoteManufacturerPubkey, info.mAttestationElementsBuffer,
info.mAttestationChallengeBuffer, 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.mPaiDerBuffer, 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.mDacDerBuffer) == CHIP_NO_ERROR,
attestationError = AttestationVerificationResult::kDacExpired);
#endif

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

VerifyOrExit(IsCertificateValidAtIssuance(dacDerBuffer, paaDerBuffer) == CHIP_NO_ERROR,
VerifyOrExit(IsCertificateValidAtIssuance(info.mDacDerBuffer, 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.mPaiDerBuffer.data(),
info.mPaiDerBuffer.size(), info.mDacDerBuffer.data(), info.mDacDerBuffer.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.mVendorId,
.productId = info.mProductId,
.dacVendorId = dacVendorId,
.paiVendorId = dacVendorId,
};

VerifyOrExit(DeconstructAttestationElements(attestationInfoBuffer, certificationDeclarationSpan, attestationNonceSpan,
timestampDeconstructed, firmwareInfoSpan, vendorReserved) == CHIP_NO_ERROR,
VerifyOrExit(DeconstructAttestationElements(info.mAttestationElementsBuffer, 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.mAttestationNonce),
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.mDacDerBuffer, 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.mPaiDerBuffer, deviceInfo.paiProductId);
VerifyOrExit(error == CHIP_NO_ERROR || error == CHIP_ERROR_KEY_NOT_FOUND,
attestationError = AttestationVerificationResult::kPaiFormatInvalid);

Expand Down
Loading