Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Darwin API to parse the CSR out of a nocsr-elements. #26035

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions src/darwin/Framework/CHIP/MTRCSRInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#import <Foundation/Foundation.h>

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

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -34,8 +35,7 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
@property (nonatomic, copy, readonly) MTRCSRDERBytes csr;

/**
* The nonce provided in the original CSRRequest command that led to this CSR
* being created.
* The nonce associated with this CSR.
*/
@property (nonatomic, copy, readonly) NSData * csrNonce;

Expand All @@ -54,11 +54,42 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
*/
@property (nonatomic, copy, readonly) NSData * attestationSignature;

/**
* Initialize an MTROperationalCSRInfo by providing all the fields. This will
* ensure that csr and csrNonce match the data in csrElementsTLV.
*/
- (instancetype)initWithCSR:(MTRCSRDERBytes)csr
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;

/**
* Initialize an MTROperationalCSRInfo by providing the csrNonce (for example,
* the nonce the client initially supplied), and the csrElementsTLV and
* attestationSignature that the server returned. This will ensure that
* csrNonce matches the data in csrElementsTLV, and extract the csr from
* csrElementsTLV.
*/
- (instancetype)initWithCSRNonce:(NSData *)csrNonce
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature MTR_NEWLY_AVAILABLE;

/**
* Initialize an MTROperationalCSRInfo by providing just the csrElementsTLV and
* attestationSignature (which can come from an
* MTROperationalCredentialsClusterCSRResponseParams). This will extract the
* csr and csrNonce from the csrElementsTLV, if possible, and return nil if that
* fails.
*/
- (instancetype)initWithCSRElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature MTR_NEWLY_AVAILABLE;

/**
* Initialize an MTROperationalCSRInfo by providing an
* MTROperationalCredentialsClusterCSRResponseParams. This will extract the
* relevant fields from the response data.
*/
- (instancetype)initWithCSRResponseParams:(MTROperationalCredentialsClusterCSRResponseParams *)responseParams MTR_NEWLY_AVAILABLE;
@end

MTR_DEPRECATED("Please use MTROperationalCSRInfo", ios(16.1, 16.4), macos(13.0, 13.3), watchos(9.1, 9.4), tvos(16.1, 16.4))
Expand Down
92 changes: 88 additions & 4 deletions src/darwin/Framework/CHIP/MTRCSRInfo.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,41 @@
*/

#import "MTRCSRInfo.h"
#import "MTRFramework.h"
#import "MTRLogging_Internal.h"
#import "NSDataSpanConversion.h"

#include <credentials/DeviceAttestationConstructor.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/Span.h>

static CHIP_ERROR ExtractCSRAndNonce(MTRTLVBytes csrElementsTLV, chip::ByteSpan & csr, chip::ByteSpan & nonce)
{
// We don't care about vendor_reserved*.
chip::ByteSpan vendor_reserved1, vendor_reserved2, vendor_reserved3;
CHIP_ERROR err = chip::Credentials::DeconstructNOCSRElements(
AsByteSpan(csrElementsTLV), csr, nonce, vendor_reserved1, vendor_reserved2, vendor_reserved3);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Failed to parse csrElementsTLV %@: %" CHIP_ERROR_FORMAT, csrElementsTLV, err.Format());
}
return err;
}

NS_ASSUME_NONNULL_BEGIN

@implementation MTROperationalCSRInfo : NSObject

- (instancetype)initWithCSR:(MTRCSRDERBytes)csr
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;
+ (void)initialize
{
// Needed for some of our init* methods.
MTRFrameworkInit();
}

- (instancetype)_initWithValidatedCSR:(MTRCSRDERBytes)csr
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;
{
if (self = [super init]) {
_csr = csr;
Expand All @@ -34,6 +60,64 @@ - (instancetype)initWithCSR:(MTRCSRDERBytes)csr
}
return self;
}

- (instancetype)initWithCSR:(MTRCSRDERBytes)csr
csrNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature;
{
chip::ByteSpan extractedCSR, extractedNonce;
VerifyOrReturnValue(ExtractCSRAndNonce(csrElementsTLV, extractedCSR, extractedNonce) == CHIP_NO_ERROR, nil);

if (!extractedCSR.data_equal(AsByteSpan(csr))) {
MTR_LOG_ERROR("Provided CSR does not match provided csrElementsTLV");
return nil;
}

if (!extractedNonce.data_equal(AsByteSpan(csrNonce))) {
MTR_LOG_ERROR("Provided CSR nonce does not match provided csrElementsTLV");
return nil;
}

return [self _initWithValidatedCSR:csr
csrNonce:csrNonce
csrElementsTLV:csrElementsTLV
attestationSignature:attestationSignature];
}

