Skip to content

Commit

Permalink
Add MTRCertificateInfo / MTRDistinguishedNameInfo (#24631)
Browse files Browse the repository at this point in the history
* Add MTRCertificateInfo / MTRDistinguishedNameInfo.

These are wrappers around ChipCert and ChipDN.
Fixes #23668

* Address review comments
  • Loading branch information
ksperling-apple authored and pull[bot] committed Sep 22, 2023
1 parent 9349d0e commit 30bd0aa
Show file tree
Hide file tree
Showing 8 changed files with 468 additions and 0 deletions.
86 changes: 86 additions & 0 deletions src/darwin/Framework/CHIP/MTRCertificateInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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

NS_ASSUME_NONNULL_BEGIN

@class MTRDistinguishedNameInfo;

/**
* Exposes Matter-specific information from an operational X.509 certificate.
*
* Note: This class does not support parsing certificates related to Device Attestation.
*/
NS_SWIFT_SENDABLE
MTR_NEWLY_AVAILABLE
@interface MTRCertificateInfo : NSObject <NSCopying>

+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;

/**
* Initializes the receiver with an operational certificate in Matter TLV format.
*/
- (nullable instancetype)initWithTLVBytes:(MTRCertificateTLVBytes)bytes;

@property (readonly) MTRDistinguishedNameInfo * issuer;
@property (readonly) MTRDistinguishedNameInfo * subject;

@property (readonly) NSDate * notBefore;
@property (readonly) NSDate * notAfter;

@end

/**
* Represents the Matter-specific components of an X.509 Distinguished Name.
*/
NS_SWIFT_SENDABLE
MTR_NEWLY_AVAILABLE
@interface MTRDistinguishedNameInfo : NSObject <NSCopying>

+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;

/**
* The Node ID contained in the DN, if any.
*/
@property (readonly, nullable) NSNumber * nodeID;

/**
* The Fabric ID contained in the DN, if any.
*/
@property (readonly, nullable) NSNumber * fabricID;

/**
* The `RCAC` ID contained in the DN, if any.
*/
@property (readonly, nullable) NSNumber * rootCACertificateID;

/**
* The `ICAC` ID contained in the DN, if any.
*/
@property (readonly, nullable) NSNumber * intermediateCACertificateID;

/**
* The set of CASE Authenticated Tags contained in the DN.
*/
@property (readonly) NSSet<NSNumber *> * tags;

@end

NS_ASSUME_NONNULL_END
185 changes: 185 additions & 0 deletions src/darwin/Framework/CHIP/MTRCertificateInfo.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "MTRCertificateInfo.h"

#import "MTRConversion.h"
#import "MTRDefines_Internal.h"

#include <credentials/CHIPCert.h>

NS_ASSUME_NONNULL_BEGIN

using namespace chip;
using namespace chip::Credentials;
using namespace chip::ASN1;

@interface MTRCertificateInfo ()
- (nullable instancetype)initWithTLVBytes:(MTRCertificateTLVBytes)bytes NS_DESIGNATED_INITIALIZER;
@end

@interface MTRDistinguishedNameInfo ()
- (instancetype)initWithDN:(const ChipDN &)dn;
@end

MTR_DIRECT_MEMBERS
@implementation MTRCertificateInfo {
NSData * _bytes; // needs to be kept around, _data may contain pointers into the backing buffer
struct ChipCertificateData _data;
}

- (nullable instancetype)initWithTLVBytes:(MTRCertificateTLVBytes)bytes
{
if (self = [super init]) {
VerifyOrReturnValue(_bytes = [bytes copy], nil);
VerifyOrReturnValue(DecodeChipCert(AsByteSpan(_bytes), _data) == CHIP_NO_ERROR, nil);
}
return self;
}

- (MTRDistinguishedNameInfo *)issuer
{
return [[MTRDistinguishedNameInfo alloc] initWithDN:_data.mIssuerDN];
}

- (MTRDistinguishedNameInfo *)subject
{
return [[MTRDistinguishedNameInfo alloc] initWithDN:_data.mSubjectDN];
}

- (NSDate *)notBefore
{
return ChipEpochSecondsAsDate(_data.mNotBeforeTime);
}

- (NSDate *)notAfter
{
// "no expiry" is encoded as kNullCertTime (see ChipEpochToASN1Time)
return (_data.mNotAfterTime != kNullCertTime) ? ChipEpochSecondsAsDate(_data.mNotAfterTime) : NSDate.distantFuture;
}

- (id)copyWithZone:(nullable NSZone *)zone
{
return self; // immutable, no need to copy
}

- (BOOL)isEqual:(id)object
{
if (self == object) {
return YES;
}
if ([object class] != MTRCertificateInfo.class) {
return NO;
}
auto other = (MTRCertificateInfo *) object;
return [_bytes isEqual:other->_bytes];
}

- (NSUInteger)hash
{
return _bytes.hash;
}

@end

MTR_DIRECT_MEMBERS
@implementation MTRDistinguishedNameInfo {
ChipDN _dn;
}

- (instancetype)initWithDN:(const ChipDN &)dn
{
if (self = [super init]) {
_dn = dn;
}
return self;
}

- (nullable NSNumber *)nodeID
{
return [self identifierWithUniqueOID:kOID_AttributeType_MatterNodeId];
}

- (nullable NSNumber *)fabricID
{
return [self identifierWithUniqueOID:kOID_AttributeType_MatterFabricId];
}

- (nullable NSNumber *)rootCACertificateID
{
return [self identifierWithUniqueOID:kOID_AttributeType_MatterRCACId];
}

- (nullable NSNumber *)intermediateCACertificateID
{
return [self identifierWithUniqueOID:kOID_AttributeType_MatterICACId];
}

- (nullable NSNumber *)identifierWithUniqueOID:(OID)oid
{
NSAssert(IsChipDNAttr(oid), @"Invalid OID");

ChipRDN const * match = nullptr;
for (auto const & rdn : _dn.rdn) {
if (rdn.IsEmpty()) {
break;
} else if (rdn.mAttrOID == oid) {
VerifyOrReturnValue(!match, nil); // invalid, there should be only one matching RDN
match = &rdn;
}
}

return (match) ? @(match->mChipVal) : nil;
}

- (NSSet<NSNumber *> *)tags
{
NSMutableSet<NSNumber *> * result;
for (auto const & rdn : _dn.rdn) {
if (rdn.IsEmpty()) {
break;
} else if (rdn.mAttrOID == kOID_AttributeType_MatterCASEAuthTag) {
NSNumber * tag = @(rdn.mChipVal);
if (!result) {
result = [NSMutableSet setWithObject:tag];
} else {
[result addObject:tag];
}
}
}
return (result) ? [result copy] : [NSSet set];
}

- (id)copyWithZone:(nullable NSZone *)zone
{
return self; // immutable, no need to copy
}

- (BOOL)isEqual:(id)object
{
if (self == object) {
return YES;
}
if ([object class] != MTRDistinguishedNameInfo.class) {
return NO;
}
auto other = (MTRDistinguishedNameInfo *) object;
return _dn.IsEqual(other->_dn);
}

@end

NS_ASSUME_NONNULL_END
3 changes: 3 additions & 0 deletions src/darwin/Framework/CHIP/MTRCertificates.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ NS_ASSUME_NONNULL_BEGIN

@interface MTRCertificates : NSObject

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

/**
* Create a root (self-signed) X.509 DER encoded certificate that has the
* right fields to be a valid Matter root certificate.
Expand Down
6 changes: 6 additions & 0 deletions src/darwin/Framework/CHIP/MTRConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import <Foundation/Foundation.h>

#include <lib/core/Optional.h>
#include <lib/support/TimeUtils.h>
#include <type_traits>

NS_ASSUME_NONNULL_BEGIN
Expand All @@ -32,4 +33,9 @@ AsNumber(chip::Optional<T> optional)
return (optional.HasValue()) ? @(optional.Value()) : nil;
}

inline NSDate * ChipEpochSecondsAsDate(uint32_t chipEpochSeconds)
{
return [NSDate dateWithTimeIntervalSince1970:(chip::kChipEpochSecondsSinceUnixEpoch + (NSTimeInterval) chipEpochSeconds)];
}

NS_ASSUME_NONNULL_END
29 changes: 29 additions & 0 deletions src/darwin/Framework/CHIP/MTRDefines_Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) 2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Matter/MTRDefines.h>

#if __has_attribute(objc_direct)
#define MTR_DIRECT __attribute__((objc_direct))
#else
#define MTR_DIRECT
#endif

#if __has_attribute(objc_direct_members)
#define MTR_DIRECT_MEMBERS __attribute__((objc_direct_members))
#else
#define MTR_DIRECT_MEMBERS
#endif
1 change: 1 addition & 0 deletions src/darwin/Framework/CHIP/Matter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#import <Matter/MTRBaseClusters.h>
#import <Matter/MTRBaseDevice.h>
#import <Matter/MTRCSRInfo.h>
#import <Matter/MTRCertificateInfo.h>
#import <Matter/MTRCertificates.h>
#import <Matter/MTRCluster.h>
#import <Matter/MTRClusterConstants.h>
Expand Down
Loading

0 comments on commit 30bd0aa

Please sign in to comment.