From 9a7a3151364ec33a093148c9031f2389cf3f014c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 2 Dec 2022 19:01:58 -0500 Subject: [PATCH 1/3] Fix APIs involved in the MTROperationalCredentialsDelegate. * Rename CSRInfo to MTROperationalCSRInfo * Rename the properties of MTROperationalCSRInfo to match the spec more closely. * Rename AttestationInfo to MTRAttestationInfo. * Fix naming of the API on MTRDeviceController to follow conventions better, document the API more clearly, and have it return errors as needed. * Rename MTRNOCChainIssuer to MTROperationalCertificateIssuer * Change signature of the one method on MTROperationalCertificateIssuer to have better naming, take a controller, and name the completion block "completion". * Change the completion signature on MTROperationalCertificateIssuer to allow the external certificate issuer to return an error (e.g. if its device attestation checks failed). * Don't ask the external issuer for the IPK, since we should already have that anyway (from our controller init). * Allow the external issuer to return nil for the intermediate certificate, to indicate that there isn't one. * Make sure that all our access to mOnNOCCompletionCallback happens on the Matter queue, so we don't have thread races on that member. * Make all the dispatch we do as part of the credential-issuing process async. * Introduce backwards-compat shims for all the API changes for now. Fixes https://github.com/project-chip/connectedhomeip/issues/23439 --- .../Framework/CHIP/MTRAttestationInfo.h | 30 +++ .../Framework/CHIP/MTRAttestationInfo.mm | 26 +++ src/darwin/Framework/CHIP/MTRCSRInfo.h | 24 ++- src/darwin/Framework/CHIP/MTRCSRInfo.mm | 17 ++ .../Framework/CHIP/MTRDeviceController.h | 35 +++- .../Framework/CHIP/MTRDeviceController.mm | 84 ++++++++- src/darwin/Framework/CHIP/MTRNOCChainIssuer.h | 53 ------ .../CHIP/MTROperationalCertificateIssuer.h | 91 +++++++++ .../CHIP/MTROperationalCertificateIssuer.mm | 36 ++++ .../CHIP/MTROperationalCredentialsDelegate.h | 42 ++--- .../CHIP/MTROperationalCredentialsDelegate.mm | 176 +++++++++--------- src/darwin/Framework/CHIP/Matter.h | 2 +- .../Matter.xcodeproj/project.pbxproj | 12 +- 13 files changed, 435 insertions(+), 193 deletions(-) delete mode 100644 src/darwin/Framework/CHIP/MTRNOCChainIssuer.h create mode 100644 src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h create mode 100644 src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.h b/src/darwin/Framework/CHIP/MTRAttestationInfo.h index a31c181b0daebd..e499f341aeb94e 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.h +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.h @@ -23,6 +23,36 @@ NS_ASSUME_NONNULL_BEGIN * Represents information relating to product attestation. * */ +@interface MTRAttestationInfo : NSObject + +@property (nonatomic, copy, readonly) NSData * challenge; + +@property (nonatomic, copy, readonly) NSData * nonce; + +@property (nonatomic, copy, readonly) NSData * elements; + +@property (nonatomic, copy, readonly) NSData * elementsSignature; + +@property (nonatomic, copy, readonly) NSData * dac; + +@property (nonatomic, copy, readonly) NSData * pai; + +@property (nonatomic, copy, readonly) NSData * certificationDeclaration; + +@property (nonatomic, copy, readonly) NSData * firmwareInfo; + +- (instancetype)initWithChallenge:(NSData *)challenge + nonce:(NSData *)nonce + elements:(NSData *)elements + elementsSignature:(NSData *)elementsSignature + dac:(NSData *)dac + pai:(NSData *)pai + certificationDeclaration:(NSData *)certificationDeclaration + firmwareInfo:(NSData *)firmwareInfo; + +@end + +MTR_NEWLY_DEPRECATED("Please use MTRAttestationInfo") @interface AttestationInfo : NSObject @property (nonatomic, copy) NSData * challenge; diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm index 93b9483cce6fe0..cb68bb239b32a4 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm @@ -19,6 +19,32 @@ NS_ASSUME_NONNULL_BEGIN +@implementation MTRAttestationInfo : NSObject + +- (instancetype)initWithChallenge:(NSData *)challenge + nonce:(NSData *)nonce + elements:(NSData *)elements + elementsSignature:(NSData *)elementsSignature + dac:(NSData *)dac + pai:(NSData *)pai + certificationDeclaration:(NSData *)certificationDeclaration + firmwareInfo:(NSData *)firmwareInfo +{ + if (self = [super init]) { + _challenge = challenge; + _nonce = nonce; + _elements = elements; + _elementsSignature = elementsSignature; + _dac = dac; + _pai = pai; + _certificationDeclaration = certificationDeclaration; + _firmwareInfo = firmwareInfo; + } + return self; +} + +@end + @implementation AttestationInfo : NSObject - (instancetype)initWithChallenge:(NSData *)challenge diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.h b/src/darwin/Framework/CHIP/MTRCSRInfo.h index 8971bfd6fbd294..3ea9b99603d1f7 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.h +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.h @@ -20,9 +20,31 @@ NS_ASSUME_NONNULL_BEGIN /** - * Represents information relating to NOC CSR. + * Represents information relating to a certificate signing request for a Matter + * operational certificate. The entire TLV nocsr-elements structure, including + * any vendor-specific data, is included, as well as the parsed-out CSR and + * CSRNonce fields from that structure. * + * The AttestationSignature from the CSRResponse command is also included. This + * signs a concatenation of csrElements and the attestationChallenge found in + * MTRAttestationInfo. */ +MTR_NEWLY_AVAILABLE +@interface MTROperationalCSRInfo : NSObject + +@property (nonatomic, copy, readonly) NSData * csr; +@property (nonatomic, copy, readonly) NSData * csrNonce; +@property (nonatomic, copy, readonly) NSData * csrElements; +@property (nonatomic, copy, readonly) NSData * attestationSignature; + +- (instancetype)initWithCSR:(NSData *)csr + csrNonce:(NSData *)csrNonce + csrElements:(NSData *)csrElements + attestationSignature:(NSData *)attestationSignature; + +@end + +MTR_NEWLY_DEPRECATED("Please use MTROperationalCSRInfo") @interface CSRInfo : NSObject @property (nonatomic, copy) NSData * nonce; diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.mm b/src/darwin/Framework/CHIP/MTRCSRInfo.mm index 676aa1ed36e5b4..2ac9b070077982 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.mm +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.mm @@ -19,6 +19,23 @@ NS_ASSUME_NONNULL_BEGIN +@implementation MTROperationalCSRInfo : NSObject + +- (instancetype)initWithCSR:(NSData *)csr + csrNonce:(NSData *)csrNonce + csrElements:(NSData *)csrElements + attestationSignature:(NSData *)attestationSignature; +{ + if (self = [super init]) { + _csr = csr; + _csrNonce = csrNonce; + _csrElements = csrElements; + _attestationSignature = attestationSignature; + } + return self; +} +@end + @implementation CSRInfo : NSObject - (instancetype)initWithNonce:(NSData *)nonce diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.h b/src/darwin/Framework/CHIP/MTRDeviceController.h index 6a2616a53eeb00..7b371baf862ef4 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController.h @@ -17,7 +17,7 @@ #import -#import +#import @class MTRBaseDevice; @@ -118,18 +118,33 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS - (void)setDeviceControllerDelegate:(id)delegate queue:(dispatch_queue_t)queue MTR_NEWLY_AVAILABLE; /** - * Sets this MTRDeviceController to use the given issuer for issuing operational certs. By default, the MTRDeviceController uses an - * internal issuer. + * Sets this MTRDeviceController to use the given issuer for issuing operational + * certificates. By default, the MTRDeviceController uses an internal issuer + * using the signing provided when it was created. * - * When a nocChainIssuer is set, the device commissioner will delegate verification to the chip::Credentials::PartialDACVerifier so - * that DAC chain and CD validation can be performed by custom code triggered by MTRNOCChainIssuer.onNOCChainGenerationNeeded(). - * Otherwise, the device commissioner uses the chip::Credentials::DefaultDACVerifier + * Both arguments must be nil (to stop using an external operational certificate + * issuer) or both must be non-nil. * - * @param[in] nocChainIssuer the NOC Chain issuer to use for issuer operational certs + * When using an external operational certificate issuer, all device attestation + * checks that require some sort of trust anchors are delegated to the external + * certificate issuer. Specifically, the following device attestation checks + * are not performed and must be done by the operationalCertificateIssuer: * - * @param[in] queue The queue on which the callbacks will be delivered + * (1) Make sure the PAA is valid and approved by CSA. + * (2) vid-scoped PAA check: if the PAA is vid scoped, then its vid must match the DAC vid. + * (3) cert chain check: verify PAI is signed by PAA, and DAC is signed by PAI. + * (4) PAA subject key id extraction: the PAA subject key must match the PAA key referenced in the PAI. + * (5) CD signature check: make sure a valid CSA CD key is used to sign the CD. + * + * @param[in] operationalCertificateIssuer the operationalCertificateIssuer to + * use for issuing operational certs + * + * @param[in] queue The queue on which the calls into the + * operationalCertificateIssuer will happen. */ -- (void)setNocChainIssuer:(id)nocChainIssuer queue:(dispatch_queue_t)queue; +- (BOOL)setOperationalCertificateIssuer:(nullable id)operationalCertificateIssuer + queue:(nullable dispatch_queue_t)queue + error:(NSError * __autoreleasing *)error MTR_NEWLY_AVAILABLE; /** * Return the attestation challenge for the secure session of the device being commissioned. @@ -221,6 +236,8 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS - (void)setPairingDelegate:(id)delegate queue:(dispatch_queue_t)queue MTR_NEWLY_DEPRECATED("Please use setDeviceControllerDelegate:"); +- (void)setNocChainIssuer:(id)nocChainIssuer + queue:(dispatch_queue_t)queue MTR_NEWLY_DEPRECATED("Please use setOperationalCertificateIssuer"); @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index c3e1c710e8f861..b8bba122266677 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -114,7 +114,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory queue:(dis return nil; } - _operationalCredentialsDelegate = new MTROperationalCredentialsDelegate(); + _operationalCredentialsDelegate = new MTROperationalCredentialsDelegate(self); if ([self checkForInitError:(_operationalCredentialsDelegate != nullptr) logMsg:kErrorOperationalCredentialsInit]) { return nil; } @@ -548,20 +548,33 @@ - (void)setDeviceControllerDelegate:(id)delegate qu }); } -- (void)setNocChainIssuer:(id)nocChainIssuer queue:(dispatch_queue_t)queue +- (BOOL)setOperationalCertificateIssuer:(nullable id)operationalCertificateIssuer + queue:(nullable dispatch_queue_t)queue + error:(NSError * __autoreleasing *)error { - VerifyOrReturn([self checkIsRunning]); + if ((operationalCertificateIssuer != nil && queue == nil) || (operationalCertificateIssuer == nil && queue != nil)) { + if (error) { + *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT]; + } + return NO; + } + + VerifyOrReturnValue([self checkIsRunning:error], NO); + __block BOOL success = NO; dispatch_sync(_chipWorkQueue, ^{ - VerifyOrReturn([self checkIsRunning]); + VerifyOrReturn([self checkIsRunning:error]); - if (nocChainIssuer != nil) { - self->_operationalCredentialsDelegate->SetNocChainIssuer(nocChainIssuer, queue); + if (operationalCertificateIssuer != nil) { + self->_operationalCredentialsDelegate->SetOperationalCertificateIssuer(operationalCertificateIssuer, queue); self->_cppCommissioner->SetDeviceAttestationVerifier(_partialDACVerifier); } else { self->_cppCommissioner->SetDeviceAttestationVerifier(chip::Credentials::GetDeviceAttestationVerifier()); } + success = YES; }); + + return success; } + (nullable NSData *)computePASEVerifierForSetupPasscode:(NSNumber *)setupPasscode @@ -882,6 +895,59 @@ - (void)onPairingDeleted:(NSError * _Nullable)error @end +/** + * Shim to allow us to treat an MTRNOCChainIssuer as an + * MTROperationalCertificateIssuer. + */ +@interface MTROperationalCertificateChainIssuerShim : NSObject +@property (nonatomic, readonly) id nocChainIssuer; +- (instancetype)initWithIssuer:(id)nocChainIssuer; +@end + +@implementation MTROperationalCertificateChainIssuerShim +- (instancetype)initWithIssuer:(id)nocChainIssuer +{ + if (self = [super init]) { + _nocChainIssuer = nocChainIssuer; + } + return self; +} + +- (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo + attestationInfo:(MTRAttestationInfo *)attestationInfo + controller:(MTRDeviceController *)controller + completion:(MTROperationalCertificateIssuedHandler)completion +{ + CSRInfo * oldCSRInfo = [[CSRInfo alloc] initWithNonce:csrInfo.csrNonce + elements:csrInfo.csrElements + elementsSignature:csrInfo.attestationSignature + csr:csrInfo.csr]; + AttestationInfo * oldAttestationInfo = [[AttestationInfo alloc] initWithChallenge:attestationInfo.challenge + nonce:attestationInfo.nonce + elements:attestationInfo.elements + elementsSignature:attestationInfo.elementsSignature + dac:attestationInfo.dac + pai:attestationInfo.pai + certificationDeclaration:attestationInfo.certificationDeclaration + firmwareInfo:attestationInfo.firmwareInfo]; + [self.nocChainIssuer + onNOCChainGenerationNeeded:oldCSRInfo + attestationInfo:oldAttestationInfo + onNOCChainGenerationComplete:^(NSData * operationalCertificate, NSData * intermediateCertificate, NSData * rootCertificate, + NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error) { + auto * info = [MTROperationalCertificateInfo infoWithOperationalCertificate:operationalCertificate + intermediateCertificate:intermediateCertificate + rootCertificate:rootCertificate + adminSubject:adminSubject]; + completion(info, nil); + if (error != nil) { + *error = nil; + } + }]; +} + +@end + @implementation MTRDeviceController (Deprecated) - (NSNumber *)controllerNodeId @@ -1105,4 +1171,10 @@ - (void)setPairingDelegate:(id)delegate queue:(dispatc [self setDeviceControllerDelegate:delegateShim queue:queue]; } +- (void)setNocChainIssuer:(id)nocChainIssuer queue:(dispatch_queue_t)queue +{ + [self setOperationalCertificateIssuer:[[MTROperationalCertificateChainIssuerShim alloc] initWithIssuer:nocChainIssuer] + queue:queue + error:nil]; +} @end diff --git a/src/darwin/Framework/CHIP/MTRNOCChainIssuer.h b/src/darwin/Framework/CHIP/MTRNOCChainIssuer.h deleted file mode 100644 index 7c1eb03e37c1b7..00000000000000 --- a/src/darwin/Framework/CHIP/MTRNOCChainIssuer.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * - * 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 -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^MTRNOCChainGenerationCompleteHandler)(NSData * operationalCertificate, NSData * intermediateCertificate, - NSData * rootCertificate, NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error); - -@protocol MTRNOCChainIssuer -@required - -/** - * @brief When a MTRNOCChainIssuer is set for the MTRDeviceController, then onNOCChainGenerationNeeded will be - * called when the NOC CSR needs to be signed. This allows for custom credentials issuer - * implementations, for example, when a proprietary cloud API will perform the CSR signing. - - * The commissioning workflow will stop upon the onNOCChainGenerationNeeded callback and - * resume once onNOCChainGenerationComplete is called - - * The following fields MUST be passed to onNOCChainGenerationComplete with non-nil values: - * rootCertificate, intermediateCertificate, operationalCertificate. - * If ipk and adminSubject are passed, then they will be used in - * the AddNOC command sent to the commissionee. If they are not passed, then the values - * provided in the MTRDeviceController initialization will be used. - * - * All csr and attestation fields are provided to allow for custom attestestation checks. - */ -- (void)onNOCChainGenerationNeeded:(CSRInfo *)csrInfo - attestationInfo:(AttestationInfo *)attestationInfo - onNOCChainGenerationComplete:(MTRNOCChainGenerationCompleteHandler)onNOCChainGenerationComplete; - -@end - -NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h new file mode 100644 index 00000000000000..0a6bd14a039ff1 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h @@ -0,0 +1,91 @@ +/** + * + * 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 +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class MTRDeviceController; + +/** + * A representation of the operation certificate info for a node. + * + * A nil intermediateCertificate means there is no intermediate. + * + * adminSubject is passed to the device as part of the AddNOC command. A nil + * adminSubject means the node id of the relevant MTRDeviceController will be + * used. + */ +MTR_NEWLY_AVAILABLE +@interface MTROperationalCertificateInfo : NSObject +@property (nonatomic, copy) MTRCertificateDERBytes operationalCertificate; +@property (nonatomic, copy, nullable) MTRCertificateDERBytes intermediateCertificate; +@property (nonatomic, copy) MTRCertificateDERBytes rootCertificate; +@property (nonatomic, copy, nullable) NSNumber * adminSubject; + ++ (instancetype)infoWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate + intermediateCertificate:(nullable MTRCertificateDERBytes)intermediateCertificate + rootCertificate:(MTRCertificateDERBytes)rootCertificate + adminSubject:(nullable NSNumber *)adminSubject; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +@end + +typedef void (^MTROperationalCertificateIssuedHandler)(MTROperationalCertificateInfo * _Nullable info, NSError * _Nullable error); + +MTR_NEWLY_AVAILABLE +@protocol MTROperationalCertificateIssuer +@required + +/** + * @brief When an MTROperationalCertificateIssuer is set for an + * MTRDeviceController, it will be used to issue operational certificates as + * needed during commissioning. + * + * Commissioning will pause when + * issueOperationalCertificateForRequest:attestationInfo:completion: is called, + * and resume when the completion is invoked with a non-nil + * MTROperationalCertificateInfo. When the completion is invoked with an error, + * commissioning will fail. + */ +- (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo + attestationInfo:(MTRAttestationInfo *)attestationInfo + controller:(MTRDeviceController *)controller + completion:(MTROperationalCertificateIssuedHandler)completion; + +@end + +MTR_NEWLY_DEPRECATED("Please use MTROperationalCertificateIssuedHandler") +typedef void (^MTRNOCChainGenerationCompleteHandler)(NSData * operationalCertificate, NSData * intermediateCertificate, + NSData * rootCertificate, NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error); + +MTR_NEWLY_DEPRECATED("Please use MTROperationalCertificateIssuer") +@protocol MTRNOCChainIssuer +@required + +- (void)onNOCChainGenerationNeeded:(CSRInfo *)csrInfo + attestationInfo:(AttestationInfo *)attestationInfo + onNOCChainGenerationComplete:(MTRNOCChainGenerationCompleteHandler)onNOCChainGenerationComplete; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm new file mode 100644 index 00000000000000..c51e7abee2226b --- /dev/null +++ b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm @@ -0,0 +1,36 @@ +/** + * 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 "MTROperationalCertificateIssuer.h" + +@implementation MTROperationalCertificateInfo + ++ (instancetype)infoWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate + intermediateCertificate:(nullable MTRCertificateDERBytes)intermediateCertificate + rootCertificate:(MTRCertificateDERBytes)rootCertificate + adminSubject:(nullable NSNumber *)adminSubject +{ + auto * info = [[MTROperationalCertificateInfo alloc] init]; + info.operationalCertificate = operationalCertificate; + info.intermediateCertificate = intermediateCertificate; + info.rootCertificate = rootCertificate; + info.adminSubject = adminSubject; + return info; +} + +@end diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h index b6427512f31106..351609a5283b61 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h @@ -20,9 +20,10 @@ #import #import +#import "MTRDeviceController.h" #import "MTRError_Internal.h" #import "MTRKeypair.h" -#import "MTRNOCChainIssuer.h" +#import "MTROperationalCertificateIssuer.h" #import "MTRP256KeypairBridge.h" #import "MTRPersistentStorageDelegateBridge.h" @@ -37,6 +38,7 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr public: using ChipP256KeypairPtr = chip::Crypto::P256Keypair *; + MTROperationalCredentialsDelegate(MTRDeviceController * deviceController); ~MTROperationalCredentialsDelegate() {} CHIP_ERROR Init(MTRPersistentStorageDelegateBridge * storage, ChipP256KeypairPtr nocSigner, NSData * ipk, NSData * rootCert, @@ -69,15 +71,13 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr void setChipWorkQueue(dispatch_queue_t chipWorkQueue) { mChipWorkQueue = chipWorkQueue; } - void SetNocChainIssuer(id nocChainIssuer, dispatch_queue_t nocChainIssuerQueue) + void SetOperationalCertificateIssuer( + id operationalCertificateIssuer, dispatch_queue_t operationalCertificateIssuerQueue) { - mNocChainIssuer = nocChainIssuer; - mNocChainIssuerQueue = nocChainIssuerQueue; + mOperationalCertificateIssuer = operationalCertificateIssuer; + mOperationalCertificateIssuerQueue = operationalCertificateIssuerQueue; } - CHIP_ERROR NOCChainGenerated(CHIP_ERROR status, const chip::ByteSpan & noc, const chip::ByteSpan & icac, - const chip::ByteSpan & rcac, chip::Optional ipk, chip::Optional adminSubject); - CHIP_ERROR GenerateNOC(chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey, chip::MutableByteSpan & noc); @@ -120,22 +120,9 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey, chip::MutableByteSpan & noc); - /** - * When a NOCChainIssuer is set, then onNOCChainGenerationNeeded will be called when the NOC CSR needs to be - * signed. This allows for custom credentials issuer implementations, for example, when a proprietary cloud API will perform the - * CSR signing. The commissioning workflow will stop upon the onNOCChainGenerationNeeded callback and resume once - * onNOCChainGenerationComplete is called. - * - * Caller must pass a non-nil value for the rootCertificate, intermediateCertificate, operationalCertificate - * If ipk and adminSubject are non nil, then they will be used in the AddNOC command sent to the commissionee. If they are not - * populated, then the values provided in the MTRDeviceController initialization will be used. - */ - void onNOCChainGenerationComplete(NSData * operationalCertificate, NSData * intermediateCertificate, NSData * rootCertificate, - NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error); - - void setNSError(CHIP_ERROR err, NSError * __autoreleasing * outError); - - CHIP_ERROR CallbackGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, + void ExternalNOCChainGenerated(MTROperationalCertificateInfo * _Nullable info, NSError * _Nullable error); + + CHIP_ERROR ExternalGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion); @@ -162,11 +149,12 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr NSData * _Nullable mRootCert; NSData * _Nullable mIntermediateCert; - chip::Controller::DeviceCommissioner * mCppCommissioner = nullptr; - id _Nullable mNocChainIssuer; - dispatch_queue_t _Nullable mNocChainIssuerQueue; + MTRDeviceController * __weak mWeakController; + chip::Controller::DeviceCommissioner * _Nullable mCppCommissioner = nullptr; + id _Nullable mOperationalCertificateIssuer; + dispatch_queue_t _Nullable mOperationalCertificateIssuerQueue; dispatch_queue_t _Nullable mChipWorkQueue; - chip::Callback::Callback * mOnNOCCompletionCallback = nullptr; + chip::Callback::Callback * _Nullable mOnNOCCompletionCallback = nullptr; }; NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm index ba11b3c947a479..a83019062beca2 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm @@ -35,12 +35,18 @@ #include #include #include +#include using namespace chip; using namespace TLV; using namespace Credentials; using namespace Crypto; +MTROperationalCredentialsDelegate::MTROperationalCredentialsDelegate(MTRDeviceController * deviceController) + : mWeakController(deviceController) +{ +} + CHIP_ERROR MTROperationalCredentialsDelegate::Init(MTRPersistentStorageDelegateBridge * storage, ChipP256KeypairPtr nocSigner, NSData * ipk, NSData * rootCert, NSData * _Nullable icaCert) { @@ -113,39 +119,29 @@ return NewNodeOperationalX509Cert(noc_request, pubkey, signingKeypair, noc); } -CHIP_ERROR MTROperationalCredentialsDelegate::NOCChainGenerated(CHIP_ERROR status, const ByteSpan & noc, const ByteSpan & icac, - const ByteSpan & rcac, Optional ipk, Optional adminSubject) -{ - ReturnErrorCodeIf(mOnNOCCompletionCallback == nullptr, CHIP_ERROR_INCORRECT_STATE); - - Callback::Callback * onCompletion = mOnNOCCompletionCallback; - mOnNOCCompletionCallback = nullptr; - - // Call-back into commissioner with the generated data. - dispatch_sync(mChipWorkQueue, ^{ - onCompletion->mCall(onCompletion->mContext, status, noc, icac, rcac, ipk, adminSubject); - }); - - return CHIP_NO_ERROR; -} - CHIP_ERROR MTROperationalCredentialsDelegate::GenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion) { - if (mNocChainIssuer != nil) { - return CallbackGenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI, onCompletion); + if (mOperationalCertificateIssuer != nil) { + return ExternalGenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI, onCompletion); } else { return LocalGenerateNOCChain(csrElements, csrNonce, attestationSignature, attestationChallenge, DAC, PAI, onCompletion); } } -CHIP_ERROR MTROperationalCredentialsDelegate::CallbackGenerateNOCChain(const chip::ByteSpan & csrElements, +CHIP_ERROR MTROperationalCredentialsDelegate::ExternalGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & csrElementsSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion) { + assertChipStackLockedByCurrentThread(); + VerifyOrReturnError(mCppCommissioner != nullptr, CHIP_ERROR_INCORRECT_STATE); + + MTRDeviceController * strongController = mWeakController; + VerifyOrReturnError(strongController != nil, CHIP_ERROR_INCORRECT_STATE); + mOnNOCCompletionCallback = onCompletion; TLVReader reader; @@ -166,10 +162,10 @@ reader.Get(csr); reader.ExitContainer(containerType); - CSRInfo * csrInfo = [[CSRInfo alloc] initWithNonce:AsData(csrNonce) - elements:AsData(csrElements) - elementsSignature:AsData(csrElementsSignature) - csr:AsData(csr)]; + auto * csrInfo = [[MTROperationalCSRInfo alloc] initWithCSR:AsData(csr) + csrNonce:AsData(csrNonce) + csrElements:AsData(csrElements) + attestationSignature:AsData(csrElementsSignature)]; chip::ByteSpan certificationDeclarationSpan; chip::ByteSpan attestationNonceSpan; @@ -187,90 +183,86 @@ chip::Credentials::DeconstructAttestationElements(commissioningParameters.Value().GetAttestationElements().Value(), certificationDeclarationSpan, attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, vendorReserved)); - AttestationInfo * attestationInfo = - [[AttestationInfo alloc] initWithChallenge:AsData(attestationChallenge) - nonce:AsData(commissioningParameters.Value().GetAttestationNonce().Value()) - elements:AsData(commissioningParameters.Value().GetAttestationElements().Value()) - elementsSignature:AsData(commissioningParameters.Value().GetAttestationSignature().Value()) - dac:AsData(DAC) - pai:AsData(PAI) - certificationDeclaration:AsData(certificationDeclarationSpan) - firmwareInfo:AsData(firmwareInfoSpan)]; - - dispatch_sync(mNocChainIssuerQueue, ^{ - [mNocChainIssuer onNOCChainGenerationNeeded:csrInfo - attestationInfo:attestationInfo - onNOCChainGenerationComplete:^void(NSData * operationalCertificate, NSData * intermediateCertificate, - NSData * rootCertificate, NSData * ipk, NSNumber * adminSubject, NSError * __autoreleasing * error) { - onNOCChainGenerationComplete( - operationalCertificate, intermediateCertificate, rootCertificate, ipk, adminSubject, error); - }]; + MTRAttestationInfo * attestationInfo = + [[MTRAttestationInfo alloc] initWithChallenge:AsData(attestationChallenge) + nonce:AsData(commissioningParameters.Value().GetAttestationNonce().Value()) + elements:AsData(commissioningParameters.Value().GetAttestationElements().Value()) + elementsSignature:AsData(commissioningParameters.Value().GetAttestationSignature().Value()) + dac:AsData(DAC) + pai:AsData(PAI) + certificationDeclaration:AsData(certificationDeclarationSpan) + firmwareInfo:AsData(firmwareInfoSpan)]; + + MTRDeviceController * __weak weakController = mWeakController; + dispatch_async(mOperationalCertificateIssuerQueue, ^{ + [mOperationalCertificateIssuer + issueOperationalCertificateForRequest:csrInfo + attestationInfo:attestationInfo + controller:strongController + completion:^(MTROperationalCertificateInfo * _Nullable info, NSError * _Nullable error) { + MTRDeviceController * strongController = weakController; + if (strongController == nil || !strongController.isRunning) { + // No longer safe to touch "this" + return; + } + this->ExternalNOCChainGenerated(info, error); + }]; }); return CHIP_NO_ERROR; } -void MTROperationalCredentialsDelegate::setNSError(CHIP_ERROR err, NSError * __autoreleasing * outError) +void MTROperationalCredentialsDelegate::ExternalNOCChainGenerated( + MTROperationalCertificateInfo * _Nullable info, NSError * _Nullable error) { - if (outError) { - *outError = [MTRError errorForCHIPErrorCode:err]; - } -} + MTRDeviceController * __weak weakController = mWeakController; + dispatch_async(mChipWorkQueue, ^{ + MTRDeviceController * strongController = weakController; + if (strongController == nil || !strongController.isRunning) { + // No longer safe to touch "this" + return; + } -void MTROperationalCredentialsDelegate::onNOCChainGenerationComplete(NSData * operationalCertificate, - NSData * intermediateCertificate, NSData * rootCertificate, NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, - NSError * __autoreleasing * error) -{ - if (operationalCertificate == nil || intermediateCertificate == nil || rootCertificate == nil) { - setNSError(CHIP_ERROR_INVALID_ARGUMENT, error); - return; - } + if (mOnNOCCompletionCallback == nullptr) { + return; + } - if (mCppCommissioner == nullptr) { - setNSError(CHIP_ERROR_INCORRECT_STATE, error); - return; - } + auto * onCompletion = mOnNOCCompletionCallback; + mOnNOCCompletionCallback = nullptr; - __block chip::Optional commissioningParameters; - dispatch_sync(mChipWorkQueue, ^{ - commissioningParameters = mCppCommissioner->GetCommissioningParameters(); - }); - if (!commissioningParameters.HasValue()) { - setNSError(CHIP_ERROR_INCORRECT_STATE, error); - return; - } + if (mCppCommissioner == nullptr) { + // Quite unexpected, since we checked that our controller is running already. + return; + } - chip::Optional ipkOptional; - uint8_t ipkValue[chip::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES]; - chip::Crypto::AesCcm128KeySpan ipkTempSpan(ipkValue); - if (ipk != nil) { - if ([ipk length] != sizeof(ipkValue)) { - setNSError(CHIP_ERROR_INCORRECT_STATE, error); + if (info == nil) { + onCompletion->mCall(onCompletion->mContext, [MTRError errorToCHIPErrorCode:error], ByteSpan(), ByteSpan(), ByteSpan(), + NullOptional, NullOptional); return; } - memcpy(&ipkValue[0], [ipk bytes], [ipk length]); - ipkOptional.SetValue(ipkTempSpan); - } else if (commissioningParameters.Value().GetIpk().HasValue()) { - ipkOptional.SetValue(commissioningParameters.Value().GetIpk().Value()); - } - chip::Optional adminSubjectOptional; - if (adminSubject != nil) { - adminSubjectOptional.SetValue(adminSubject.unsignedLongLongValue); - } else { - adminSubjectOptional = commissioningParameters.Value().GetAdminSubject(); - } + auto commissioningParameters = mCppCommissioner->GetCommissioningParameters(); + if (!commissioningParameters.HasValue()) { + return; + } - // This could potentially be done as an async operation as a future optimization. But it ultimately calls - // DeviceCommissioner::OnDeviceNOCChainGeneration which sends the AddNoc message to the target. The call returns without - // blocking as it is. - CHIP_ERROR err = NOCChainGenerated(CHIP_NO_ERROR, AsByteSpan(operationalCertificate), AsByteSpan(intermediateCertificate), - AsByteSpan(rootCertificate), ipkOptional, adminSubjectOptional); + AesCcm128KeySpan ipk = commissioningParameters.Value().GetIpk().ValueOr(GetIPK()); - if (err != CHIP_NO_ERROR) { - MTR_LOG_ERROR("Failed to SetNocChain for the device: %" CHIP_ERROR_FORMAT, err.Format()); - setNSError(CHIP_ERROR_INCORRECT_STATE, error); - } + Optional adminSubject; + if (info.adminSubject != nil) { + adminSubject.SetValue(info.adminSubject.unsignedLongLongValue); + } else { + adminSubject = commissioningParameters.Value().GetAdminSubject(); + } + + ByteSpan intermediateCertificate; + if (info.intermediateCertificate != nil) { + intermediateCertificate = AsByteSpan(info.intermediateCertificate); + } + + onCompletion->mCall(onCompletion->mContext, CHIP_NO_ERROR, AsByteSpan(info.operationalCertificate), intermediateCertificate, + AsByteSpan(info.rootCertificate), MakeOptional(ipk), adminSubject); + }); } CHIP_ERROR MTROperationalCredentialsDelegate::LocalGenerateNOCChain(const chip::ByteSpan & csrElements, diff --git a/src/darwin/Framework/CHIP/Matter.h b/src/darwin/Framework/CHIP/Matter.h index 179c28424581ba..b5c699e20c695f 100644 --- a/src/darwin/Framework/CHIP/Matter.h +++ b/src/darwin/Framework/CHIP/Matter.h @@ -49,10 +49,10 @@ #import #import #import -#import #import #import #import +#import #import #import #import diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index af1f6c339433e5..7a419bdbf3aa36 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -36,12 +36,13 @@ 3CF134A9289D8D800017A19E /* MTRCSRInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */; }; 3CF134AB289D8DF70017A19E /* MTRAttestationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3CF134AD289D8E570017A19E /* MTRAttestationInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */; }; - 3CF134AF289D90FF0017A19E /* MTRNOCChainIssuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3CF134AF289D90FF0017A19E /* MTROperationalCertificateIssuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3D69868529383096007314E7 /* com.csa.matter.plist in Copy Logging Preferences */ = {isa = PBXBuildFile; fileRef = 3D69868029382EF4007314E7 /* com.csa.matter.plist */; }; 3DECCB6E29347D2D00585AEC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DECCB6D29347D2C00585AEC /* Security.framework */; }; 3DECCB702934AECD00585AEC /* MTRLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DECCB6F2934AC1C00585AEC /* MTRLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3DECCB722934AFE200585AEC /* MTRLogging.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3DECCB712934AFE200585AEC /* MTRLogging.mm */; }; 3DECCB742934C21B00585AEC /* MTRDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DECCB732934C21B00585AEC /* MTRDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 51029DF6293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51029DF5293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm */; }; 5112F606287CD2C100B827E7 /* privilege-storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5112F605287CD2C100B827E7 /* privilege-storage.cpp */; }; 511913FB28C100EF009235E9 /* MTRBaseSubscriptionCallback.mm in Sources */ = {isa = PBXBuildFile; fileRef = 511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */; }; 511913FC28C100EF009235E9 /* MTRBaseSubscriptionCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */; }; @@ -196,12 +197,13 @@ 3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCSRInfo.mm; sourceTree = ""; }; 3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRAttestationInfo.h; sourceTree = ""; }; 3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttestationInfo.mm; sourceTree = ""; }; - 3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRNOCChainIssuer.h; sourceTree = ""; }; + 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROperationalCertificateIssuer.h; sourceTree = ""; }; 3D69868029382EF4007314E7 /* com.csa.matter.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.csa.matter.plist; sourceTree = ""; }; 3DECCB6D29347D2C00585AEC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 3DECCB6F2934AC1C00585AEC /* MTRLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRLogging.h; sourceTree = ""; }; 3DECCB712934AFE200585AEC /* MTRLogging.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRLogging.mm; sourceTree = ""; }; 3DECCB732934C21B00585AEC /* MTRDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDefines.h; sourceTree = ""; }; + 51029DF5293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROperationalCertificateIssuer.mm; sourceTree = ""; }; 5112F605287CD2C100B827E7 /* privilege-storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "privilege-storage.cpp"; path = "../../../app/util/privilege-storage.cpp"; sourceTree = ""; }; 511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRBaseSubscriptionCallback.mm; sourceTree = ""; }; 511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRBaseSubscriptionCallback.h; sourceTree = ""; }; @@ -497,10 +499,11 @@ 3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */, 3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */, 3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */, - 3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */, + 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */, 511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */, 511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */, 51E4D120291D0EB400C8C535 /* MTRBaseClustersCpp_Internal.h */, + 51029DF5293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm */, ); path = CHIP; sourceTree = ""; @@ -572,7 +575,7 @@ 991DC0842475F45400C13860 /* MTRDeviceController.h in Headers */, AF1CB86E2874B03B00865A96 /* MTROTAProviderDelegate.h in Headers */, 754F3DF427FBB94B00E60580 /* MTREventTLVValueDecoder_Internal.h in Headers */, - 3CF134AF289D90FF0017A19E /* MTRNOCChainIssuer.h in Headers */, + 3CF134AF289D90FF0017A19E /* MTROperationalCertificateIssuer.h in Headers */, 3CF134AB289D8DF70017A19E /* MTRAttestationInfo.h in Headers */, B2E0D7B2245B0B5C003C5B48 /* MTRManualSetupPayloadParser.h in Headers */, 3CF134A7289D8ADA0017A19E /* MTRCSRInfo.h in Headers */, @@ -742,6 +745,7 @@ 2CB7163C252E8A7C0026E2BB /* MTRDeviceControllerDelegateBridge.mm in Sources */, 997DED162695343400975E97 /* MTRThreadOperationalDataset.mm in Sources */, 515C1C6F284F9FFB00A48F0C /* MTRFramework.mm in Sources */, + 51029DF6293AA6100087AFB0 /* MTROperationalCertificateIssuer.mm in Sources */, 27A53C1827FBC6920053F131 /* MTRAttestationTrustStoreBridge.mm in Sources */, 998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */, 5136661428067D550025EDAE /* MTRDeviceControllerFactory.mm in Sources */, From e05b7a44acf8eef78bee2c64bd82f1d5b75cc7ea Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 5 Dec 2022 19:56:52 -0500 Subject: [PATCH 2/3] Address review comment. --- .../Framework/CHIP/MTRAttestationInfo.h | 21 +++++++++++-------- .../Framework/CHIP/MTRAttestationInfo.mm | 18 ++++++++-------- .../Framework/CHIP/MTRDeviceController.mm | 17 ++++++++------- .../CHIP/MTROperationalCredentialsDelegate.mm | 4 ++-- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.h b/src/darwin/Framework/CHIP/MTRAttestationInfo.h index e499f341aeb94e..70cb9d39f3a0f4 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.h +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.h @@ -17,12 +17,15 @@ #import +#import + NS_ASSUME_NONNULL_BEGIN /** * Represents information relating to product attestation. * */ +MTR_NEWLY_AVAILABLE @interface MTRAttestationInfo : NSObject @property (nonatomic, copy, readonly) NSData * challenge; @@ -33,22 +36,22 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy, readonly) NSData * elementsSignature; -@property (nonatomic, copy, readonly) NSData * dac; +@property (nonatomic, copy, readonly) MTRCertificateDERBytes deviceAttestationCertificate; -@property (nonatomic, copy, readonly) NSData * pai; +@property (nonatomic, copy, readonly) MTRCertificateDERBytes productAttestationIntermediateCertificate; @property (nonatomic, copy, readonly) NSData * certificationDeclaration; @property (nonatomic, copy, readonly) NSData * firmwareInfo; - (instancetype)initWithChallenge:(NSData *)challenge - nonce:(NSData *)nonce - elements:(NSData *)elements - elementsSignature:(NSData *)elementsSignature - dac:(NSData *)dac - pai:(NSData *)pai - certificationDeclaration:(NSData *)certificationDeclaration - firmwareInfo:(NSData *)firmwareInfo; + nonce:(NSData *)nonce + elements:(NSData *)elements + elementsSignature:(NSData *)elementsSignature + deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate + productAttestationIntermediateCertificate:(MTRCertificateDERBytes)processAttestationIntermediateCertificate + certificationDeclaration:(NSData *)certificationDeclaration + firmwareInfo:(NSData *)firmwareInfo; @end diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm index cb68bb239b32a4..0201fcd1a46941 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm @@ -22,21 +22,21 @@ @implementation MTRAttestationInfo : NSObject - (instancetype)initWithChallenge:(NSData *)challenge - nonce:(NSData *)nonce - elements:(NSData *)elements - elementsSignature:(NSData *)elementsSignature - dac:(NSData *)dac - pai:(NSData *)pai - certificationDeclaration:(NSData *)certificationDeclaration - firmwareInfo:(NSData *)firmwareInfo + nonce:(NSData *)nonce + elements:(NSData *)elements + elementsSignature:(NSData *)elementsSignature + deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate + productAttestationIntermediateCertificate:(MTRCertificateDERBytes)productAttestationIntermediateCertificate + certificationDeclaration:(NSData *)certificationDeclaration + firmwareInfo:(NSData *)firmwareInfo { if (self = [super init]) { _challenge = challenge; _nonce = nonce; _elements = elements; _elementsSignature = elementsSignature; - _dac = dac; - _pai = pai; + _deviceAttestationCertificate = deviceAttestationCertificate; + _productAttestationIntermediateCertificate = productAttestationIntermediateCertificate; _certificationDeclaration = certificationDeclaration; _firmwareInfo = firmwareInfo; } diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index b8bba122266677..c105ef9f155463 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -922,14 +922,15 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo elements:csrInfo.csrElements elementsSignature:csrInfo.attestationSignature csr:csrInfo.csr]; - AttestationInfo * oldAttestationInfo = [[AttestationInfo alloc] initWithChallenge:attestationInfo.challenge - nonce:attestationInfo.nonce - elements:attestationInfo.elements - elementsSignature:attestationInfo.elementsSignature - dac:attestationInfo.dac - pai:attestationInfo.pai - certificationDeclaration:attestationInfo.certificationDeclaration - firmwareInfo:attestationInfo.firmwareInfo]; + AttestationInfo * oldAttestationInfo = + [[AttestationInfo alloc] initWithChallenge:attestationInfo.challenge + nonce:attestationInfo.nonce + elements:attestationInfo.elements + elementsSignature:attestationInfo.elementsSignature + dac:attestationInfo.deviceAttestationCertificate + pai:attestationInfo.productAttestationIntermediateCertificate + certificationDeclaration:attestationInfo.certificationDeclaration + firmwareInfo:attestationInfo.firmwareInfo]; [self.nocChainIssuer onNOCChainGenerationNeeded:oldCSRInfo attestationInfo:oldAttestationInfo diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm index a83019062beca2..8ab2d178b6b786 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm @@ -188,8 +188,8 @@ nonce:AsData(commissioningParameters.Value().GetAttestationNonce().Value()) elements:AsData(commissioningParameters.Value().GetAttestationElements().Value()) elementsSignature:AsData(commissioningParameters.Value().GetAttestationSignature().Value()) - dac:AsData(DAC) - pai:AsData(PAI) + deviceAttestationCertificate:AsData(DAC) + productAttestationIntermediateCertificate:AsData(PAI) certificationDeclaration:AsData(certificationDeclarationSpan) firmwareInfo:AsData(firmwareInfoSpan)]; From bcca4516201727d87f53756d4d4e03512a628565 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 12 Dec 2022 12:28:13 -0500 Subject: [PATCH 3/3] Address review comments. --- .../Framework/CHIP/MTRAttestationInfo.h | 46 ++++++++++++++---- .../Framework/CHIP/MTRAttestationInfo.mm | 4 +- src/darwin/Framework/CHIP/MTRCSRInfo.h | 38 ++++++++++----- src/darwin/Framework/CHIP/MTRCSRInfo.mm | 6 +-- src/darwin/Framework/CHIP/MTRDefines.h | 2 + .../Framework/CHIP/MTRDeviceController.h | 32 +------------ .../Framework/CHIP/MTRDeviceController.mm | 47 ++++++++++++------- .../CHIP/MTRDeviceControllerStartupParams.h | 34 ++++++++++++-- .../CHIP/MTROperationalCertificateIssuer.h | 2 +- .../CHIP/MTROperationalCertificateIssuer.mm | 15 +++--- .../CHIP/MTROperationalCredentialsDelegate.h | 3 ++ .../CHIP/MTROperationalCredentialsDelegate.mm | 10 ++-- 12 files changed, 151 insertions(+), 88 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.h b/src/darwin/Framework/CHIP/MTRAttestationInfo.h index 70cb9d39f3a0f4..74c89241d518cc 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.h +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.h @@ -18,6 +18,7 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -28,25 +29,50 @@ NS_ASSUME_NONNULL_BEGIN MTR_NEWLY_AVAILABLE @interface MTRAttestationInfo : NSObject +/** + * The attestation challenge from the secure session. + */ @property (nonatomic, copy, readonly) NSData * challenge; - +/** + * The attestation nonce from the AttestationRequest command. + */ @property (nonatomic, copy, readonly) NSData * nonce; - -@property (nonatomic, copy, readonly) NSData * elements; - +/** + * The TLV-encoded attestation_elements_message that was used to find the + * certificationDeclaration and firmwareInfo. + */ +@property (nonatomic, copy, readonly) MTRTLVBytes elementsTLV; +/** + * A signature, using the device attestation private key of the device that sent + * the attestation information, over the concatenation of elementsTLV and the + * attestation challenge from the secure session. + */ @property (nonatomic, copy, readonly) NSData * elementsSignature; - +/** + * The device attestation certificate for the device. This can be used to + * verify signatures created with the device attestation private key. + */ @property (nonatomic, copy, readonly) MTRCertificateDERBytes deviceAttestationCertificate; - +/** + * The product attestation intermediate certificate that can be used to verify + * the authenticity of the device attestation certificate. + */ @property (nonatomic, copy, readonly) MTRCertificateDERBytes productAttestationIntermediateCertificate; - +/** + * The certification declaration of the device. This is a DER-encoded string + * representing a CMS-formatted certification declaration. + */ @property (nonatomic, copy, readonly) NSData * certificationDeclaration; - -@property (nonatomic, copy, readonly) NSData * firmwareInfo; +/* + * Firmware information, if any, provided in the elementsTLV. The encoding of + * this is not currently specified, but if present this must match the + * Distributed Compliance Ledger entry for the device. + */ +@property (nonatomic, copy, readonly, nullable) NSData * firmwareInfo; - (instancetype)initWithChallenge:(NSData *)challenge nonce:(NSData *)nonce - elements:(NSData *)elements + elementsTLV:(MTRTLVBytes)elementsTLV elementsSignature:(NSData *)elementsSignature deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate productAttestationIntermediateCertificate:(MTRCertificateDERBytes)processAttestationIntermediateCertificate diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm index 0201fcd1a46941..7edfc38b114763 100644 --- a/src/darwin/Framework/CHIP/MTRAttestationInfo.mm +++ b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm @@ -23,7 +23,7 @@ @implementation MTRAttestationInfo : NSObject - (instancetype)initWithChallenge:(NSData *)challenge nonce:(NSData *)nonce - elements:(NSData *)elements + elementsTLV:(MTRTLVBytes)elementsTLV elementsSignature:(NSData *)elementsSignature deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate productAttestationIntermediateCertificate:(MTRCertificateDERBytes)productAttestationIntermediateCertificate @@ -33,7 +33,7 @@ - (instancetype)initWithChallenge:(NSData *)challenge if (self = [super init]) { _challenge = challenge; _nonce = nonce; - _elements = elements; + _elementsTLV = elementsTLV; _elementsSignature = elementsSignature; _deviceAttestationCertificate = deviceAttestationCertificate; _productAttestationIntermediateCertificate = productAttestationIntermediateCertificate; diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.h b/src/darwin/Framework/CHIP/MTRCSRInfo.h index 3ea9b99603d1f7..f90c108e239c88 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.h +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.h @@ -17,29 +17,45 @@ #import +#import + +typedef NSData * MTRCSRDERBytes; + NS_ASSUME_NONNULL_BEGIN /** * Represents information relating to a certificate signing request for a Matter - * operational certificate. The entire TLV nocsr-elements structure, including - * any vendor-specific data, is included, as well as the parsed-out CSR and - * CSRNonce fields from that structure. - * - * The AttestationSignature from the CSRResponse command is also included. This - * signs a concatenation of csrElements and the attestationChallenge found in - * MTRAttestationInfo. + * operational certificate. */ MTR_NEWLY_AVAILABLE @interface MTROperationalCSRInfo : NSObject -@property (nonatomic, copy, readonly) NSData * csr; +/** + * DER-encoded certificate signing request. + */ +@property (nonatomic, copy, readonly) MTRCSRDERBytes csr; +/** + * The nonce provided in the original CSRRequest command hat led to this CSR + * being created. + */ @property (nonatomic, copy, readonly) NSData * csrNonce; -@property (nonatomic, copy, readonly) NSData * csrElements; +/** + * TLV-encoded nocsr-elements structure. This includes the "csr" and "csrNonce" + * fields, and can include additional vendor-specific information. + */ +@property (nonatomic, copy, readonly) MTRTLVBytes csrElementsTLV; +/** + * A signature, using the device attestation private key of the device that + * created the CSR, over the concatenation of csrElementsTLV and the attestation + * challenge from the secure session. + * + * The attestation challenge is available in MTRAttestionInfo. + */ @property (nonatomic, copy, readonly) NSData * attestationSignature; -- (instancetype)initWithCSR:(NSData *)csr +- (instancetype)initWithCSR:(MTRCSRDERBytes)csr csrNonce:(NSData *)csrNonce - csrElements:(NSData *)csrElements + csrElementsTLV:(MTRTLVBytes)csrElementsTLV attestationSignature:(NSData *)attestationSignature; @end diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.mm b/src/darwin/Framework/CHIP/MTRCSRInfo.mm index 2ac9b070077982..d8a77fba5e941a 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.mm +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.mm @@ -21,15 +21,15 @@ @implementation MTROperationalCSRInfo : NSObject -- (instancetype)initWithCSR:(NSData *)csr +- (instancetype)initWithCSR:(MTRCSRDERBytes)csr csrNonce:(NSData *)csrNonce - csrElements:(NSData *)csrElements + csrElementsTLV:(MTRTLVBytes)csrElementsTLV attestationSignature:(NSData *)attestationSignature; { if (self = [super init]) { _csr = csr; _csrNonce = csrNonce; - _csrElements = csrElements; + _csrElementsTLV = csrElementsTLV; _attestationSignature = attestationSignature; } return self; diff --git a/src/darwin/Framework/CHIP/MTRDefines.h b/src/darwin/Framework/CHIP/MTRDefines.h index 0751dda4011c77..80bfaaf5ff875b 100644 --- a/src/darwin/Framework/CHIP/MTRDefines.h +++ b/src/darwin/Framework/CHIP/MTRDefines.h @@ -24,3 +24,5 @@ #else #define MTR_EXTERN extern MTR_EXPORT #endif + +typedef NSData * MTRTLVBytes; diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.h b/src/darwin/Framework/CHIP/MTRDeviceController.h index 7b371baf862ef4..1de706f10cfbb4 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController.h @@ -117,35 +117,6 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS */ - (void)setDeviceControllerDelegate:(id)delegate queue:(dispatch_queue_t)queue MTR_NEWLY_AVAILABLE; -/** - * Sets this MTRDeviceController to use the given issuer for issuing operational - * certificates. By default, the MTRDeviceController uses an internal issuer - * using the signing provided when it was created. - * - * Both arguments must be nil (to stop using an external operational certificate - * issuer) or both must be non-nil. - * - * When using an external operational certificate issuer, all device attestation - * checks that require some sort of trust anchors are delegated to the external - * certificate issuer. Specifically, the following device attestation checks - * are not performed and must be done by the operationalCertificateIssuer: - * - * (1) Make sure the PAA is valid and approved by CSA. - * (2) vid-scoped PAA check: if the PAA is vid scoped, then its vid must match the DAC vid. - * (3) cert chain check: verify PAI is signed by PAA, and DAC is signed by PAI. - * (4) PAA subject key id extraction: the PAA subject key must match the PAA key referenced in the PAI. - * (5) CD signature check: make sure a valid CSA CD key is used to sign the CD. - * - * @param[in] operationalCertificateIssuer the operationalCertificateIssuer to - * use for issuing operational certs - * - * @param[in] queue The queue on which the calls into the - * operationalCertificateIssuer will happen. - */ -- (BOOL)setOperationalCertificateIssuer:(nullable id)operationalCertificateIssuer - queue:(nullable dispatch_queue_t)queue - error:(NSError * __autoreleasing *)error MTR_NEWLY_AVAILABLE; - /** * Return the attestation challenge for the secure session of the device being commissioned. * @@ -237,7 +208,8 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS queue:(dispatch_queue_t)queue MTR_NEWLY_DEPRECATED("Please use setDeviceControllerDelegate:"); - (void)setNocChainIssuer:(id)nocChainIssuer - queue:(dispatch_queue_t)queue MTR_NEWLY_DEPRECATED("Please use setOperationalCertificateIssuer"); + queue:(dispatch_queue_t)queue + MTR_NEWLY_DEPRECATED("Please set the operationalCertificateIssuer in the MTRDeviceControllerStartupParams instead."); @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index c105ef9f155463..a2dc32c1bed1ee 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -341,9 +341,21 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams if (commissionerInitialized == NO) { [self cleanupAfterStartup]; + return NO; } - return commissionerInitialized; + // TODO: Once setNocChainIssuer no longer needs to be supported, + // we can just move the internals of + // setOperationalCertificateIssuer into the sync-dispatched block + // above. + if (![self setOperationalCertificateIssuer:startupParams.operationalCertificateIssuer + queue:startupParams.operationalCertificateIssuerQueue]) { + MTR_LOG_ERROR("operationalCertificateIssuer and operationalCertificateIssuerQueue must both be nil or both be non-nil"); + [self cleanupAfterStartup]; + return NO; + } + + return YES; } - (NSNumber *)controllerNodeID @@ -550,26 +562,24 @@ - (void)setDeviceControllerDelegate:(id)delegate qu - (BOOL)setOperationalCertificateIssuer:(nullable id)operationalCertificateIssuer queue:(nullable dispatch_queue_t)queue - error:(NSError * __autoreleasing *)error { if ((operationalCertificateIssuer != nil && queue == nil) || (operationalCertificateIssuer == nil && queue != nil)) { - if (error) { - *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT]; - } return NO; } - VerifyOrReturnValue([self checkIsRunning:error], NO); + VerifyOrReturnValue([self checkIsRunning], NO); __block BOOL success = NO; dispatch_sync(_chipWorkQueue, ^{ - VerifyOrReturn([self checkIsRunning:error]); + VerifyOrReturn([self checkIsRunning]); if (operationalCertificateIssuer != nil) { self->_operationalCredentialsDelegate->SetOperationalCertificateIssuer(operationalCertificateIssuer, queue); self->_cppCommissioner->SetDeviceAttestationVerifier(_partialDACVerifier); } else { - self->_cppCommissioner->SetDeviceAttestationVerifier(chip::Credentials::GetDeviceAttestationVerifier()); + // TODO: Once we are not supporting setNocChainIssuer this + // branch can just go away. + self->_cppCommissioner->SetDeviceAttestationVerifier(_factory.deviceAttestationVerifier); } success = YES; }); @@ -919,27 +929,31 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo completion:(MTROperationalCertificateIssuedHandler)completion { CSRInfo * oldCSRInfo = [[CSRInfo alloc] initWithNonce:csrInfo.csrNonce - elements:csrInfo.csrElements + elements:csrInfo.csrElementsTLV elementsSignature:csrInfo.attestationSignature csr:csrInfo.csr]; + NSData * _Nullable firmwareInfo = attestationInfo.firmwareInfo; + if (firmwareInfo == nil) { + firmwareInfo = [NSData data]; + } AttestationInfo * oldAttestationInfo = [[AttestationInfo alloc] initWithChallenge:attestationInfo.challenge nonce:attestationInfo.nonce - elements:attestationInfo.elements + elements:attestationInfo.elementsTLV elementsSignature:attestationInfo.elementsSignature dac:attestationInfo.deviceAttestationCertificate pai:attestationInfo.productAttestationIntermediateCertificate certificationDeclaration:attestationInfo.certificationDeclaration - firmwareInfo:attestationInfo.firmwareInfo]; + firmwareInfo:firmwareInfo]; [self.nocChainIssuer onNOCChainGenerationNeeded:oldCSRInfo attestationInfo:oldAttestationInfo onNOCChainGenerationComplete:^(NSData * operationalCertificate, NSData * intermediateCertificate, NSData * rootCertificate, NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error) { - auto * info = [MTROperationalCertificateInfo infoWithOperationalCertificate:operationalCertificate - intermediateCertificate:intermediateCertificate - rootCertificate:rootCertificate - adminSubject:adminSubject]; + auto * info = [[MTROperationalCertificateInfo alloc] initWithOperationalCertificate:operationalCertificate + intermediateCertificate:intermediateCertificate + rootCertificate:rootCertificate + adminSubject:adminSubject]; completion(info, nil); if (error != nil) { *error = nil; @@ -1175,7 +1189,6 @@ - (void)setPairingDelegate:(id)delegate queue:(dispatc - (void)setNocChainIssuer:(id)nocChainIssuer queue:(dispatch_queue_t)queue { [self setOperationalCertificateIssuer:[[MTROperationalCertificateChainIssuerShim alloc] initWithIssuer:nocChainIssuer] - queue:queue - error:nil]; + queue:queue]; } @end diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.h b/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.h index 8ff5775ed71279..36090b9766dd44 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.h @@ -17,6 +17,7 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -27,11 +28,11 @@ NS_ASSUME_NONNULL_BEGIN * Keypair used to sign operational certificates. This is the root CA keypair * if not using an intermediate CA, the intermediate CA's keypair otherwise. * - * Allowed to be nil if this controller will not be issuing operational - * certificates. In that case, the MTRDeviceControllerStartupParams object must - * be initialized using + * Allowed to be nil if this controller will not be issuing internally-generated + * operational certificates. In that case, the MTRDeviceControllerStartupParams + * object must be initialized using * initWithIPK:operationalKeypair:operationalCertificate:intermediateCertificate:rootCertificate: - * (to provide the operational credentials for the controller itself). + * (to provide the operational credentials for t2he controller itself). */ @property (nonatomic, copy, readonly, nullable) id nocSigner; /** @@ -187,6 +188,31 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, strong, nullable) id operationalKeypair; +/** + * The certificate issuer delegate to use for issuing operational certificates + * when commmissioning devices. Allowed to be nil if this controller either + * does not issue operational certificates at all or internally generates the + * certificates to be issued. In the latter case, nocSigner must not be nil. + * + * When this property is non-nill, all device attestation checks that require + * some sort of trust anchors are delegated to the operationalCertificateIssuer. + * Specifically, the following device attestation checks are not performed and + * must be done by the operationalCertificateIssuer: + * + * (1) Make sure the PAA is valid and approved by CSA. + * (2) VID-scoped PAA check: if the PAA is VID scoped, then its VID must match the DAC VID. + * (3) cert chain check: verify PAI is signed by PAA, and DAC is signed by PAI. + * (4) PAA subject key id extraction: the PAA subject key must match the PAA key referenced in the PAI. + * (5) CD signature check: make sure a valid CSA CD key is used to sign the CD. + */ +@property (nonatomic, strong, nullable) id operationalCertificateIssuer MTR_NEWLY_AVAILABLE; + +/** + * The dispatch queue on which operationalCertificateIssuer should be called. + * Allowed to be nil if and only if operationalCertificateIssuer is nil. + */ +@property (nonatomic, strong, nullable) dispatch_queue_t operationalCertificateIssuerQueue MTR_NEWLY_AVAILABLE; + - (instancetype)init NS_UNAVAILABLE; /** diff --git a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h index 0a6bd14a039ff1..84566e20dbee14 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h +++ b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h @@ -41,7 +41,7 @@ MTR_NEWLY_AVAILABLE @property (nonatomic, copy) MTRCertificateDERBytes rootCertificate; @property (nonatomic, copy, nullable) NSNumber * adminSubject; -+ (instancetype)infoWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate +- (instancetype)initWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate intermediateCertificate:(nullable MTRCertificateDERBytes)intermediateCertificate rootCertificate:(MTRCertificateDERBytes)rootCertificate adminSubject:(nullable NSNumber *)adminSubject; diff --git a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm index c51e7abee2226b..21ee514e8b242b 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm +++ b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.mm @@ -20,17 +20,18 @@ @implementation MTROperationalCertificateInfo -+ (instancetype)infoWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate +- (instancetype)initWithOperationalCertificate:(MTRCertificateDERBytes)operationalCertificate intermediateCertificate:(nullable MTRCertificateDERBytes)intermediateCertificate rootCertificate:(MTRCertificateDERBytes)rootCertificate adminSubject:(nullable NSNumber *)adminSubject { - auto * info = [[MTROperationalCertificateInfo alloc] init]; - info.operationalCertificate = operationalCertificate; - info.intermediateCertificate = intermediateCertificate; - info.rootCertificate = rootCertificate; - info.adminSubject = adminSubject; - return info; + if (self = [super init]) { + _operationalCertificate = operationalCertificate; + _intermediateCertificate = intermediateCertificate; + _rootCertificate = rootCertificate; + _adminSubject = adminSubject; + } + return self; } @end diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h index 351609a5283b61..e0e34130aa5a8e 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h @@ -120,6 +120,9 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey, chip::MutableByteSpan & noc); + // Called asynchronously in response to the MTROperationalCertificateIssuer + // calling the completion we passed it when asking it to generate a NOC + // chain. void ExternalNOCChainGenerated(MTROperationalCertificateInfo * _Nullable info, NSError * _Nullable error); CHIP_ERROR ExternalGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm index 8ab2d178b6b786..40e2fd3f8028a4 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm @@ -164,7 +164,7 @@ auto * csrInfo = [[MTROperationalCSRInfo alloc] initWithCSR:AsData(csr) csrNonce:AsData(csrNonce) - csrElements:AsData(csrElements) + csrElementsTLV:AsData(csrElements) attestationSignature:AsData(csrElementsSignature)]; chip::ByteSpan certificationDeclarationSpan; @@ -183,15 +183,19 @@ chip::Credentials::DeconstructAttestationElements(commissioningParameters.Value().GetAttestationElements().Value(), certificationDeclarationSpan, attestationNonceSpan, timestampDeconstructed, firmwareInfoSpan, vendorReserved)); + NSData * firmwareInfo = nil; + if (!firmwareInfoSpan.empty()) { + firmwareInfo = AsData(firmwareInfoSpan); + } MTRAttestationInfo * attestationInfo = [[MTRAttestationInfo alloc] initWithChallenge:AsData(attestationChallenge) nonce:AsData(commissioningParameters.Value().GetAttestationNonce().Value()) - elements:AsData(commissioningParameters.Value().GetAttestationElements().Value()) + elementsTLV:AsData(commissioningParameters.Value().GetAttestationElements().Value()) elementsSignature:AsData(commissioningParameters.Value().GetAttestationSignature().Value()) deviceAttestationCertificate:AsData(DAC) productAttestationIntermediateCertificate:AsData(PAI) certificationDeclaration:AsData(certificationDeclarationSpan) - firmwareInfo:AsData(firmwareInfoSpan)]; + firmwareInfo:firmwareInfo]; MTRDeviceController * __weak weakController = mWeakController; dispatch_async(mOperationalCertificateIssuerQueue, ^{