diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index d94449dbc5ea66..f910f87fe3f3a1 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -127,7 +127,7 @@ CHIP_ERROR DeviceController::Init(ControllerInitParams params) mVendorId = params.controllerVendorId; if (params.operationalKeypair != nullptr || !params.controllerNOC.empty() || !params.controllerRCAC.empty()) { - ReturnErrorOnFailure(ProcessControllerNOCChain(params)); + ReturnErrorOnFailure(InitControllerNOCChain(params)); if (params.enableServerInteractions) { @@ -144,7 +144,7 @@ CHIP_ERROR DeviceController::Init(ControllerInitParams params) return CHIP_NO_ERROR; } -CHIP_ERROR DeviceController::ProcessControllerNOCChain(const ControllerInitParams & params) +CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams & params) { FabricInfo newFabric; constexpr uint32_t chipCertAllocatedLen = kMaxCHIPCertLength; @@ -152,7 +152,15 @@ CHIP_ERROR DeviceController::ProcessControllerNOCChain(const ControllerInitParam Credentials::P256PublicKeySpan rootPublicKey; FabricId fabricId; - ReturnErrorOnFailure(newFabric.SetOperationalKeypair(params.operationalKeypair)); + if (params.hasExternallyOwnedOperationalKeypair) + { + ReturnErrorOnFailure(newFabric.SetExternallyOwnedOperationalKeypair(params.operationalKeypair)); + } + else + { + ReturnErrorOnFailure(newFabric.SetOperationalKeypair(params.operationalKeypair)); + } + newFabric.SetVendorId(params.controllerVendorId); ReturnErrorCodeIf(!chipCert.Alloc(chipCertAllocatedLen), CHIP_ERROR_NO_MEMORY); diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 266fa84e7224f8..2449a798c7ea06 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -95,6 +95,13 @@ struct ControllerInitParams controllerNOC. It's used by controller to establish CASE sessions with devices */ Crypto::P256Keypair * operationalKeypair = nullptr; + /** + * Controls whether or not the operationalKeypair should be owned by the caller. + * By default, this is false, but if the keypair cannot be serialized, then + * setting this to true will allow you to manage this keypair's lifecycle. + */ + bool hasExternallyOwnedOperationalKeypair = false; + /* The following certificates must be in x509 DER format */ ByteSpan controllerNOC; ByteSpan controllerICAC; @@ -240,6 +247,13 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate, public Abstr */ CHIP_ERROR DisconnectDevice(NodeId nodeId); + /** + * @brief + * Configures a new set of operational credentials to be used with this + * controller. + */ + CHIP_ERROR InitControllerNOCChain(const ControllerInitParams & params); + protected: enum class State { @@ -275,8 +289,6 @@ class DLL_EXPORT DeviceController : public SessionRecoveryDelegate, public Abstr private: void ReleaseOperationalDevice(OperationalDeviceProxy * device); - - CHIP_ERROR ProcessControllerNOCChain(const ControllerInitParams & params); }; #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY diff --git a/src/credentials/FabricTable.cpp b/src/credentials/FabricTable.cpp index c7301b6ae38f00..f2178fd3cc824b 100644 --- a/src/credentials/FabricTable.cpp +++ b/src/credentials/FabricTable.cpp @@ -95,7 +95,7 @@ CHIP_ERROR FabricInfo::CommitToStorage(PersistentStorageDelegate * storage) { Crypto::P256SerializedKeypair serializedOpKey; - if (mOperationalKey != nullptr) + if (!mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) { ReturnErrorOnFailure(mOperationalKey->Serialize(serializedOpKey)); } @@ -117,7 +117,10 @@ CHIP_ERROR FabricInfo::CommitToStorage(PersistentStorageDelegate * storage) ReturnErrorOnFailure(writer.Put(kOpKeyVersionTag, kOpKeyVersion)); - ReturnErrorOnFailure(writer.Put(kOpKeyDataTag, ByteSpan(serializedOpKey.Bytes(), serializedOpKey.Length()))); + if (!mHasExternallyOwnedOperationalKey) + { + ReturnErrorOnFailure(writer.Put(kOpKeyDataTag, ByteSpan(serializedOpKey.Bytes(), serializedOpKey.Length()))); + } ReturnErrorOnFailure(writer.EndContainer(outerType)); @@ -318,9 +321,12 @@ CHIP_ERROR FabricInfo::DeleteFromStorage(PersistentStorageDelegate * storage, Fa return prevDeleteErr; } -CHIP_ERROR FabricInfo::SetOperationalKeypair(const P256Keypair * keyPair) +CHIP_ERROR FabricInfo::SetOperationalKeypair(P256Keypair * keyPair) { VerifyOrReturnError(keyPair != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + mHasExternallyOwnedOperationalKey = false; + P256SerializedKeypair serialized; ReturnErrorOnFailure(keyPair->Serialize(serialized)); if (mOperationalKey == nullptr) @@ -335,6 +341,20 @@ CHIP_ERROR FabricInfo::SetOperationalKeypair(const P256Keypair * keyPair) return mOperationalKey->Deserialize(serialized); } +CHIP_ERROR FabricInfo::SetExternallyOwnedOperationalKeypair(P256Keypair * keyPair) +{ + VerifyOrReturnError(keyPair != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + if (!mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) + { + chip::Platform::Delete(mOperationalKey); + mOperationalKey = nullptr; + } + + mHasExternallyOwnedOperationalKey = true; + mOperationalKey = keyPair; + return CHIP_NO_ERROR; +} + void FabricInfo::ReleaseCert(MutableByteSpan & cert) { if (cert.data() != nullptr) @@ -565,7 +585,15 @@ CHIP_ERROR FabricInfo::SetFabricInfo(FabricInfo & newFabric) ReturnErrorOnFailure(VerifyCredentials(newFabric.mNOCCert, newFabric.mICACert, newFabric.mRootCert, validContext, operationalId, fabricId, pubkey)); - SetOperationalKeypair(newFabric.GetOperationalKey()); + if (newFabric.mHasExternallyOwnedOperationalKey) + { + ReturnErrorOnFailure(SetExternallyOwnedOperationalKeypair(newFabric.GetOperationalKey())); + } + else + { + ReturnErrorOnFailure(SetOperationalKeypair(newFabric.GetOperationalKey())); + } + SetRootCert(newFabric.mRootCert); mOperationalId = operationalId; mFabricId = fabricId; diff --git a/src/credentials/FabricTable.h b/src/credentials/FabricTable.h index 62c2f5525100db..698cce7e4261fe 100644 --- a/src/credentials/FabricTable.h +++ b/src/credentials/FabricTable.h @@ -74,7 +74,7 @@ class DLL_EXPORT FabricInfo ~FabricInfo() { - if (mOperationalKey != nullptr) + if (!mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) { chip::Platform::Delete(mOperationalKey); } @@ -123,7 +123,31 @@ class DLL_EXPORT FabricInfo } return mOperationalKey; } - CHIP_ERROR SetOperationalKeypair(const Crypto::P256Keypair * keyPair); + + + /** + * Sets the P256Keypair used for this fabric, transferring ownership of the + * key to this object by making a copy via the P256Keypair::Serialize and + * P256Keypair::Deserialize methods. + * + * If your P256Keypair does not support serialization, use the + * `SetExternallyOwnedOperationalKeypair` method instead. + */ + CHIP_ERROR SetOperationalKeypair(Crypto::P256Keypair * keyPair); + + /** + * Sets the P256Keypair used for this fabric, delegating ownership of the + * key to the caller. The P256Keypair provided here must be freed later by + * the caller of this method. + * + * This should be used if your P256Keypair does not support serialization + * and deserialization (e.g. your private key is held in a secure element + * and cannot be accessed directly). + * + * To have the ownership of the key managed for you, use + * SetOperationalKeypair instead. + */ + CHIP_ERROR SetExternallyOwnedOperationalKeypair(Crypto::P256Keypair * keyPair); // TODO - Update these APIs to take ownership of the buffer, instead of copying // internally. @@ -186,7 +210,7 @@ class DLL_EXPORT FabricInfo mVendorId = VendorId::NotSpecified; mFabricLabel[0] = '\0'; - if (mOperationalKey != nullptr) + if (mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr) { chip::Platform::Delete(mOperationalKey); mOperationalKey = nullptr; @@ -229,6 +253,7 @@ class DLL_EXPORT FabricInfo #else mutable Crypto::P256Keypair * mOperationalKey = nullptr; #endif + bool mHasExternallyOwnedOperationalKey = false; MutableByteSpan mRootCert; MutableByteSpan mICACert;