From bb2e6ef9bccef72bf25756102abfc20a4cd64838 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 16 May 2022 13:26:49 -0400 Subject: [PATCH] Allow Darwin framework consumers to provide a controller NOC and keypair. Specific changes: * Rename initWithKeypair API to initWithSigningKeypair, since we can now also init with an operational keypair. * Fix FabricInfo::SetOperationalKeypair to correcty handle the mHasExternallyOwnedOperationalKey case. The old code would try to deserialize into the externally owned keypair. * Fix FabricInfo::GetOperationalKey to just return the key even it it's null, instead of allocating a random key that does not match anything. I have checked that consumers all either null-check the call or have just called SetOperationalKeypair or SetExternallyOwnedOperationalKeypair. SetFabricInfo is updated to error out if the incoming fabric info has a null operational key. This change was needed for basic API sanity in terms of not accidentally switching a fabric from an externally managed operational key to an internally managed randomly generated one. * Fix backwards boolean check in FabricInfo::Reset that was causing us to leak internally managed keys and try to delete externally managed ones. * Change Darwin CHIPDeviceControllerStartupParams to allow providing an operational keypair to be used for the NOC. * Change Darwin CHIPDeviceControllerStartupParams To allow providing a NOC instead of having one generated inside the framework. * Refactor the code for initializing CHIPDeviceControllerStartupParamsInternal to better share code and support the new functionality. * Allow initializing CHIPOperationalCredentialsDelegate without a NOC-signing keypair. This is needed because the SDK's controller init requires a credentials delegate. When initialized in this way, the delegate will just return error when asked to create a NOC. * Added tests for the new API (which caught a number of the issues listed above). Fixes https://github.com/project-chip/connectedhomeip/issues/18444 --- .../commands/common/CHIPCommandBridge.mm | 4 +- src/credentials/FabricTable.cpp | 22 +- src/credentials/FabricTable.h | 18 +- .../Framework Helpers/DefaultsUtils.m | 4 +- .../Framework/CHIP/CHIPDeviceController.mm | 64 ++- .../CHIP/CHIPDeviceControllerStartupParams.h | 114 +++-- .../CHIP/CHIPDeviceControllerStartupParams.mm | 291 ++++++++++++- ...IPDeviceControllerStartupParams_Internal.h | 72 +++- .../CHIPOperationalCredentialsDelegate.mm | 6 +- .../Framework/CHIP/MatterControllerFactory.mm | 182 +------- .../Framework/CHIPTests/CHIPClustersTests.m | 2 +- .../Framework/CHIPTests/CHIPControllerTests.m | 393 ++++++++++++++++-- .../Framework/CHIPTests/CHIPDeviceTests.m | 2 +- .../CHIPTests/CHIPXPCListenerSampleTests.m | 2 +- 14 files changed, 878 insertions(+), 298 deletions(-) diff --git a/examples/chip-tool-darwin/commands/common/CHIPCommandBridge.mm b/examples/chip-tool-darwin/commands/common/CHIPCommandBridge.mm index 7c9863ae71f1a3..b5d8a6c1d0051b 100644 --- a/examples/chip-tool-darwin/commands/common/CHIPCommandBridge.mm +++ b/examples/chip-tool-darwin/commands/common/CHIPCommandBridge.mm @@ -56,7 +56,9 @@ constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma }; for (size_t i = 0; i < ArraySize(identities); ++i) { - auto controllerParams = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:nocSigner fabricId:(i + 1) ipk:ipk]; + auto controllerParams = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:nocSigner + fabricId:(i + 1) + ipk:ipk]; // We're not sure whether we're creating a new fabric or using an // existing one, so just try both. diff --git a/src/credentials/FabricTable.cpp b/src/credentials/FabricTable.cpp index cd32d304727443..c56ce5fe30782c 100644 --- a/src/credentials/FabricTable.cpp +++ b/src/credentials/FabricTable.cpp @@ -324,10 +324,16 @@ CHIP_ERROR FabricInfo::SetOperationalKeypair(const P256Keypair * keyPair) { VerifyOrReturnError(keyPair != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - mHasExternallyOwnedOperationalKey = false; - P256SerializedKeypair serialized; ReturnErrorOnFailure(keyPair->Serialize(serialized)); + + if (mHasExternallyOwnedOperationalKey) + { + // Drop it, so we will allocate an internally owned one. + mOperationalKey = nullptr; + mHasExternallyOwnedOperationalKey = false; + } + if (mOperationalKey == nullptr) { #ifdef ENABLE_HSM_CASE_OPS_KEY @@ -583,13 +589,21 @@ CHIP_ERROR FabricInfo::SetFabricInfo(FabricInfo & newFabric) ReturnErrorOnFailure(VerifyCredentials(newFabric.mNOCCert, newFabric.mICACert, newFabric.mRootCert, validContext, operationalId, fabricId, pubkey)); + auto * operationalKey = newFabric.GetOperationalKey(); + if (operationalKey == nullptr) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // TODO: Should verify that pubkey matches operationalKey's public key. + if (newFabric.mHasExternallyOwnedOperationalKey) { - ReturnErrorOnFailure(SetExternallyOwnedOperationalKeypair(newFabric.GetOperationalKey())); + ReturnErrorOnFailure(SetExternallyOwnedOperationalKeypair(operationalKey)); } else { - ReturnErrorOnFailure(SetOperationalKeypair(newFabric.GetOperationalKey())); + ReturnErrorOnFailure(SetOperationalKeypair(operationalKey)); } SetRootCert(newFabric.mRootCert); diff --git a/src/credentials/FabricTable.h b/src/credentials/FabricTable.h index 8fdacf020a5294..e131dffb8e31e5 100644 --- a/src/credentials/FabricTable.h +++ b/src/credentials/FabricTable.h @@ -109,21 +109,7 @@ class DLL_EXPORT FabricInfo void SetVendorId(uint16_t vendorId) { mVendorId = vendorId; } - Crypto::P256Keypair * GetOperationalKey() const - { - if (!mHasExternallyOwnedOperationalKey && (mOperationalKey == nullptr)) - { - // TODO: Refactor the following two cases to go through SetOperationalKey() -#ifdef ENABLE_HSM_CASE_OPS_KEY - mOperationalKey = chip::Platform::New(); - mOperationalKey->CreateOperationalKey(mFabricIndex); -#else - mOperationalKey = chip::Platform::New(); - mOperationalKey->Initialize(); -#endif - } - return mOperationalKey; - } + Crypto::P256Keypair * GetOperationalKey() const { return mOperationalKey; } /** * Sets the P256Keypair used for this fabric. This will make a copy of the keypair @@ -212,7 +198,7 @@ class DLL_EXPORT FabricInfo mVendorId = VendorId::NotSpecified; mFabricLabel[0] = '\0'; - if (mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) + if (!mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) { chip::Platform::Delete(mOperationalKey); } diff --git a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m index 5e5ed7fb1f147b..c9b4df8a017960 100644 --- a/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m +++ b/src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m @@ -87,7 +87,7 @@ void CHIPSetNextAvailableDeviceID(uint64_t id) return; } - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:keys fabricId:1 ipk:keys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:keys fabricId:1 ipk:keys.ipk]; params.vendorId = @(kTestVendorId); // We're not sure whether we have a fabric configured already; try as if @@ -113,7 +113,7 @@ void CHIPSetNextAvailableDeviceID(uint64_t id) [controller shutdown]; NSLog(@"Starting up the stack"); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:keys fabricId:1 ipk:keys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:keys fabricId:1 ipk:keys.ipk]; sController = [[MatterControllerFactory sharedInstance] startControllerOnExistingFabric:params]; diff --git a/src/darwin/Framework/CHIP/CHIPDeviceController.mm b/src/darwin/Framework/CHIP/CHIPDeviceController.mm index 2b6bee57a55537..ba3a6fac3b0bb4 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceController.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceController.mm @@ -52,7 +52,9 @@ static NSString * const kErrorCommissionerInit = @"Init failure while initializing a commissioner"; static NSString * const kErrorIPKInit = @"Init failure while initializing IPK"; +static NSString * const kErrorSigningKeypairInit = @"Init failure while creating signing keypair bridge"; static NSString * const kErrorOperationalCredentialsInit = @"Init failure while creating operational credentials delegate"; +static NSString * const kErrorOperationalKeypairInit = @"Init failure while creating operational keypair bridge"; static NSString * const kErrorPairingInit = @"Init failure while creating a pairing delegate"; static NSString * const kErrorPairDevice = @"Failure while pairing the device"; static NSString * const kErrorUnpairDevice = @"Failure while unpairing the device"; @@ -70,7 +72,9 @@ @interface CHIPDeviceController () @property (readonly) chip::Controller::DeviceCommissioner * cppCommissioner; @property (readonly) CHIPDevicePairingDelegateBridge * pairingDelegateBridge; @property (readonly) CHIPOperationalCredentialsDelegate * operationalCredentialsDelegate; -@property (readonly) CHIPP256KeypairBridge keypairBridge; +@property (readonly) CHIPP256KeypairBridge signingKeypairBridge; +@property (readonly) CHIPP256KeypairBridge operationalKeypairBridge; +@property (readonly) chip::Optional operationalKeypairNativeBridge; @property (readonly) CHIPDeviceAttestationDelegateBridge * deviceAttestationDelegateBridge; @property (readonly) MatterControllerFactory * factory; @end @@ -159,17 +163,18 @@ - (BOOL)startup:(CHIPDeviceControllerStartupParamsInternal *)startupParams return; } - if (startupParams.nodeId == nil) { + if (startupParams.operationalCertificate == nil && startupParams.nodeId == nil) { CHIP_LOG_ERROR("Can't start a controller if we don't know what node id it is"); return; } - if ([startupParams nocSignerMatchesCerts] == NO) { - CHIP_LOG_ERROR("Provided nocSigner does not match certificates"); + if ([startupParams keypairsMatchCertificates] == NO) { + CHIP_LOG_ERROR("Provided keypairs do not match certificates"); return; } - if (startupParams.operationalCertificate != nil && startupParams.operationalKeypair == nullptr) { + if (startupParams.operationalCertificate != nil && startupParams.operationalKeypair == nil + && startupParams.serializedOperationalKeypair == nullptr) { CHIP_LOG_ERROR("Have no operational keypair for our operational certificate"); return; } @@ -177,9 +182,14 @@ - (BOOL)startup:(CHIPDeviceControllerStartupParamsInternal *)startupParams CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE; // create a CHIPP256KeypairBridge here and pass it to the operationalCredentialsDelegate - _keypairBridge.Init(startupParams.nocSigner); - auto nativeBridge = std::make_unique(_keypairBridge); - + std::unique_ptr nativeBridge; + if (startupParams.nocSigner) { + errorCode = _signingKeypairBridge.Init(startupParams.nocSigner); + if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorSigningKeypairInit]) { + return; + } + nativeBridge = std::make_unique(_signingKeypairBridge); + } errorCode = _operationalCredentialsDelegate->Init(_factory.storageDelegateBridge, std::move(nativeBridge), startupParams.ipk, startupParams.rootCertificate, startupParams.intermediateCertificate); if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorOperationalCredentialsInit]) { @@ -191,6 +201,15 @@ - (BOOL)startup:(CHIPDeviceControllerStartupParamsInternal *)startupParams return; } + // internallyCreatedOperationalKeypair might not be used, but + // if it is it needs to live long enough (until after we are + // done using commissionerParams). + chip::Crypto::P256Keypair internallyCreatedOperationalKeypair; + // nocBuffer might not be used, but if it is it needs to live + // long enough (until after we are done using + // commissionerParams). + uint8_t nocBuffer[chip::Controller::kMaxCHIPDERCertLength]; + chip::Controller::SetupParams commissionerParams; commissionerParams.pairingDelegate = _pairingDelegateBridge; @@ -200,26 +219,33 @@ - (BOOL)startup:(CHIPDeviceControllerStartupParamsInternal *)startupParams commissionerParams.controllerRCAC = _operationalCredentialsDelegate->RootCertSpan(); commissionerParams.controllerICAC = _operationalCredentialsDelegate->IntermediateCertSpan(); - chip::Crypto::P256Keypair operationalKeypair; - if (startupParams.operationalKeypair != nullptr) { - errorCode = operationalKeypair.Deserialize(*startupParams.operationalKeypair); + if (startupParams.operationalKeypair != nil) { + errorCode = _operationalKeypairBridge.Init(startupParams.operationalKeypair); + if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorOperationalKeypairInit]) { + return; + } + _operationalKeypairNativeBridge.Emplace(_operationalKeypairBridge); + commissionerParams.operationalKeypair = &_operationalKeypairNativeBridge.Value(); + commissionerParams.hasExternallyOwnedOperationalKeypair = true; } else { - errorCode = operationalKeypair.Initialize(); - } - if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorCommissionerInit]) { - return; + if (startupParams.serializedOperationalKeypair != nullptr) { + errorCode = internallyCreatedOperationalKeypair.Deserialize(*startupParams.serializedOperationalKeypair); + } else { + errorCode = internallyCreatedOperationalKeypair.Initialize(); + } + if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorCommissionerInit]) { + return; + } + commissionerParams.operationalKeypair = &internallyCreatedOperationalKeypair; } - commissionerParams.operationalKeypair = &operationalKeypair; - // nocBuffer might not be used, but if it is it needs to live long enough. - uint8_t nocBuffer[chip::Controller::kMaxCHIPDERCertLength]; if (startupParams.operationalCertificate) { commissionerParams.controllerNOC = AsByteSpan(startupParams.operationalCertificate); } else { chip::MutableByteSpan noc(nocBuffer); errorCode = _operationalCredentialsDelegate->GenerateNOC([startupParams.nodeId unsignedLongLongValue], - startupParams.fabricId, chip::kUndefinedCATs, operationalKeypair.Pubkey(), noc); + startupParams.fabricId, chip::kUndefinedCATs, commissionerParams.operationalKeypair->Pubkey(), noc); if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorCommissionerInit]) { return; } diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.h b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.h index f50d2d5ab20b66..03b7b43d080b7b 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.h +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.h @@ -27,17 +27,23 @@ 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 CHIPDeviceControllerStartupParams object + * must be initialized using initWithOperationalKeypair (to provide the + * operational credentials for the controller itself). */ -@property (strong, nonatomic, readonly) id nocSigner; +@property (strong, nonatomic, readonly, nullable) id nocSigner; /** * Fabric id for the controller. Must be set to a nonzero value. This is * scoped by the root public key, which is determined as follows: * - * * If an intermediate CA is being used, the root public key is the public key - * of the root certificate (which must be known in that case). + * * If a root certificate is provided, it is the public key of the root + * certificate. * - * * If an intermediate CA is not being used, the root public key is the public - * key of the nocSigner keypair. + * * If a root certificate is not provided, the root public key is the public + * key of the nocSigner keypair, since in this case we are not using an + * intermediate certificate. */ @property (nonatomic, readonly) uint64_t fabricId; /** @@ -67,20 +73,29 @@ NS_ASSUME_NONNULL_BEGIN /** * Node id for this controller. * + * If operationalCertificate is not nil, must be nil. The provided operational + * certificate will be used as-is. + * * If not nil, must be a valid Matter operational node id. * - * When creating a new fabric: + * If operationalCertificate is nil, nodeId and operationalKeypair are used to + * determine an operational certificate, as follows: * - * * Allowed to be nil to indicate that a random node id should be generated. + * * When creating a new fabric: * - * When using an existing fabric: + * ** nodeId is allowed to be nil to indicate that a random node id should be + * generated. + * + * * When using an existing fabric: * - * * Allowed to be nil to indicate that the existing operational identity (node - * id and operational keys) should be used. + * ** nodeId is allowed to be nil to indicate that the existing operational node + * id should be used. The existing operational keys will also be used, + * unless operationalKeypair is provided. * - * * If not nil, a new operational certificate will be generated for the - * provided node id (even if that matches the existing node id), using a new - * operational key. + * ** If nodeId is not nil, a new operational certificate will be generated for + * the provided node id (even if that matches the existing node id), using + * either the operationalKeypair if that is provided or a new randomly + * generated operational key. * */ @property (strong, nonatomic, nullable) NSNumber * nodeId; @@ -94,20 +109,22 @@ NS_ASSUME_NONNULL_BEGIN * of the root public key. * * If not nil, and if an intermediate CA is not being used, the public key of - * this certificate must match the public key of nocSigner. + * this certificate must match the public key of nocSigner, if nocSigner is not + * nil. * * When creating a new fabric: * - * * May be nil if an intermediate CA is not being used. In that case the - * nocSigner keypair, which is the keypair for the root certificate, will be - * used to generate and sign a root certificate, with a random issuer id. In - * this case, the fabricId will be included in the root certificate's subject - * DN. + * * May be nil if nocSigner is not nil and an intermediate CA is not being + * used. In that case the nocSigner keypair, which is the keypair for the + * root certificate, will be used to generate and sign a root certificate, + * with a random issuer id. In this case, the fabricId will be included in + * the root certificate's subject DN. * * When using an existing fabric: * - * * May be nil if an intermediate CA is not being used. In that case, the - * existing root certificate for the fabric will be used. + * * May be nil if nocSigner is not nil and an intermediate CA is not being + * used. In that case, the existing root certificate for the fabric will be + * used. * * * If not nil must satisfy the following properties: * @@ -124,8 +141,8 @@ NS_ASSUME_NONNULL_BEGIN * If not nil, rootCertificate must not be nil, and the intermediate certificate * must be signed by rootCertificate. * - * If not nil, the public key of this certificate must match the public key of - * nocSigner. + * If not nil, and nocSigner is not nil, the public key of this certificate must + * match the public key of nocSigner. * * When creating a new fabric: * @@ -140,8 +157,9 @@ NS_ASSUME_NONNULL_BEGIN * * * If nil: * - * * If there is an existing intermediate certificate, and it matches the - * nocSigner public key, the existing intermediate certificate will be used. + * * If nocSigner is not nil, there is an existing intermediate certificate, + * and it matches the nocSigner public key, the existing intermediate + * certificate will be used. * * * Otherwise the fabric will not use an intermediate certificate. This * allows switching from using an intermediate CA to not using one. @@ -149,14 +167,58 @@ NS_ASSUME_NONNULL_BEGIN */ @property (strong, nonatomic, nullable) NSData * intermediateCertificate; +/** + * Operational certificate, in X.509 DER form, to use. + * + * If not nil, will be used as the operational certificate. In this case + * operationalKeypair must not be nil. + * + * If nil, an operational certificate will be determined as described in the + * documentation for nodeId. + */ +@property (strong, nonatomic, nullable, readonly) NSData * operationalCertificate; + +/** + * Operational keypair to use. If operationalCertificate is not nil, the public + * key must match operationalCertificate. + * + * If not nil, and if operationalCertificate is nil, a new operational + * certificate will be generated for the given operationalKeypair. The node id + * will for that certificated will be determined as described in the + * documentation for nodeId. + */ +@property (strong, nonatomic, nullable) id operationalKeypair; + - (instancetype)init NS_UNAVAILABLE; /** + * Prepare to initialize a controller given a keypair to use for signing + * operational certificates. + * * fabricId must be set to a valid (i.e. nonzero) value. * * ipk must be 16 bytes in length */ -- (instancetype)initWithKeypair:(id)nocSigner fabricId:(uint64_t)fabricId ipk:(NSData *)ipk; +- (instancetype)initWithSigningKeypair:(id)nocSigner fabricId:(uint64_t)fabricId ipk:(NSData *)ipk; + +/** + * Prepare to initialize a controller with a complete operational certificate + * chain. This initialization method should be used when none of the + * certificate-signing private keys are available locally. + * + * The fabric id and node if to use will be derived from the provided + * operationalCertificate. + * + * intermediateCertificate may be nil if operationalCertificate is signed by + * rootCertificate. + * + * ipk must be 16 bytes in length. + */ +- (instancetype)initWithOperationalKeypair:(id)operationalKeypair + operationalCertificate:(NSData *)operationalCertificate + intermediateCertificate:(nullable NSData *)intermediateCertificate + rootCertificate:(NSData *)rootCertificate + ipk:(NSData *)ipk; @end diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.mm b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.mm index 5ea5653989f50a..ed172b5ca9e1ef 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.mm +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams.mm @@ -19,13 +19,18 @@ #import "CHIPLogging.h" #import "CHIPP256KeypairBridge.h" #import "MTRCertificates.h" +#import "NSDataSpanConversion.h" +#include #include +#include #include +using namespace chip; + @implementation CHIPDeviceControllerStartupParams -- (instancetype)initWithKeypair:(id)nocSigner fabricId:(uint64_t)fabricId ipk:(NSData *)ipk +- (instancetype)initWithSigningKeypair:(id)nocSigner fabricId:(uint64_t)fabricId ipk:(NSData *)ipk { if (!(self = [super init])) { return nil; @@ -43,28 +48,296 @@ - (instancetype)initWithKeypair:(id)nocSigner fabricId:(uint64_t)fa return self; } +- (instancetype)initWithOperationalKeypair:(id)operationalKeypair + operationalCertificate:(NSData *)operationalCertificate + intermediateCertificate:(nullable NSData *)intermediateCertificate + rootCertificate:(NSData *)rootCertificate + ipk:(NSData *)ipk +{ + if (!(self = [super init])) { + return nil; + } + + { // Scope for temporaries + // ExtractNodeIdFabricIdFromOpCert needs a TLV-encoded opcert, not a DER-encoded one. + uint8_t tlvOpCertBuf[Credentials::kMaxCHIPCertLength]; + MutableByteSpan tlvOpCert(tlvOpCertBuf); + CHIP_ERROR err = Credentials::ConvertX509CertToChipCert(AsByteSpan(operationalCertificate), tlvOpCert); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Unable to convert operational certificate to TLV: %s", ErrorStr(err)); + return nil; + } + + FabricId fabricId; + NodeId unused; + err = Credentials::ExtractNodeIdFabricIdFromOpCert(tlvOpCert, &unused, &fabricId); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Unable to extract fabric id from operational certificate: %s", ErrorStr(err)); + return nil; + } + if (fabricId == chip::kUndefinedFabricId) { + CHIP_LOG_ERROR("%llu is not a valid fabric id to initialize a device controller with", fabricId); + return nil; + } + _fabricId = fabricId; + } + + _operationalKeypair = operationalKeypair; + _operationalCertificate = operationalCertificate; + _intermediateCertificate = intermediateCertificate; + _rootCertificate = rootCertificate; + _ipk = ipk; + + return self; +} + +- (instancetype)initWithParams:(CHIPDeviceControllerStartupParams *)params +{ + if (!(self = [super init])) { + return nil; + } + + _nocSigner = params.nocSigner; + _fabricId = params.fabricId; + _ipk = params.ipk; + _vendorId = params.vendorId; + _nodeId = params.nodeId; + _rootCertificate = params.rootCertificate; + _intermediateCertificate = params.intermediateCertificate; + _operationalCertificate = params.operationalCertificate; + _operationalKeypair = params.operationalKeypair; + + return self; +} + @end +// Conver a ByteSpan representing a Matter TLV certificate into NSData holding a +// DER X.509 certificate. Returns nil on failures. +static NSData * _Nullable MatterCertToX509Data(const ByteSpan & cert) +{ + uint8_t buf[Controller::kMaxCHIPDERCertLength]; + MutableByteSpan derCert(buf); + CHIP_ERROR err = Credentials::ConvertChipCertToX509Cert(cert, derCert); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Failed do convert Matter certificate to X.509 DER: %s", ErrorStr(err)); + return nil; + } + + return AsData(derCert); +} + @implementation CHIPDeviceControllerStartupParamsInternal -- (BOOL)nocSignerMatchesCerts +- (instancetype)initWithParams:(CHIPDeviceControllerStartupParams *)params +{ + if (!(self = [super initWithParams:params])) { + return nil; + } + + if (self.nocSigner == nil && self.rootCertificate == nil) { + CHIP_LOG_ERROR("nocSigner and rootCertificate are both nil; no public key available to identify the fabric"); + return nil; + } + + if (self.operationalCertificate != nil && self.nodeId != nil) { + CHIP_LOG_ERROR("nodeId must be nil if operationalCertificate is not nil"); + return nil; + } + + if (self.operationalCertificate != nil) { + if (self.operationalKeypair == nil) { + CHIP_LOG_ERROR("Must have an operational keypair if an operational certificate is provided"); + return nil; + } + + if (![MTRCertificates keypair:self.operationalKeypair matchesCertificate:self.operationalCertificate]) { + CHIP_LOG_ERROR("operationalKeypair public key does not match operationalCertificate"); + return nil; + } + } + + return self; +} + +- (instancetype)initForNewFabric:(CHIPDeviceControllerStartupParams *)params +{ + if (!(self = [self initWithParams:params])) { + return nil; + } + + if (self.nocSigner == nil && self.operationalCertificate == nil) { + CHIP_LOG_ERROR("No way to get an operational certificate: nocSigner and operationalCertificate are both nil"); + return nil; + } + + if (self.operationalCertificate == nil && self.nodeId == nil) { + // Just avoid setting the top bit, to avoid issues with node + // ids outside the operational range. + uint64_t nodeId = arc4random(); + nodeId = (nodeId << 31) | (arc4random() >> 1); + self.nodeId = @(nodeId); + } + + if (self.rootCertificate == nil) { + NSError * error; + self.rootCertificate = [MTRCertificates generateRootCertificate:self.nocSigner + issuerId:nil + fabricId:@(self.fabricId) + error:&error]; + if (error != nil || self.rootCertificate == nil) { + CHIP_LOG_ERROR("Failed to generate root certificate: %@", error); + return nil; + } + } + + return self; +} + +- (instancetype)initForExistingFabric:(FabricInfo *)fabric params:(CHIPDeviceControllerStartupParams *)params { - NSData * signingCert = self.intermediateCertificate; - if (signingCert == nil) { - signingCert = self.rootCertificate; + if (!(self = [self initWithParams:params])) { + return nil; + } + + if (self.vendorId == nil) { + self.vendorId = @(fabric->GetVendorId()); + } + + BOOL usingExistingNOC = NO; + if (self.operationalCertificate == nil && self.nodeId == nil) { + self.nodeId = @(fabric->GetNodeId()); + + if (self.operationalKeypair == nil) { + ByteSpan noc; + CHIP_ERROR err = fabric->GetNOCCert(noc); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Failed to get existing NOC: %s", ErrorStr(err)); + return nil; + } + self.operationalCertificate = MatterCertToX509Data(noc); + if (self.operationalCertificate == nil) { + CHIP_LOG_ERROR("Failed to convert TLV NOC to DER X.509: %s", ErrorStr(err)); + return nil; + } + if (fabric->GetOperationalKey() == nullptr) { + CHIP_LOG_ERROR("No existing operational key for fabric"); + return nil; + } + _serializedOperationalKeypair = new Crypto::P256SerializedKeypair(); + if (_serializedOperationalKeypair == nullptr) { + CHIP_LOG_ERROR("Failed to allocate serialized keypair"); + return nil; + } + + err = fabric->GetOperationalKey()->Serialize(*_serializedOperationalKeypair); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Failed to serialize operational keypair: %s", ErrorStr(err)); + return nil; + } + } + + usingExistingNOC = YES; + } + + NSData * oldIntermediateCert = nil; + { + ByteSpan icaCert; + CHIP_ERROR err = fabric->GetICACert(icaCert); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Failed to get existing intermediate certificate: %s", ErrorStr(err)); + return nil; + } + // There might not be an ICA cert for this fabric. + if (!icaCert.empty()) { + oldIntermediateCert = MatterCertToX509Data(icaCert); + if (oldIntermediateCert == nil) { + return nil; + } + } + } + + if (self.nocSigner != nil && self.intermediateCertificate == nil && oldIntermediateCert != nil) { + // It's possible that we are switching from using an ICA cert to not using + // one. We can detect this case by checking whether the provided nocSigner + // matches the ICA cert. + if ([MTRCertificates keypair:self.nocSigner matchesCertificate:oldIntermediateCert] == YES) { + // Keep using the existing intermediate certificate. + self.intermediateCertificate = oldIntermediateCert; + } + // else presumably the nocSigner matches the root (will be verified later) + // and we are no longer using an intermediate. + } + + // If we were planning to use our existing NOC from the fabric info but we are + // changing from having an ICA to not having one, or changing from having one + // to not having one, or changing the identity of our ICA, we need to generate + // a new NOC. But we can keep our existing operational keypair and node id; + // nothing is forcing us to rotate those. + if (usingExistingNOC == YES + && ((oldIntermediateCert == nil) != (self.intermediateCertificate == nil) + || ((oldIntermediateCert != nil) && + [MTRCertificates isCertificate:oldIntermediateCert equalTo:self.intermediateCertificate] == NO))) { + self.operationalCertificate = nil; + } + + NSData * oldRootCert; + { + ByteSpan rootCert; + CHIP_ERROR err = fabric->GetRootCert(rootCert); + if (err != CHIP_NO_ERROR) { + CHIP_LOG_ERROR("Failed to get existing root certificate: %s", ErrorStr(err)); + return nil; + } + oldRootCert = MatterCertToX509Data(rootCert); + if (oldRootCert == nil) { + return nil; + } + } + + if (self.rootCertificate == nil) { + self.rootCertificate = oldRootCert; + } else if ([MTRCertificates isCertificate:oldRootCert equalTo:self.rootCertificate] == NO) { + CHIP_LOG_ERROR("Root certificate identity does not match existing root certificate"); + return nil; + } + + return self; +} + +- (BOOL)keypairsMatchCertificates +{ + if (self.nocSigner != nil) { + NSData * signingCert = self.intermediateCertificate; if (signingCert == nil) { + signingCert = self.rootCertificate; + if (signingCert == nil) { + CHIP_LOG_ERROR("No certificate to match nocSigner"); + return NO; + } + } + + if ([MTRCertificates keypair:self.nocSigner matchesCertificate:signingCert] == NO) { + CHIP_LOG_ERROR("Provided nocSigner does not match certificates"); + return NO; + } + } + + if (self.operationalCertificate != nil && self.operationalKeypair != nil) { + if ([MTRCertificates keypair:self.operationalKeypair matchesCertificate:self.operationalCertificate] == NO) { + CHIP_LOG_ERROR("Provided operationalKeypair does not match operationalCertificate"); return NO; } } - return [MTRCertificates keypair:self.nocSigner matchesCertificate:signingCert]; + return YES; } - (void)dealloc { - if (self.operationalKeypair != nullptr) { - delete self.operationalKeypair; - self.operationalKeypair = nullptr; + if (_serializedOperationalKeypair != nullptr) { + delete _serializedOperationalKeypair; + _serializedOperationalKeypair = nullptr; } } @end diff --git a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams_Internal.h b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams_Internal.h index 4ea9b7dc51230c..d21928a4220144 100644 --- a/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams_Internal.h +++ b/src/darwin/Framework/CHIP/CHIPDeviceControllerStartupParams_Internal.h @@ -21,43 +21,75 @@ #include +namespace chip { +class FabricInfo; +} + NS_ASSUME_NONNULL_BEGIN +@interface CHIPDeviceControllerStartupParams () +// We want to be able to write to operationalCertificate in +// CHIPDeviceControllerStartupParamsInternal. +@property (strong, nonatomic, nullable) NSData * operationalCertificate; + +// Init method that just copies the values of all our ivars. +- (instancetype)initWithParams:(CHIPDeviceControllerStartupParams *)params; +@end + @interface CHIPDeviceControllerStartupParamsInternal : CHIPDeviceControllerStartupParams /** - * Operational certificate to use for the controller bringup. Allowed to be - * nil to indicate that a new operational certificate should be generated. + * We may have an operational keypair either provided externally, via + * operationalKeypair, or internally (from the fabric table) via + * serializedOperationalKeypair. * - * Meant to be set by MatterControllerFactory. - */ -@property (strong, nonatomic, nullable) NSData * operationalCertificate; - -/** - * Operational keypair to use for the controller bringup. If nullptr, a new - * random operational keypair should be generated. + * If operationalKeypair is nil and serializedOperationalKeypair is nullptr, a + * new random operational keypair will be generated. * - * If operationalCertificate is not nil, operationalKeypair must not be - * nullptr. + * If operationalCertificate is not nil, either operationalKeypair must be not + * nil or serializedOperationalKeypair must be not nullptr. * - * If operationalCertificate is nil, operationalKeypair may be non-nullptr; that - * corresponds to needing to create a new NOC (e.g. if our signing certificate - * changed) without changing our operational identity. + * If operationalCertificate is nil, operationalKeypair may be not nil or + * serializedOperationalKeypair may be not nullptr; that corresponds to needing + * to create a new NOC (e.g. if our signing certificate changed) without + * changing our operational identity. * * Meant to be set by MatterControllerFactory. * * Assumed to be allocated via C++ new and will be deleted via C++ delete. */ -@property (nonatomic, nullable) chip::Crypto::P256SerializedKeypair * operationalKeypair; +@property (nonatomic, nullable, readonly) chip::Crypto::P256SerializedKeypair * serializedOperationalKeypair; + +/** + * Helper method that checks that our keypairs match our certificates. + * Specifically: + * + * 1) If we have a nocSigner keypair, its public key matches the intermediate + * cert (if there is one) or the root cert (if there is no intermediate + * cert). Returns YES if we have no nocSigner or if the keys match, NO if + * the keys do not match or if we can't even extract public keys from the + * certs and nocSigner. + * 2) If we have both an operationalKeypair and an operationalCertificate, + * their public keys match. + */ +- (BOOL)keypairsMatchCertificates; + +/** + * Initialize for controller bringup on a new fabric. + */ +- (instancetype)initForNewFabric:(CHIPDeviceControllerStartupParams *)params; /** - * Helper method that checks that the nocSigner keypair public key matches the - * intermediate cert (if there is one) or the root cert (if there is no - * intermediate cert). Returns YES if it does, NO if it does not or if we can't - * even extract public keys from the cert and nocSigner. + * Initialize for controller bringup on an existing fabric. */ -- (BOOL)nocSignerMatchesCerts; +- (instancetype)initForExistingFabric:(chip::FabricInfo *)fabric params:(CHIPDeviceControllerStartupParams *)params; +- (instancetype)initWithSigningKeypair:(id)nocSigner fabricId:(uint64_t)fabricId ipk:(NSData *)ipk NS_UNAVAILABLE; +- (instancetype)initWithOperationalKeypair:(id)operationalKeypair + operationalCertificate:(NSData *)operationalCertificate + intermediateCertificate:(nullable NSData *)intermediateCertificate + rootCertificate:(NSData *)rootCertificate + ipk:(NSData *)ipk NS_UNAVAILABLE; @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/CHIPOperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/CHIPOperationalCredentialsDelegate.mm index 163449a365b717..755bc53fc9e886 100644 --- a/src/darwin/Framework/CHIP/CHIPOperationalCredentialsDelegate.mm +++ b/src/darwin/Framework/CHIP/CHIPOperationalCredentialsDelegate.mm @@ -43,7 +43,7 @@ CHIP_ERROR CHIPOperationalCredentialsDelegate::Init(CHIPPersistentStorageDelegateBridge * storage, ChipP256KeypairPtr nocSigner, NSData * ipk, NSData * rootCert, NSData * _Nullable icaCert) { - if (storage == nil || nocSigner == nullptr || ipk == nil || rootCert == nil) { + if (storage == nil || ipk == nil || rootCert == nil) { return CHIP_ERROR_INVALID_ARGUMENT; } @@ -77,6 +77,10 @@ CHIP_ERROR CHIPOperationalCredentialsDelegate::GenerateNOC( NodeId nodeId, FabricId fabricId, const chip::CATValues & cats, const Crypto::P256PublicKey & pubkey, MutableByteSpan & noc) { + if (!mIssuerKey) { + return CHIP_ERROR_INCORRECT_STATE; + } + return GenerateNOC( *mIssuerKey, (mIntermediateCert != nil) ? mIntermediateCert : mRootCert, nodeId, fabricId, cats, pubkey, noc); } diff --git a/src/darwin/Framework/CHIP/MatterControllerFactory.mm b/src/darwin/Framework/CHIP/MatterControllerFactory.mm index b65b532a13709e..28cd2f424e9929 100644 --- a/src/darwin/Framework/CHIP/MatterControllerFactory.mm +++ b/src/darwin/Framework/CHIP/MatterControllerFactory.mm @@ -30,7 +30,6 @@ #import "NSDataSpanConversion.h" #include -#include #include #include #include @@ -68,21 +67,6 @@ - (BOOL)findMatchingFabric:(FabricTable &)fabricTable fabric:(FabricInfo * _Nullable * _Nonnull)fabric; @end -// Conver a ByteSpan representing a Matter TLV certificate into NSData holding a -// DER X.509 certificate. Returns nil on failures. -static NSData * _Nullable MatterCertToX509Data(const ByteSpan & cert) -{ - uint8_t buf[Controller::kMaxCHIPDERCertLength]; - MutableByteSpan derCert(buf); - CHIP_ERROR err = Credentials::ConvertChipCertToX509Cert(cert, derCert); - if (err != CHIP_NO_ERROR) { - CHIP_LOG_ERROR("Failed do convert Matter certificate to X.509 DER: %s", ErrorStr(err)); - return nil; - } - - return AsData(derCert); -} - @implementation MatterControllerFactory + (instancetype)sharedInstance @@ -279,31 +263,18 @@ - (CHIPDeviceController * _Nullable)startControllerOnExistingFabric:(CHIPDeviceC return nil; } - // Make a copy of the startup params, because we're going to fill - // out various optional fields and we don't want to modify what - // the caller passed us, especially from another work queue. - auto * params = [[CHIPDeviceControllerStartupParamsInternal alloc] initWithKeypair:startupParams.nocSigner - fabricId:startupParams.fabricId - ipk:startupParams.ipk]; - if (params == nil) { - return nil; - } - params.vendorId = startupParams.vendorId; - params.nodeId = startupParams.nodeId; - params.rootCertificate = startupParams.rootCertificate; - params.intermediateCertificate = startupParams.intermediateCertificate; - - // Create the controller, so we start the event loop, since we plan to do our fabric table operations there. + // Create the controller, so we start the event loop, since we plan to do + // our fabric table operations there. auto * controller = [self createController]; if (controller == nil) { return nil; } - __block BOOL okToStart = NO; + __block CHIPDeviceControllerStartupParamsInternal * params = nil; dispatch_sync(_chipWorkQueue, ^{ FabricTable fabricTable; FabricInfo * fabric = nullptr; - BOOL ok = [self findMatchingFabric:fabricTable params:params fabric:&fabric]; + BOOL ok = [self findMatchingFabric:fabricTable params:startupParams fabric:&fabric]; if (!ok) { CHIP_LOG_ERROR("Can't start on existing fabric: fabric matching failed"); return; @@ -327,106 +298,10 @@ - (CHIPDeviceController * _Nullable)startControllerOnExistingFabric:(CHIPDeviceC } } - // Fill out our params. - if (params.vendorId == nil) { - params.vendorId = @(fabric->GetVendorId()); - } - - if (params.nodeId == nil) { - params.nodeId = @(fabric->GetNodeId()); - ByteSpan noc; - CHIP_ERROR err = fabric->GetNOCCert(noc); - if (err != CHIP_NO_ERROR) { - CHIP_LOG_ERROR("Failed to get existing NOC: %s", ErrorStr(err)); - return; - } - params.operationalCertificate = MatterCertToX509Data(noc); - if (params.operationalCertificate == nil) { - CHIP_LOG_ERROR("Failed to convert TLV NOC to DER X.509: %s", ErrorStr(err)); - return; - } - if (fabric->GetOperationalKey() == nullptr) { - CHIP_LOG_ERROR("No existing operational key for fabric"); - return; - } - params.operationalKeypair = new Crypto::P256SerializedKeypair(); - if (params.operationalKeypair == nullptr) { - CHIP_LOG_ERROR("Failed to allocate serialized keypair"); - return; - } - - err = fabric->GetOperationalKey()->Serialize(*params.operationalKeypair); - if (err != CHIP_NO_ERROR) { - CHIP_LOG_ERROR("Failed to serialize operational keypair: %s", ErrorStr(err)); - return; - } - } - - NSData * oldIntermediateCert = nil; - { - ByteSpan icaCert; - CHIP_ERROR err = fabric->GetICACert(icaCert); - if (err != CHIP_NO_ERROR) { - CHIP_LOG_ERROR("Failed to get existing intermediate certificate: %s", ErrorStr(err)); - return; - } - // There might not be an ICA cert for this fabric. - if (!icaCert.empty()) { - oldIntermediateCert = MatterCertToX509Data(icaCert); - if (oldIntermediateCert == nil) { - return; - } - } - } - - if (params.intermediateCertificate == nil && oldIntermediateCert != nil) { - // It's possible that we are switching from using an ICA cert to - // not using one. We can detect this case by checking whether the - // provided nocSigner matches the ICA cert. - if ([MTRCertificates keypair:params.nocSigner matchesCertificate:oldIntermediateCert] == YES) { - // Keep using the existing intermediate certificate. - params.intermediateCertificate = oldIntermediateCert; - } - // else presumably the nocSigner matches the root (will be - // verified later) and we are no longer using an intermediate. - } - - // If we are changing from having an ICA to not having one, or changing - // from having one to not having one, or changing the identity of our - // ICA, we need to generate a new NOC. But we can keep our existing - // operational keypair and node id; nothing is forcing us to rotate - // those. - if ((oldIntermediateCert == nil) != (params.intermediateCertificate == nil) - || ((oldIntermediateCert != nil) && - [MTRCertificates isCertificate:oldIntermediateCert equalTo:params.intermediateCertificate] == NO)) { - params.operationalCertificate = nil; - } - - NSData * oldRootCert; - { - ByteSpan rootCert; - CHIP_ERROR err = fabric->GetRootCert(rootCert); - if (err != CHIP_NO_ERROR) { - CHIP_LOG_ERROR("Failed to get existing root certificate: %s", ErrorStr(err)); - return; - } - oldRootCert = MatterCertToX509Data(rootCert); - if (oldRootCert == nil) { - return; - } - } - - if (params.rootCertificate == nil) { - params.rootCertificate = oldRootCert; - } else if ([MTRCertificates isCertificate:oldRootCert equalTo:params.rootCertificate] == NO) { - CHIP_LOG_ERROR("Root certificate identity does not match existing root certificate"); - return; - } - - okToStart = YES; + params = [[CHIPDeviceControllerStartupParamsInternal alloc] initForExistingFabric:fabric params:startupParams]; }); - if (okToStart == NO) { + if (params == nil) { [self controllerShuttingDown:controller]; return nil; } @@ -456,31 +331,18 @@ - (CHIPDeviceController * _Nullable)startControllerOnNewFabric:(CHIPDeviceContro return nil; } - // Make a copy of the startup params, because we're going to fill - // out various optional fields and we don't want to modify what - // the caller passed us, especially from another work queue. - auto * params = [[CHIPDeviceControllerStartupParamsInternal alloc] initWithKeypair:startupParams.nocSigner - fabricId:startupParams.fabricId - ipk:startupParams.ipk]; - if (params == nil) { - return nil; - } - params.vendorId = startupParams.vendorId; - params.nodeId = startupParams.nodeId; - params.rootCertificate = startupParams.rootCertificate; - params.intermediateCertificate = startupParams.intermediateCertificate; - - // Create the controller, so we start the event loop, since we plan to do our fabric table operations there. + // Create the controller, so we start the event loop, since we plan to do + // our fabric table operations there. auto * controller = [self createController]; if (controller == nil) { return nil; } - __block BOOL okToStart = NO; + __block CHIPDeviceControllerStartupParamsInternal * params = nil; dispatch_sync(_chipWorkQueue, ^{ FabricTable fabricTable; FabricInfo * fabric = nullptr; - BOOL ok = [self findMatchingFabric:fabricTable params:params fabric:&fabric]; + BOOL ok = [self findMatchingFabric:fabricTable params:startupParams fabric:&fabric]; if (!ok) { CHIP_LOG_ERROR("Can't start on new fabric: fabric matching failed"); return; @@ -491,30 +353,10 @@ - (CHIPDeviceController * _Nullable)startControllerOnNewFabric:(CHIPDeviceContro return; } - if (params.nodeId == nil) { - // Just avoid setting the top bit, to avoid issues with node - // ids outside the operational range. - uint64_t nodeId = arc4random(); - nodeId = (nodeId << 31) | (arc4random() >> 1); - params.nodeId = @(nodeId); - } - - if (params.rootCertificate == nil) { - NSError * error; - params.rootCertificate = [MTRCertificates generateRootCertificate:params.nocSigner - issuerId:nil - fabricId:@(params.fabricId) - error:&error]; - if (error != nil || params.rootCertificate == nil) { - CHIP_LOG_ERROR("Failed to generate root certificate: %@", error); - return; - } - } - - okToStart = YES; + params = [[CHIPDeviceControllerStartupParamsInternal alloc] initForNewFabric:startupParams]; }); - if (okToStart == NO) { + if (params == nil) { [self controllerShuttingDown:controller]; return nil; } diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index 3d616c0cd9f1dc..cb103165fa05e5 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -110,7 +110,7 @@ - (void)testInitStack __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; diff --git a/src/darwin/Framework/CHIPTests/CHIPControllerTests.m b/src/darwin/Framework/CHIPTests/CHIPControllerTests.m index 00e38f5a01a1cc..78bf7e5e695337 100644 --- a/src/darwin/Framework/CHIPTests/CHIPControllerTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPControllerTests.m @@ -69,7 +69,9 @@ - (void)testControllerLifecycle __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -113,7 +115,9 @@ - (void)testFactoryShutdownShutsDownController __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -138,7 +142,9 @@ - (void)testControllerMultipleShutdown __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -165,7 +171,9 @@ - (void)testControllerInvalidAccess __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -196,7 +204,9 @@ - (void)testControllerNewFabricMatchesOldFabric __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -229,7 +239,9 @@ - (void)testControllerExistingFabricMatchesRunningController __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -261,7 +273,9 @@ - (void)testControllerStartControllersOnTwoFabricIds __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params1 = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params1 = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params1); + params1.vendorId = @(kTestVendorId); CHIPDeviceController * controller1 = [factory startControllerOnNewFabric:params1]; @@ -270,7 +284,9 @@ - (void)testControllerStartControllersOnTwoFabricIds // Now try to start a new controller with the same root but a // different fabric id. - __auto_type * params2 = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:2 ipk:testKeys.ipk]; + __auto_type * params2 = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:2 ipk:testKeys.ipk]; + XCTAssertNotNil(params2); + params2.vendorId = @(kTestVendorId); CHIPDeviceController * controller2 = [factory startControllerOnNewFabric:params2]; @@ -311,7 +327,9 @@ - (void)testControllerStartControllerSameFabricWrongSubject __auto_type * root3 = [MTRCertificates generateRootCertificate:testKeys issuerId:@2 fabricId:@1 error:nil]; XCTAssertNotNil(root3); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); params.rootCertificate = root1; @@ -374,7 +392,9 @@ - (void)testControllerFabricIdRootCertMismatch __auto_type * root2 = [MTRCertificates generateRootCertificate:testKeys issuerId:@1 fabricId:@2 error:nil]; XCTAssertNotNil(root2); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Try to start controller when fabric id in root cert subject does not match provided fabric id. @@ -428,7 +448,11 @@ - (void)testControllerSignerDoesNotMatchRoot __auto_type * root = [MTRCertificates generateRootCertificate:rootKeys issuerId:nil fabricId:nil error:nil]; XCTAssertNotNil(root); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:signerKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:signerKeys + fabricId:1 + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); params.rootCertificate = root; @@ -468,7 +492,9 @@ - (void)testControllerSignerKeyWithIntermediate error:nil]; XCTAssertNotNil(intermediate); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Try to start controller when there is an ICA and the ICA cert does not match signing key. @@ -478,7 +504,7 @@ - (void)testControllerSignerKeyWithIntermediate XCTAssertNil(controller); // Now start controller with the signing key matching the intermediate cert. - params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; + params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; params.vendorId = @(kTestVendorId); params.rootCertificate = root; params.intermediateCertificate = intermediate; @@ -507,7 +533,7 @@ - (void)testControllerStartupParamsInvalidFabric XCTAssertNotNil(rootKeys); // Invalid fabric ID. - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:0 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:0 ipk:rootKeys.ipk]; XCTAssertNil(params); [factory shutdown]; @@ -527,7 +553,9 @@ - (void)testControllerStartupParamsInvalidVendor __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(rootKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + // Invalid vendor ID ("standard"). params.vendorId = @(0); @@ -551,7 +579,9 @@ - (void)testControllerStartupNodeIdPreserved __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(rootKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; @@ -589,7 +619,9 @@ - (void)testControllerStartupNodeIdUsed __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(rootKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Bring up with node id 17. @@ -642,7 +674,9 @@ - (void)testControllerStartupNodeIdValidation __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(rootKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Try to bring up with node id 0. @@ -698,7 +732,9 @@ - (void)testControllerRotateToICA error:nil]; XCTAssertNotNil(intermediate); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Create a new fabric without the ICA. @@ -713,7 +749,7 @@ - (void)testControllerRotateToICA XCTAssertFalse([controller isRunning]); // Now start controller on the same fabric but using the ICA. - params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; + params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; params.vendorId = @(kTestVendorId); params.rootCertificate = root; params.intermediateCertificate = intermediate; @@ -758,7 +794,11 @@ - (void)testControllerRotateFromICA error:nil]; XCTAssertNotNil(intermediate); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys + fabricId:1 + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Create a new fabric without the ICA. @@ -774,7 +814,7 @@ - (void)testControllerRotateFromICA XCTAssertFalse([controller isRunning]); // Now start controller on the same fabric but without using the ICA. - params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; params.vendorId = @(kTestVendorId); params.rootCertificate = root; controller = [factory startControllerOnExistingFabric:params]; @@ -829,9 +869,11 @@ - (void)testControllerRotateICA error:nil]; XCTAssertNotNil(intermediate2); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys1 - fabricId:1 - ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys1 + fabricId:1 + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Create a new fabric without the first ICA. @@ -847,7 +889,7 @@ - (void)testControllerRotateICA XCTAssertFalse([controller isRunning]); // Now start controller on the same fabric but using the second ICA. - params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys2 fabricId:1 ipk:rootKeys.ipk]; + params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys2 fabricId:1 ipk:rootKeys.ipk]; params.vendorId = @(kTestVendorId); params.rootCertificate = root; params.intermediateCertificate = intermediate2; @@ -891,7 +933,11 @@ - (void)testControllerICAWithoutRoot error:nil]; XCTAssertNotNil(intermediate); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:intermediateKeys fabricId:1 ipk:rootKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:intermediateKeys + fabricId:1 + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + params.vendorId = @(kTestVendorId); // Pass in an intermediate but no root. Should fail. @@ -903,4 +949,297 @@ - (void)testControllerICAWithoutRoot XCTAssertFalse([factory isRunning]); } +- (void)testControllerProvideFullCertChain +{ + __auto_type * factory = [MatterControllerFactory sharedInstance]; + XCTAssertNotNil(factory); + + __auto_type * storage = [[CHIPTestStorage alloc] init]; + __auto_type * factoryParams = [[MatterControllerFactoryParams alloc] initWithStorage:storage]; + XCTAssertTrue([factory startup:factoryParams]); + XCTAssertTrue([factory isRunning]); + + __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(rootKeys); + + __auto_type * root = [MTRCertificates generateRootCertificate:rootKeys issuerId:nil fabricId:nil error:nil]; + XCTAssertNotNil(root); + + __auto_type * intermediateKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(intermediateKeys); + + __auto_type * intermediate = [MTRCertificates generateIntermediateCertificate:rootKeys + rootCertificate:root + intermediatePublicKey:intermediateKeys.pubkey + issuerId:nil + fabricId:nil + error:nil]; + XCTAssertNotNil(intermediate); + + __auto_type * operationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(operationalKeys); + + __auto_type * operational = [MTRCertificates generateOperationalCertificate:intermediateKeys + signingCertificate:intermediate + operationalPublicKey:operationalKeys.pubkey + fabricId:@123 + nodeId:@456 + caseAuthenticatedTags:nil + error:nil]; + XCTAssertNotNil(operational); + + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithOperationalKeypair:operationalKeys + operationalCertificate:operational + intermediateCertificate:intermediate + rootCertificate:root + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + + params.vendorId = @(kTestVendorId); + + CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + XCTAssertEqualObjects([controller controllerNodeId], @456); + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + // Trying to bring up another new fabric with the same root and NOC should fail. + controller = [factory startControllerOnNewFabric:params]; + XCTAssertNil(controller); + + // Trying to bring up the same fabric should succeed. + controller = [factory startControllerOnExistingFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + XCTAssertEqualObjects([controller controllerNodeId], @456); + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + [factory shutdown]; + XCTAssertFalse([factory isRunning]); +} + +- (void)testControllerProvideCertChainNoICA +{ + __auto_type * factory = [MatterControllerFactory sharedInstance]; + XCTAssertNotNil(factory); + + __auto_type * storage = [[CHIPTestStorage alloc] init]; + __auto_type * factoryParams = [[MatterControllerFactoryParams alloc] initWithStorage:storage]; + XCTAssertTrue([factory startup:factoryParams]); + XCTAssertTrue([factory isRunning]); + + __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(rootKeys); + + __auto_type * root = [MTRCertificates generateRootCertificate:rootKeys issuerId:nil fabricId:nil error:nil]; + XCTAssertNotNil(root); + + __auto_type * operationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(operationalKeys); + + __auto_type * operational = [MTRCertificates generateOperationalCertificate:rootKeys + signingCertificate:root + operationalPublicKey:operationalKeys.pubkey + fabricId:@123 + nodeId:@456 + caseAuthenticatedTags:nil + error:nil]; + XCTAssertNotNil(operational); + + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithOperationalKeypair:operationalKeys + operationalCertificate:operational + intermediateCertificate:nil + rootCertificate:root + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + + params.vendorId = @(kTestVendorId); + + CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + XCTAssertEqualObjects([controller controllerNodeId], @456); + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + [factory shutdown]; + XCTAssertFalse([factory isRunning]); +} + +- (void)testControllerCertChainFabricMismatchRoot +{ + __auto_type * factory = [MatterControllerFactory sharedInstance]; + XCTAssertNotNil(factory); + + __auto_type * storage = [[CHIPTestStorage alloc] init]; + __auto_type * factoryParams = [[MatterControllerFactoryParams alloc] initWithStorage:storage]; + XCTAssertTrue([factory startup:factoryParams]); + XCTAssertTrue([factory isRunning]); + + __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(rootKeys); + + __auto_type * root = [MTRCertificates generateRootCertificate:rootKeys issuerId:nil fabricId:@111 error:nil]; + XCTAssertNotNil(root); + + __auto_type * operationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(operationalKeys); + + __auto_type * operational = [MTRCertificates generateOperationalCertificate:rootKeys + signingCertificate:root + operationalPublicKey:operationalKeys.pubkey + fabricId:@123 + nodeId:@456 + caseAuthenticatedTags:nil + error:nil]; + XCTAssertNotNil(operational); + + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithOperationalKeypair:operationalKeys + operationalCertificate:operational + intermediateCertificate:nil + rootCertificate:root + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + + params.vendorId = @(kTestVendorId); + + CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; + XCTAssertNil(controller); + + [factory shutdown]; + XCTAssertFalse([factory isRunning]); +} + +- (void)testControllerCertChainFabricMismatchIntermediate +{ + __auto_type * factory = [MatterControllerFactory sharedInstance]; + XCTAssertNotNil(factory); + + __auto_type * storage = [[CHIPTestStorage alloc] init]; + __auto_type * factoryParams = [[MatterControllerFactoryParams alloc] initWithStorage:storage]; + XCTAssertTrue([factory startup:factoryParams]); + XCTAssertTrue([factory isRunning]); + + __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(rootKeys); + + __auto_type * root = [MTRCertificates generateRootCertificate:rootKeys issuerId:nil fabricId:@123 error:nil]; + XCTAssertNotNil(root); + + __auto_type * intermediateKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(intermediateKeys); + + __auto_type * intermediate = [MTRCertificates generateIntermediateCertificate:rootKeys + rootCertificate:root + intermediatePublicKey:intermediateKeys.pubkey + issuerId:nil + fabricId:@111 + error:nil]; + XCTAssertNotNil(intermediate); + + __auto_type * operationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(operationalKeys); + + __auto_type * operational = [MTRCertificates generateOperationalCertificate:intermediateKeys + signingCertificate:intermediate + operationalPublicKey:operationalKeys.pubkey + fabricId:@123 + nodeId:@456 + caseAuthenticatedTags:nil + error:nil]; + XCTAssertNotNil(operational); + + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithOperationalKeypair:operationalKeys + operationalCertificate:operational + intermediateCertificate:intermediate + rootCertificate:root + ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + + params.vendorId = @(kTestVendorId); + + CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; + XCTAssertNil(controller); + + [factory shutdown]; + XCTAssertFalse([factory isRunning]); +} + +- (void)testControllerExternallyProvidedOperationalKey +{ + __auto_type * factory = [MatterControllerFactory sharedInstance]; + XCTAssertNotNil(factory); + + __auto_type * storage = [[CHIPTestStorage alloc] init]; + __auto_type * factoryParams = [[MatterControllerFactoryParams alloc] initWithStorage:storage]; + XCTAssertTrue([factory startup:factoryParams]); + XCTAssertTrue([factory isRunning]); + + __auto_type * rootKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(rootKeys); + + __auto_type * operationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(operationalKeys); + + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:rootKeys fabricId:1 ipk:rootKeys.ipk]; + XCTAssertNotNil(params); + + params.vendorId = @(kTestVendorId); + params.operationalKeypair = operationalKeys; + + CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + __auto_type nodeId = [controller controllerNodeId]; + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + // Trying to bring up the same fabric without specifying the operational + // keypair should now fail, because we won't know what operational keys to + // use. + params.operationalKeypair = nil; + controller = [factory startControllerOnExistingFabric:params]; + XCTAssertNil(controller); + + // But bringing up the controller with provided operational keys should + // work, and have the same node id. + params.operationalKeypair = operationalKeys; + controller = [factory startControllerOnExistingFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + XCTAssertEqualObjects([controller controllerNodeId], nodeId); + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + // And bringing up the controller with a different provided operational key + // should work too. + __auto_type * newOperationalKeys = [[CHIPTestKeys alloc] init]; + XCTAssertNotNil(newOperationalKeys); + + params.operationalKeypair = newOperationalKeys; + controller = [factory startControllerOnExistingFabric:params]; + XCTAssertNotNil(controller); + XCTAssertTrue([controller isRunning]); + + XCTAssertEqualObjects([controller controllerNodeId], nodeId); + + [controller shutdown]; + XCTAssertFalse([controller isRunning]); + + [factory shutdown]; + XCTAssertFalse([factory isRunning]); +} + @end diff --git a/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m b/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m index 698c37281ce2b4..5104e1ace0de43 100644 --- a/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPDeviceTests.m @@ -157,7 +157,7 @@ - (void)initStack __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params]; diff --git a/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m b/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m index c5ad10bf05211e..1fa455d18cf1ae 100644 --- a/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPXPCListenerSampleTests.m @@ -524,7 +524,7 @@ - (void)initStack __auto_type * testKeys = [[CHIPTestKeys alloc] init]; XCTAssertNotNil(testKeys); - __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; + __auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithSigningKeypair:testKeys fabricId:1 ipk:testKeys.ipk]; params.vendorId = @(kTestVendorId); CHIPDeviceController * controller = [factory startControllerOnNewFabric:params];