diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 0bf9ee911359d9..1fcfd783da2042 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -796,8 +796,8 @@ CHIP_ERROR DeviceCommissioner::Commission(NodeId remoteDeviceId) } CHIP_ERROR -DeviceCommissioner::ContinueCommissioningAfterDeviceAttestationFailure(DeviceProxy * device, - Credentials::AttestationVerificationResult attestationResult) +DeviceCommissioner::ContinueCommissioningAfterDeviceAttestation(DeviceProxy * device, + Credentials::AttestationVerificationResult attestationResult) { MATTER_TRACE_EVENT_SCOPE("continueCommissioningDevice", "DeviceCommissioner"); if (device == nullptr || device != mDeviceBeingCommissioned) @@ -993,7 +993,8 @@ void DeviceCommissioner::OnAttestationResponse(void * context, commissioner->CommissioningStageComplete(CHIP_NO_ERROR, report); } -void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * context, AttestationVerificationResult result) +void DeviceCommissioner::OnDeviceAttestationInformationVerification( + void * context, const Credentials::DeviceAttestationVerifier::AttestationInfo & info, AttestationVerificationResult result) { MATTER_TRACE_EVENT_SCOPE("OnDeviceAttestationInformationVerification", "DeviceCommissioner"); DeviceCommissioner * commissioner = reinterpret_cast(context); @@ -1004,6 +1005,9 @@ void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * conte return; } + auto & params = commissioner->mDefaultCommissioner->GetCommissioningParameters(); + Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate(); + if (result != AttestationVerificationResult::kSuccess) { CommissioningDelegate::CommissioningReport report; @@ -1024,14 +1028,11 @@ void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * conte // Go look at AttestationVerificationResult enum in src/credentials/attestation_verifier/DeviceAttestationVerifier.h to // understand the errors. - auto & params = commissioner->mDefaultCommissioner->GetCommissioningParameters(); - Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate(); - // If a device attestation status delegate is installed, delegate handling of failure to the client and let them // decide on whether to proceed further or not. if (deviceAttestationDelegate) { - commissioner->ExtendArmFailSafeForFailedDeviceAttestation(result); + commissioner->ExtendArmFailSafeForDeviceAttestation(info, result); } else { @@ -1040,15 +1041,22 @@ void DeviceCommissioner::OnDeviceAttestationInformationVerification(void * conte } else { - ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device."); - commissioner->CommissioningStageComplete(CHIP_NO_ERROR); + if (deviceAttestationDelegate && deviceAttestationDelegate->ShouldWaitAfterDeviceAttestation()) + { + commissioner->ExtendArmFailSafeForDeviceAttestation(info, result); + } + else + { + ChipLogProgress(Controller, "Successfully validated 'Attestation Information' command received from the device."); + commissioner->CommissioningStageComplete(CHIP_NO_ERROR); + } } } -void DeviceCommissioner::OnArmFailSafeExtendedForFailedDeviceAttestation( +void DeviceCommissioner::OnArmFailSafeExtendedForDeviceAttestation( void * context, const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data) { - // If this function starts using "data", need to fix ExtendArmFailSafeForFailedDeviceAttestation accordingly. + // If this function starts using "data", need to fix ExtendArmFailSafeForDeviceAttestation accordingly. DeviceCommissioner * commissioner = static_cast(context); if (!commissioner->mDeviceBeingCommissioned) @@ -1061,8 +1069,9 @@ void DeviceCommissioner::OnArmFailSafeExtendedForFailedDeviceAttestation( if (deviceAttestationDelegate) { ChipLogProgress(Controller, "Device attestation failed, delegating error handling to client"); - deviceAttestationDelegate->OnDeviceAttestationFailed(commissioner, commissioner->mDeviceBeingCommissioned, - commissioner->mAttestationResult); + deviceAttestationDelegate->OnDeviceAttestationCompleted(commissioner, commissioner->mDeviceBeingCommissioned, + *commissioner->mAttestationDeviceInfo, + commissioner->mAttestationResult); } else { @@ -1073,7 +1082,7 @@ void DeviceCommissioner::OnArmFailSafeExtendedForFailedDeviceAttestation( } } -void DeviceCommissioner::OnFailedToExtendedArmFailSafeFailedDeviceAttestation(void * context, CHIP_ERROR error) +void DeviceCommissioner::OnFailedToExtendedArmFailSafeDeviceAttestation(void * context, CHIP_ERROR error) { ChipLogProgress(Controller, "Failed to extend fail-safe timer to handle attestation failure %s", chip::ErrorStr(error)); DeviceCommissioner * commissioner = static_cast(context); @@ -1083,13 +1092,29 @@ void DeviceCommissioner::OnFailedToExtendedArmFailSafeFailedDeviceAttestation(vo commissioner->CommissioningStageComplete(CHIP_ERROR_INTERNAL, report); } -void DeviceCommissioner::ExtendArmFailSafeForFailedDeviceAttestation(AttestationVerificationResult result) +void DeviceCommissioner::ClearAttestationDeviceInfo() +{ + if (mAttestationDeviceInfo != nullptr) + { + chip::Platform::Delete(mAttestationDeviceInfo); + mAttestationDeviceInfo = nullptr; + } +} + +void DeviceCommissioner::ExtendArmFailSafeForDeviceAttestation(const Credentials::DeviceAttestationVerifier::AttestationInfo & info, + Credentials::AttestationVerificationResult result) { mAttestationResult = result; auto & params = mDefaultCommissioner->GetCommissioningParameters(); Credentials::DeviceAttestationDelegate * deviceAttestationDelegate = params.GetDeviceAttestationDelegate(); - auto expiryLengthSeconds = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs(); + + if (deviceAttestationDelegate->ShouldWaitAfterDeviceAttestation()) + { + mAttestationDeviceInfo = chip::Platform::New(info); + } + + auto expiryLengthSeconds = deviceAttestationDelegate->FailSafeExpiryTimeoutSecs(); if (expiryLengthSeconds.HasValue()) { GeneralCommissioning::Commands::ArmFailSafe::Type request; @@ -1098,8 +1123,8 @@ void DeviceCommissioner::ExtendArmFailSafeForFailedDeviceAttestation(Attestation ChipLogProgress(Controller, "Changing fail-safe timer to %u seconds to handle DA failure", request.expiryLengthSeconds); // Per spec, anything we do with the fail-safe armed must not time out // in less than kMinimumCommissioningStepTimeout. - SendCommand(mDeviceBeingCommissioned, request, OnArmFailSafeExtendedForFailedDeviceAttestation, - OnFailedToExtendedArmFailSafeFailedDeviceAttestation, + SendCommand(mDeviceBeingCommissioned, request, OnArmFailSafeExtendedForDeviceAttestation, + OnFailedToExtendedArmFailSafeDeviceAttestation, MakeOptional(kMinimumCommissioningStepTimeout)); } else @@ -1107,7 +1132,7 @@ void DeviceCommissioner::ExtendArmFailSafeForFailedDeviceAttestation(Attestation ChipLogProgress(Controller, "Proceeding without changing fail-safe timer value as delegate has not set it"); // Callee does not use data argument. const GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType data; - OnArmFailSafeExtendedForFailedDeviceAttestation(this, data); + OnArmFailSafeExtendedForDeviceAttestation(this, data); } } @@ -1474,6 +1499,9 @@ void OnBasicFailure(void * context, CHIP_ERROR error) void DeviceCommissioner::CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus) { commissioningCompletionStatus = completionStatus; + + ClearAttestationDeviceInfo(); + if (completionStatus.err == CHIP_NO_ERROR) { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 62f97c0c30e80d..029f2665fbe532 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -487,15 +487,14 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, /** * @brief * This function instructs the commissioner to proceed to the next stage of commissioning after - * attestation failure is reported to an installed attestation delegate. + * attestation is reported to an installed attestation delegate. * * @param[in] device The device being commissioned. * @param[in] attestationResult The attestation result to use instead of whatever the device * attestation verifier came up with. May be a success or an error result. */ CHIP_ERROR - ContinueCommissioningAfterDeviceAttestationFailure(DeviceProxy * device, - Credentials::AttestationVerificationResult attestationResult); + ContinueCommissioningAfterDeviceAttestation(DeviceProxy * device, Credentials::AttestationVerificationResult attestationResult); CHIP_ERROR GetDeviceBeingCommissioned(NodeId deviceId, CommissioneeDeviceProxy ** device); @@ -715,7 +714,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, /* Callback when the previously sent CSR request results in failure */ static void OnCSRFailureResponse(void * context, CHIP_ERROR error); - void ExtendArmFailSafeForFailedDeviceAttestation(Credentials::AttestationVerificationResult result); + void ClearAttestationDeviceInfo(); + void ExtendArmFailSafeForDeviceAttestation(const Credentials::DeviceAttestationVerifier::AttestationInfo & info, + Credentials::AttestationVerificationResult result); static void OnCertificateChainFailureResponse(void * context, CHIP_ERROR error); static void OnCertificateChainResponse( void * context, const app::Clusters::OperationalCredentials::Commands::CertificateChainResponse::DecodableType & response); @@ -754,7 +755,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, static void OnDeviceConnectedFn(void * context, Messaging::ExchangeManager & exchangeMgr, SessionHandle & sessionHandle); static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error); - static void OnDeviceAttestationInformationVerification(void * context, Credentials::AttestationVerificationResult result); + static void OnDeviceAttestationInformationVerification(void * context, + const Credentials::DeviceAttestationVerifier::AttestationInfo & info, + Credentials::AttestationVerificationResult result); static void OnDeviceNOCChainGeneration(void * context, CHIP_ERROR status, const ByteSpan & noc, const ByteSpan & icac, const ByteSpan & rcac, Optional ipk, Optional adminSubject); @@ -779,9 +782,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data); static void OnDisarmFailsafeFailure(void * context, CHIP_ERROR error); void DisarmDone(); - static void OnArmFailSafeExtendedForFailedDeviceAttestation( + static void OnArmFailSafeExtendedForDeviceAttestation( void * context, const chip::app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data); - static void OnFailedToExtendedArmFailSafeFailedDeviceAttestation(void * context, CHIP_ERROR error); + static void OnFailedToExtendedArmFailSafeDeviceAttestation(void * context, CHIP_ERROR error); /** * @brief @@ -860,7 +863,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, chip::Callback::Callback mOnDeviceConnectedCallback; chip::Callback::Callback mOnDeviceConnectionFailureCallback; - chip::Callback::Callback mDeviceAttestationInformationVerificationCallback; + chip::Callback::Callback + mDeviceAttestationInformationVerificationCallback; chip::Callback::Callback mDeviceNOCChainCallback; SetUpCodePairer mSetUpCodePairer; @@ -874,7 +878,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, Platform::UniquePtr mAttributeCache; Platform::UniquePtr mReadClient; Credentials::AttestationVerificationResult mAttestationResult; - Credentials::DeviceAttestationVerifier * mDeviceAttestationVerifier = nullptr; + Credentials::DeviceAttestationVerifier::AttestationDeviceInfo * mAttestationDeviceInfo = nullptr; + Credentials::DeviceAttestationVerifier * mDeviceAttestationVerifier = nullptr; }; } // namespace Controller diff --git a/src/controller/CommissioningDelegate.h b/src/controller/CommissioningDelegate.h index 1e3fdef1276e44..628f096a00b2e8 100644 --- a/src/controller/CommissioningDelegate.h +++ b/src/controller/CommissioningDelegate.h @@ -414,6 +414,7 @@ class CommissioningParameters CompletionStatus completionStatus; Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate = nullptr; // Delegate to handle device attestation failures during commissioning + Optional mShouldWaitPostDeviceAttestation; Optional mAttemptWiFiNetworkScan; Optional mAttemptThreadNetworkScan; // This automatically gets set to false when a ThreadOperationalDataset is set Optional mSkipCommissioningComplete; diff --git a/src/credentials/attestation_verifier/DacOnlyPartialAttestationVerifier.cpp b/src/credentials/attestation_verifier/DacOnlyPartialAttestationVerifier.cpp index 4dd6ab7d35a8f2..0d40f240fdcec4 100644 --- a/src/credentials/attestation_verifier/DacOnlyPartialAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DacOnlyPartialAttestationVerifier.cpp @@ -148,7 +148,7 @@ void PartialDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer } exit: - onCompletion->mCall(onCompletion->mContext, attestationError); + onCompletion->mCall(onCompletion->mContext, info, attestationError); } } // namespace Credentials diff --git a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp index 07db1d3726d9b9..f60d4b2d70d325 100644 --- a/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DefaultDeviceAttestationVerifier.cpp @@ -277,7 +277,7 @@ void DefaultDACVerifier::VerifyAttestationInformation(const DeviceAttestationVer } exit: - onCompletion->mCall(onCompletion->mContext, attestationError); + onCompletion->mCall(onCompletion->mContext, info, attestationError); } AttestationVerificationResult DefaultDACVerifier::ValidateCertificationDeclarationSignature(const ByteSpan & cmsEnvelopeBuffer, diff --git a/src/credentials/attestation_verifier/DeviceAttestationDelegate.h b/src/credentials/attestation_verifier/DeviceAttestationDelegate.h index 41ad284932abcf..874ca533244656 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationDelegate.h +++ b/src/credentials/attestation_verifier/DeviceAttestationDelegate.h @@ -48,14 +48,29 @@ class DeviceAttestationDelegate /** * @brief * This method is invoked when device attestation fails for a device that is being commissioned. The client - * handling the failure has the option to continue commissionning or fail the operation. + * handling the failure has the option to continue commissioning or fail the operation. + * + * If ShouldWaitAfterDeviceAttestation returns false, then in the case attestationResult is successful, the + * commissioner would finish commissioning the device after OnDeviceAttestationCompleted returns. + * + * If ShouldWaitAfterDeviceAttestation returns true, then the commissioner will always wait for a + * ContinueCommissioningAfterDeviceAttestation call after calling OnDeviceAttestationCompleted. * * @param deviceCommissioner The commissioner object that is commissioning the device * @param device The proxy represent the device being commissioned + * @param info The structure holding device infor for additional verification by the application * @param attestationResult The failure code for the device attestation validation operation */ - virtual void OnDeviceAttestationFailed(Controller::DeviceCommissioner * deviceCommissioner, DeviceProxy * device, - AttestationVerificationResult attestationResult) = 0; + virtual void OnDeviceAttestationCompleted(Controller::DeviceCommissioner * deviceCommissioner, DeviceProxy * device, + const DeviceAttestationVerifier::AttestationDeviceInfo & info, + AttestationVerificationResult attestationResult) = 0; + + /** + * @brief + * Override this method to return whether the attestation delegate wants the commissioner to wait for a + * ContinueCommissioningAfterDeviceAttestation call in the case attestationResult is successful. + */ + virtual bool ShouldWaitAfterDeviceAttestation() { return false; }; }; } // namespace Credentials diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.cpp b/src/credentials/attestation_verifier/DeviceAttestationVerifier.cpp index 68c69136893e19..de13abfe3b5e22 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.cpp +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.cpp @@ -16,7 +16,9 @@ */ #include "DeviceAttestationVerifier.h" +#include #include +#include using namespace chip::Crypto; @@ -111,5 +113,42 @@ void SetDeviceAttestationVerifier(DeviceAttestationVerifier * verifier) gDacVerifier = verifier; } +ByteSpan DupByteSpanHelper(const ByteSpan & span_to_dup) +{ + uint8_t * bytes = (uint8_t *) chip::Platform::MemoryAlloc(span_to_dup.size()); + memcpy(bytes, span_to_dup.data(), span_to_dup.size()); + return ByteSpan(bytes, span_to_dup.size()); +} + +DeviceAttestationVerifier::AttestationDeviceInfo::AttestationDeviceInfo(const AttestationInfo & attestationInfo) : + mPaiDerBuffer(DupByteSpanHelper(attestationInfo.paiDerBuffer)), mDacDerBuffer(DupByteSpanHelper(attestationInfo.dacDerBuffer)) +{ + mAttestationElementsBufferCopy = chip::Platform::MemoryAlloc(attestationInfo.attestationElementsBuffer.size()); + memcpy(mAttestationElementsBufferCopy, attestationInfo.attestationElementsBuffer.data(), + attestationInfo.attestationElementsBuffer.size()); + + ByteSpan certificationDeclarationSpan; + ByteSpan attestationNonceSpan; + uint32_t timestampDeconstructed; + ByteSpan firmwareInfoSpan; + DeviceAttestationVendorReservedDeconstructor vendorReserved; + + ByteSpan attestationElementsBufferSpan = + ByteSpan((uint8_t *) mAttestationElementsBufferCopy, attestationInfo.attestationElementsBuffer.size()); + + if (DeconstructAttestationElements(attestationElementsBufferSpan, certificationDeclarationSpan, attestationNonceSpan, + timestampDeconstructed, firmwareInfoSpan, vendorReserved) == CHIP_NO_ERROR) + { + mCdBuffer = MakeOptional(certificationDeclarationSpan); + } +} + +DeviceAttestationVerifier::AttestationDeviceInfo::~AttestationDeviceInfo() +{ + chip::Platform::MemoryFree(mAttestationElementsBufferCopy); + chip::Platform::MemoryFree((void *) mPaiDerBuffer.data()); + chip::Platform::MemoryFree((void *) mPaiDerBuffer.data()); +} + } // namespace Credentials } // namespace chip diff --git a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h index 756759d32ebe03..bee7abe98e826e 100644 --- a/src/credentials/attestation_verifier/DeviceAttestationVerifier.h +++ b/src/credentials/attestation_verifier/DeviceAttestationVerifier.h @@ -108,8 +108,6 @@ struct DeviceInfoForAttestation uint8_t paaSKID[Crypto::kSubjectKeyIdentifierLength] = { 0 }; }; -typedef void (*OnAttestationInformationVerification)(void * context, AttestationVerificationResult result); - /** * @brief Helper utility to model a basic trust store usable for device attestation verifiers. * @@ -222,6 +220,25 @@ class DeviceAttestationVerifier uint16_t productId; }; + // Copies the bytes passed to it, and holds the PAI, DAC, and CD for additional verification step + class AttestationDeviceInfo + { + public: + AttestationDeviceInfo(const AttestationInfo & attestationInfo); + AttestationDeviceInfo(const ByteSpan & attestationElementsBuffer, const ByteSpan paiDerBuffer, const ByteSpan dacDerBuffer); + + ~AttestationDeviceInfo(); + + ByteSpan mPaiDerBuffer; // Buffer containing the PAI certificate from device in DER format. + ByteSpan mDacDerBuffer; // Buffer containing the DAC certificate from device in DER format. + Optional mCdBuffer; // Buffer containing the certificate declaration from device. + private: + void * mAttestationElementsBufferCopy; + }; + + typedef void (*OnAttestationInformationVerification)(void * context, const AttestationInfo & info, + AttestationVerificationResult result); + /** * @brief Verify an attestation information payload against a DAC/PAI chain. * diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index 5af5b2db5bc828..28549eb9b55d31 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -148,7 +148,8 @@ static void TestDACProvidersExample_Signature(nlTestSuite * inSuite, void * inCo NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); } -static void OnAttestationInformationVerificationCallback(void * context, AttestationVerificationResult result) +static void OnAttestationInformationVerificationCallback(void * context, const DeviceAttestationVerifier::AttestationInfo & info, + AttestationVerificationResult result) { AttestationVerificationResult * pResult = reinterpret_cast(context); *pResult = result; @@ -205,7 +206,7 @@ static void TestDACVerifierExample_AttestationInfoVerification(nlTestSuite * inS NL_TEST_ASSERT(inSuite, default_verifier == example_dac_verifier); attestationResult = AttestationVerificationResult::kNotImplemented; - Callback::Callback attestationInformationVerificationCallback( + Callback::Callback attestationInformationVerificationCallback( OnAttestationInformationVerificationCallback, &attestationResult); Credentials::DeviceAttestationVerifier::AttestationInfo info( diff --git a/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj b/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj index 659474185dd30e..74b054c191cb1c 100644 --- a/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj +++ b/src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj @@ -565,7 +565,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = CHIPTool/CHIPTool.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; @@ -588,7 +587,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = CHIPTool/CHIPTool.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.h b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.h index 42ffa6212e9697..63e0672c2edd9d 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.h +++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.h @@ -21,12 +21,36 @@ NS_ASSUME_NONNULL_BEGIN @class MTRDeviceController; +@interface MTRDeviceAttestationDeviceInfo : NSObject +@property (nonatomic, readonly) NSData * dacCertificate; +@property (nonatomic, readonly) NSData * dacPAICertificate; +@property (nonatomic, readonly) NSData * certificateDeclaration; +@end + /** * The protocol definition for the MTRDeviceAttestationDelegate * * All delegate methods will be called on the callers queue. */ @protocol MTRDeviceAttestationDelegate +@optional +/** + * Notify the delegate when device attestation completed with device info for additional verification. If + * this callback is implemented, continueCommissioningDevice on MTRDeviceController is expected + * to be called if commisioning should continue. + * + * This allows the delegate to stop commissioning after examining the device info (DAC, PAI, CD). + * + * @param controller Controller corresponding to the commissioning process + * @param device Handle of device being commissioned + * @param attestationDeviceInfo Attestation information for the device + * @param error NSError representing the error code for the failure + */ +- (void)deviceAttestation:(MTRDeviceController *)controller + completedForDevice:(void *)device + attestationDeviceInfo:(MTRDeviceAttestationDeviceInfo *)attestationDeviceInfo + error:(NSError * _Nonnull)error; + /** * Notify the delegate when device attestation fails * diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.mm b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.mm new file mode 100644 index 00000000000000..83cd8d8a6288ab --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate.mm @@ -0,0 +1,33 @@ +/** + * + * Copyright (c) 2022 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. + */ + +#import +#import + +@implementation MTRDeviceAttestationDeviceInfo +- (instancetype)initWithDACCertificate:(NSData *)dacCertificate + dacPAICertificate:(NSData *)dacPAICertificate + certificateDeclaration:(NSData *)certificateDeclaration +{ + if (self = [super init]) { + _dacCertificate = [dacCertificate copy]; + _dacPAICertificate = [dacPAICertificate copy]; + _certificateDeclaration = [certificateDeclaration copy]; + } + return self; +} +@end diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.h b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.h index cc44ef3584c91f..121b97f11b4a24 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.h +++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.h @@ -29,12 +29,13 @@ class MTRDeviceAttestationDelegateBridge : public chip::Credentials::DeviceAttes public: MTRDeviceAttestationDelegateBridge(MTRDeviceController * deviceController, id deviceAttestationDelegate, dispatch_queue_t queue, - chip::Optional expiryTimeoutSecs) + chip::Optional expiryTimeoutSecs, bool shouldWaitAfterDeviceAttestation = false) : mResult(chip::Credentials::AttestationVerificationResult::kSuccess) , mDeviceController(deviceController) , mDeviceAttestationDelegate(deviceAttestationDelegate) , mQueue(queue) , mExpiryTimeoutSecs(expiryTimeoutSecs) + , mShouldWaitAfterDeviceAttestation(shouldWaitAfterDeviceAttestation) { } @@ -42,9 +43,12 @@ class MTRDeviceAttestationDelegateBridge : public chip::Credentials::DeviceAttes chip::Optional FailSafeExpiryTimeoutSecs() const override { return mExpiryTimeoutSecs; } - void OnDeviceAttestationFailed(chip::Controller::DeviceCommissioner * deviceCommissioner, chip::DeviceProxy * device, + void OnDeviceAttestationCompleted(chip::Controller::DeviceCommissioner * deviceCommissioner, chip::DeviceProxy * device, + const chip::Credentials::DeviceAttestationVerifier::AttestationDeviceInfo & info, chip::Credentials::AttestationVerificationResult attestationResult) override; + bool ShouldWaitAfterDeviceAttestation() override { return mShouldWaitAfterDeviceAttestation; } + chip::Credentials::AttestationVerificationResult attestationVerificationResult() const { return mResult; } private: @@ -53,6 +57,7 @@ class MTRDeviceAttestationDelegateBridge : public chip::Credentials::DeviceAttes id mDeviceAttestationDelegate; dispatch_queue_t mQueue; chip::Optional mExpiryTimeoutSecs; + bool mShouldWaitAfterDeviceAttestation; }; NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm index db8f277ca8a144..2ce9ccc3df9349 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm @@ -17,9 +17,11 @@ #import "MTRDeviceAttestationDelegateBridge.h" #import "MTRError_Internal.h" +#import -void MTRDeviceAttestationDelegateBridge::OnDeviceAttestationFailed(chip::Controller::DeviceCommissioner * deviceCommissioner, - chip::DeviceProxy * device, chip::Credentials::AttestationVerificationResult attestationResult) +void MTRDeviceAttestationDelegateBridge::OnDeviceAttestationCompleted(chip::Controller::DeviceCommissioner * deviceCommissioner, + chip::DeviceProxy * device, const chip::Credentials::DeviceAttestationVerifier::AttestationDeviceInfo & info, + chip::Credentials::AttestationVerificationResult attestationResult) { dispatch_async(mQueue, ^{ NSLog(@"MTRDeviceAttestationDelegateBridge::OnDeviceAttestationFailed failed with result: %hu", attestationResult); @@ -27,7 +29,27 @@ mResult = attestationResult; id strongDelegate = mDeviceAttestationDelegate; - if ([strongDelegate respondsToSelector:@selector(deviceAttestation:failedForDevice:error:)]) { + if ([strongDelegate respondsToSelector:@selector(deviceAttestation:completedForDevice:attestationDeviceInfo:error:)]) { + MTRDeviceController * strongController = mDeviceController; + if (strongController) { + NSData * dacData = [NSData dataWithBytes:info.mDacDerBuffer.data() length:info.mDacDerBuffer.size()]; + NSData * paiData = [NSData dataWithBytes:info.mPaiDerBuffer.data() length:info.mPaiDerBuffer.size()]; + NSData * cdData = info.mCdBuffer.HasValue() + ? [NSData dataWithBytes:info.mCdBuffer.Value().data() length:info.mCdBuffer.Value().size()] + : nil; + MTRDeviceAttestationDeviceInfo * deviceInfo = + [[MTRDeviceAttestationDeviceInfo alloc] initWithDACCertificate:dacData + dacPAICertificate:paiData + certificateDeclaration:cdData]; + NSError * error = (attestationResult == chip::Credentials::AttestationVerificationResult::kSuccess) + ? nil + : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTEGRITY_CHECK_FAILED]; + [strongDelegate deviceAttestation:mDeviceController + completedForDevice:device + attestationDeviceInfo:deviceInfo + error:error]; + } + } else if ([strongDelegate respondsToSelector:@selector(deviceAttestation:failedForDevice:error:)]) { MTRDeviceController * strongController = mDeviceController; if (strongController) { diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate_Internal.h b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate_Internal.h new file mode 100644 index 00000000000000..aa6eec6917a989 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegate_Internal.h @@ -0,0 +1,33 @@ +/** + * + * Copyright (c) 2022 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MTRDeviceAttestationDeviceInfo () +- (instancetype)initWithDACCertificate:(NSData *)dacCertificate + dacPAICertificate:(NSData *)dacPAICertificate + certificateDeclaration:(NSData *)certificateDeclaration; + +//@property (nonatomic, readonly) NSData * dacCertificate; +//@property (nonatomic, readonly) NSData * dacPAICertificate; +//@property (nonatomic, readonly) NSData * certificateDeclaration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index d122d28f93e16f..d97ab24c7d6114 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -472,7 +472,7 @@ - (BOOL)continueCommissioningDevice:(void *)device : chip::Credentials::AttestationVerificationResult::kSuccess; auto deviceProxy = static_cast(device); - auto errorCode = self.cppCommissioner->ContinueCommissioningAfterDeviceAttestationFailure(deviceProxy, + auto errorCode = self.cppCommissioner->ContinueCommissioningAfterDeviceAttestation(deviceProxy, ignoreAttestationFailure ? chip::Credentials::AttestationVerificationResult::kSuccess : lastAttestationResult); success = ![self checkForError:errorCode logMsg:kErrorPairDevice error:error]; }); diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 7102d13c7be998..a1716f0ba9451c 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -81,6 +81,8 @@ 5ACDDD7D27CD16D200EFD68A /* MTRAttributeCacheContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5ACDDD7C27CD16D200EFD68A /* MTRAttributeCacheContainer.mm */; }; 5ACDDD7E27CD3F3A00EFD68A /* MTRAttributeCacheContainer_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ACDDD7B27CD14AF00EFD68A /* MTRAttributeCacheContainer_Internal.h */; }; 5AE6D4E427A99041001F2493 /* MTRDeviceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */; }; + 7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */; }; + 7534F12928BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */; }; 754F3DF427FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 754F3DF327FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h */; }; 7560FD1C27FBBD3F005E85B3 /* MTREventTLVValueDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7560FD1B27FBBD3F005E85B3 /* MTREventTLVValueDecoder.mm */; }; 7596A83E28751220004DAE0E /* MTRBaseClusters_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 7596A83D28751220004DAE0E /* MTRBaseClusters_internal.h */; }; @@ -217,6 +219,8 @@ 5ACDDD7B27CD14AF00EFD68A /* MTRAttributeCacheContainer_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRAttributeCacheContainer_Internal.h; sourceTree = ""; }; 5ACDDD7C27CD16D200EFD68A /* MTRAttributeCacheContainer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttributeCacheContainer.mm; sourceTree = ""; }; 5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceTests.m; sourceTree = ""; }; + 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceAttestationDelegate.mm; sourceTree = ""; }; + 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationDelegate_Internal.h; sourceTree = ""; }; 754F3DF327FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTREventTLVValueDecoder_Internal.h; sourceTree = ""; }; 7560FD1B27FBBD3F005E85B3 /* MTREventTLVValueDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MTREventTLVValueDecoder.mm; path = "zap-generated/MTREventTLVValueDecoder.mm"; sourceTree = ""; }; 7596A83D28751220004DAE0E /* MTRBaseClusters_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTRBaseClusters_internal.h; path = "zap-generated/MTRBaseClusters_internal.h"; sourceTree = ""; }; @@ -355,6 +359,8 @@ 27A53C1527FBC6920053F131 /* MTRAttestationTrustStoreBridge.h */, 27A53C1627FBC6920053F131 /* MTRAttestationTrustStoreBridge.mm */, 88EBF8CB27FABDD500686BC1 /* MTRDeviceAttestationDelegate.h */, + 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */, + 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */, 88EBF8CD27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h */, 88EBF8CC27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm */, 513DDB852761F69300DAA01A /* MTRAttributeTLVValueDecoder_Internal.h */, @@ -500,6 +506,7 @@ 99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */, 5136661528067D550025EDAE /* MTRControllerFactory_Internal.h in Headers */, 515C1C70284F9FFB00A48F0C /* MTRMemory.h in Headers */, + 7534F12928BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h in Headers */, D4772A46285AE98400383630 /* MTRClusterConstants.h in Headers */, B289D4212639C0D300D4E314 /* MTROnboardingPayloadParser.h in Headers */, 513DDB862761F69300DAA01A /* MTRAttributeTLVValueDecoder_Internal.h in Headers */, @@ -680,6 +687,7 @@ 5136661428067D550025EDAE /* MTRControllerFactory.mm in Sources */, 51B22C2A2740CB47008D5055 /* MTRCommandPayloadsObjc.mm in Sources */, AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */, + 7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */, 2C5EEEF7268A85C400CAE3D3 /* MTRDeviceConnectionBridge.mm in Sources */, 51B22C262740CB32008D5055 /* MTRStructsObjc.mm in Sources */, 2C222AD1255C620600E446B9 /* MTRBaseDevice.mm in Sources */,