| /** |
| * 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 "MTRLogging.h" |
| #import "MTRMemory.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 |
| |
| + (MTRCertificateDERBytes * _Nullable)createRootCertificate:(id<MTRKeypair>)keypair |
| issuerID:(NSNumber * _Nullable)issuerID |
| fabricID:(NSNumber * _Nullable)fabricID |
| error:(NSError * __autoreleasing *)error |
| { |
| NSLog(@"Generating root certificate"); |
| |
| [MTRMemory ensureInit]; |
| |
| NSData * rootCert = nil; |
| CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateRootCertificate(keypair, issuerID, fabricID, &rootCert); |
| if (error) { |
| *error = [MTRError errorForCHIPErrorCode:err]; |
| } |
| |
| if (err != CHIP_NO_ERROR) { |
| NSLog(@"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 |
| { |
| NSLog(@"Generating intermediate certificate"); |
| |
| [MTRMemory ensureInit]; |
| |
| 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) { |
| NSLog(@"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 |
| { |
| NSLog(@"Generating operational certificate"); |
| |
| [MTRMemory ensureInit]; |
| |
| 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) { |
| NSLog(@"Generating operational certificate failed: %s", ErrorStr(err)); |
| } |
| |
| return opcert; |
| } |
| |
| + (BOOL)keypair:(id<MTRKeypair>)keypair matchesCertificate:(NSData *)certificate |
| { |
| [MTRMemory ensureInit]; |
| |
| P256PublicKey keypairPubKey; |
| CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(keypair.publicKey, &keypairPubKey); |
| if (err != CHIP_NO_ERROR) { |
| NSLog(@"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) { |
| NSLog(@"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 |
| { |
| [MTRMemory ensureInit]; |
| |
| P256PublicKey pubKey1; |
| CHIP_ERROR err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate1), pubKey1); |
| if (err != CHIP_NO_ERROR) { |
| NSLog(@"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) { |
| NSLog(@"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) { |
| NSLog(@"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) { |
| NSLog(@"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 |
| { |
| [MTRMemory ensureInit]; |
| |
| 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: %{public}s", chip::ErrorStr(errorCode)); |
| |
| if (errorCode != CHIP_NO_ERROR) |
| return nil; |
| |
| return AsData(chipCertBytes); |
| } |
| |
| @end |