blob: c1699d616c3706bbb9b676589288045f75a707bf [file] [log] [blame]
/**
* 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 "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
error:(NSError * __autoreleasing *)error
{
MTR_LOG_DEFAULT("Generating root certificate");
NSData * rootCert = nil;
CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateRootCertificate(keypair, issuerID, fabricID, &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)createIntermediateCertificate:(id<MTRKeypair>)rootKeypair
rootCertificate:(MTRCertificateDERBytes)rootCertificate
intermediatePublicKey:(SecKeyRef)intermediatePublicKey
issuerID:(NSNumber * _Nullable)issuerID
fabricID:(NSNumber * _Nullable)fabricID
error:(NSError * __autoreleasing *)error
{
MTR_LOG_DEFAULT("Generating intermediate certificate");
NSData * intermediate = nil;
CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateIntermediateCertificate(
rootKeypair, rootCertificate, intermediatePublicKey, issuerID, fabricID, &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)createOperationalCertificate:(id<MTRKeypair>)signingKeypair
signingCertificate:(MTRCertificateDERBytes)signingCertificate
operationalPublicKey:(SecKeyRef)operationalPublicKey
fabricID:(NSNumber *)fabricID
nodeID:(NSNumber *)nodeID
caseAuthenticatedTags:(NSArray<NSNumber *> * _Nullable)caseAuthenticatedTags
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, &opcert);
if (error) {
*error = [MTRError errorForCHIPErrorCode:err];
}
if (err != CHIP_NO_ERROR) {
MTR_LOG_ERROR("Generating operational certificate failed: %s", ErrorStr(err));
}
return opcert;
}
+ (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[kMAX_CSR_Length];
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);
MTR_LOG_ERROR("ConvertX509CertToChipCert: %s", chip::ErrorStr(errorCode));
if (errorCode != CHIP_NO_ERROR)
return nil;
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("ConvertChipCertToX509Cert: %s", chip::ErrorStr(errorCode));
return nil;
}
return AsData(derCertBytes);
}
@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
{
return [MTRCertificates createOperationalCertificate:signingKeypair
signingCertificate:signingCertificate
operationalPublicKey:operationalPublicKey
fabricID:fabricId
nodeID:nodeId
caseAuthenticatedTags:caseAuthenticatedTags
error:error];
}
+ (nullable NSData *)generateCertificateSigningRequest:(id<MTRKeypair>)keypair
error:(NSError * __autoreleasing _Nullable * _Nullable)error
{
return [MTRCertificates createCertificateSigningRequest:keypair error:error];
}
@end