diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 091058452af1fb..c88efed873db57 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -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 @@ -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() || @@ -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()) { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 9161eb05b37770..0362576b258abd 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -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 diff --git a/src/credentials/DeviceAttestationVerifier.cpp b/src/credentials/DeviceAttestationVerifier.cpp index ab71dc8b637191..68c69136893e19 100644 --- a/src/credentials/DeviceAttestationVerifier.cpp +++ b/src/credentials/DeviceAttestationVerifier.cpp @@ -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 * onCompletion) override { - (void) attestationInfoBuffer; - (void) attestationChallengeBuffer; - (void) attestationSignatureBuffer; - (void) paiDerBuffer; - (void) dacDerBuffer; - (void) attestationNonce; + (void) info; (void) onCompletion; } diff --git a/src/credentials/DeviceAttestationVerifier.h b/src/credentials/DeviceAttestationVerifier.h index e4a983e7386af7..5fc0831f2976a5 100644 --- a/src/credentials/DeviceAttestationVerifier.h +++ b/src/credentials/DeviceAttestationVerifier.h @@ -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 * onCompletion) = 0; /** diff --git a/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp b/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp index 35bcf5115a130d..0f084cb50d28e3 100644 --- a/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/examples/DefaultDeviceAttestationVerifier.cpp @@ -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 * onCompletion) override; AttestationVerificationResult ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer, @@ -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 * onCompletion) { AttestationVerificationResult attestationError = AttestationVerificationResult::kSuccess; @@ -185,8 +178,9 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati Platform::ScopedMemoryBuffer 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 @@ -194,9 +188,9 @@ void DefaultDACVerifier::VerifyAttestationInformation(const ByteSpan & attestati 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); @@ -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); } @@ -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); @@ -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. @@ -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); diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index 1f22286e36484e..b0a3285219379c 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -208,10 +208,11 @@ static void TestDACVerifierExample_AttestationInfoVerification(nlTestSuite * inS Callback::Callback attestationInformationVerificationCallback( OnAttestationInformationVerificationCallback, &attestationResult); - default_verifier->VerifyAttestationInformation( + Credentials::DeviceAttestationVerifier::AttestationInfo info( ByteSpan(attestationElementsTestVector), ByteSpan(attestationChallengeTestVector), ByteSpan(attestationSignatureTestVector), TestCerts::sTestCert_PAI_FFF1_8000_Cert, TestCerts::sTestCert_DAC_FFF1_8000_0004_Cert, ByteSpan(attestationNonceTestVector), - static_cast(0xFFF1), 0x8000, &attestationInformationVerificationCallback); + static_cast(0xFFF1), 0x8000); + default_verifier->VerifyAttestationInformation(info, &attestationInformationVerificationCallback); NL_TEST_ASSERT(inSuite, attestationResult == AttestationVerificationResult::kSuccess); }