blob: 9444ae920cc44ca67e16b8f1072a4b9d446e4598 [file] [log] [blame]
/**
* Copyright (c) 2022-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 "MTRCertificates.h"
#import "MTRError_Internal.h"
#import "MTRFramework.h"
#import "MTRLogging_Internal.h"
#import "MTROperationalCredentialsDelegate.h"
#import "MTRP256KeypairBridge.h"
#import "NSDataSpanConversion.h"
#include <credentials/CHIPCert.h>
#include <crypto/CHIPCryptoPAL.h>
using namespace chip;
using namespace chip::Crypto;
using namespace chip::Credentials;
@implementation MTRCertificates
+ (void)initialize
{
MTRFrameworkInit();
}
+ (MTRCertificateDERBytes _Nullable)createRootCertificate:(id<MTRKeypair>)keypair
issuerID:(NSNumber * _Nullable)issuerID
fabricID:(NSNumber * _Nullable)fabricID
validityPeriod:(NSDateInterval *)validityPeriod
error:(NSError * __autoreleasing *)error
{
MTR_LOG_DEFAULT("Generating root certificate");
NSData * rootCert = nil;
CHIP_ERROR err
= MTROperationalCredentialsDelegate::GenerateRootCertificate(keypair, issuerID, fabricID, validityPeriod, &rootCert);
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Generating root certificate failed: %s", ErrorStr(err));
}
return rootCert;
}
+ (MTRCertificateDERBytes _Nullable)createRootCertificate:(id<MTRKeypair>)keypair
issuerID:(NSNumber * _Nullable)issuerID
fabricID:(NSNumber * _Nullable)fabricID
error:(NSError * __autoreleasing *)error
{
auto * validityPeriod = [[NSDateInterval alloc] initWithStartDate:[NSDate now] endDate:[NSDate distantFuture]];
return [self createRootCertificate:keypair issuerID:issuerID fabricID:fabricID validityPeriod:validityPeriod error:error];
}
+ (MTRCertificateDERBytes _Nullable)createIntermediateCertificate:(id<MTRKeypair>)rootKeypair
rootCertificate:(MTRCertificateDERBytes)rootCertificate
intermediatePublicKey:(SecKeyRef)intermediatePublicKey
issuerID:(NSNumber * _Nullable)issuerID
fabricID:(NSNumber * _Nullable)fabricID
validityPeriod:(NSDateInterval *)validityPeriod
error:(NSError * __autoreleasing *)error
{
MTR_LOG_DEFAULT("Generating intermediate certificate");
NSData * intermediate = nil;
CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateIntermediateCertificate(
rootKeypair, rootCertificate, intermediatePublicKey, issuerID, fabricID, validityPeriod, &intermediate);
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Generating intermediate certificate failed: %s", ErrorStr(err));
}
return intermediate;
}
+ (MTRCertificateDERBytes _Nullable)createIntermediateCertificate:(id<MTRKeypair>)rootKeypair
rootCertificate:(MTRCertificateDERBytes)rootCertificate
intermediatePublicKey:(SecKeyRef)intermediatePublicKey
issuerID:(NSNumber * _Nullable)issuerID
fabricID:(NSNumber * _Nullable)fabricID
error:(NSError * __autoreleasing *)error
{
auto * validityPeriod = [[NSDateInterval alloc] initWithStartDate:[NSDate now] endDate:[NSDate distantFuture]];
return [self createIntermediateCertificate:rootKeypair
rootCertificate:rootCertificate
intermediatePublicKey:intermediatePublicKey
issuerID:issuerID
fabricID:fabricID
validityPeriod:validityPeriod
error:error];
}
+ (MTRCertificateDERBytes _Nullable)createOperationalCertificate:(id<MTRKeypair>)signingKeypair
signingCertificate:(MTRCertificateDERBytes)signingCertificate
operationalPublicKey:(SecKeyRef)operationalPublicKey
fabricID:(NSNumber *)fabricID
nodeID:(NSNumber *)nodeID
caseAuthenticatedTags:(NSSet<NSNumber *> * _Nullable)caseAuthenticatedTags
validityPeriod:(NSDateInterval *)validityPeriod
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
MTR_LOG_DEFAULT("Generating operational certificate");
NSData * opcert = nil;
CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateOperationalCertificate(
signingKeypair, signingCertificate, operationalPublicKey, fabricID, nodeID, caseAuthenticatedTags, validityPeriod, &opcert);
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Generating operational certificate failed: %s", ErrorStr(err));
}
return opcert;
}
+ (MTRCertificateDERBytes _Nullable)createOperationalCertificate:(id<MTRKeypair>)signingKeypair
signingCertificate:(MTRCertificateDERBytes)signingCertificate
operationalPublicKey:(SecKeyRef)operationalPublicKey
fabricID:(NSNumber *)fabricID
nodeID:(NSNumber *)nodeID
caseAuthenticatedTags:(NSSet<NSNumber *> * _Nullable)caseAuthenticatedTags
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
auto * validityPeriod = [[NSDateInterval alloc] initWithStartDate:[NSDate now] endDate:[NSDate distantFuture]];
return [self createOperationalCertificate:signingKeypair
signingCertificate:signingCertificate
operationalPublicKey:operationalPublicKey
fabricID:fabricID
nodeID:nodeID
caseAuthenticatedTags:caseAuthenticatedTags
validityPeriod:validityPeriod
error:error];
}
+ (BOOL)keypair:(id<MTRKeypair>)keypair matchesCertificate:(NSData *)certificate
{
P256PublicKey keypairPubKey;
CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(keypair.publicKey, &keypairPubKey);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract public key from keypair: %s", ErrorStr(err));
return NO;
}
P256PublicKeySpan keypairKeySpan(keypairPubKey.ConstBytes());
P256PublicKey certPubKey;
err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate), certPubKey);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract public key from certificate: %s", ErrorStr(err));
return NO;
}
P256PublicKeySpan certKeySpan(certPubKey.ConstBytes());
return certKeySpan.data_equal(keypairKeySpan);
}
+ (BOOL)isCertificate:(MTRCertificateDERBytes)certificate1 equalTo:(MTRCertificateDERBytes)certificate2
{
P256PublicKey pubKey1;
CHIP_ERROR err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate1), pubKey1);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract public key from first certificate: %s", ErrorStr(err));
return NO;
}
P256PublicKeySpan keySpan1(pubKey1.ConstBytes());
P256PublicKey pubKey2;
err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate2), pubKey2);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract public key from second certificate: %s", ErrorStr(err));
return NO;
}
P256PublicKeySpan keySpan2(pubKey1.ConstBytes());
if (!keySpan1.data_equal(keySpan2)) {
return NO;
}
ChipDN subject1;
err = ExtractSubjectDNFromX509Cert(AsByteSpan(certificate1), subject1);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract subject DN from first certificate: %s", ErrorStr(err));
return NO;
}
ChipDN subject2;
err = ExtractSubjectDNFromX509Cert(AsByteSpan(certificate2), subject2);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Can't extract subject DN from second certificate: %s", ErrorStr(err));
return NO;
}
return subject1.IsEqual(subject2);
}
+ (NSData * _Nullable)createCertificateSigningRequest:(id<MTRKeypair>)keypair
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
MTRP256KeypairBridge keypairBridge;
CHIP_ERROR err = CHIP_NO_ERROR;
do {
err = keypairBridge.Init(keypair);
if (err != CHIP_NO_ERROR) {
break;
}
uint8_t buf[kMIN_CSR_Buffer_Size];
MutableByteSpan csr(buf);
err = GenerateCertificateSigningRequest(&keypairBridge, csr);
if (err != CHIP_NO_ERROR) {
break;
}
return AsData(csr);
} while (0);
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
return nil;
}
+ (MTRCertificateTLVBytes _Nullable)convertX509Certificate:(MTRCertificateDERBytes)x509Certificate
{
chip::ByteSpan x509CertBytes = AsByteSpan(x509Certificate);
uint8_t chipCertBuffer[chip::Credentials::kMaxCHIPCertLength];
chip::MutableByteSpan chipCertBytes(chipCertBuffer);
CHIP_ERROR errorCode = chip::Credentials::ConvertX509CertToChipCert(x509CertBytes, chipCertBytes);
if (errorCode != CHIP_NO_ERROR) {
MTR_LOG_ERROR("convertX509Certificate: %s", errorCode.AsString());
return nil;
}
MTR_LOG_INFO("convertX509Certificate: Success");
return AsData(chipCertBytes);
}
+ (MTRCertificateDERBytes _Nullable)convertMatterCertificate:(MTRCertificateTLVBytes)matterCertificate
{
chip::ByteSpan tlvCertBytes = AsByteSpan(matterCertificate);
uint8_t derCertBuffer[chip::Controller::kMaxCHIPDERCertLength];
chip::MutableByteSpan derCertBytes(derCertBuffer);
CHIP_ERROR errorCode = chip::Credentials::ConvertChipCertToX509Cert(tlvCertBytes, derCertBytes);
if (errorCode != CHIP_NO_ERROR) {
MTR_LOG_ERROR("convertMatterCertificate: %s", chip::ErrorStr(errorCode));
return nil;
}
return AsData(derCertBytes);
}
+ (NSData * _Nullable)publicKeyFromCSR:(MTRCSRDERBytes)certificateSigningRequest
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
auto requestSpan = AsByteSpan(certificateSigningRequest);
P256PublicKey publicKey;
CHIP_ERROR err = VerifyCertificateSigningRequest(requestSpan.data(), requestSpan.size(), publicKey);
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("publicKeyFromCSR: %s", chip::ErrorStr(err));
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
return nil;
}
P256PublicKeySpan publicKeySpan(publicKey.ConstBytes());
return AsData(publicKeySpan);
}
@end
@implementation MTRCertificates (Deprecated)
+ (nullable NSData *)generateRootCertificate:(id<MTRKeypair>)keypair
issuerId:(nullable NSNumber *)issuerId
fabricId:(nullable NSNumber *)fabricId
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
return [MTRCertificates createRootCertificate:keypair issuerID:issuerId fabricID:fabricId error:error];
}
+ (nullable NSData *)generateIntermediateCertificate:(id<MTRKeypair>)rootKeypair
rootCertificate:(NSData *)rootCertificate
intermediatePublicKey:(SecKeyRef)intermediatePublicKey
issuerId:(nullable NSNumber *)issuerId
fabricId:(nullable NSNumber *)fabricId
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
return [MTRCertificates createIntermediateCertificate:rootKeypair
rootCertificate:rootCertificate
intermediatePublicKey:intermediatePublicKey
issuerID:issuerId
fabricID:fabricId
error:error];
}
+ (nullable NSData *)generateOperationalCertificate:(id<MTRKeypair>)signingKeypair
signingCertificate:(NSData *)signingCertificate
operationalPublicKey:(SecKeyRef)operationalPublicKey
fabricId:(NSNumber *)fabricId
nodeId:(NSNumber *)nodeId
caseAuthenticatedTags:(NSArray<NSNumber *> * _Nullable)caseAuthenticatedTags
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
NSSet<NSNumber *> * tags = nil;
if (caseAuthenticatedTags != nil) {
tags = [NSSet setWithArray:caseAuthenticatedTags];
}
return [MTRCertificates createOperationalCertificate:signingKeypair
signingCertificate:signingCertificate
operationalPublicKey:operationalPublicKey
fabricID:fabricId
nodeID:nodeId
caseAuthenticatedTags:tags
error:error];
}
+ (nullable NSData *)generateCertificateSigningRequest:(id<MTRKeypair>)keypair
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
return [MTRCertificates createCertificateSigningRequest:keypair error:error];
}
@end