From be8b650f17908d2a16d992e36ad22b215d6ff57d Mon Sep 17 00:00:00 2001 From: chendejin Date: Wed, 6 Mar 2024 20:31:05 +0800 Subject: [PATCH] Setup controller by given fabric index without providing NOC chain and update NOC after DeviceController::Init --- src/controller/CHIPDeviceController.cpp | 74 ++++++++++++++++++- src/controller/CHIPDeviceController.h | 23 ++++++ .../CHIPDeviceControllerFactory.cpp | 4 + src/controller/CHIPDeviceControllerFactory.h | 7 ++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 2c67693b30dd4d..597c8f4cba85fc 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -111,14 +111,24 @@ CHIP_ERROR DeviceController::Init(ControllerInitParams params) mDNSResolver.SetCommissioningDelegate(this); RegisterDeviceDiscoveryDelegate(params.deviceDiscoveryDelegate); - VerifyOrReturnError(params.operationalCredentialsDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - mOperationalCredentialsDelegate = params.operationalCredentialsDelegate; - mVendorId = params.controllerVendorId; if (params.operationalKeypair != nullptr || !params.controllerNOC.empty() || !params.controllerRCAC.empty()) { ReturnErrorOnFailure(InitControllerNOCChain(params)); } + else if (params.fabricIndex.HasValue()) + { + VerifyOrReturnError(params.systemState->Fabrics()->FabricCount() > 0, CHIP_ERROR_INVALID_ARGUMENT); + if (params.systemState->Fabrics()->FindFabricWithIndex(params.fabricIndex.Value()) != nullptr) + { + mFabricIndex = params.fabricIndex.Value(); + } + else + { + ChipLogError(Controller, "There is no fabric corresponding to the given fabricIndex"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + } mSystemState = params.systemState->Retain(); mState = State::Initialized; @@ -305,8 +315,62 @@ CHIP_ERROR DeviceController::InitControllerNOCChain(const ControllerInitParams & ReturnErrorOnFailure(err); VerifyOrReturnError(fabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL); - mFabricIndex = fabricIndex; + mFabricIndex = fabricIndex; + mAdvertiseIdentity = advertiseOperational; + return CHIP_NO_ERROR; +} + +CHIP_ERROR DeviceController::UpdateControllerNOCChain(const ByteSpan & noc, const ByteSpan & icac, + Crypto::P256Keypair * operationalKeypair, + bool operationalKeypairExternalOwned) +{ + VerifyOrReturnError(mFabricIndex != kUndefinedFabricIndex, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mSystemState != nullptr, CHIP_ERROR_INTERNAL); + FabricTable * fabricTable = mSystemState->Fabrics(); + CHIP_ERROR err = CHIP_NO_ERROR; + FabricId fabricId; + NodeId nodeId; + CATValues oldCats; + CATValues newCats; + ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(noc, &nodeId, &fabricId)); + ReturnErrorOnFailure(fabricTable->FetchCATs(mFabricIndex, oldCats)); + ReturnErrorOnFailure(ExtractCATsFromOpCert(noc, newCats)); + bool needCloseSession = true; + if (GetFabricInfo()->GetNodeId() == nodeId && oldCats == newCats) + { + needCloseSession = false; + } + + if (operationalKeypair != nullptr) + { + err = fabricTable->UpdatePendingFabricWithProvidedOpKey(mFabricIndex, noc, icac, operationalKeypair, + operationalKeypairExternalOwned, mAdvertiseIdentity); + } + else + { + VerifyOrReturnError(fabricTable->HasOperationalKeyForFabric(mFabricIndex), CHIP_ERROR_KEY_NOT_FOUND); + err = fabricTable->UpdatePendingFabricWithOperationalKeystore(mFabricIndex, noc, icac, mAdvertiseIdentity); + } + + if (err == CHIP_NO_ERROR) + { + err = fabricTable->CommitPendingFabricData(); + } + else + { + fabricTable->RevertPendingFabricData(); + } + + ReturnErrorOnFailure(err); + if (needCloseSession) + { + // If the node id or CATs have changed, our existing CASE sessions are no longer valid, + // because the other side will think anything coming over those sessions comes from our + // old node ID, and the new CATs might not satisfy the ACL requirements of the other side. + mSystemState->SessionMgr()->ExpireAllSessionsForFabric(mFabricIndex); + } + ChipLogProgress(Controller, "Controller NOC chain has updated"); return CHIP_NO_ERROR; } @@ -397,6 +461,8 @@ DeviceCommissioner::DeviceCommissioner() : CHIP_ERROR DeviceCommissioner::Init(CommissionerInitParams params) { + VerifyOrReturnError(params.operationalCredentialsDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + mOperationalCredentialsDelegate = params.operationalCredentialsDelegate; ReturnErrorOnFailure(DeviceController::Init(params)); mPairingDelegate = params.pairingDelegate; diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index a635edb958a632..f89ca44bd3d980 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -136,6 +136,13 @@ struct ControllerInitParams */ bool removeFromFabricTableOnShutdown = true; + /** + * Specifies whether to utilize the fabric table entry for the given FabricIndex + * for initialization. If provided and neither the operational key pair nor the NOC + * chain are provided, then attempt to locate a fabric corresponding to the given FabricIndex. + */ + chip::Optional fabricIndex; + chip::VendorId controllerVendorId; }; @@ -351,6 +358,20 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController */ CHIP_ERROR InitControllerNOCChain(const ControllerInitParams & params); + /** + * @brief Update the NOC chain of controller. + * + * @param[in] noc NOC in CHIP certificate format. + * @param[in] icac ICAC in CHIP certificate format. If no icac, an empty ByteSpan should be passed. + * @param[in] externalOperationalKeypair External operational keypair. If null, use keypair in OperationalKeystore. + * @param[in] operationalKeypairExternalOwned If true, external operational keypair must outlive the fabric. + * If false, the keypair is copied and owned in heap of a FabricInfo. + * + * @return CHIP_ERROR CHIP_NO_ERROR on success. + */ + CHIP_ERROR UpdateControllerNOCChain(const ByteSpan & noc, const ByteSpan & icac, Crypto::P256Keypair * operationalKeypair, + bool operationalKeypairExternalOwned); + protected: enum class State { @@ -374,6 +395,8 @@ class DLL_EXPORT DeviceController : public AbstractDnssdDiscoveryController bool mRemoveFromFabricTableOnShutdown = true; + FabricTable::AdvertiseIdentity mAdvertiseIdentity = FabricTable::AdvertiseIdentity::Yes; + // TODO(cecille): Make this configuarable. static constexpr int kMaxCommissionableNodes = 10; Dnssd::DiscoveredNodeData mCommissionableNodes[kMaxCommissionableNodes]; diff --git a/src/controller/CHIPDeviceControllerFactory.cpp b/src/controller/CHIPDeviceControllerFactory.cpp index 25bcd12b190a09..115d865e0ac0cb 100644 --- a/src/controller/CHIPDeviceControllerFactory.cpp +++ b/src/controller/CHIPDeviceControllerFactory.cpp @@ -310,6 +310,10 @@ void DeviceControllerFactory::PopulateInitParams(ControllerInitParams & controll controllerParams.controllerVendorId = params.controllerVendorId; controllerParams.enableServerInteractions = params.enableServerInteractions; + if (params.fabricIndex.HasValue()) + { + controllerParams.fabricIndex.SetValue(params.fabricIndex.Value()); + } } void DeviceControllerFactory::ControllerInitialized(const DeviceController & controller) diff --git a/src/controller/CHIPDeviceControllerFactory.h b/src/controller/CHIPDeviceControllerFactory.h index 6b4aa77fdc00c8..94585d4fbf877f 100644 --- a/src/controller/CHIPDeviceControllerFactory.h +++ b/src/controller/CHIPDeviceControllerFactory.h @@ -102,6 +102,13 @@ struct SetupParams */ bool removeFromFabricTableOnShutdown = true; + /** + * Specifies whether to utilize the fabric table entry for the given FabricIndex + * for initialization. If provided and neither the operational key pair nor the NOC + * chain are provided, then attempt to locate a fabric corresponding to the given FabricIndex. + */ + chip::Optional fabricIndex; + Credentials::DeviceAttestationVerifier * deviceAttestationVerifier = nullptr; CommissioningDelegate * defaultCommissioner = nullptr; };