Skip to content

Commit 0c59ebf

Browse files
authored
[darwin-framework-tool] Add an option to use per-controller storage instead of a global shared storage (project-chip#36044)
1 parent 03d6fbb commit 0c59ebf

18 files changed

+896
-115
lines changed

examples/darwin-framework-tool/BUILD.gn

+6
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,16 @@ executable("darwin-framework-tool") {
190190
"commands/common/CHIPCommandBridge.mm",
191191
"commands/common/CHIPCommandStorageDelegate.mm",
192192
"commands/common/CHIPToolKeypair.mm",
193+
"commands/common/CertificateIssuer.h",
194+
"commands/common/CertificateIssuer.mm",
195+
"commands/common/ControllerStorage.h",
196+
"commands/common/ControllerStorage.mm",
193197
"commands/common/MTRDevice_Externs.h",
194198
"commands/common/MTRError.mm",
195199
"commands/common/MTRError_Utils.h",
196200
"commands/common/MTRLogging.h",
201+
"commands/common/PreferencesStorage.h",
202+
"commands/common/PreferencesStorage.mm",
197203
"commands/common/RemoteDataModelLogger.h",
198204
"commands/common/RemoteDataModelLogger.mm",
199205
"commands/configuration/Commands.h",

examples/darwin-framework-tool/commands/common/CHIPCommandBridge.h

+9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class CHIPCommandBridge : public Command {
4141
"Sets the commissioner node ID of the given "
4242
"commissioner-name. Interactive mode will only set a single commissioner on the inital command. "
4343
"The commissioner node ID will be persisted until a different one is specified.");
44+
AddArgument("commissioner-shared-storage", 0, 1, &mCommissionerSharedStorage,
45+
"Use a shared storage instance instead of individual storage for each commissioner. Default is true.");
4446
AddArgument("paa-trust-store-path", &mPaaTrustStorePath,
4547
"Path to directory holding PAA certificate information. Can be absolute or relative to the current working "
4648
"directory.");
@@ -87,6 +89,7 @@ class CHIPCommandBridge : public Command {
8789

8890
// This method returns the commissioner instance to be used for running the command.
8991
MTRDeviceController * CurrentCommissioner();
92+
NSNumber * CurrentCommissionerFabricId();
9093

9194
MTRDeviceController * GetCommissioner(const char * identity);
9295

@@ -130,6 +133,8 @@ class CHIPCommandBridge : public Command {
130133
void StopWaiting();
131134

132135
CHIP_ERROR MaybeSetUpStack();
136+
CHIP_ERROR SetUpStackWithSharedStorage(NSArray<NSData *> * productAttestationAuthorityCertificates);
137+
CHIP_ERROR SetUpStackWithPerControllerStorage(NSArray<NSData *> * productAttestationAuthorityCertificates);
133138
void MaybeTearDownStack();
134139

135140
CHIP_ERROR GetPAACertsFromFolder(NSArray<NSData *> * __autoreleasing * paaCertsResult);
@@ -140,6 +145,9 @@ class CHIPCommandBridge : public Command {
140145
// The current controller; the one the current command should be using.
141146
MTRDeviceController * mCurrentController;
142147

148+
static bool sUseSharedStorage;
149+
chip::Optional<bool> mCommissionerSharedStorage;
150+
143151
std::condition_variable cvWaitingForResponse;
144152
std::mutex cvWaitingForResponseMutex;
145153
chip::Optional<char *> mCommissionerName;
@@ -148,4 +156,5 @@ class CHIPCommandBridge : public Command {
148156
static dispatch_queue_t mOTAProviderCallbackQueue;
149157
chip::Optional<char *> mPaaTrustStorePath;
150158
chip::Optional<chip::VendorId> mCommissionerVendorId;
159+
std::string mCurrentIdentity;
151160
};

examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm

+128-45
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323

2424
#include <lib/core/CHIPConfig.h>
2525
#include <lib/core/CHIPVendorIdentifiers.hpp>
26+
#include <protocols/secure_channel/PASESession.h> // for chip::kTestControllerNodeId
2627

28+
#import "CHIPCommandStorageDelegate.h"
29+
#import "CertificateIssuer.h"
30+
#import "ControllerStorage.h"
2731
#include "MTRError_Utils.h"
2832

2933
#include <map>
@@ -34,10 +38,9 @@
3438
std::map<std::string, MTRDeviceController *> CHIPCommandBridge::mControllers;
3539
dispatch_queue_t CHIPCommandBridge::mOTAProviderCallbackQueue;
3640
OTAProviderDelegate * CHIPCommandBridge::mOTADelegate;
41+
bool CHIPCommandBridge::sUseSharedStorage = true;
3742
constexpr char kTrustStorePathVariable[] = "PAA_TRUST_STORE_PATH";
3843

39-
CHIPToolKeypair * gNocSigner = [[CHIPToolKeypair alloc] init];
40-
4144
CHIP_ERROR CHIPCommandBridge::Run()
4245
{
4346
// In interactive mode, we want to avoid memory accumulating in the main autorelease pool,
@@ -120,61 +123,113 @@
120123

121124
CHIP_ERROR CHIPCommandBridge::MaybeSetUpStack()
122125
{
123-
if (IsInteractive()) {
124-
return CHIP_NO_ERROR;
125-
}
126-
NSData * ipk;
127-
gNocSigner = [[CHIPToolKeypair alloc] init];
128-
storage = [[CHIPToolPersistentStorageDelegate alloc] init];
126+
VerifyOrReturnError(!IsInteractive(), CHIP_NO_ERROR);
129127

130128
mOTADelegate = [[OTAProviderDelegate alloc] init];
129+
storage = [[CHIPToolPersistentStorageDelegate alloc] init];
131130

132-
auto factory = [MTRDeviceControllerFactory sharedInstance];
133-
if (factory == nil) {
134-
ChipLogError(chipTool, "Controller factory is nil");
135-
return CHIP_ERROR_INTERNAL;
131+
NSError * error;
132+
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];
133+
[certificateIssuer startWithStorage:storage error:&error];
134+
VerifyOrReturnError(nil == error, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Can not start the certificate issuer: %@", error));
135+
136+
NSArray<NSData *> * productAttestationAuthorityCertificates = nil;
137+
ReturnLogErrorOnFailure(GetPAACertsFromFolder(&productAttestationAuthorityCertificates));
138+
if ([productAttestationAuthorityCertificates count] == 0) {
139+
productAttestationAuthorityCertificates = nil;
136140
}
137141

138-
auto params = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
139-
params.shouldStartServer = YES;
140-
params.otaProviderDelegate = mOTADelegate;
141-
NSArray<NSData *> * paaCertResults;
142-
ReturnLogErrorOnFailure(GetPAACertsFromFolder(&paaCertResults));
143-
if ([paaCertResults count] > 0) {
144-
params.productAttestationAuthorityCertificates = paaCertResults;
142+
sUseSharedStorage = mCommissionerSharedStorage.ValueOr(true);
143+
if (sUseSharedStorage) {
144+
return SetUpStackWithSharedStorage(productAttestationAuthorityCertificates);
145145
}
146146

147-
NSError * error;
148-
if ([factory startControllerFactory:params error:&error] == NO) {
149-
ChipLogError(chipTool, "Controller factory startup failed");
150-
return MTRErrorToCHIPErrorCode(error);
147+
return SetUpStackWithPerControllerStorage(productAttestationAuthorityCertificates);
148+
}
149+
150+
CHIP_ERROR CHIPCommandBridge::SetUpStackWithPerControllerStorage(NSArray<NSData *> * productAttestationAuthorityCertificates)
151+
{
152+
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];
153+
154+
constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
155+
std::string commissionerName = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
156+
for (size_t i = 0; i < ArraySize(identities); ++i) {
157+
__auto_type * uuidString = [NSString stringWithFormat:@"%@%@", @"8DCADB14-AF1F-45D0-B084-00000000000", @(i)];
158+
__auto_type * controllerId = [[NSUUID alloc] initWithUUIDString:uuidString];
159+
__auto_type * vendorId = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
160+
__auto_type * fabricId = @(i + 1);
161+
__auto_type * nodeId = @(chip::kTestControllerNodeId);
162+
163+
if (commissionerName.compare(identities[i]) == 0 && mCommissionerNodeId.HasValue()) {
164+
nodeId = @(mCommissionerNodeId.Value());
165+
}
166+
167+
__auto_type * controllerStorage = [[ControllerStorage alloc] initWithControllerID:controllerId];
168+
169+
NSError * error;
170+
__auto_type * operationalKeypair = [certificateIssuer issueOperationalKeypairWithControllerStorage:controllerStorage error:&error];
171+
__auto_type * operational = [certificateIssuer issueOperationalCertificateForNodeID:nodeId
172+
fabricID:fabricId
173+
publicKey:operationalKeypair.publicKey
174+
error:&error];
175+
VerifyOrReturnError(nil == error, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Can not issue an operational certificate: %@", error));
176+
177+
__auto_type * controllerStorageQueue = dispatch_queue_create("com.chip.storage", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
178+
__auto_type * params = [[MTRDeviceControllerExternalCertificateParameters alloc] initWithStorageDelegate:controllerStorage
179+
storageDelegateQueue:controllerStorageQueue
180+
uniqueIdentifier:controllerId
181+
ipk:certificateIssuer.ipk
182+
vendorID:vendorId
183+
operationalKeypair:operationalKeypair
184+
operationalCertificate:operational
185+
intermediateCertificate:nil
186+
rootCertificate:certificateIssuer.rootCertificate];
187+
[params setOperationalCertificateIssuer:certificateIssuer queue:controllerStorageQueue];
188+
params.productAttestationAuthorityCertificates = productAttestationAuthorityCertificates;
189+
190+
__auto_type * controller = [[MTRDeviceController alloc] initWithParameters:params error:&error];
191+
VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error));
192+
mControllers[identities[i]] = controller;
151193
}
152194

153-
ReturnLogErrorOnFailure([gNocSigner createOrLoadKeys:storage]);
195+
return CHIP_NO_ERROR;
196+
}
197+
198+
CHIP_ERROR CHIPCommandBridge::SetUpStackWithSharedStorage(NSArray<NSData *> * productAttestationAuthorityCertificates)
199+
{
200+
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
201+
VerifyOrReturnError(nil != factory, CHIP_ERROR_INTERNAL, ChipLogError(chipTool, "Controller factory is nil"));
202+
203+
auto factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
204+
factoryParams.shouldStartServer = YES;
205+
factoryParams.otaProviderDelegate = mOTADelegate;
206+
factoryParams.productAttestationAuthorityCertificates = productAttestationAuthorityCertificates;
154207

155-
ipk = [gNocSigner getIPK];
208+
NSError * error;
209+
auto started = [factory startControllerFactory:factoryParams error:&error];
210+
VerifyOrReturnError(started, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller factory startup failed"));
211+
212+
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];
156213

157214
constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
158215
std::string commissionerName = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
159216
for (size_t i = 0; i < ArraySize(identities); ++i) {
160-
auto controllerParams = [[MTRDeviceControllerStartupParams alloc] initWithIPK:ipk fabricID:@(i + 1) nocSigner:gNocSigner];
161-
217+
__auto_type * fabricId = @(i + 1);
218+
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:certificateIssuer.ipk
219+
fabricID:fabricId
220+
nocSigner:certificateIssuer.signingKey];
162221
if (commissionerName.compare(identities[i]) == 0 && mCommissionerNodeId.HasValue()) {
163-
controllerParams.nodeId = @(mCommissionerNodeId.Value());
222+
params.nodeId = @(mCommissionerNodeId.Value());
164223
}
165-
// We're not sure whether we're creating a new fabric or using an
166-
// existing one, so just try both.
167-
auto controller = [factory createControllerOnExistingFabric:controllerParams error:&error];
224+
225+
// We're not sure whether we're creating a new fabric or using an existing one, so just try both.
226+
auto controller = [factory createControllerOnExistingFabric:params error:&error];
168227
if (controller == nil) {
169228
// Maybe we didn't have this fabric yet.
170-
controllerParams.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
171-
controller = [factory createControllerOnNewFabric:controllerParams error:&error];
229+
params.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
230+
controller = [factory createControllerOnNewFabric:params error:&error];
172231
}
173-
if (controller == nil) {
174-
ChipLogError(chipTool, "Controller startup failure.");
175-
return MTRErrorToCHIPErrorCode(error);
176-
}
177-
232+
VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error));
178233
mControllers[identities[i]] = controller;
179234
}
180235

@@ -197,11 +252,29 @@
197252
kIdentityBeta, kIdentityGamma);
198253
chipDie();
199254
}
255+
mCurrentIdentity = name;
200256
mCurrentController = mControllers[name];
201257
}
202258

203259
MTRDeviceController * CHIPCommandBridge::CurrentCommissioner() { return mCurrentController; }
204260

261+
NSNumber * CHIPCommandBridge::CurrentCommissionerFabricId()
262+
{
263+
if (mCurrentIdentity.compare(kIdentityAlpha) == 0) {
264+
return @(1);
265+
} else if (mCurrentIdentity.compare(kIdentityBeta) == 0) {
266+
return @(2);
267+
} else if (mCurrentIdentity.compare(kIdentityGamma) == 0) {
268+
return @(3);
269+
} else {
270+
ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s]", mCurrentIdentity.c_str(), kIdentityAlpha,
271+
kIdentityBeta, kIdentityGamma);
272+
chipDie();
273+
}
274+
275+
return @(0); // This should never happens.
276+
}
277+
205278
MTRDeviceController * CHIPCommandBridge::GetCommissioner(const char * identity) { return mControllers[identity]; }
206279

207280
MTRBaseDevice * CHIPCommandBridge::BaseDeviceWithNodeId(chip::NodeId nodeId)
@@ -223,15 +296,25 @@
223296
{
224297
StopCommissioners();
225298

226-
auto factory = [MTRDeviceControllerFactory sharedInstance];
227-
NSData * ipk = [gNocSigner getIPK];
299+
if (sUseSharedStorage) {
300+
auto factory = [MTRDeviceControllerFactory sharedInstance];
228301

229-
constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
230-
for (size_t i = 0; i < ArraySize(identities); ++i) {
231-
auto controllerParams = [[MTRDeviceControllerStartupParams alloc] initWithIPK:ipk fabricID:@(i + 1) nocSigner:gNocSigner];
302+
constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
303+
for (size_t i = 0; i < ArraySize(identities); ++i) {
304+
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];
305+
auto controllerParams = [[MTRDeviceControllerStartupParams alloc] initWithIPK:certificateIssuer.ipk fabricID:@(i + 1) nocSigner:certificateIssuer.signingKey];
232306

233-
auto controller = [factory createControllerOnExistingFabric:controllerParams error:nil];
234-
mControllers[identities[i]] = controller;
307+
auto controller = [factory createControllerOnExistingFabric:controllerParams error:nil];
308+
mControllers[identities[i]] = controller;
309+
}
310+
} else {
311+
NSArray<NSData *> * productAttestationAuthorityCertificates = nil;
312+
ReturnOnFailure(GetPAACertsFromFolder(&productAttestationAuthorityCertificates));
313+
if ([productAttestationAuthorityCertificates count] == 0) {
314+
productAttestationAuthorityCertificates = nil;
315+
}
316+
317+
ReturnOnFailure(SetUpStackWithPerControllerStorage(productAttestationAuthorityCertificates));
235318
}
236319
}
237320

examples/darwin-framework-tool/commands/common/CHIPCommandStorageDelegate.h

+20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
119
#import <Foundation/Foundation.h>
220
#import <Matter/Matter.h>
321

422
NS_ASSUME_NONNULL_BEGIN
523

24+
extern NSString * const kDarwinFrameworkToolCertificatesDomain;
25+
626
@interface CHIPToolPersistentStorageDelegate : NSObject <MTRStorage>
727
- (nullable NSData *)storageDataForKey:(NSString *)key;
828
- (BOOL)setStorageData:(NSData *)value forKey:(NSString *)key;

0 commit comments

Comments
 (0)