Skip to content

Commit

Permalink
[darwin-framework-tool] Add an option to use per-controller storage i…
Browse files Browse the repository at this point in the history
…nstead of a global shared storage
  • Loading branch information
vivien-apple committed Oct 14, 2024
1 parent 9524ac9 commit 2521842
Show file tree
Hide file tree
Showing 16 changed files with 790 additions and 104 deletions.
6 changes: 6 additions & 0 deletions examples/darwin-framework-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,16 @@ executable("darwin-framework-tool") {
"commands/common/CHIPCommandBridge.mm",
"commands/common/CHIPCommandStorageDelegate.mm",
"commands/common/CHIPToolKeypair.mm",
"commands/common/CertificateIssuer.h",
"commands/common/CertificateIssuer.mm",
"commands/common/ControllerStorage.h",
"commands/common/ControllerStorage.mm",
"commands/common/MTRDevice_Externs.h",
"commands/common/MTRError.mm",
"commands/common/MTRError_Utils.h",
"commands/common/MTRLogging.h",
"commands/common/PreferencesStorage.h",
"commands/common/PreferencesStorage.mm",
"commands/common/RemoteDataModelLogger.h",
"commands/common/RemoteDataModelLogger.mm",
"commands/configuration/Commands.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class CHIPCommandBridge : public Command {
"Sets the commissioner node ID of the given "
"commissioner-name. Interactive mode will only set a single commissioner on the inital command. "
"The commissioner node ID will be persisted until a different one is specified.");
AddArgument("commissioner-shared-storage", 0, 1, &mCommissionerSharedStorage,
"Use a shared storage instance instead of individual storage for each commissioner. Default is true.");
AddArgument("paa-trust-store-path", &mPaaTrustStorePath,
"Path to directory holding PAA certificate information. Can be absolute or relative to the current working "
"directory.");
Expand Down Expand Up @@ -87,6 +89,7 @@ class CHIPCommandBridge : public Command {

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

MTRDeviceController * GetCommissioner(const char * identity);

Expand Down Expand Up @@ -130,6 +133,8 @@ class CHIPCommandBridge : public Command {
void StopWaiting();

CHIP_ERROR MaybeSetUpStack();
CHIP_ERROR SetUpStackWithSharedStorage(NSArray<NSData *> * productAttestationAuthorityCertificates);
CHIP_ERROR SetUpStackWithPerControllerStorage(NSArray<NSData *> * productAttestationAuthorityCertificates);
void MaybeTearDownStack();

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

static bool sUseSharedStorage;
chip::Optional<bool> mCommissionerSharedStorage;

std::condition_variable cvWaitingForResponse;
std::mutex cvWaitingForResponseMutex;
chip::Optional<char *> mCommissionerName;
Expand All @@ -148,4 +156,5 @@ class CHIPCommandBridge : public Command {
static dispatch_queue_t mOTAProviderCallbackQueue;
chip::Optional<char *> mPaaTrustStorePath;
chip::Optional<chip::VendorId> mCommissionerVendorId;
std::string mCurrentIdentity;
};
168 changes: 124 additions & 44 deletions examples/darwin-framework-tool/commands/common/CHIPCommandBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@

#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPVendorIdentifiers.hpp>
#include <protocols/secure_channel/PASESession.h> // for chip::kTestControllerNodeId

#import "CertificateIssuer.h"
#import "ControllerStorage.h"
#include "MTRError_Utils.h"

#include <map>
Expand All @@ -34,10 +37,9 @@
std::map<std::string, MTRDeviceController *> CHIPCommandBridge::mControllers;
dispatch_queue_t CHIPCommandBridge::mOTAProviderCallbackQueue;
OTAProviderDelegate * CHIPCommandBridge::mOTADelegate;
bool CHIPCommandBridge::sUseSharedStorage = true;
constexpr char kTrustStorePathVariable[] = "PAA_TRUST_STORE_PATH";

CHIPToolKeypair * gNocSigner = [[CHIPToolKeypair alloc] init];

CHIP_ERROR CHIPCommandBridge::Run()
{
// In interactive mode, we want to avoid memory accumulating in the main autorelease pool,
Expand Down Expand Up @@ -120,61 +122,111 @@

CHIP_ERROR CHIPCommandBridge::MaybeSetUpStack()
{
if (IsInteractive()) {
return CHIP_NO_ERROR;
}
NSData * ipk;
gNocSigner = [[CHIPToolKeypair alloc] init];
storage = [[CHIPToolPersistentStorageDelegate alloc] init];
VerifyOrReturnError(!IsInteractive(), CHIP_NO_ERROR);

mOTADelegate = [[OTAProviderDelegate alloc] init];
storage = [[CHIPToolPersistentStorageDelegate alloc] init];

auto factory = [MTRDeviceControllerFactory sharedInstance];
if (factory == nil) {
ChipLogError(chipTool, "Controller factory is nil");
return CHIP_ERROR_INTERNAL;
NSError * error;
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];
[certificateIssuer startWithStorage:storage error:&error];
VerifyOrReturnError(nil == error, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Can not start the certificate issuer: %@", error));

NSArray<NSData *> * productAttestationAuthorityCertificates = nil;
ReturnLogErrorOnFailure(GetPAACertsFromFolder(&productAttestationAuthorityCertificates));
if ([productAttestationAuthorityCertificates count] == 0) {
productAttestationAuthorityCertificates = nil;
}

auto params = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
params.shouldStartServer = YES;
params.otaProviderDelegate = mOTADelegate;
NSArray<NSData *> * paaCertResults;
ReturnLogErrorOnFailure(GetPAACertsFromFolder(&paaCertResults));
if ([paaCertResults count] > 0) {
params.productAttestationAuthorityCertificates = paaCertResults;
sUseSharedStorage = mCommissionerSharedStorage.ValueOr(true);
if (sUseSharedStorage) {
return SetUpStackWithSharedStorage(productAttestationAuthorityCertificates);
}

NSError * error;
if ([factory startControllerFactory:params error:&error] == NO) {
ChipLogError(chipTool, "Controller factory startup failed");
return MTRErrorToCHIPErrorCode(error);
return SetUpStackWithPerControllerStorage(productAttestationAuthorityCertificates);
}

CHIP_ERROR CHIPCommandBridge::SetUpStackWithPerControllerStorage(NSArray<NSData *> * productAttestationAuthorityCertificates)
{
__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];

constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
std::string commissionerName = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
for (size_t i = 0; i < ArraySize(identities); ++i) {
__auto_type * uuidString = [NSString stringWithFormat:@"%@%@", @"8DCADB14-AF1F-45D0-B084-00000000000", @(i)];
__auto_type * controllerId = [[NSUUID alloc] initWithUUIDString:uuidString];
__auto_type * vendorId = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
__auto_type * fabricId = @(i + 1);
__auto_type * nodeId = @(chip::kTestControllerNodeId);

if (commissionerName.compare(identities[i]) == 0 && mCommissionerNodeId.HasValue()) {
nodeId = @(mCommissionerNodeId.Value());
}

NSError * error;
__auto_type * operational = [certificateIssuer issueOperationalCertificateForNodeID:nodeId fabricID:fabricId error:&error];

__auto_type * controllerStorage = [[ControllerStorage alloc] initWithControllerID:controllerId];
__auto_type * controllerStorageQueue = dispatch_queue_create("com.chip.storage", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
__auto_type * params = [[MTRDeviceControllerExternalCertificateParameters alloc] initWithStorageDelegate:controllerStorage
storageDelegateQueue:controllerStorageQueue
uniqueIdentifier:controllerId
ipk:certificateIssuer.ipk
vendorID:vendorId
operationalKeypair:certificateIssuer.signingKey
operationalCertificate:operational
intermediateCertificate:nil
rootCertificate:certificateIssuer.rootCertificate];
[params setOperationalCertificateIssuer:certificateIssuer queue:controllerStorageQueue];
params.productAttestationAuthorityCertificates = productAttestationAuthorityCertificates;

__auto_type * controller = [[MTRDeviceController alloc] initWithParameters:params error:&error];
VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error));
mControllers[identities[i]] = controller;
}

ReturnLogErrorOnFailure([gNocSigner createOrLoadKeys:storage]);
return CHIP_NO_ERROR;
}

ipk = [gNocSigner getIPK];
CHIP_ERROR CHIPCommandBridge::SetUpStackWithSharedStorage(NSArray<NSData *> * productAttestationAuthorityCertificates)
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
VerifyOrReturnError(nil != factory, CHIP_ERROR_INTERNAL, ChipLogError(chipTool, "Controller factory is nil"));

auto factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
factoryParams.shouldStartServer = YES;
factoryParams.otaProviderDelegate = mOTADelegate;
factoryParams.productAttestationAuthorityCertificates = productAttestationAuthorityCertificates;

NSError * error;
auto started = [factory startControllerFactory:factoryParams error:&error];
VerifyOrReturnError(started, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller factory startup failed"));

__auto_type * certificateIssuer = [CertificateIssuer sharedInstance];

constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
std::string commissionerName = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;
for (size_t i = 0; i < ArraySize(identities); ++i) {
auto controllerParams = [[MTRDeviceControllerStartupParams alloc] initWithIPK:ipk fabricID:@(i + 1) nocSigner:gNocSigner];
__auto_type * fabricId = @(i + 1);
NSNumber * nodeId = nil;

__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:certificateIssuer.ipk
fabricID:fabricId
nocSigner:certificateIssuer.signingKey];
if (commissionerName.compare(identities[i]) == 0 && mCommissionerNodeId.HasValue()) {
controllerParams.nodeId = @(mCommissionerNodeId.Value());
params.nodeId = @(mCommissionerNodeId.Value());
}
// We're not sure whether we're creating a new fabric or using an
// existing one, so just try both.
auto controller = [factory createControllerOnExistingFabric:controllerParams error:&error];

params.nodeId = nodeId;

// We're not sure whether we're creating a new fabric or using an existing one, so just try both.
auto controller = [factory createControllerOnExistingFabric:params error:&error];
if (controller == nil) {
// Maybe we didn't have this fabric yet.
controllerParams.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
controller = [factory createControllerOnNewFabric:controllerParams error:&error];
params.vendorID = @(mCommissionerVendorId.ValueOr(chip::VendorId::TestVendor1));
controller = [factory createControllerOnNewFabric:params error:&error];
}
if (controller == nil) {
ChipLogError(chipTool, "Controller startup failure.");
return MTRErrorToCHIPErrorCode(error);
}

VerifyOrReturnError(nil != controller, MTRErrorToCHIPErrorCode(error), ChipLogError(chipTool, "Controller startup failure: %@", error));
mControllers[identities[i]] = controller;
}

Expand All @@ -197,11 +249,29 @@
kIdentityBeta, kIdentityGamma);
chipDie();
}
mCurrentIdentity = name;
mCurrentController = mControllers[name];
}

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

NSNumber * CHIPCommandBridge::CurrentCommissionerFabricId()
{
if (mCurrentIdentity.compare(kIdentityAlpha) == 0) {
return @(1);
} else if (mCurrentIdentity.compare(kIdentityBeta) == 0) {
return @(2);
} else if (mCurrentIdentity.compare(kIdentityGamma) == 0) {
return @(3);
} else {
ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s]", mCurrentIdentity.c_str(), kIdentityAlpha,
kIdentityBeta, kIdentityGamma);
chipDie();
}

