Skip to content

Commit

Permalink
Addressing second round of feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
woody-apple authored and sharadb-amazon committed Aug 18, 2022
1 parent 9b8c8bd commit 5c16e52
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 87 deletions.
31 changes: 3 additions & 28 deletions src/darwin/Framework/CHIP/MTRDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,40 +120,15 @@ typedef void (^MTRDeviceConnectionCallback)(MTRBaseDevice * _Nullable device, NS
*/
- (void)setPairingDelegate:(id<MTRDevicePairingDelegate>)delegate queue:(dispatch_queue_t)queue;

/**
* Set the Delegate for the Device Pairing as well as the Queue on which the Delegate callbacks will be triggered
*
* @param[in] delegate The delegate the pairing process should use
*
* @param[in] queue The queue on which the callbacks will be delivered
*/

/**
* Sets this MTRDeviceController to use the given issuer for issuing operational certs. By default, the MTRDeviceController uses an
* internal, OperationalCredentialsDelegate (see MTROperationalCredentialsDelegate)
* internal issuer.
*
* @param[in] nocChainIssuer the NOC Chain issuer to use for issuer operational certs
*/
- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer;

/**
* When a NOCChainIssuer is set for this controller, then onNOCChainGenerationNeeded will be called when the NOC CSR needs to be
* signed. This allows for custom credentials issuer implementations, for example, when a proprietary cloud API will perform the CSR
* signing. The commissioning workflow will stop upon the onNOCChainGenerationNeeded callback and resume once onNOCChainGeneration
* is called.
*
* Caller must pass a non-nil value for the rootCertificate, intermediateCertificate, operationalCertificate
* If ipk and adminSubject are non nil, then they will be used in the AddNOC command sent to the commissionee. If they are not
* populated, then the values provided in the ChipDeviceController initialization will be used.
*
* @return error code (0 is no error)
* @param[in] queue The queue on which the callbacks will be delivered
*/
- (NSNumber *)onNOCChainGenerationComplete:(NSData *)operationalCertificate
intermediateCertificate:(NSData *)intermediateCertificate
rootCertificate:(NSData *)rootCertificate
ipk:(NSData *)ipk
adminSubject:(NSNumber *)adminSubject
error:(NSError * __autoreleasing *)error;
- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer queue:(dispatch_queue_t)queue;

/**
* Shutdown the controller. Calls to shutdown after the first one are NO-OPs.
Expand Down
56 changes: 3 additions & 53 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ - (instancetype)initWithFactory:(MTRControllerFactory *)factory queue:(dispatch_
if ([self checkForInitError:(_operationalCredentialsDelegate != nullptr) logMsg:kErrorOperationalCredentialsInit]) {
return nil;
}
_operationalCredentialsDelegate->setChipWorkQueue(_chipWorkQueue);
}
return self;
}
Expand Down Expand Up @@ -656,68 +657,17 @@ - (void)setPairingDelegate:(id<MTRDevicePairingDelegate>)delegate queue:(dispatc
});
}

- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer
- (void)setNocChainIssuer:(id<MTRNOCChainIssuer>)nocChainIssuer queue:(dispatch_queue_t)queue
{
VerifyOrReturn([self checkIsRunning]);

dispatch_sync(_chipWorkQueue, ^{
VerifyOrReturn([self checkIsRunning]);

self->_operationalCredentialsDelegate->SetNocChainIssuer(nocChainIssuer);
self->_operationalCredentialsDelegate->SetNocChainIssuer(nocChainIssuer, queue);
});
}

- (NSNumber *)onNOCChainGenerationComplete:(NSData *)operationalCertificate
intermediateCertificate:(NSData *)intermediateCertificate
rootCertificate:(NSData *)rootCertificate
ipk:(NSData *)ipk
adminSubject:(NSNumber *)adminSubject
error:(NSError * __autoreleasing *)error
{
VerifyOrReturnValue([self checkIsRunning:error], [NSNumber numberWithUnsignedInt:CHIP_ERROR_INCORRECT_STATE.AsInteger()]);
VerifyOrReturnValue(operationalCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);
VerifyOrReturnValue(intermediateCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);
VerifyOrReturnValue(rootCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);

// use ipk and adminSubject from CommissioningParameters if not passed in
chip::Optional<chip::Controller::CommissioningParameters> commissioningParameters
= _cppCommissioner->GetCommissioningParameters();
VerifyOrReturnValue(
commissioningParameters.HasValue(), [NSNumber numberWithUnsignedInt:CHIP_ERROR_INCORRECT_STATE.AsInteger()]);

chip::Optional<chip::Crypto::AesCcm128KeySpan> ipkOptional;
uint8_t ipkValue[chip::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
chip::Crypto::AesCcm128KeySpan ipkTempSpan(ipkValue);
if (ipk != nil) {
VerifyOrReturnValue(
[ipk length] == sizeof(ipkValue), [NSNumber numberWithUnsignedInt:CHIP_ERROR_INCORRECT_STATE.AsInteger()]);
memcpy(&ipkValue[0], [ipk bytes], [ipk length]);
ipkOptional.SetValue(ipkTempSpan);
} else if (commissioningParameters.Value().GetIpk().HasValue()) {
ipkOptional.SetValue(commissioningParameters.Value().GetIpk().Value());
}

chip::Optional<chip::NodeId> adminSubjectOptional;
if (adminSubject == nil) {
// if no value passed in, use value from CommissioningParameters
adminSubjectOptional.SetValue(commissioningParameters.Value().GetAdminSubject().ValueOr(chip::kUndefinedNodeId));
} else {
adminSubjectOptional.SetValue(adminSubject.unsignedLongLongValue);
}

__block CHIP_ERROR err = CHIP_NO_ERROR;
dispatch_sync(_chipWorkQueue, ^{
VerifyOrReturn([self checkIsRunning:error]);
err = self->_operationalCredentialsDelegate->NOCChainGenerated(CHIP_NO_ERROR, AsByteSpan(operationalCertificate),
AsByteSpan(intermediateCertificate), AsByteSpan(rootCertificate), ipkOptional, adminSubjectOptional);
});

if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Failed to SetNocChain for the device: %" CHIP_ERROR_FORMAT, err.Format());
}
return [NSNumber numberWithUnsignedInt:err.AsInteger()];
}

- (BOOL)checkForInitError:(BOOL)condition logMsg:(NSString *)logMsg
{
if (condition) {
Expand Down
10 changes: 7 additions & 3 deletions src/darwin/Framework/CHIP/MTRNOCChainIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ NS_ASSUME_NONNULL_BEGIN
@required

/**
* @brief When a MTRNOCChainIssuer is set for this controller, then onNOCChainGenerationNeeded will be
* @brief When a MTRNOCChainIssuer is set for the MTRDeviceController, then onNOCChainGenerationNeeded will be
* called when the NOC CSR needs to be signed. This allows for custom credentials issuer
* implementations, for example, when a proprietary cloud API will perform the CSR signing.
* The commissioning workflow will stop upon the onNOCChainGenerationNeeded callback and
* resume once onNOCChainGeneration is called.
* resume once onNOCChainGenerationComplete is called
* The following fields MUST be passed to onNOCChainGenerationComplete with non-nil values:
* rootCertificate, intermediateCertificate, operationalCertificate.
Expand All @@ -41,7 +41,11 @@ NS_ASSUME_NONNULL_BEGIN
*
* All csr and attestation fields are provided to allow for custom attestestation checks.
*/
- (void)onNOCChainGenerationNeeded:(CSRInfo *)csrInfo attestationInfo:(AttestationInfo *)attestationInfo;
- (void)onNOCChainGenerationNeeded:(CSRInfo *)csrInfo
attestationInfo:(AttestationInfo *)attestationInfo
onNOCChainGenerationComplete:(NSNumber * (^)(NSData * operationalCertificate, NSData * intermediateCertificate,
NSData * rootCertificate, NSData * ipk,
NSNumber * adminSubject))onNOCChainGenerationComplete;

@end

Expand Down
25 changes: 24 additions & 1 deletion src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr
return mCppCommissioner == nullptr ? chip::NullOptional : mCppCommissioner->GetCommissioningParameters();
}

