From 0d64c0b8ce98318cf8b14078838eb2db2caa1da9 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 11 Aug 2022 14:57:40 -0400 Subject: [PATCH] Spin up commissioners in chip-tool as needed. (#21830) The basic change is that instead of spinning up commissioners during "stack startup" for the three default identities plus the command's identity (in case that's not one of the three defaults) we: 1) Spin up the commissioner for the command's identity when we're actually running the command (on the Matter event loop). This allows commands in interactive mode to use an identity that is not one of the three default identities and fixes https://github.com/project-chip/connectedhomeip/issues/21828 2) Spin up commissioners as needed when they are requested. This allows YAML test steps (which are not distinct commands) to use an identity that is not one of the three default identities. --- .../chip-tool/commands/common/CHIPCommand.cpp | 130 +++++++++++------- .../chip-tool/commands/common/CHIPCommand.h | 13 +- 2 files changed, 88 insertions(+), 55 deletions(-) diff --git a/examples/chip-tool/commands/common/CHIPCommand.cpp b/examples/chip-tool/commands/common/CHIPCommand.cpp index e511ebb9795325..663ebee8257d61 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.cpp +++ b/examples/chip-tool/commands/common/CHIPCommand.cpp @@ -43,6 +43,9 @@ constexpr chip::FabricId kIdentityGammaFabricId = 3; constexpr chip::FabricId kIdentityOtherFabricId = 4; constexpr const char * kTrustStorePathVariable = "CHIPTOOL_PAA_TRUST_STORE_PATH"; +const chip::Credentials::AttestationTrustStore * CHIPCommand::sPaaTrustStore = nullptr; +chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric }; + namespace { const chip::Credentials::AttestationTrustStore * GetTestFileAttestationTrustStore(const char * paaTrustStorePath) { @@ -86,10 +89,10 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() // and the DeviceControllerFactory all "share" in the same underlying data. // Different commissioner implementations may want to use alternate implementations // of GroupDataProvider for injection through factoryInitParams. - mGroupDataProvider.SetStorageDelegate(&mDefaultStorage); - ReturnLogErrorOnFailure(mGroupDataProvider.Init()); - chip::Credentials::SetGroupDataProvider(&mGroupDataProvider); - factoryInitParams.groupDataProvider = &mGroupDataProvider; + sGroupDataProvider.SetStorageDelegate(&mDefaultStorage); + ReturnLogErrorOnFailure(sGroupDataProvider.Init()); + chip::Credentials::SetGroupDataProvider(&sGroupDataProvider); + factoryInitParams.groupDataProvider = &sGroupDataProvider; uint16_t port = mDefaultStorage.GetListenPort(); if (port != 0) @@ -108,11 +111,10 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() mPaaTrustStorePath.SetValue(trust_store_path); } } - const chip::Credentials::AttestationTrustStore * trustStore = mPaaTrustStorePath.HasValue() - ? GetTestFileAttestationTrustStore(mPaaTrustStorePath.Value()) - : chip::Credentials::GetTestAttestationTrustStore(); + sPaaTrustStore = mPaaTrustStorePath.HasValue() ? GetTestFileAttestationTrustStore(mPaaTrustStorePath.Value()) + : chip::Credentials::GetTestAttestationTrustStore(); ; - if (mPaaTrustStorePath.HasValue() && trustStore == nullptr) + if (mPaaTrustStorePath.HasValue() && sPaaTrustStore == nullptr) { ChipLogError(chipTool, "No PAAs found in path: %s", mPaaTrustStorePath.Value()); ChipLogError(chipTool, @@ -123,42 +125,7 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack() return CHIP_ERROR_INVALID_ARGUMENT; } - ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityNull, kIdentityNullFabricId, trustStore)); - ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityAlpha, kIdentityAlphaFabricId, trustStore)); - ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityBeta, kIdentityBetaFabricId, trustStore)); - ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityGamma, kIdentityGammaFabricId, trustStore)); - - std::string name = GetIdentity(); - chip::FabricId fabricId = strtoull(name.c_str(), nullptr, 0); - if (fabricId >= kIdentityOtherFabricId) - { - ReturnLogErrorOnFailure(InitializeCommissioner(name, fabricId, trustStore)); - } - - // Initialize Group Data, including IPK - for (auto it = mCommissioners.begin(); it != mCommissioners.end(); it++) - { - if (0 == it->first.compare(kIdentityNull)) - { - continue; - } - const chip::Controller::DeviceCommissioner * controller = it->second.get(); - - chip::FabricIndex fabricIndex = controller->GetFabricIndex(); - uint8_t compressed_fabric_id[sizeof(uint64_t)]; - chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id); - ReturnLogErrorOnFailure(controller->GetCompressedFabricIdBytes(compressed_fabric_id_span)); - - ReturnLogErrorOnFailure(chip::GroupTesting::InitData(&mGroupDataProvider, fabricIndex, compressed_fabric_id_span)); - - // Configure the default IPK for all fabrics used by CHIP-tool. The epoch - // key is the same, but the derived keys will be different for each fabric. - // This has to be done here after we know the Compressed Fabric ID of all - // chip-tool-managed fabrics - chip::ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); - ReturnLogErrorOnFailure( - chip::Credentials::SetSingleIpkEpochKey(&mGroupDataProvider, fabricIndex, defaultIpk, compressed_fabric_id_span)); - } + ReturnLogErrorOnFailure(InitializeCommissioner(kIdentityNull, kIdentityNullFabricId)); return CHIP_NO_ERROR; } @@ -183,6 +150,40 @@ void CHIPCommand::MaybeTearDownStack() StopTracing(); } +CHIP_ERROR CHIPCommand::EnsureCommissionerForIdentity(std::string identity) +{ + if (mCommissioners.find(identity) != mCommissioners.end()) + { + return CHIP_NO_ERROR; + } + + // Need to initialize the commissioner. + chip::FabricId fabricId; + if (identity == kIdentityAlpha) + { + fabricId = kIdentityAlphaFabricId; + } + else if (identity == kIdentityBeta) + { + fabricId = kIdentityBetaFabricId; + } + else if (identity == kIdentityGamma) + { + fabricId = kIdentityGammaFabricId; + } + else + { + fabricId = strtoull(identity.c_str(), nullptr, 0); + if (fabricId < kIdentityOtherFabricId) + { + ChipLogError(chipTool, "Invalid identity: %s", identity.c_str()); + return CHIP_ERROR_INVALID_ARGUMENT; + } + } + + return InitializeCommissioner(identity, fabricId); +} + CHIP_ERROR CHIPCommand::Run() { ReturnErrorOnFailure(MaybeSetUpStack()); @@ -313,13 +314,18 @@ chip::FabricId CHIPCommand::CurrentCommissionerId() chip::Controller::DeviceCommissioner & CHIPCommand::CurrentCommissioner() { - auto item = mCommissioners.find(GetIdentity()); - return *item->second; + return GetCommissioner(GetIdentity()); } -chip::Controller::DeviceCommissioner & CHIPCommand::GetCommissioner(const char * identity) +chip::Controller::DeviceCommissioner & CHIPCommand::GetCommissioner(std::string identity) { + // We don't have a great way to handle commissioner setup failures here. + // This only matters for commands (like TestCommand) that involve multiple + // identities. + VerifyOrDie(EnsureCommissionerForIdentity(identity) == CHIP_NO_ERROR); + auto item = mCommissioners.find(identity); + VerifyOrDie(item != mCommissioners.end()); return *item->second; } @@ -328,8 +334,7 @@ void CHIPCommand::ShutdownCommissioner(std::string key) mCommissioners[key].get()->Shutdown(); } -CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId fabricId, - const chip::Credentials::AttestationTrustStore * trustStore) +CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId fabricId) { chip::Platform::ScopedMemoryBuffer noc; chip::Platform::ScopedMemoryBuffer icac; @@ -338,7 +343,7 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId f std::unique_ptr commissioner = std::make_unique(); chip::Controller::SetupParams commissionerParams; - ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, trustStore)); + ReturnLogErrorOnFailure(mCredIssuerCmds->SetupDeviceAttestation(commissionerParams, sPaaTrustStore)); VerifyOrReturnError(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); VerifyOrReturnError(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); @@ -375,6 +380,24 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId f commissionerParams.controllerVendorId = chip::VendorId::TestVendor1; ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().SetupCommissioner(commissionerParams, *(commissioner.get()))); + + if (key != kIdentityNull) + { + // Initialize Group Data, including IPK + chip::FabricIndex fabricIndex = commissioner->GetFabricIndex(); + uint8_t compressed_fabric_id[sizeof(uint64_t)]; + chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id); + ReturnLogErrorOnFailure(commissioner->GetCompressedFabricIdBytes(compressed_fabric_id_span)); + + ReturnLogErrorOnFailure(chip::GroupTesting::InitData(&sGroupDataProvider, fabricIndex, compressed_fabric_id_span)); + + // Configure the default IPK for all fabrics used by CHIP-tool. The epoch + // key is the same, but the derived keys will be different for each fabric. + chip::ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); + ReturnLogErrorOnFailure( + chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, fabricIndex, defaultIpk, compressed_fabric_id_span)); + } + mCommissioners[key] = std::move(commissioner); return CHIP_NO_ERROR; @@ -383,7 +406,12 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId f void CHIPCommand::RunQueuedCommand(intptr_t commandArg) { auto * command = reinterpret_cast(commandArg); - CHIP_ERROR err = command->RunCommand(); + CHIP_ERROR err = command->EnsureCommissionerForIdentity(command->GetIdentity()); + if (err == CHIP_NO_ERROR) + { + err = command->RunCommand(); + } + if (err != CHIP_NO_ERROR) { command->SetCommandExitStatus(err); diff --git a/examples/chip-tool/commands/common/CHIPCommand.h b/examples/chip-tool/commands/common/CHIPCommand.h index 47bcc78a55080b..1714928ea1096c 100644 --- a/examples/chip-tool/commands/common/CHIPCommand.h +++ b/examples/chip-tool/commands/common/CHIPCommand.h @@ -124,7 +124,7 @@ class CHIPCommand : public Command chip::PersistentStorageOperationalKeystore mOperationalKeystore; chip::Credentials::PersistentStorageOpCertStore mOpCertStore; - chip::Credentials::GroupDataProviderImpl mGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric }; + static chip::Credentials::GroupDataProviderImpl sGroupDataProvider; CredentialIssuerCommands * mCredIssuerCmds; std::string GetIdentity(); @@ -135,14 +135,15 @@ class CHIPCommand : public Command // --identity "instance name" when running a command. ChipDeviceCommissioner & CurrentCommissioner(); - ChipDeviceCommissioner & GetCommissioner(const char * identity); + ChipDeviceCommissioner & GetCommissioner(std::string identity); private: CHIP_ERROR MaybeSetUpStack(); void MaybeTearDownStack(); - CHIP_ERROR InitializeCommissioner(std::string key, chip::FabricId fabricId, - const chip::Credentials::AttestationTrustStore * trustStore); + CHIP_ERROR EnsureCommissionerForIdentity(std::string identity); + + CHIP_ERROR InitializeCommissioner(std::string key, chip::FabricId fabricId); void ShutdownCommissioner(std::string key); chip::FabricId CurrentCommissionerId(); static std::map> mCommissioners; @@ -153,6 +154,10 @@ class CHIPCommand : public Command chip::Optional mBleAdapterId; chip::Optional mPaaTrustStorePath; + // Cached trust store so commands other than the original startup command + // can spin up commissioners as needed. + static const chip::Credentials::AttestationTrustStore * sPaaTrustStore; + static void RunQueuedCommand(intptr_t commandArg); CHIP_ERROR mCommandExitStatus = CHIP_ERROR_INTERNAL;