return @(0); // This should never happens.
}

MTRDeviceController * CHIPCommandBridge::GetCommissioner(const char * identity) { return mControllers[identity]; }

MTRBaseDevice * CHIPCommandBridge::BaseDeviceWithNodeId(chip::NodeId nodeId)
Expand All @@ -223,15 +293,25 @@
{
StopCommissioners();

auto factory = [MTRDeviceControllerFactory sharedInstance];
NSData * ipk = [gNocSigner getIPK];
if (sUseSharedStorage) {
auto factory = [MTRDeviceControllerFactory sharedInstance];

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

auto controller = [factory createControllerOnExistingFabric:controllerParams error:nil];
mControllers[identities[i]] = controller;
auto controller = [factory createControllerOnExistingFabric:controllerParams error:nil];
mControllers[identities[i]] = controller;
}
} else {
NSArray<NSData *> * productAttestationAuthorityCertificates = nil;
ReturnOnFailure(GetPAACertsFromFolder(&productAttestationAuthorityCertificates));
if ([productAttestationAuthorityCertificates count] == 0) {
productAttestationAuthorityCertificates = nil;
}

ReturnOnFailure(SetUpStackWithPerControllerStorage(productAttestationAuthorityCertificates));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
/*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* 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 <Foundation/Foundation.h>
#import <Matter/Matter.h>

NS_ASSUME_NONNULL_BEGIN

extern NSString * const kDarwinFrameworkToolCertificatesDomain;

@interface CHIPToolPersistentStorageDelegate : NSObject <MTRStorage>
- (nullable NSData *)storageDataForKey:(NSString *)key;
- (BOOL)setStorageData:(NSData *)value forKey:(NSString *)key;
Expand Down
Loading

0 comments on commit 2521842

Please sign in to comment.