void SetNocChainIssuer(id<MTRNOCChainIssuer> nocChainIssuer) { mNocChainIssuer = nocChainIssuer; }
void setChipWorkQueue(dispatch_queue_t chipWorkQueue) { mChipWorkQueue = chipWorkQueue; }

void SetNocChainIssuer(id<MTRNOCChainIssuer> nocChainIssuer, dispatch_queue_t nocChainIssuerQueue)
{
mNocChainIssuer = nocChainIssuer;
mNocChainIssuerQueue = nocChainIssuerQueue;
}

CHIP_ERROR NOCChainGenerated(CHIP_ERROR status, const chip::ByteSpan & noc, const chip::ByteSpan & icac,
const chip::ByteSpan & rcac, chip::Optional<chip::Crypto::AesCcm128KeySpan> ipk, chip::Optional<chip::NodeId> adminSubject);
Expand Down Expand Up @@ -111,6 +117,21 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr
chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey,
chip::MutableByteSpan & noc);

/**
* When a NOCChainIssuer is set, then onNOCChainGenerationNeeded will be called when the NOC CSR needs to be
* signed. This allows for custom credentials issuer implementations, for example, when a proprietary cloud API will perform the
* CSR signing. The commissioning workflow will stop upon the onNOCChainGenerationNeeded callback and resume once
* onNOCChainGenerationComplete is called.
*
* Caller must pass a non-nil value for the rootCertificate, intermediateCertificate, operationalCertificate
* If ipk and adminSubject are non nil, then they will be used in the AddNOC command sent to the commissionee. If they are not
* populated, then the values provided in the MTRDeviceController initialization will be used.
*
* @return error code (0 is no error)
*/
NSNumber * onNOCChainGenerationComplete(MTROperationalCredentialsDelegate * thisDelegate, NSData * operationalCertificate,
NSData * intermediateCertificate, NSData * rootCertificate, NSData * _Nullable ipk, NSNumber * _Nullable adminSubject);

