Skip to content

Commit

Permalink
Allow per-controller control of PAAs and CD signing keys. (#28998)
Browse files Browse the repository at this point in the history
* Allow per-controller control of PAAs and CD signing keys.

* Address review comments.

Also fixes some API docs and init bits.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Feb 9, 2024
1 parent e69f9d0 commit 1243145
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 61 deletions.
51 changes: 49 additions & 2 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#import "MTRDeviceController_Internal.h"

#import "MTRAttestationTrustStoreBridge.h"
#import "MTRBaseDevice_Internal.h"
#import "MTRCommissionableBrowser.h"
#import "MTRCommissionableBrowserResult_Internal.h"
Expand Down Expand Up @@ -86,6 +87,7 @@
static NSString * const kErrorGetAttestationChallenge = @"Failure getting attestation challenge";
static NSString * const kErrorSpake2pVerifierGenerationFailed = @"PASE verifier generation failed";
static NSString * const kErrorSpake2pVerifierSerializationFailed = @"PASE verifier serialization failed";
static NSString * const kErrorCDCertStoreInit = @"Init failure while initializing Certificate Declaration Signing Keys store";

typedef void (^SyncWorkQueueBlock)(void);
typedef id (^SyncWorkQueueBlockWithReturnValue)(void);
Expand All @@ -101,6 +103,7 @@ @interface MTRDeviceController () {

@property (readonly) chip::Controller::DeviceCommissioner * cppCommissioner;
@property (readonly) chip::Credentials::PartialDACVerifier * partialDACVerifier;
@property (readonly) chip::Credentials::DefaultDACVerifier * defaultDACVerifier;
@property (readonly) MTRDeviceControllerDelegateBridge * deviceControllerDelegateBridge;
@property (readonly) MTROperationalCredentialsDelegate * operationalCredentialsDelegate;
@property (readonly) MTRP256KeypairBridge signingKeypairBridge;
Expand All @@ -110,6 +113,8 @@ @interface MTRDeviceController () {
@property (readonly) NSMutableDictionary * nodeIDToDeviceMap;
@property (readonly) os_unfair_lock deviceMapLock; // protects nodeIDToDeviceMap
@property (readonly) MTRCommissionableBrowser * commissionableBrowser;
@property (readonly) MTRAttestationTrustStoreBridge * attestationTrustStoreBridge;

@end

@implementation MTRDeviceController
Expand Down Expand Up @@ -234,6 +239,16 @@ - (void)cleanup
{
VerifyOrDie(_cppCommissioner == nullptr);

if (_defaultDACVerifier) {
delete _defaultDACVerifier;
_defaultDACVerifier = nullptr;
}

if (_attestationTrustStoreBridge) {
delete _attestationTrustStoreBridge;
_attestationTrustStoreBridge = nullptr;
}

[self clearDeviceAttestationDelegateBridge];

if (_operationalCredentialsDelegate) {
Expand Down Expand Up @@ -388,9 +403,41 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams
// fabric information for the relevant fabric indices on controller
// bring-up.
commissionerParams.removeFromFabricTableOnShutdown = false;
commissionerParams.deviceAttestationVerifier = _factory.deviceAttestationVerifier;
commissionerParams.permitMultiControllerFabrics = startupParams.allowMultipleControllersPerFabric;

// Set up our attestation verifier. Assume we want to use the default
// one, until something tells us otherwise.
const chip::Credentials::AttestationTrustStore * trustStore;
if (startupParams.productAttestationAuthorityCertificates) {
_attestationTrustStoreBridge
= new MTRAttestationTrustStoreBridge(startupParams.productAttestationAuthorityCertificates);
trustStore = _attestationTrustStoreBridge;
} else {
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
trustStore = chip::Credentials::GetTestAttestationTrustStore();
}

_defaultDACVerifier = new chip::Credentials::DefaultDACVerifier(trustStore);

if (startupParams.certificationDeclarationCertificates) {
auto cdTrustStore = _defaultDACVerifier->GetCertificationDeclarationTrustStore();
if (cdTrustStore == nullptr) {
errorCode = CHIP_ERROR_INCORRECT_STATE;
}
if ([self checkForStartError:errorCode logMsg:kErrorCDCertStoreInit]) {
return;
}

for (NSData * cdSigningCert in startupParams.certificationDeclarationCertificates) {
errorCode = cdTrustStore->AddTrustedKey(AsByteSpan(cdSigningCert));
if ([self checkForStartError:errorCode logMsg:kErrorCDCertStoreInit]) {
return;
}
}
}

commissionerParams.deviceAttestationVerifier = _defaultDACVerifier;

auto & factory = chip::Controller::DeviceControllerFactory::GetInstance();

errorCode = factory.SetupCommissioner(commissionerParams, *_cppCommissioner);
Expand Down Expand Up @@ -725,7 +772,7 @@ - (BOOL)setOperationalCertificateIssuer:(nullable id<MTROperationalCertificateIs
} else {
// TODO: Once we are not supporting setNocChainIssuer this
// branch can just go away.
self->_cppCommissioner->SetDeviceAttestationVerifier(self->_factory.deviceAttestationVerifier);
self->_cppCommissioner->SetDeviceAttestationVerifier(self->_defaultDACVerifier);
}
return YES;
};
Expand Down
81 changes: 24 additions & 57 deletions src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#import "MTRDeviceControllerFactory.h"
#import "MTRDeviceControllerFactory_Internal.h"

#import "MTRAttestationTrustStoreBridge.h"
#import "MTRCertificates.h"
#import "MTRControllerAccessControl.h"
#import "MTRDemuxingStorage.h"
Expand All @@ -43,8 +42,6 @@
#include <credentials/FabricTable.h>
#include <credentials/GroupDataProviderImpl.h>
#include <credentials/PersistentStorageOpCertStore.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <crypto/PersistentStorageOperationalKeystore.h>
#include <crypto/RawKeySessionKeystore.h>
#include <lib/support/Pool.h>
Expand All @@ -58,15 +55,12 @@

static NSString * const kErrorPersistentStorageInit = @"Init failure while creating a persistent storage delegate";
static NSString * const kErrorSessionResumptionStorageInit = @"Init failure while creating a session resumption storage delegate";
static NSString * const kErrorAttestationTrustStoreInit = @"Init failure while creating the attestation trust store";
static NSString * const kErrorDACVerifierInit = @"Init failure while creating the device attestation verifier";
static NSString * const kErrorGroupProviderInit = @"Init failure while initializing group data provider";
static NSString * const kErrorControllersInit = @"Init controllers array failure";
static NSString * const kErrorCertificateValidityPolicyInit = @"Init certificate validity policy failure";
static NSString * const kErrorControllerFactoryInit = @"Init failure while initializing controller factory";
static NSString * const kErrorKeystoreInit = @"Init failure while initializing persistent storage keystore";
static NSString * const kErrorCertStoreInit = @"Init failure while initializing persistent storage operational certificate store";
static NSString * const kErrorCDCertStoreInit = @"Init failure while initializing Certificate Declaration Signing Keys store";
static NSString * const kErrorOtaProviderInit = @"Init failure while creating an OTA provider delegate";
static NSString * const kErrorSessionKeystoreInit = @"Init failure while initializing session keystore";

Expand All @@ -78,7 +72,6 @@ @interface MTRDeviceControllerFactory ()
@property (atomic, readonly) dispatch_queue_t chipWorkQueue;
@property (readonly) DeviceControllerFactory * controllerFactory;
@property (readonly) PersistentStorageDelegate * persistentStorageDelegate;
@property (readonly) MTRAttestationTrustStoreBridge * attestationTrustStoreBridge;
@property (readonly) MTROTAProviderDelegateBridge * otaProviderDelegateBridge;
@property (readonly) Crypto::RawKeySessionKeystore * sessionKeystore;
// We use TestPersistentStorageDelegate just to get an in-memory store to back
Expand All @@ -90,7 +83,12 @@ @interface MTRDeviceControllerFactory ()
@property (readonly) PersistentStorageOperationalKeystore * keystore;
@property (readonly) Credentials::PersistentStorageOpCertStore * opCertStore;
@property (readonly) MTROperationalBrowser * operationalBrowser;
@property () chip::Credentials::DeviceAttestationVerifier * deviceAttestationVerifier;

// productAttestationAuthorityCertificates and certificationDeclarationCertificates are just copied
// from MTRDeviceControllerFactoryParams.
@property (readonly, nullable) NSArray<MTRCertificateDERBytes> * productAttestationAuthorityCertificates;
@property (readonly, nullable) NSArray<MTRCertificateDERBytes> * certificationDeclarationCertificates;

@property (readonly) BOOL advertiseOperational;
@property (nonatomic, readonly) Credentials::IgnoreCertificateValidityPeriodPolicy * certificateValidityPolicy;
@property (readonly) MTRSessionResumptionStorageBridge * sessionResumptionStorage;
Expand Down Expand Up @@ -291,16 +289,6 @@ - (void)cleanupInitObjects

- (void)cleanupStartupObjects
{
if (_deviceAttestationVerifier) {
delete _deviceAttestationVerifier;
_deviceAttestationVerifier = nullptr;
}

if (_attestationTrustStoreBridge) {
delete _attestationTrustStoreBridge;
_attestationTrustStoreBridge = nullptr;
}

if (_otaProviderDelegateBridge) {
delete _otaProviderDelegateBridge;
_otaProviderDelegateBridge = nullptr;
Expand Down Expand Up @@ -504,44 +492,8 @@ - (BOOL)startControllerFactory:(MTRDeviceControllerFactoryParams *)startupParams
return;
}

// Initialize device attestation verifier
const Credentials::AttestationTrustStore * trustStore;
if (startupParams.productAttestationAuthorityCertificates) {
_attestationTrustStoreBridge
= new MTRAttestationTrustStoreBridge(startupParams.productAttestationAuthorityCertificates);
if (_attestationTrustStoreBridge == nullptr) {
MTR_LOG_ERROR("Error: %@", kErrorAttestationTrustStoreInit);
errorCode = CHIP_ERROR_NO_MEMORY;
return;
}
trustStore = _attestationTrustStoreBridge;
} else {
// TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
trustStore = Credentials::GetTestAttestationTrustStore();
}
_deviceAttestationVerifier = new Credentials::DefaultDACVerifier(trustStore);
if (_deviceAttestationVerifier == nullptr) {
MTR_LOG_ERROR("Error: %@", kErrorDACVerifierInit);
errorCode = CHIP_ERROR_NO_MEMORY;
return;
}

if (startupParams.certificationDeclarationCertificates) {
auto cdTrustStore = _deviceAttestationVerifier->GetCertificationDeclarationTrustStore();
if (cdTrustStore == nullptr) {
MTR_LOG_ERROR("Error: %@", kErrorCDCertStoreInit);
errorCode = CHIP_ERROR_INCORRECT_STATE;
return;
}

for (NSData * cdSigningCert in startupParams.certificationDeclarationCertificates) {
errorCode = cdTrustStore->AddTrustedKey(AsByteSpan(cdSigningCert));
if (errorCode != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Error: %@", kErrorCDCertStoreInit);
return;
}
}
}
_productAttestationAuthorityCertificates = [startupParams.productAttestationAuthorityCertificates copy];
_certificationDeclarationCertificates = [startupParams.certificationDeclarationCertificates copy];

chip::Controller::FactoryInitParams params;
if (startupParams.port != nil) {
Expand Down Expand Up @@ -827,6 +779,9 @@ - (MTRDeviceController * _Nullable)createControllerOnExistingFabric:(MTRDeviceCo
params:startupParams];
if (params == nil) {
fabricError = CHIP_ERROR_NO_MEMORY;
} else {
params.productAttestationAuthorityCertificates = self.productAttestationAuthorityCertificates;
params.certificationDeclarationCertificates = self.certificationDeclarationCertificates;
}

return params;
Expand Down Expand Up @@ -879,6 +834,9 @@ - (MTRDeviceController * _Nullable)createControllerOnNewFabric:(MTRDeviceControl
params:startupParams];
if (params == nil) {
fabricError = CHIP_ERROR_NO_MEMORY;
} else {
params.productAttestationAuthorityCertificates = self.productAttestationAuthorityCertificates;
params.certificationDeclarationCertificates = self.certificationDeclarationCertificates;
}
return params;
}
Expand All @@ -893,13 +851,22 @@ - (MTRDeviceController * _Nullable)createController:(MTRDeviceControllerStartupP
return [self _startDeviceController:startupParameters
fabricChecker:^MTRDeviceControllerStartupParamsInternal *(
FabricTable * fabricTable, MTRDeviceController * controller, CHIP_ERROR & fabricError) {
return
auto * params =
[[MTRDeviceControllerStartupParamsInternal alloc] initForNewController:controller
fabricTable:fabricTable
keystore:self->_keystore
advertiseOperational:self.advertiseOperational
params:startupParameters
error:fabricError];
if (params != nil) {
if (params.productAttestationAuthorityCertificates == nil) {
params.productAttestationAuthorityCertificates = self.productAttestationAuthorityCertificates;
}
if (params.certificationDeclarationCertificates == nil) {
params.certificationDeclarationCertificates = self.certificationDeclarationCertificates;
}
}
return params;
}
error:error];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
namespace chip {
namespace Credentials {
class GroupDataProvider;
class DeviceAttestationVerifier;
} // namespace Credentials
} // namespace chip

Expand Down Expand Up @@ -70,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN

@property (readonly) chip::PersistentStorageDelegate * storageDelegate;
@property (readonly) chip::Credentials::GroupDataProvider * groupData;
@property (readonly) chip::Credentials::DeviceAttestationVerifier * deviceAttestationVerifier;

@end

NS_ASSUME_NONNULL_END
19 changes: 19 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerStartupParameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ MTR_NEWLY_AVAILABLE
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

/**
* The Product Attestation Authority certificates that are trusted to sign
* device attestation information (and in particular to sign Product Attestation
* Intermediate certificates, which then sign Device Attestation Certificates).
*
* Defaults to nil.
*/
@property (nonatomic, copy, nullable) NSArray<MTRCertificateDERBytes> * productAttestationAuthorityCertificates;

/**
* The Certification Declaration certificates whose public keys correspond to
* private keys that are trusted to sign certification declarations. Defaults
* to nil.
*
* These certificates are used in addition to, not replacing, the default set of
* well-known certification declaration signing keys.
*/
@property (nonatomic, copy, nullable) NSArray<MTRCertificateDERBytes> * certificationDeclarationCertificates;

/**
* Set an MTROperationalCertificateIssuer to call (on the provided queue) when
* operational certificates need to be provided during commissioning.
Expand Down
5 changes: 5 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ - (instancetype)initWithStorageDelegate:(id<MTRDeviceControllerStorageDelegate>)
return nil;
}

_productAttestationAuthorityCertificates = nil;
_certificationDeclarationCertificates = nil;

_ipk = ipk;
_vendorID = vendorID;
_rootCertificate = rootCertificate;
Expand Down Expand Up @@ -601,6 +604,8 @@ - (instancetype)initForNewController:(MTRDeviceController *)controller
_allowMultipleControllersPerFabric = YES;
_storageDelegate = params.storageDelegate;
_storageDelegateQueue = params.storageDelegateQueue;
_productAttestationAuthorityCertificates = params.productAttestationAuthorityCertificates;
_certificationDeclarationCertificates = params.certificationDeclarationCertificates;

return self;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ MTR_HIDDEN

@property (nonatomic, assign, readonly) BOOL allowMultipleControllersPerFabric;

@property (nonatomic, nullable) NSArray<MTRCertificateDERBytes> * productAttestationAuthorityCertificates;
@property (nonatomic, nullable) NSArray<MTRCertificateDERBytes> * certificationDeclarationCertificates;

/**
* A storage delegate that can be provided when initializing the startup params.
* This must be provided if and only if the controller factory was initialized
Expand Down

0 comments on commit 1243145

Please sign in to comment.