From ca4a4a81ffee18989f44af7945d7c4246c2b6d69 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 10 Apr 2023 15:01:59 -0400 Subject: [PATCH] Add a Darwin API to parse the CSR out of a nocsr-elements. Addresses the most immediate problem that led to https://github.com/project-chip/connectedhomeip/issues/24978 being filed. --- src/darwin/Framework/CHIP/MTRCSRInfo.h | 37 +++++++++++- src/darwin/Framework/CHIP/MTRCSRInfo.mm | 56 +++++++++++++++++++ .../CHIP/MTROperationalCertificateIssuer.h | 6 ++ .../CHIP/MTROperationalCredentialsDelegate.mm | 25 +-------- .../MTROperationalCertificateIssuerTests.m | 7 +++ 5 files changed, 107 insertions(+), 24 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.h b/src/darwin/Framework/CHIP/MTRCSRInfo.h index b20c34d469a944..5c6bc37a89b4bc 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.h +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.h @@ -17,6 +17,7 @@ #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -34,8 +35,10 @@ 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. Depending on where the + * MTROperationalCSRInfo comes from, this could be the nonce from the CSRRequest + * command that led to this CSR being created, or the nonce from the + * csrElementsTLV. */ @property (nonatomic, copy, readonly) NSData * csrNonce; @@ -54,11 +57,41 @@ 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. It's the + * caller's responsibility to ensure that the provided csr matches + * csrElementsTLV. + */ - (instancetype)initWithCSR:(MTRCSRDERBytes)csr 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. + */ +- (instancetype)initWithCSRNonce:(NSData *)csrNonce + 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)) diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.mm b/src/darwin/Framework/CHIP/MTRCSRInfo.mm index d8a77fba5e941a..000415617221e0 100644 --- a/src/darwin/Framework/CHIP/MTRCSRInfo.mm +++ b/src/darwin/Framework/CHIP/MTRCSRInfo.mm @@ -16,11 +16,37 @@ */ #import "MTRCSRInfo.h" +#import "MTRFramework.h" +#import "MTRLogging_Internal.h" +#import "NSDataSpanConversion.h" + +#include +#include +#include +#include + +static CHIP_ERROR ExtracCSRAndNonce(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 ++ (void)initialize +{ + // Needed for some of our init* methods. + MTRFrameworkInit(); +} + - (instancetype)initWithCSR:(MTRCSRDERBytes)csr csrNonce:(NSData *)csrNonce csrElementsTLV:(MTRTLVBytes)csrElementsTLV @@ -34,6 +60,36 @@ - (instancetype)initWithCSR:(MTRCSRDERBytes)csr } return self; } + +- (instancetype)initWithCSRNonce:(NSData *)csrNonce + csrElementsTLV:(MTRTLVBytes)csrElementsTLV + attestationSignature:(NSData *)attestationSignature +{ + chip::ByteSpan csr; + { + // We don't care about the nonce. + chip::ByteSpan ignoredNonce; + VerifyOrReturnValue(ExtracCSRAndNonce(csrElementsTLV, csr, ignoredNonce) == CHIP_NO_ERROR, nil); + } + + return [self initWithCSR:AsData(csr) csrNonce:csrNonce csrElementsTLV:csrElementsTLV attestationSignature:attestationSignature]; +} + +- (instancetype)initWithCSRElementsTLV:(MTRTLVBytes)csrElementsTLV attestationSignature:(NSData *)attestationSignature +{ + chip::ByteSpan csr, csrNonce; + VerifyOrReturnValue(ExtracCSRAndNonce(csrElementsTLV, csr, csrNonce) == CHIP_NO_ERROR, nil); + + return [self initWithCSR: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 diff --git a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h index e97d02ed3e1976..74d7cff0523b69 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h +++ b/src/darwin/Framework/CHIP/MTROperationalCertificateIssuer.h @@ -74,6 +74,12 @@ 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 _we_ + * provided when sending the CSRRequest commmand. If device attestation + * succeeded, this will match the nonce returned in the CSRResponse command. + * The actual nonce returned in CSRResponse can be determined by initializing a + * new MTROperationalCSRInfo with csrInfo.csrElementsTLV. */ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo attestationInfo:(MTRDeviceAttestationInfo *)attestationInfo diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm index 16ae9da59103ab..b14ac062784105 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm @@ -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; diff --git a/src/darwin/Framework/CHIPTests/MTROperationalCertificateIssuerTests.m b/src/darwin/Framework/CHIPTests/MTROperationalCertificateIssuerTests.m index bb9c1597900709..8efc8989abb689 100644 --- a/src/darwin/Framework/CHIPTests/MTROperationalCertificateIssuerTests.m +++ b/src/darwin/Framework/CHIPTests/MTROperationalCertificateIssuerTests.m @@ -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]); }