Skip to content

Commit

Permalink
Fix APIs involved in the MTROperationalCredentialsDelegate. (#23893)
Browse files Browse the repository at this point in the history
* Fix APIs involved in the MTROperationalCredentialsDelegate.

* Rename CSRInfo to MTROperationalCSRInfo
* Rename the properties of MTROperationalCSRInfo to match the spec more closely.
* Rename AttestationInfo to MTRAttestationInfo.
* Fix naming of the API on MTRDeviceController to follow conventions better,
  document the API more clearly, and have it return errors as needed.
* Rename MTRNOCChainIssuer to MTROperationalCertificateIssuer
* Change signature of the one method on MTROperationalCertificateIssuer to have
  better naming, take a controller, and name the completion block "completion".
* Change the completion signature on MTROperationalCertificateIssuer to allow
  the external certificate issuer to return an error (e.g. if its device
  attestation checks failed).
* Don't ask the external issuer for the IPK, since we should already have that
  anyway (from our controller init).
* Allow the external issuer to return nil for the intermediate certificate, to
  indicate that there isn't one.
* Make sure that all our access to mOnNOCCompletionCallback happens on the
  Matter queue, so we don't have thread races on that member.
* Make all the dispatch we do as part of the credential-issuing process async.
* Introduce backwards-compat shims for all the API changes for now.

Fixes #23439

* Address review comment.

* Address review comments.
  • Loading branch information
bzbarsky-apple authored Dec 12, 2022
1 parent fb1d239 commit 6fc4beb
Show file tree
Hide file tree
Showing 15 changed files with 513 additions and 204 deletions.
59 changes: 59 additions & 0 deletions src/darwin/Framework/CHIP/MTRAttestationInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,71 @@

#import <Foundation/Foundation.h>

#import <Matter/MTRCertificates.h>
#import <Matter/MTRDefines.h>

NS_ASSUME_NONNULL_BEGIN

/**
* Represents information relating to product attestation.
*
*/
MTR_NEWLY_AVAILABLE
@interface MTRAttestationInfo : NSObject

/**
* The attestation challenge from the secure session.
*/
@property (nonatomic, copy, readonly) NSData * challenge;
/**
* The attestation nonce from the AttestationRequest command.
*/
@property (nonatomic, copy, readonly) NSData * nonce;
/**
* The TLV-encoded attestation_elements_message that was used to find the
* certificationDeclaration and firmwareInfo.
*/
@property (nonatomic, copy, readonly) MTRTLVBytes elementsTLV;
/**
* A signature, using the device attestation private key of the device that sent
* the attestation information, over the concatenation of elementsTLV and the
* attestation challenge from the secure session.
*/
@property (nonatomic, copy, readonly) NSData * elementsSignature;
/**
* The device attestation certificate for the device. This can be used to
* verify signatures created with the device attestation private key.
*/
@property (nonatomic, copy, readonly) MTRCertificateDERBytes deviceAttestationCertificate;
/**
* The product attestation intermediate certificate that can be used to verify
* the authenticity of the device attestation certificate.
*/
@property (nonatomic, copy, readonly) MTRCertificateDERBytes productAttestationIntermediateCertificate;
/**
* The certification declaration of the device. This is a DER-encoded string
* representing a CMS-formatted certification declaration.
*/
@property (nonatomic, copy, readonly) NSData * certificationDeclaration;
/*
* Firmware information, if any, provided in the elementsTLV. The encoding of
* this is not currently specified, but if present this must match the
* Distributed Compliance Ledger entry for the device.
*/
@property (nonatomic, copy, readonly, nullable) NSData * firmwareInfo;

- (instancetype)initWithChallenge:(NSData *)challenge
nonce:(NSData *)nonce
elementsTLV:(MTRTLVBytes)elementsTLV
elementsSignature:(NSData *)elementsSignature
deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate
productAttestationIntermediateCertificate:(MTRCertificateDERBytes)processAttestationIntermediateCertificate
certificationDeclaration:(NSData *)certificationDeclaration
firmwareInfo:(NSData *)firmwareInfo;

@end

MTR_NEWLY_DEPRECATED("Please use MTRAttestationInfo")
@interface AttestationInfo : NSObject

@property (nonatomic, copy) NSData * challenge;
Expand Down
26 changes: 26 additions & 0 deletions src/darwin/Framework/CHIP/MTRAttestationInfo.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,32 @@

NS_ASSUME_NONNULL_BEGIN

@implementation MTRAttestationInfo : NSObject

- (instancetype)initWithChallenge:(NSData *)challenge
nonce:(NSData *)nonce
elementsTLV:(MTRTLVBytes)elementsTLV
elementsSignature:(NSData *)elementsSignature
deviceAttestationCertificate:(MTRCertificateDERBytes)deviceAttestationCertificate
productAttestationIntermediateCertificate:(MTRCertificateDERBytes)productAttestationIntermediateCertificate
certificationDeclaration:(NSData *)certificationDeclaration
firmwareInfo:(NSData *)firmwareInfo
{
if (self = [super init]) {
_challenge = challenge;
_nonce = nonce;
_elementsTLV = elementsTLV;
_elementsSignature = elementsSignature;
_deviceAttestationCertificate = deviceAttestationCertificate;
_productAttestationIntermediateCertificate = productAttestationIntermediateCertificate;
_certificationDeclaration = certificationDeclaration;
_firmwareInfo = firmwareInfo;
}
return self;
}

@end

@implementation AttestationInfo : NSObject

- (instancetype)initWithChallenge:(NSData *)challenge
Expand Down
40 changes: 39 additions & 1 deletion src/darwin/Framework/CHIP/MTRCSRInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,50 @@

#import <Foundation/Foundation.h>

#import <Matter/MTRDefines.h>

typedef NSData * MTRCSRDERBytes;

NS_ASSUME_NONNULL_BEGIN

/**
* Represents information relating to NOC CSR.
* Represents information relating to a certificate signing request for a Matter
* operational certificate.
*/
MTR_NEWLY_AVAILABLE
@interface MTROperationalCSRInfo : NSObject

/**
* DER-encoded certificate signing request.
*/
@property (nonatomic, copy, readonly) MTRCSRDERBytes csr;
/**
* The nonce provided in the original CSRRequest command hat led to this CSR
* being created.
*/
@property (nonatomic, copy, readonly) NSData * csrNonce;
/**
* TLV-encoded nocsr-elements structure. This includes the "csr" and "csrNonce"
* fields, and can include additional vendor-specific information.
*/
@property (nonatomic, copy, readonly) MTRTLVBytes csrElementsTLV;
/**
* A signature, using the device attestation private key of the device that
* created the CSR, over the concatenation of csrElementsTLV and the attestation
* challenge from the secure session.
*
* The attestation challenge is available in MTRAttestionInfo.
*/
@property (nonatomic, copy, readonly) NSData * attestationSignature;

- (instancetype)initWithCSR:(MTRCSRDERBytes)csr
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;

@end

MTR_NEWLY_DEPRECATED("Please use MTROperationalCSRInfo")
@interface CSRInfo : NSObject

@property (nonatomic, copy) NSData * nonce;
Expand Down
17 changes: 17 additions & 0 deletions src/darwin/Framework/CHIP/MTRCSRInfo.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@

NS_ASSUME_NONNULL_BEGIN

@implementation MTROperationalCSRInfo : NSObject

- (instancetype)initWithCSR:(MTRCSRDERBytes)csr
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;
{
if (self = [super init]) {
_csr = csr;
_csrNonce = csrNonce;
_csrElementsTLV = csrElementsTLV;
_attestationSignature = attestationSignature;
}
return self;
}
@end

@implementation CSRInfo : NSObject

- (instancetype)initWithNonce:(NSData *)nonce
Expand Down
2 changes: 2 additions & 0 deletions src/darwin/Framework/CHIP/MTRDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@
#else
#define MTR_EXTERN extern MTR_EXPORT
#endif

typedef NSData * MTRTLVBytes;
19 changes: 4 additions & 15 deletions src/darwin/Framework/CHIP/MTRDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#import <Foundation/Foundation.h>

#import <Matter/MTRNOCChainIssuer.h>
#import <Matter/MTROperationalCertificateIssuer.h>

@class MTRBaseDevice;

Expand Down Expand Up @@ -127,20 +127,6 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS
*/
- (void)setDeviceControllerDelegate:(id<MTRDeviceControllerDelegate>)delegate queue:(dispatch_queue_t)queue MTR_NEWLY_AVAILABLE;

/**
* Sets this MTRDeviceController to use the given issuer for issuing operational certs. By default, the MTRDeviceController uses an
* internal issuer.
*
* When a nocChainIssuer is set, the device commissioner will delegate verification to the chip::Credentials::PartialDACVerifier so
* that DAC chain and CD validation can be performed by custom code triggered by MTRNOCChainIssuer.onNOCChainGenerationNeeded().
* Otherwise, the device commissioner uses the chip::Credentials::DefaultDACVerifier
*
* @param[in] nocChainIssuer the NOC Chain issuer to use for issuer operational certs
*
* @param[in] queue The queue on which the callbacks will be delivered
*/
- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer queue:(dispatch_queue_t)queue;

/**
* Return the attestation challenge for the secure session of the device being commissioned.
*
Expand Down Expand Up @@ -231,6 +217,9 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS
- (void)setPairingDelegate:(id<MTRDevicePairingDelegate>)delegate
queue:(dispatch_queue_t)queue MTR_NEWLY_DEPRECATED("Please use setDeviceControllerDelegate:");

- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer
queue:(dispatch_queue_t)queue
MTR_NEWLY_DEPRECATED("Please set the operationalCertificateIssuer in the MTRDeviceControllerStartupParams instead.");
@end

NS_ASSUME_NONNULL_END
100 changes: 93 additions & 7 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory queue:(dis
return nil;
}

_operationalCredentialsDelegate = new MTROperationalCredentialsDelegate();
_operationalCredentialsDelegate = new MTROperationalCredentialsDelegate(self);
if ([self checkForInitError:(_operationalCredentialsDelegate != nullptr) logMsg:kErrorOperationalCredentialsInit]) {
return nil;
}
Expand Down Expand Up @@ -347,9 +347,21 @@ - (BOOL)startup:(MTRDeviceControllerStartupParamsInternal *)startupParams

if (commissionerInitialized == NO) {
[self cleanupAfterStartup];
return NO;
}

// TODO: Once setNocChainIssuer no longer needs to be supported,
// we can just move the internals of
// setOperationalCertificateIssuer into the sync-dispatched block
// above.
if (![self setOperationalCertificateIssuer:startupParams.operationalCertificateIssuer
queue:startupParams.operationalCertificateIssuerQueue]) {
MTR_LOG_ERROR("operationalCertificateIssuer and operationalCertificateIssuerQueue must both be nil or both be non-nil");
[self cleanupAfterStartup];
return NO;
}

return commissionerInitialized;
return YES;
}

- (NSNumber *)controllerNodeID
Expand Down Expand Up @@ -568,20 +580,31 @@ - (void)setDeviceControllerDelegate:(id<MTRDeviceControllerDelegate>)delegate qu
});
}

- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer queue:(dispatch_queue_t)queue
- (BOOL)setOperationalCertificateIssuer:(nullable id<MTROperationalCertificateIssuer>)operationalCertificateIssuer
queue:(nullable dispatch_queue_t)queue
{
VerifyOrReturn([self checkIsRunning]);
if ((operationalCertificateIssuer != nil && queue == nil) || (operationalCertificateIssuer == nil && queue != nil)) {
return NO;
}

VerifyOrReturnValue([self checkIsRunning], NO);

__block BOOL success = NO;
dispatch_sync(_chipWorkQueue, ^{
VerifyOrReturn([self checkIsRunning]);

if (nocChainIssuer != nil) {
self->_operationalCredentialsDelegate->SetNocChainIssuer(nocChainIssuer, queue);
if (operationalCertificateIssuer != nil) {
self->_operationalCredentialsDelegate->SetOperationalCertificateIssuer(operationalCertificateIssuer, queue);
self->_cppCommissioner->SetDeviceAttestationVerifier(_partialDACVerifier);
} else {
self->_cppCommissioner->SetDeviceAttestationVerifier(chip::Credentials::GetDeviceAttestationVerifier());
// TODO: Once we are not supporting setNocChainIssuer this
// branch can just go away.
self->_cppCommissioner->SetDeviceAttestationVerifier(_factory.deviceAttestationVerifier);
}
success = YES;
});

return success;
}

+ (nullable NSData *)computePASEVerifierForSetupPasscode:(NSNumber *)setupPasscode
Expand Down Expand Up @@ -902,6 +925,64 @@ - (void)onPairingDeleted:(NSError * _Nullable)error

@end

/**
* Shim to allow us to treat an MTRNOCChainIssuer as an
* MTROperationalCertificateIssuer.
*/
@interface MTROperationalCertificateChainIssuerShim : NSObject <MTROperationalCertificateIssuer>
@property (nonatomic, readonly) id<MTRNOCChainIssuer> nocChainIssuer;
- (instancetype)initWithIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer;
@end

@implementation MTROperationalCertificateChainIssuerShim
- (instancetype)initWithIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer
{
if (self = [super init]) {
_nocChainIssuer = nocChainIssuer;
}
return self;
}

- (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo
attestationInfo:(MTRAttestationInfo *)attestationInfo
controller:(MTRDeviceController *)controller
completion:(MTROperationalCertificateIssuedHandler)completion
{
CSRInfo * oldCSRInfo = [[CSRInfo alloc] initWithNonce:csrInfo.csrNonce
elements:csrInfo.csrElementsTLV
elementsSignature:csrInfo.attestationSignature
csr:csrInfo.csr];
NSData * _Nullable firmwareInfo = attestationInfo.firmwareInfo;
if (firmwareInfo == nil) {
firmwareInfo = [NSData data];
}
AttestationInfo * oldAttestationInfo =
[[AttestationInfo alloc] initWithChallenge:attestationInfo.challenge
nonce:attestationInfo.nonce
elements:attestationInfo.elementsTLV
elementsSignature:attestationInfo.elementsSignature
dac:attestationInfo.deviceAttestationCertificate
pai:attestationInfo.productAttestationIntermediateCertificate
certificationDeclaration:attestationInfo.certificationDeclaration
firmwareInfo:firmwareInfo];
[self.nocChainIssuer
onNOCChainGenerationNeeded:oldCSRInfo
attestationInfo:oldAttestationInfo
onNOCChainGenerationComplete:^(NSData * operationalCertificate, NSData * intermediateCertificate, NSData * rootCertificate,
NSData * _Nullable ipk, NSNumber * _Nullable adminSubject, NSError * __autoreleasing * error) {
auto * info = [[MTROperationalCertificateInfo alloc] initWithOperationalCertificate:operationalCertificate
intermediateCertificate:intermediateCertificate
rootCertificate:rootCertificate
adminSubject:adminSubject];
completion(info, nil);
if (error != nil) {
*error = nil;
}
}];
}

@end

@implementation MTRDeviceController (Deprecated)

- (NSNumber *)controllerNodeId
Expand Down Expand Up @@ -1125,4 +1206,9 @@ - (void)setPairingDelegate:(id<MTRDevicePairingDelegate>)delegate queue:(dispatc
[self setDeviceControllerDelegate:delegateShim queue:queue];
}

- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer queue:(dispatch_queue_t)queue
{
[self setOperationalCertificateIssuer:[[MTROperationalCertificateChainIssuerShim alloc] initWithIssuer:nocChainIssuer]
queue:queue];
}
@end
Loading

0 comments on commit 6fc4beb

Please sign in to comment.