blob: 43c4117231a2e96a40abc6b2d1d94e6513e2cbcb [file] [log] [blame]
/**
* 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 "MTRCertificateInfo.h"
#import "MTRConversion.h"
#import "MTRDefines_Internal.h"
#include <credentials/CHIPCert.h>
#import "NSDataSpanConversion.h"
#include <credentials/CHIPCert.h>
#include <crypto/CHIPCryptoPAL.h>
NS_ASSUME_NONNULL_BEGIN
using namespace chip;
using namespace chip::Crypto;
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 MatterEpochSecondsAsDate(_data.mNotBeforeTime);
}
- (nullable NSData *)publicKeyData
{
P256PublicKeySpan publicKeySpan;
CHIP_ERROR err = ExtractPublicKeyFromChipCert(AsByteSpan(_bytes), publicKeySpan);
if (err != CHIP_NO_ERROR) {
return nil;
}
return AsData(publicKeySpan);
}
- (NSDate *)notAfter
{
// "no expiry" is encoded as kNullCertTime (see ChipEpochToASN1Time)
return (_data.mNotAfterTime != kNullCertTime) ? MatterEpochSecondsAsDate(_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 *> *)caseAuthenticatedTags
{
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