Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[icd] integrate ICD management command into CHIP tool #30863

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ba7cd9d
[icd] integrate ICD management command into CHIP tool
erjiaqing Dec 1, 2023
d1e4510
Delete entry on failure
erjiaqing Dec 7, 2023
a26c24b
Fix build
erjiaqing Dec 7, 2023
d6d3b3f
Update examples/chip-tool/commands/pairing/PairingCommand.cpp
yunhanw-google Dec 7, 2023
5286998
Update examples/chip-tool/commands/common/CHIPCommand.cpp
yunhanw-google Dec 7, 2023
b0977c1
Update examples/chip-tool/commands/icd/ICDCommand.cpp
yunhanw-google Dec 7, 2023
b8be709
Update examples/chip-tool/commands/pairing/PairingCommand.cpp
yunhanw-google Dec 7, 2023
7e403a7
Update examples/chip-tool/commands/pairing/PairingCommand.cpp
yunhanw-google Dec 7, 2023
ed0b33d
Update examples/chip-tool/commands/pairing/PairingCommand.cpp
yunhanw-google Dec 7, 2023
72da2df
address comments
yunhanw-google Dec 7, 2023
75986e0
address comments
yunhanw-google Dec 7, 2023
5e22065
address comments
yunhanw-google Dec 7, 2023
3d0750f
Restyled by clang-format
restyled-commits Dec 7, 2023
2a8f92d
fix typo
yunhanw-google Dec 8, 2023
e88fe61
Update
erjiaqing Dec 8, 2023
9494bcd
address comments
yunhanw-google Dec 8, 2023
31ff040
remove portected GetICDClientStorage
yunhanw-google Dec 8, 2023
a827097
polish comments
yunhanw-google Dec 8, 2023
39b193f
update doxygen
yunhanw-google Dec 8, 2023
ddc8609
Restyled by whitespace
restyled-commits Dec 8, 2023
6217a2d
Restyled by clang-format
restyled-commits Dec 8, 2023
f08e04f
update description
yunhanw-google Dec 8, 2023
f308a6c
Update src/app/icd/client/DefaultICDClientStorage.h
yunhanw-google Dec 8, 2023
0705a8b
Update src/app/icd/client/DefaultICDClientStorage.h
yunhanw-google Dec 8, 2023
44ab95b
Update examples/chip-tool/commands/common/CHIPCommand.cpp
yunhanw-google Dec 8, 2023
0368a1e
Update examples/chip-tool/commands/icd/ICDCommand.cpp
yunhanw-google Dec 8, 2023
f181fb7
address comments
yunhanw-google Dec 8, 2023
535671b
update file description
yunhanw-google Dec 8, 2023
371579f
add missing change
yunhanw-google Dec 9, 2023
ef3e4e5
Restyled by whitespace
restyled-commits Dec 9, 2023
a38ba96
Update examples/chip-tool/commands/common/CHIPCommand.cpp
yunhanw-google Dec 11, 2023
2386736
fix the assert text
yunhanw-google Dec 11, 2023
e348529
update comments
yunhanw-google Dec 11, 2023
a9e5645
address comment
yunhanw-google Dec 11, 2023
10ea5cd
Restyled by clang-format
restyled-commits Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/chip-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ static_library("chip-tool-utils") {
"commands/discover/DiscoverCommand.cpp",
"commands/discover/DiscoverCommissionablesCommand.cpp",
"commands/discover/DiscoverCommissionersCommand.cpp",
"commands/icd/ICDCommand.cpp",
"commands/icd/ICDCommand.h",
"commands/pairing/OpenCommissioningWindowCommand.cpp",
"commands/pairing/OpenCommissioningWindowCommand.h",
"commands/pairing/PairingCommand.cpp",
Expand Down Expand Up @@ -100,6 +102,7 @@ static_library("chip-tool-utils") {

public_deps = [
"${chip_root}/examples/common/tracing:commandline",
"${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/app/server",
"${chip_root}/src/app/tests/suites/commands/interaction_model",
"${chip_root}/src/controller/data_model",
Expand Down
13 changes: 12 additions & 1 deletion examples/chip-tool/commands/common/CHIPCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ constexpr char kCDTrustStorePathVariable[] = "CHIPTOOL_CD_TRUST_STORE_PATH"

const chip::Credentials::AttestationTrustStore * CHIPCommand::sTrustStore = nullptr;
chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGroupsPerFabric, kMaxGroupKeysPerFabric };
// All fabrics share the same ICD client storage.
chip::app::DefaultICDClientStorage CHIPCommand::sICDClientStorage;
chip::Crypto::RawKeySessionKeystore CHIPCommand::sSessionKeystore;

namespace {
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -100,13 +103,19 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack()
ReturnLogErrorOnFailure(mOperationalKeystore.Init(&mDefaultStorage));
ReturnLogErrorOnFailure(mOpCertStore.Init(&mDefaultStorage));

// chip-tool uses a non-persistent keystore.
// ICD storage lifetime is currently tied to the chip-tool's lifetime. Since chip-tool interactive mode is currently used for
// ICD commissioning and check-in validation, this temporary storage meets the test requirements.
// TODO: Implement persistent ICD storage for the chip-tool.
ReturnLogErrorOnFailure(sICDClientStorage.Init(&mDefaultStorage, &sSessionKeystore));

chip::Controller::FactoryInitParams factoryInitParams;

factoryInitParams.fabricIndependentStorage = &mDefaultStorage;
factoryInitParams.operationalKeystore = &mOperationalKeystore;
factoryInitParams.opCertStore = &mOpCertStore;
factoryInitParams.enableServerInteractions = NeedsOperationalAdvertising();
factoryInitParams.sessionKeystore = &mSessionKeystore;
factoryInitParams.sessionKeystore = &sSessionKeystore;

// Init group data provider that will be used for all group keys and IPKs for the
// chip-tool-configured fabrics. This is OK to do once since the fabric tables
Expand Down Expand Up @@ -486,6 +495,8 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(CommissionerIdentity & identity,
chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, fabricIndex, defaultIpk, compressed_fabric_id_span));
}

CHIPCommand::sICDClientStorage.UpdateFabricList(commissioner->GetFabricIndex());
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved

mCommissioners[identity] = std::move(commissioner);

return CHIP_NO_ERROR;
Expand Down
4 changes: 3 additions & 1 deletion examples/chip-tool/commands/common/CHIPCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Command.h"

#include <TracingCommandLineArgument.h>
#include <app/icd/client/DefaultICDClientStorage.h>
#include <commands/common/CredentialIssuerCommands.h>
#include <commands/example/ExampleCredentialIssuerCommands.h>
#include <credentials/GroupDataProviderImpl.h>
Expand Down Expand Up @@ -155,9 +156,10 @@ class CHIPCommand : public Command
#endif // CONFIG_USE_LOCAL_STORAGE
chip::PersistentStorageOperationalKeystore mOperationalKeystore;
chip::Credentials::PersistentStorageOpCertStore mOpCertStore;
chip::Crypto::RawKeySessionKeystore mSessionKeystore;
static chip::Crypto::RawKeySessionKeystore sSessionKeystore;

static chip::Credentials::GroupDataProviderImpl sGroupDataProvider;
static chip::app::DefaultICDClientStorage sICDClientStorage;
CredentialIssuerCommands * mCredIssuerCmds;

std::string GetIdentity();
Expand Down
69 changes: 69 additions & 0 deletions examples/chip-tool/commands/icd/ICDCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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 "ICDCommand.h"

#include <crypto/DefaultSessionKeystore.h>
#include <crypto/RawKeySessionKeystore.h>

using namespace ::chip;

CHIP_ERROR ICDListCommand::RunCommand()
{
app::ICDClientInfo info;
auto iter = CHIPCommand::sICDClientStorage.IterateICDClientInfo();
char icdSymmetricKeyHex[Crypto::kAES_CCM128_Key_Length * 2 + 1];

fprintf(stderr, " +-----------------------------------------------------------------------------+\n");
fprintf(stderr, " | %-75s |\n", "Known ICDs:");
fprintf(stderr, " +-----------------------------------------------------------------------------+\n");
fprintf(stderr, " | %20s | %15s | %15s | %16s |\n", "Fabric Index:Node ID", "Start Counter", "Counter Offset",
"MonitoredSubject");

while (iter->Next(info))
{
fprintf(stderr, " +-----------------------------------------------------------------------------+\n");
fprintf(stderr, " | %3" PRIu32 ":" ChipLogFormatX64 " | %15" PRIu32 " | %15" PRIu32 " | " ChipLogFormatX64 " |\n",
static_cast<uint32_t>(info.peer_node.GetFabricIndex()), ChipLogValueX64(info.peer_node.GetNodeId()),
info.start_icd_counter, info.offset, ChipLogValueX64(info.monitored_subject));

static_assert(std::is_same<decltype(CHIPCommand::sSessionKeystore), Crypto::RawKeySessionKeystore>::value,
"The following BytesToHex can copy/encode the key bytes from sharedKey to hexadecimal format, which only "
"works for RawKeySessionKeystore");
Encoding::BytesToHex(info.shared_key.As<Crypto::Symmetric128BitsKeyByteArray>(), Crypto::kAES_CCM128_Key_Length,
icdSymmetricKeyHex, sizeof(icdSymmetricKeyHex), chip::Encoding::HexFlags::kNullTerminate);
fprintf(stderr, " | Symmetric Key: %60s |\n", icdSymmetricKeyHex);
}

fprintf(stderr, " +-----------------------------------------------------------------------------+\n");

iter->Release();
SetCommandExitStatus(CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}

void registerCommandsICD(Commands & commands, CredentialIssuerCommands * credsIssuerConfig)
{
const char * name = "ICD";

commands_list list = {
make_unique<ICDListCommand>(credsIssuerConfig),
};

commands.RegisterCommandSet(name, list, "Commands for client-side ICD management.");
}
45 changes: 45 additions & 0 deletions examples/chip-tool/commands/icd/ICDCommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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.
*
*/

#pragma once

#include "../common/CHIPCommand.h"
#include "commands/common/Commands.h"

#include <lib/support/Span.h>

class ICDCommand : public CHIPCommand
{
public:
ICDCommand(const char * commandName, CredentialIssuerCommands * credIssuerCmds, const char * description) :
CHIPCommand(commandName, credIssuerCmds, description)
{}

chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(10); }
};

class ICDListCommand : public ICDCommand
{
public:
ICDListCommand(CredentialIssuerCommands * credIssuerCmds) :
ICDCommand("list", credIssuerCmds, "List ICDs registed by this controller.")
{}
CHIP_ERROR RunCommand() override;
};

void registerCommandsICD(Commands & commands, CredentialIssuerCommands * credsIssuerConfig);
34 changes: 33 additions & 1 deletion examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ CHIP_ERROR PairingCommand::RunCommand()
// Clear the CATs in OperationalCredentialsIssuer
mCredIssuerCmds->SetCredentialIssuerCATValues(kUndefinedCATs);

mDeviceIsICD = false;

if (mCASEAuthTags.HasValue() && mCASEAuthTags.Value().size() <= kMaxSubjectCATAttributeCount)
{
CATValues cats = kUndefinedCATs;
Expand Down Expand Up @@ -385,6 +387,16 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
}
else
{
// When ICD device commissioning fails, the ICDClientInfo stored in OnICDRegistrationComplete needs to be removed.
if (mDeviceIsICD)
{
CHIP_ERROR deleteEntryError =
CHIPCommand::sICDClientStorage.DeleteEntry(ScopedNodeId(mNodeId, CurrentCommissioner().GetFabricIndex()));
if (deleteEntryError != CHIP_NO_ERROR)
{
ChipLogError(chipTool, "Failed to delete ICD entry: %s", ErrorStr(err));
}
}
ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
}

Expand All @@ -395,6 +407,7 @@ void PairingCommand::OnICDRegistrationInfoRequired()
{
// Since we compute our ICD Registration info up front, we can call ICDRegistrationInfoReady() directly.
CurrentCommissioner().ICDRegistrationInfoReady();
mDeviceIsICD = true;
}

void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounter)
Expand All @@ -404,8 +417,27 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte
chip::Encoding::BytesToHex(mICDSymmetricKey.Value().data(), mICDSymmetricKey.Value().size(), icdSymmetricKeyHex,
sizeof(icdSymmetricKeyHex), chip::Encoding::HexFlags::kNullTerminate);