- (instancetype)initWithCSRNonce:(NSData *)csrNonce
csrElementsTLV:(MTRTLVBytes)csrElementsTLV
attestationSignature:(NSData *)attestationSignature
{
chip::ByteSpan csr, extractedNonce;
VerifyOrReturnValue(ExtractCSRAndNonce(csrElementsTLV, csr, extractedNonce) == CHIP_NO_ERROR, nil);

if (!extractedNonce.data_equal(AsByteSpan(csrNonce))) {
MTR_LOG_ERROR("Provided CSR nonce does not match provided csrElementsTLV");
return nil;
}

return [self _initWithValidatedCSR:AsData(csr)
csrNonce:csrNonce
csrElementsTLV:csrElementsTLV
attestationSignature:attestationSignature];
}

- (instancetype)initWithCSRElementsTLV:(MTRTLVBytes)csrElementsTLV attestationSignature:(NSData *)attestationSignature
{
chip::ByteSpan csr, csrNonce;
VerifyOrReturnValue(ExtractCSRAndNonce(csrElementsTLV, csr, csrNonce) == CHIP_NO_ERROR, nil);

return [self _initWithValidatedCSR:AsData(csr)
csrNonce:AsData(csrNonce)
csrElementsTLV:csrElementsTLV
attestationSignature:attestationSignature];
}

- (instancetype)initWithCSRResponseParams:(MTROperationalCredentialsClusterCSRResponseParams *)responseParams
{
return [self initWithCSRElementsTLV:responseParams.nocsrElements attestationSignature:responseParams.attestationSignature];
}
@end

@implementation CSRInfo : NSObject
Expand Down
4 changes: 4 additions & 0 deletions src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ API_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4))
*
* This will be called on the dispatch queue passed as
* operationalCertificateIssuerQueue in the MTRDeviceControllerFactoryParams.
*
* The csrNonce in the provided MTROperationalCSRInfo will be the nonce that was
* sent in the CSRRequest command, which will be guaranteed, at this point, to
* match the nonce in the CSRResponse command.
*/
- (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo
attestationInfo:(MTRDeviceAttestationInfo *)attestationInfo
Expand Down
25 changes: 3 additions & 22 deletions src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -145,28 +145,9 @@

mOnNOCCompletionCallback = onCompletion;

TLVReader reader;
reader.Init(csrElements);

if (reader.GetType() == kTLVType_NotSpecified) {
ReturnErrorOnFailure(reader.Next());
}

VerifyOrReturnError(reader.GetType() == kTLVType_Structure, CHIP_ERROR_WRONG_TLV_TYPE);
VerifyOrReturnError(reader.GetTag() == AnonymousTag(), CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);

TLVType containerType;
ReturnErrorOnFailure(reader.EnterContainer(containerType));
ReturnErrorOnFailure(reader.Next(kTLVType_ByteString, TLV::ContextTag(1)));

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

auto * csrInfo = [[MTROperationalCSRInfo alloc] initWithCSR:AsData(csr)
csrNonce:AsData(csrNonce)
csrElementsTLV:AsData(csrElements)
attestationSignature:AsData(csrElementsSignature)];
auto * csrInfo = [[MTROperationalCSRInfo alloc] initWithCSRNonce:AsData(csrNonce)
csrElementsTLV:AsData(csrElements)
attestationSignature:AsData(csrElementsSignature)];

chip::ByteSpan certificationDeclarationSpan;
chip::ByteSpan attestationNonceSpan;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo
XCTAssertNotNil(attestationInfo);
XCTAssertEqual(controller, sController);

__auto_type * csrInfoCopy = [[MTROperationalCSRInfo alloc] initWithCSRElementsTLV:csrInfo.csrElementsTLV
attestationSignature:csrInfo.attestationSignature];
XCTAssertEqualObjects(csrInfoCopy.csr, csrInfo.csr);
XCTAssertEqualObjects(csrInfoCopy.csrNonce, csrInfo.csrNonce);
XCTAssertEqualObjects(csrInfoCopy.csrElementsTLV, csrInfo.csrElementsTLV);
XCTAssertEqualObjects(csrInfoCopy.attestationSignature, csrInfo.attestationSignature);

completion(nil, [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeIntegrityCheckFailed userInfo:nil]);
}

Expand Down