/** * * Copyright (c) 2021-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. */ #include #import #import #import "MTRDeviceController_Concrete.h" #import "MTRError_Internal.h" #import "MTRKeypair.h" #import "MTROperationalCertificateIssuer.h" #import "MTRP256KeypairBridge.h" #import "MTRPersistentStorageDelegateBridge.h" #include #include #include #include NS_ASSUME_NONNULL_BEGIN class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCredentialsDelegate { public: using ChipP256KeypairPtr = chip::Crypto::P256Keypair *; MTROperationalCredentialsDelegate(MTRDeviceController_Concrete * deviceController); ~MTROperationalCredentialsDelegate() {} CHIP_ERROR Init(ChipP256KeypairPtr nocSigner, NSData * ipk, NSData * rootCert, NSData * _Nullable icaCert); CHIP_ERROR GenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion) override; void SetNodeIdForNextNOCRequest(chip::NodeId nodeId) override { mNextRequestedNodeId = nodeId; mNodeIdRequested = true; } void SetFabricIdForNextNOCRequest(chip::FabricId fabricId) override { mNextFabricId = fabricId; } void SetDeviceID(chip::NodeId deviceId) { mDeviceBeingPaired = deviceId; } void ResetDeviceID() { mDeviceBeingPaired = chip::kUndefinedNodeId; } void SetDeviceCommissioner(chip::Controller::DeviceCommissioner * _Nullable cppCommissioner) { mCppCommissioner = cppCommissioner; } chip::Optional GetCommissioningParameters() { return mCppCommissioner == nullptr ? chip::NullOptional : mCppCommissioner->GetCommissioningParameters(); } void SetOperationalCertificateIssuer( id operationalCertificateIssuer, dispatch_queue_t operationalCertificateIssuerQueue) { mOperationalCertificateIssuer = operationalCertificateIssuer; mOperationalCertificateIssuerQueue = operationalCertificateIssuerQueue; } CHIP_ERROR GenerateNOC(chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey, chip::MutableByteSpan & noc); const chip::Crypto::IdentityProtectionKeySpan GetIPK() { return mIPK.Span(); } // Get the root/intermediate X.509 DER certs as a ByteSpan. chip::ByteSpan RootCertSpan() const; chip::ByteSpan IntermediateCertSpan() const; // Generate a root (self-signed) DER-encoded X.509 certificate for the given // MTRKeypair. If issuerId is provided, it is used; otherwise a random one // is generated. If a fabric id is provided it is added to the subject DN // of the certificate. // // The outparam must not be null and is set to nil on errors. static CHIP_ERROR GenerateRootCertificate(id keypair, NSNumber * _Nullable issuerId, NSNumber * _Nullable fabricId, NSDateInterval * validityPeriod, NSData * _Nullable __autoreleasing * _Nonnull rootCert); // Generate an intermediate DER-encoded X.509 certificate for the given root // and intermediate public key. If issuerId is provided, it is used; // otherwise a random one is generated. If a fabric id is provided it is // added to the subject DN of the certificate. // // The outparam must not be null and is set to nil on errors. static CHIP_ERROR GenerateIntermediateCertificate(id rootKeypair, NSData * rootCertificate, SecKeyRef intermediatePublicKey, NSNumber * _Nullable issuerId, NSNumber * _Nullable fabricId, NSDateInterval * validityPeriod, NSData * _Nullable __autoreleasing * _Nonnull intermediateCert); // Generate an operational DER-encoded X.509 certificate for the given // signing certificate and operational public key, using the given fabric // id, node id, and CATs. static CHIP_ERROR GenerateOperationalCertificate(id signingKeypair, NSData * signingCertificate, SecKeyRef operationalPublicKey, NSNumber * fabricId, NSNumber * nodeId, NSSet * _Nullable caseAuthenticatedTags, NSDateInterval * validityPeriod, NSData * _Nullable __autoreleasing * _Nonnull operationalCert); private: // notAfter times can represent "forever". static bool ToChipNotAfterEpochTime(NSDate * date, uint32_t & epoch); static bool ToChipEpochTime(NSDate * date, uint32_t & epoch); static CHIP_ERROR GenerateNOC(chip::Crypto::P256Keypair & signingKeypair, NSData * signingCertificate, chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, const chip::Crypto::P256PublicKey & pubkey, NSDateInterval * validityPeriod, chip::MutableByteSpan & noc); // Called asynchronously in response to the MTROperationalCertificateIssuer // calling the completion we passed it when asking it to generate a NOC // chain. void ExternalNOCChainGenerated(MTROperationalCertificateChain * _Nullable chain, NSError * _Nullable error); CHIP_ERROR ExternalGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion); CHIP_ERROR LocalGenerateNOCChain(const chip::ByteSpan & csrElements, const chip::ByteSpan & csrNonce, const chip::ByteSpan & attestationSignature, const chip::ByteSpan & attestationChallenge, const chip::ByteSpan & DAC, const chip::ByteSpan & PAI, chip::Callback::Callback * onCompletion); ChipP256KeypairPtr mIssuerKey; chip::Crypto::IdentityProtectionKey mIPK; chip::NodeId mDeviceBeingPaired = chip::kUndefinedNodeId; chip::NodeId mNextRequestedNodeId = 1; chip::FabricId mNextFabricId = 1; bool mNodeIdRequested = false; // mRootCert should not really be nullable, but we are constructed before we // have a root cert, and at that point it gets initialized to nil. NSData * _Nullable mRootCert; NSData * _Nullable mIntermediateCert; MTRDeviceController_Concrete * __weak mWeakController; chip::Controller::DeviceCommissioner * _Nullable mCppCommissioner = nullptr; id _Nullable mOperationalCertificateIssuer; dispatch_queue_t _Nullable mOperationalCertificateIssuerQueue; chip::Callback::Callback * _Nullable mOnNOCCompletionCallback = nullptr; }; NS_ASSUME_NONNULL_END