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

Fix KeySetRemove to fail on key set index 0 #28524

Merged
merged 9 commits into from
Aug 10, 2023
8 changes: 5 additions & 3 deletions src/app/CommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ Status CommandHandler::ProcessCommandDataIB(CommandDataIB::Parser & aCommandElem

if (CommandIsFabricScoped(concretePath.mClusterId, concretePath.mCommandId))
{
// SPEC: Else if the command in the path is fabric-scoped and there is no accessing fabric,
// a CommandStatusIB SHALL be generated with the UNSUPPORTED_ACCESS Status Code.

// Fabric-scoped commands are not allowed before a specific accessing fabric is available.
// This is mostly just during a PASE session before AddNOC.
if (GetAccessingFabricIndex() == kUndefinedFabricIndex)
Expand Down Expand Up @@ -470,8 +473,7 @@ CHIP_ERROR CommandHandler::AddStatus(const ConcreteCommandPath & aCommandPath, c
return AddStatusInternal(aCommandPath, StatusIB(aStatus));
}

CHIP_ERROR CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Status aStatus,
const char * aMessage)
void CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Status aStatus, const char * aMessage)
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
{
if (aStatus != Status::Success)
{
Expand All @@ -482,7 +484,7 @@ CHIP_ERROR CommandHandler::AddStatusAndLogIfFailure(const ConcreteCommandPath &
ChipLogValueIMStatus(aStatus), aMessage);
}

return AddStatus(aCommandPath, aStatus);
LogErrorOnFailure(AddStatus(aCommandPath, aStatus));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}

CHIP_ERROR CommandHandler::AddClusterSpecificSuccess(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus)
Expand Down
7 changes: 4 additions & 3 deletions src/app/CommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ class CommandHandler : public Messaging::ExchangeDelegate
CHIP_ERROR AddStatus(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus);

// Same as AddStatus, but logs that the command represented by aCommandPath failed with the given
// error status and error message, if aStatus is an error.
CHIP_ERROR AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus,
const char * aMessage);
// error status and error message, if aStatus is an error. Errors on AddStatus are just logged
// (since the caller likely can only log and not further add a status).
void AddStatusAndLogIfFailure(const ConcreteCommandPath & aCommandPath, const Protocols::InteractionModel::Status aStatus,
const char * aMessage);

CHIP_ERROR AddClusterSpecificSuccess(const ConcreteCommandPath & aCommandPath, ClusterStatus aClusterStatus);

Expand Down
117 changes: 77 additions & 40 deletions src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,32 @@ ValidateKeySetWriteArguments(const chip::app::Clusters::GroupKeyManagement::Comm
return Status::Success;
}

constexpr uint16_t GroupKeyManagementAttributeAccess::kClusterRevision;
bool ValidateAndGetProviderAndFabric(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
Credentials::GroupDataProvider ** outGroupDataProvider, const FabricInfo ** outFabricInfo)
{
VerifyOrDie((outGroupDataProvider != nullptr) && (outFabricInfo != nullptr));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

// Internal failures on internal inconsistencies.
auto provider = GetGroupDataProvider();
auto fabric = Server::GetInstance().GetFabricTable().FindFabricWithIndex(commandObj->GetAccessingFabricIndex());

if (nullptr == provider)
{
commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on provider!");
return false;
}

if (nullptr == fabric)
{
commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on access fabric!");
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

*outGroupDataProvider = provider;
*outFabricInfo = fabric;

return true;
}

GroupKeyManagementAttributeAccess gAttribute;

Expand All @@ -420,12 +445,13 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::GroupKeyManagement::Commands::KeySetWrite::DecodableType & commandData)
{
auto provider = GetGroupDataProvider();
auto fabric = Server::GetInstance().GetFabricTable().FindFabricWithIndex(commandObj->GetAccessingFabricIndex());
Credentials::GroupDataProvider * provider = nullptr;
const FabricInfo * fabric = nullptr;

if (nullptr == provider || nullptr == fabric)
// Flight-check fabric scoping.
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (!ValidateAndGetProviderAndFabric(commandObj, commandPath, &provider, &fabric))
{
commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Internal consistency error on provider/fabric");
// Command will already have status populated from validation.
return true;
}

Expand Down Expand Up @@ -516,32 +542,30 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback(
}

// Send response
err = commandObj->AddStatus(commandPath, StatusIB(err).mStatus);
if (CHIP_NO_ERROR != err)
{
ChipLogDetail(Zcl, "GroupKeyManagementCluster: KeySetWrite failed: %" CHIP_ERROR_FORMAT, err.Format());
}
commandObj->AddStatus(commandPath, StatusIB(err).mStatus);
return true;
}