CHIP_ERROR CallbackGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce,
const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC,
const chip::ByteSpan & PAI, chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> * onCompletion);
Expand Down Expand Up @@ -140,6 +161,8 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr

chip::Controller::DeviceCommissioner * mCppCommissioner = nullptr;
id<MTRNOCChainIssuer> _Nullable mNocChainIssuer;
dispatch_queue_t _Nullable mNocChainIssuerQueue;
dispatch_queue_t _Nullable mChipWorkQueue;
chip::Callback::Callback<chip::Controller::OnNOCChainGeneration> * mOnNOCCompletionCallback = nullptr;
};

Expand Down
60 changes: 58 additions & 2 deletions src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@
ReturnErrorOnFailure(reader.EnterContainer(containerType));
ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, TLV::ContextTag(1)));

chip::ByteSpan csr(reader.GetReadPoint(), reader.GetLength());
chip::ByteSpan csr;
reader.Get(csr);
reader.ExitContainer(containerType);

CSRInfo * csrInfo = [[CSRInfo alloc] initWithNonce:AsData(csrNonce)
Expand Down Expand Up @@ -192,10 +193,65 @@
certificationDeclaration:AsData(certificationDeclarationSpan)
firmwareInfo:AsData(firmwareInfoSpan)];

[mNocChainIssuer onNOCChainGenerationNeeded:csrInfo attestationInfo:attestationInfo];
dispatch_sync(mNocChainIssuerQueue, ^{
[mNocChainIssuer onNOCChainGenerationNeeded:csrInfo
attestationInfo:attestationInfo
onNOCChainGenerationComplete:^NSNumber *(NSData * operationalCertificate, NSData * intermediateCertificate,
NSData * rootCertificate, NSData * ipk, NSNumber * adminSubject) {
__block NSNumber * rv = nil;
dispatch_sync(mChipWorkQueue, ^{
rv = onNOCChainGenerationComplete(
this, operationalCertificate, intermediateCertificate, rootCertificate, ipk, adminSubject);
});
return rv;
}];
});

return CHIP_NO_ERROR;
}

NSNumber * MTROperationalCredentialsDelegate::onNOCChainGenerationComplete(MTROperationalCredentialsDelegate * thisDelegate,
NSData * operationalCertificate, NSData * intermediateCertificate, NSData * rootCertificate, NSData * _Nullable ipk,
NSNumber * _Nullable adminSubject)
{
VerifyOrReturnValue(operationalCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);
VerifyOrReturnValue(intermediateCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);
VerifyOrReturnValue(rootCertificate != nil, [NSNumber numberWithUnsignedInt:CHIP_ERROR_INVALID_ARGUMENT.AsInteger()]);

// use ipk and adminSubject from CommissioningParameters if not passed in
chip::Optional<chip::Controller::CommissioningParameters> commissioningParameters
= mCppCommissioner->GetCommissioningParameters();
VerifyOrReturnValue(
commissioningParameters.HasValue(), [NSNumber numberWithUnsignedInt:CHIP_ERROR_INCORRECT_STATE.AsInteger()]);

chip::Optional<chip::Crypto::AesCcm128KeySpan> ipkOptional;
uint8_t ipkValue[chip::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
chip::Crypto::AesCcm128KeySpan ipkTempSpan(ipkValue);
if (ipk != nil) {
VerifyOrReturnValue(
[ipk length] == sizeof(ipkValue), [NSNumber numberWithUnsignedInt:CHIP_ERROR_INCORRECT_STATE.AsInteger()]);
memcpy(&ipkValue[0], [ipk bytes], [ipk length]);
ipkOptional.SetValue(ipkTempSpan);
} else if (commissioningParameters.Value().GetIpk().HasValue()) {
ipkOptional.SetValue(commissioningParameters.Value().GetIpk().Value());
}

chip::Optional<chip::NodeId> adminSubjectOptional;
if (adminSubject != nil) {
adminSubjectOptional.SetValue(adminSubject.unsignedLongLongValue);
} else {
adminSubjectOptional = commissioningParameters.Value().GetAdminSubject();
}

CHIP_ERROR err = NOCChainGenerated(CHIP_NO_ERROR, AsByteSpan(operationalCertificate), AsByteSpan(intermediateCertificate),
AsByteSpan(rootCertificate), ipkOptional, adminSubjectOptional);

if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Failed to SetNocChain for the device: %" CHIP_ERROR_FORMAT, err.Format());
}
return [NSNumber numberWithUnsignedInt:err.AsInteger()];
}

CHIP_ERROR MTROperationalCredentialsDelegate::LocalGenerateNOCChain(const chip::ByteSpan & csrElements,
const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge,
const chip::ByteSpan & DAC, const chip::ByteSpan & PAI,
Expand Down

0 comments on commit 5c16e52

Please sign in to comment.