Setup controller by given fabric index without providing NOC chain and update NOC after DeviceController::Init (#32194)
diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp
index 50afb6e..fa65b96 100644
--- a/src/controller/CHIPDeviceController.cpp
+++ b/src/controller/CHIPDeviceController.cpp
@@ -112,14 +112,24 @@
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;
@@ -306,8 +316,62 @@
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;
}
@@ -398,6 +462,8 @@
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 a60e206..979a5f0 100644
--- a/src/controller/CHIPDeviceController.h
+++ b/src/controller/CHIPDeviceController.h
@@ -135,6 +135,13 @@
*/
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> fabricIndex;
+
chip::VendorId controllerVendorId;
};
@@ -350,6 +357,21 @@
*/
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 is present, 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
{
@@ -373,6 +395,8 @@
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 25bcd12..115d865 100644
--- a/src/controller/CHIPDeviceControllerFactory.cpp
+++ b/src/controller/CHIPDeviceControllerFactory.cpp
@@ -310,6 +310,10 @@
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 764149c..3bb560a 100644
--- a/src/controller/CHIPDeviceControllerFactory.h
+++ b/src/controller/CHIPDeviceControllerFactory.h
@@ -102,6 +102,13 @@
*/
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> fabricIndex;
+
Credentials::DeviceAttestationVerifier * deviceAttestationVerifier = nullptr;
CommissioningDelegate * defaultCommissioner = nullptr;
};