bool emberAfGroupKeyManagementClusterKeySetReadCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::GroupKeyManagement::Commands::KeySetRead::DecodableType & commandData)
{
auto fabric = commandObj->GetAccessingFabricIndex();
auto * provider = GetGroupDataProvider();
Credentials::GroupDataProvider * provider = nullptr;
const FabricInfo * fabric = nullptr;

if (nullptr == provider)
// Flight-check fabric scoping.
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (!ValidateAndGetProviderAndFabric(commandObj, commandPath, &provider, &fabric))
{
commandObj->AddStatus(commandPath, Status::Failure);
// Command will already have status populated from validation.
return true;
}

FabricIndex fabricIndex = fabric->GetFabricIndex();
GroupDataProvider::KeySet keyset;
if (CHIP_NO_ERROR != provider->GetKeySet(fabric, commandData.groupKeySetID, keyset))
if (CHIP_NO_ERROR != provider->GetKeySet(fabricIndex, commandData.groupKeySetID, keyset))
{
// KeySet ID not found
commandObj->AddStatus(commandPath, Status::NotFound);
commandObj->AddStatusAndLogIfFailure(commandPath, Status::NotFound, "Keyset ID not found in KeySetRead");
return true;
}

Expand Down Expand Up @@ -592,30 +616,41 @@ bool emberAfGroupKeyManagementClusterKeySetRemoveCallback(
const chip::app::Clusters::GroupKeyManagement::Commands::KeySetRemove::DecodableType & commandData)

{
auto fabric = commandObj->GetAccessingFabricIndex();
auto * provider = GetGroupDataProvider();
Status status = Status::Failure;
Credentials::GroupDataProvider * provider = nullptr;
const FabricInfo * fabric = nullptr;

if (nullptr != provider)
// Flight-check fabric scoping.
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (!ValidateAndGetProviderAndFabric(commandObj, commandPath, &provider, &fabric))
{
// Remove keyset
CHIP_ERROR err = provider->RemoveKeySet(fabric, commandData.groupKeySetID);
if (CHIP_ERROR_KEY_NOT_FOUND == err)
{
status = Status::NotFound;
}
else if (CHIP_NO_ERROR == err)
{
status = Status::Success;
}
// Command will already have status populated from validation.
return true;
}

// Send response
CHIP_ERROR send_err = commandObj->AddStatus(commandPath, status);
if (CHIP_NO_ERROR != send_err)
if (commandData.groupKeySetID == GroupDataProvider::kIdentityProtectionKeySetId)
{
// SPEC: This command SHALL fail with an INVALID_COMMAND status code back to the initiator if the GroupKeySetID being
// removed is 0, which is the Key Set associated with the Identity Protection Key (IPK).
commandObj->AddStatusAndLogIfFailure(commandPath, Status::InvalidCommand,
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
"Attempted to KeySetRemove the identity protection key!");
return true;
}

// Remove keyset
FabricIndex fabricIndex = fabric->GetFabricIndex();
CHIP_ERROR err = provider->RemoveKeySet(fabricIndex, commandData.groupKeySetID);

Status status = Status::Success;
if (CHIP_ERROR_KEY_NOT_FOUND == err)
{
status = Status::NotFound;
}
else if (CHIP_NO_ERROR != err)
{
ChipLogDetail(Zcl, "GroupKeyManagementCluster: KeySetRemove failed: %" CHIP_ERROR_FORMAT, send_err.Format());
status = Status::Failure;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}

// Send status response.
commandObj->AddStatusAndLogIfFailure(commandPath, status, "KeySetRemove failed");
return true;
}

Expand Down Expand Up @@ -654,19 +689,21 @@ bool emberAfGroupKeyManagementClusterKeySetReadAllIndicesCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::GroupKeyManagement::Commands::KeySetReadAllIndices::DecodableType & commandData)
{
auto fabric = commandObj->GetAccessingFabricIndex();
auto * provider = GetGroupDataProvider();
Credentials::GroupDataProvider * provider = nullptr;
const FabricInfo * fabric = nullptr;

if (nullptr == provider)
// Flight-check fabric scoping.
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
if (!ValidateAndGetProviderAndFabric(commandObj, commandPath, &provider, &fabric))
{
commandObj->AddStatus(commandPath, Status::Failure);
// Command will already have status populated from validation.
return true;
}

auto keysIt = provider->IterateKeySets(fabric);
FabricIndex fabricIndex = fabric->GetFabricIndex();
auto keysIt = provider->IterateKeySets(fabricIndex);
if (nullptr == keysIt)
{
commandObj->AddStatus(commandPath, Status::Failure);
commandObj->AddStatusAndLogIfFailure(commandPath, Status::Failure, "Failed iteration of key set indices!");
return true;
}

Expand Down
9 changes: 9 additions & 0 deletions src/app/tests/suites/TestGroupKeyManagementCluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,15 @@ tests:
response:
error: RESOURCE_EXHAUSTED

- label: "Try to remove KeySet index 0 should fail"
command: "KeySetRemove"
arguments:
values:
- name: "GroupKeySetID"
value: 0
response:
error: INVALID_COMMAND

- label: "Write Group Keys (invalid)"
command: "writeAttribute"
attribute: "GroupKeyMap"
Expand Down
5 changes: 5 additions & 0 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,11 @@ FabricInfo * FabricTable::GetMutableFabricByIndex(FabricIndex fabricIndex)

const FabricInfo * FabricTable::FindFabricWithIndex(FabricIndex fabricIndex) const
{
if (fabricIndex == kUndefinedFabricIndex)
{
return nullptr;
}

// Try to match pending fabric first if available
if (HasPendingFabricUpdate() && (mPendingFabric.GetFabricIndex() == fabricIndex))
{
Expand Down
5 changes: 5 additions & 0 deletions src/credentials/tests/TestFabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,11 @@ void TestFabricLookup(nlTestSuite * inSuite, void * inContext)
}
NL_TEST_ASSERT(inSuite, fabricInfo->GetFabricIndex() == 2);
}

// Attempt lookup of FabricIndex 0 --> should always fail.
{
NL_TEST_ASSERT(inSuite, fabricTable.FindFabricWithIndex(0) == nullptr);
}
}

void TestFetchCATs(nlTestSuite * inSuite, void * inContext)
Expand Down
Loading