// TODO: Persist symmetric key.
app::ICDClientInfo clientInfo;
clientInfo.peer_node = ScopedNodeId(nodeId, CurrentCommissioner().GetFabricIndex());
clientInfo.monitored_subject = mICDMonitoredSubject.Value();
clientInfo.start_icd_counter = icdCounter;

CHIP_ERROR err = CHIPCommand::sICDClientStorage.SetKey(clientInfo, mICDSymmetricKey.Value());
if (err == CHIP_NO_ERROR)
{
err = CHIPCommand::sICDClientStorage.StoreEntry(clientInfo);
}

if (err != CHIP_NO_ERROR)
{
CHIPCommand::sICDClientStorage.RemoveKey(clientInfo);
ChipLogError(chipTool, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId),
err.AsString());
SetCommandExitStatus(err);
return;
}

ChipLogProgress(chipTool, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId));
ChipLogProgress(chipTool,
"ICD Registration Complete for device " ChipLogFormatX64 " / Check-In NodeID: " ChipLogFormatX64
" / Monitored Subject: " ChipLogFormatX64 " / Symmetric Key: %s",
Expand Down
2 changes: 2 additions & 0 deletions examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,13 @@ class PairingCommand : public CHIPCommand,
uint64_t mDiscoveryFilterCode;
char * mDiscoveryFilterInstanceName;

bool mDeviceIsICD;
uint8_t mRandomGeneratedICDSymmetricKey[chip::Crypto::kAES_CCM128_Key_Length];

// For unpair
chip::Platform::UniquePtr<chip::Controller::CurrentFabricRemover> mCurrentFabricRemover;
chip::Callback::Callback<chip::Controller::OnCurrentFabricRemove> mCurrentFabricRemoveCallback;

static void OnCurrentFabricRemove(void * context, NodeId remoteNodeId, CHIP_ERROR status);
void PersistIcdInfo();
};
2 changes: 2 additions & 0 deletions examples/chip-tool/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "commands/delay/Commands.h"
#include "commands/discover/Commands.h"
#include "commands/group/Commands.h"
#include "commands/icd/ICDCommand.h"
#include "commands/interactive/Commands.h"
#include "commands/pairing/Commands.h"
#include "commands/payload/Commands.h"
Expand All @@ -40,6 +41,7 @@ int main(int argc, char * argv[])
Commands commands;
registerCommandsDelay(commands, &credIssuerCommands);
registerCommandsDiscover(commands, &credIssuerCommands);
registerCommandsICD(commands, &credIssuerCommands);
registerCommandsInteractive(commands, &credIssuerCommands);
registerCommandsPayload(commands);
registerCommandsPairing(commands, &credIssuerCommands);
Expand Down
1 change: 1 addition & 0 deletions examples/tv-casting-app/tv-casting-common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ chip_data_model("tv-casting-common") {

deps = [
"${chip_root}/examples/common/tracing:commandline",
"${chip_root}/src/app/icd/client:manager",
"${chip_root}/src/app/tests/suites/commands/interaction_model",
"${chip_root}/src/lib/support/jsontlv",
"${chip_root}/src/tracing",
Expand Down
15 changes: 15 additions & 0 deletions src/app/icd/client/DefaultICDClientStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
* limitations under the License.
*/

// Do not use the DefaultICDClientStorage class in settings where fabric indices are not stable.
// This class relies on the stability of fabric indices for efficient storage and retrieval of ICD client information.
// If fabric indices are not stable, the functionality of this class will be compromised and can lead to unexpected behavior.

#pragma once

#include "ICDClientStorage.h"
Expand Down Expand Up @@ -52,6 +56,17 @@ class DefaultICDClientStorage : public ICDClientStorage

ICDClientInfoIterator * IterateICDClientInfo() override;

/**
* When decrypting check-in messages, the system needs to iterate through all keys
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
* from all ICD clientInfos. In DefaultICDClientStorage, ICDClientInfos for the same fabric are stored in
* storage using the fabricIndex as the key. To retrieve all relevant ICDClientInfos
* from storage, the system needs to know all fabricIndices in advance. The
* `UpdateFabricList` function provides a way to inject newly created fabricIndices
* into a dedicated table. It is recommended to call this function whenever a controller is created
* with a new fabric index.
*
* @param[in] fabricIndex The newly created fabric index.
*/
CHIP_ERROR UpdateFabricList(FabricIndex fabricIndex);

CHIP_ERROR SetKey(ICDClientInfo & clientInfo, const ByteSpan keyData) override;
Expand Down
Loading