diff --git a/examples/chip-tool/commands/common/Commands.cpp b/examples/chip-tool/commands/common/Commands.cpp index e6b98bc0662b40..0e39f0afa6706d 100644 --- a/examples/chip-tool/commands/common/Commands.cpp +++ b/examples/chip-tool/commands/common/Commands.cpp @@ -25,6 +25,7 @@ #include #include +#include void Commands::Register(const char * clusterName, commands_list commandsList) { @@ -41,8 +42,8 @@ int Commands::Run(int argc, char ** argv) err = chip::Platform::MemoryInit(); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Memory failure: %s", chip::ErrorStr(err))); - err = mStorage.Init(); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Storage failure: %s", chip::ErrorStr(err))); + err = chip::GroupTesting::InitGroupData(); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Group Data failure: %s", chip::ErrorStr(err))); chip::Logging::SetLogFilter(mStorage.GetLoggingLevel()); diff --git a/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp b/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp index 0ec8ebbbcf48d1..cb720bd5d6a3b8 100644 --- a/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp +++ b/src/app/clusters/group-key-mgmt-server/group-key-mgmt-server.cpp @@ -267,7 +267,7 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback( return true; } - if (commandData.groupKeySet.epochKey0.empty() || (0 == commandData.groupKeySet.epochStartTime0)) + if (commandData.groupKeySet.epochKey0.empty() || 0 == commandData.groupKeySet.epochStartTime0) { // If the EpochKey0 field is null or its associated EpochStartTime0 field is null, // then this command SHALL fail with an INVALID_COMMAND @@ -285,7 +285,8 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback( // Epoch Key 1 if (!commandData.groupKeySet.epochKey1.empty()) { - if (commandData.groupKeySet.epochStartTime1 <= commandData.groupKeySet.epochStartTime0) + if (0 == commandData.groupKeySet.epochStartTime1 || + commandData.groupKeySet.epochStartTime1 <= commandData.groupKeySet.epochStartTime0) { // If the EpochKey1 field is not null, its associated EpochStartTime1 field SHALL contain // a later epoch start time than the epoch start time found in the EpochStartTime0 field. @@ -300,11 +301,13 @@ bool emberAfGroupKeyManagementClusterKeySetWriteCallback( // Epoch Key 2 if (!commandData.groupKeySet.epochKey2.empty()) { - keyset.num_keys_used++; - if (commandData.groupKeySet.epochStartTime2 <= commandData.groupKeySet.epochStartTime1) + if (commandData.groupKeySet.epochKey1.empty() || 0 == commandData.groupKeySet.epochStartTime2 || + commandData.groupKeySet.epochStartTime2 <= commandData.groupKeySet.epochStartTime1) { - // If the EpochKey1 field is not null, its associated EpochStartTime1 field SHALL contain - // a later epoch start time than the epoch start time found in the EpochStartTime0 field. + // If the EpochKey2 field is not null then: + // * The EpochKey1 field SHALL NOT be null + // * Its associated EpochStartTime1 field SHALL contain a later epoch start time + // than the epoch start time found in the EpochStartTime0 field. emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INVALID_COMMAND); return true; } @@ -364,35 +367,34 @@ bool emberAfGroupKeyManagementClusterKeySetReadCallback( if (keyset.num_keys_used > 0) { response.groupKeySet.epochStartTime0 = keyset.epoch_keys[0].start_time; - response.groupKeySet.epochKey0 = chip::ByteSpan(nullptr, 0); } else { response.groupKeySet.epochStartTime0 = 0; - response.groupKeySet.epochKey0 = chip::ByteSpan(nullptr, 0); } + response.groupKeySet.epochKey0 = ByteSpan(); + // Keyset 1 if (keyset.num_keys_used > 1) { response.groupKeySet.epochStartTime1 = keyset.epoch_keys[1].start_time; - response.groupKeySet.epochKey1 = chip::ByteSpan(nullptr, 0); } else { response.groupKeySet.epochStartTime1 = 0; - response.groupKeySet.epochKey1 = chip::ByteSpan(nullptr, 0); } + response.groupKeySet.epochKey1 = ByteSpan(); + // Keyset 2 if (keyset.num_keys_used > 2) { response.groupKeySet.epochStartTime2 = keyset.epoch_keys[2].start_time; - response.groupKeySet.epochKey2 = chip::ByteSpan(nullptr, 0); } else { response.groupKeySet.epochStartTime2 = 0; - response.groupKeySet.epochKey2 = chip::ByteSpan(nullptr, 0); } + response.groupKeySet.epochKey2 = ByteSpan(); CHIP_ERROR err = commandObj->AddResponseData(commandPath, response); if (CHIP_NO_ERROR != err) diff --git a/src/app/tests/TestWriteInteraction.cpp b/src/app/tests/TestWriteInteraction.cpp index a0e3af4d5d508c..cd9b7f3ee088e7 100644 --- a/src/app/tests/TestWriteInteraction.cpp +++ b/src/app/tests/TestWriteInteraction.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -417,12 +418,6 @@ void TestWriteInteraction::TestWriteRoundtrip(nlTestSuite * apSuite, void * apCo namespace { -constexpr uint16_t kMaxGroupsPerFabric = 5; -constexpr uint16_t kMaxGroupKeysPerFabric = 8; - -static chip::TestPersistentStorageDelegate sDelegate; -static chip::Credentials::GroupDataProviderImpl sProvider(sDelegate, kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); - /** * Test Suite. It lists all the test functions. */ @@ -446,13 +441,12 @@ const nlTest sTests[] = */ int Test_Setup(void * inContext) { - SetGroupDataProvider(&sProvider); VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); - VerifyOrReturnError(CHIP_NO_ERROR == sProvider.Init(), FAILURE); - VerifyOrReturnError(TestContext::Initialize(inContext) == SUCCESS, FAILURE); + VerifyOrReturnError(CHIP_NO_ERROR == chip::GroupTesting::InitGroupData(), FAILURE); + return SUCCESS; } diff --git a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml index e72319faffe01f..c58b022bae6699 100644 --- a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml +++ b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml @@ -23,6 +23,19 @@ tests: cluster: "DelayCommands" command: "WaitForCommissionee" + - label: "Read maxGroupsPerFabric" + command: "readAttribute" + attribute: "maxGroupsPerFabric" + response: + constraints: + minValue: 2 + + - label: "Read maxGroupKeysPerFabric" + command: "readAttribute" + attribute: "maxGroupKeysPerFabric" + response: + value: 2 + - label: "Add Group 1" disabled: true cluster: "Groups" @@ -167,15 +180,3 @@ tests: groupName: "Group #1", }, ] - - - label: "Read maxGroupsPerFabric" - command: "readAttribute" - attribute: "maxGroupsPerFabric" - response: - value: 1 - - - label: "Read maxGroupKeysPerFabric" - command: "readAttribute" - attribute: "maxGroupKeysPerFabric" - response: - value: 1 diff --git a/src/app/tests/suites/TestGroupMessaging.yaml b/src/app/tests/suites/TestGroupMessaging.yaml index 47a80f09899d1f..39874c28ca97a6 100644 --- a/src/app/tests/suites/TestGroupMessaging.yaml +++ b/src/app/tests/suites/TestGroupMessaging.yaml @@ -63,6 +63,39 @@ tests: - name: "groupId" value: 0x0001 + - label: "KeySet Write" + cluster: "Group Key Management" + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + groupKeySetID: 0x0101, + securityPolicy: 0, + epochKey0: "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + epochStartTime0: 1110000, + epochKey1: "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf", + epochStartTime1: 1110001, + epochKey2: "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", + epochStartTime2: 1110002, + } + response: + error: 0 + + - label: "Write Group Keys" + cluster: "Group Key Management" + command: "writeAttribute" + attribute: "groupKeyMap" + arguments: + value: + [ + { fabricIndex: 1, groupId: 0x1234, groupKeySetID: 0x0101 }, + { fabricIndex: 1, groupId: 0x0001, groupKeySetID: 0x0101 }, + ] + response: + error: 0 + # Test Pair 1 : Sends a Group Write Attribute - label: "Group Write Attribute" command: "writeAttribute" diff --git a/src/credentials/GroupDataProviderImpl.cpp b/src/credentials/GroupDataProviderImpl.cpp index 4ef35571217a39..0e53a24721880a 100644 --- a/src/credentials/GroupDataProviderImpl.cpp +++ b/src/credentials/GroupDataProviderImpl.cpp @@ -1596,6 +1596,9 @@ CHIP_ERROR GroupDataProviderImpl::SetKeySet(chip::FabricIndex fabric_index, cons keyset.policy = in_keyset.policy; keyset.keys_count = in_keyset.num_keys_used; memset(keyset.operational_keys, 0x00, sizeof(keyset.operational_keys)); + keyset.operational_keys[0].start_time = in_keyset.epoch_keys[0].start_time; + keyset.operational_keys[1].start_time = in_keyset.epoch_keys[1].start_time; + keyset.operational_keys[2].start_time = in_keyset.epoch_keys[2].start_time; // Store the operational keys and hash instead of the epoch keys for (size_t i = 0; i < in_keyset.num_keys_used; ++i) @@ -1638,8 +1641,11 @@ CHIP_ERROR GroupDataProviderImpl::GetKeySet(chip::FabricIndex fabric_index, uint out_keyset.keyset_id = keyset.keyset_id; out_keyset.policy = keyset.policy; out_keyset.num_keys_used = keyset.keys_count; - // Epoch keys are not read back + // Epoch keys are not read back, only the times memset(out_keyset.epoch_keys, 0x00, sizeof(out_keyset.epoch_keys)); + out_keyset.epoch_keys[0].start_time = keyset.operational_keys[0].start_time; + out_keyset.epoch_keys[1].start_time = keyset.operational_keys[1].start_time; + out_keyset.epoch_keys[2].start_time = keyset.operational_keys[2].start_time; return CHIP_NO_ERROR; } diff --git a/src/credentials/tests/TestGroupDataProvider.cpp b/src/credentials/tests/TestGroupDataProvider.cpp index 766f551fb440d0..82380503af384c 100644 --- a/src/credentials/tests/TestGroupDataProvider.cpp +++ b/src/credentials/tests/TestGroupDataProvider.cpp @@ -99,7 +99,7 @@ static KeySet kKeySet1(kKeysetId1, KeySet::SecurityPolicy::kLowLatency, 1); static KeySet kKeySet2(kKeysetId2, KeySet::SecurityPolicy::kLowLatency, 2); static KeySet kKeySet3(kKeysetId3, KeySet::SecurityPolicy::kStandard, 3); -uint8_t kZeroKeys[KeySet::kEpochKeysMax][EpochKey::kLengthBytes] = { { 0 }, { 0 }, { 0 } }; +uint8_t kZeroKey[EpochKey::kLengthBytes] = { 0 }; class TestListener : public GroupDataProvider::GroupListener { @@ -132,6 +132,19 @@ class TestListener : public GroupDataProvider::GroupListener }; static TestListener sListener; +bool CompareKeySets(const KeySet & keyset1, const KeySet & keyset2) +{ + VerifyOrReturnError(keyset1.policy == keyset2.policy, false); + VerifyOrReturnError(keyset1.num_keys_used == keyset2.num_keys_used, false); + VerifyOrReturnError(keyset1.epoch_keys[0].start_time == keyset2.epoch_keys[0].start_time, false); + VerifyOrReturnError(keyset1.epoch_keys[1].start_time == keyset2.epoch_keys[1].start_time, false); + VerifyOrReturnError(keyset1.epoch_keys[2].start_time == keyset2.epoch_keys[2].start_time, false); + VerifyOrReturnError(0 == memcmp(kZeroKey, keyset1.epoch_keys[0].key, EpochKey::kLengthBytes), false); + VerifyOrReturnError(0 == memcmp(kZeroKey, keyset1.epoch_keys[1].key, EpochKey::kLengthBytes), false); + VerifyOrReturnError(0 == memcmp(kZeroKey, keyset1.epoch_keys[2].key, EpochKey::kLengthBytes), false); + return true; +} + void TestStorageDelegate(nlTestSuite * apSuite, void * apContext) { chip::TestPersistentStorageDelegate delegate; @@ -709,44 +722,28 @@ void TestKeySets(nlTestSuite * apSuite, void * apContext) // Get KeySets NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId3, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet3.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet3.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet3)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId1, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId0, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId2, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet2.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet2.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet2)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId3, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet3.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet3.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet3)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId2, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet2.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet2.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet2)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); // Remove Keysets @@ -759,30 +756,20 @@ void TestKeySets(nlTestSuite * apSuite, void * apContext) NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, kKeysetId3, keyset)); NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, kKeysetId1, keyset)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId0, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId2, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet2.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet2.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet2)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId3, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet3.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet3.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet3)); NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric2, kKeysetId2, keyset)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keyset)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keyset.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keyset.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); // Remove all @@ -844,7 +831,9 @@ void TestKeySetIterator(nlTestSuite * apSuite, void * apContext) NL_TEST_ASSERT(apSuite, expected_f1.count(keyset.keyset_id) > 0); NL_TEST_ASSERT(apSuite, keyset.keyset_id == expected_f1[keyset.keyset_id].keyset_id); NL_TEST_ASSERT(apSuite, keyset.policy == expected_f1[keyset.keyset_id].policy); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[0].key, sizeof(kZeroKey))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[1].key, sizeof(kZeroKey))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[2].key, sizeof(kZeroKey))); count++; } NL_TEST_ASSERT(apSuite, count == expected_f1.size()); @@ -867,7 +856,9 @@ void TestKeySetIterator(nlTestSuite * apSuite, void * apContext) NL_TEST_ASSERT(apSuite, expected_f2.count(keyset.keyset_id) > 0); NL_TEST_ASSERT(apSuite, keyset.keyset_id == expected_f2[keyset.keyset_id].keyset_id); NL_TEST_ASSERT(apSuite, keyset.policy == expected_f2[keyset.keyset_id].policy); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keyset.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[0].key, sizeof(kZeroKey))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[1].key, sizeof(kZeroKey))); + NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKey, keyset.epoch_keys[2].key, sizeof(kZeroKey))); count++; } NL_TEST_ASSERT(apSuite, count == expected_f2.size()); @@ -935,7 +926,7 @@ void TestPerFabricData(nlTestSuite * apSuite, void * apContext) // Keys - KeySet keys; + KeySet keyset; NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->SetKeySet(kFabric2, kKeySet0)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->SetKeySet(kFabric1, kKeySet2)); @@ -944,35 +935,23 @@ void TestPerFabricData(nlTestSuite * apSuite, void * apContext) NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->SetKeySet(kFabric2, kKeySet2)); NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->SetKeySet(kFabric1, kKeySet0)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keys)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keys)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId2, keys)); - NL_TEST_ASSERT(apSuite, kKeySet2.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet2.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId2, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet2)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId2, keys)); - NL_TEST_ASSERT(apSuite, kKeySet2.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet2.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId2, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet2)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId1, keys)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId1, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId0, keys)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric1, kKeysetId0, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); // // Remove Fabric @@ -1005,24 +984,15 @@ void TestPerFabricData(nlTestSuite * apSuite, void * apContext) // Keys - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keys)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); - - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keys)); - NL_TEST_ASSERT(apSuite, kKeySet1.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet1.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId1, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet1)); - NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keys)); - NL_TEST_ASSERT(apSuite, kKeySet0.policy == keys.policy); - NL_TEST_ASSERT(apSuite, kKeySet0.num_keys_used == keys.num_keys_used); - NL_TEST_ASSERT(apSuite, 0 == memcmp(kZeroKeys, keys.epoch_keys, sizeof(kZeroKeys))); + NL_TEST_ASSERT(apSuite, CHIP_NO_ERROR == provider->GetKeySet(kFabric2, kKeysetId0, keyset)); + NL_TEST_ASSERT(apSuite, CompareKeySets(keyset, kKeySet0)); - NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 202, keys)); - NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 404, keys)); - NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 606, keys)); + NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 202, keyset)); + NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 404, keyset)); + NL_TEST_ASSERT(apSuite, CHIP_ERROR_NOT_FOUND == provider->GetKeySet(kFabric1, 606, keyset)); } void TestGroupDecryption(nlTestSuite * apSuite, void * apContext) diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 027b99fdd382e3..618c5676196b81 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -1246,8 +1246,8 @@ CHIP_ERROR GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_ * records from a Node's root public key and Fabric ID. This is a conveniance * overload that writes to a uint64_t (CompressedFabricId) type. * - * @param[in] root_public_key The root public key associated with the node's fabric - * @param[in] fabric_id The fabric ID associated with the node's fabric + * @param[in] rootPublicKey The root public key associated with the node's fabric + * @param[in] fabricId The fabric ID associated with the node's fabric * @param[out] compressedFabricId output location for compressed fabric ID * @returns a CHIP_ERROR on failure or CHIP_NO_ERROR otherwise. */ @@ -1355,7 +1355,7 @@ class SymmetricKeyContext virtual ~SymmetricKeyContext() = default; /** * @brief Perform the message encryption as described in 4.7.2. (Security Processing of Outgoing Messages) - * @param[inout] plaintext Outgoing message payload. + * @param[in,out] plaintext Outgoing message payload. * @param[in] aad Additional data (message header contents) * @param[in] nonce Nonce (Security Flags | Message Counter | Source Node ID) * @param[out] out_mic Outgoing Message Integrity Check @@ -1365,10 +1365,10 @@ class SymmetricKeyContext MutableByteSpan & out_mic) const = 0; /** * @brief Perform the message decryption as described in 4.7.3.(Security Processing of Incoming Messages) - * @param ciphertext[inout] Incoming encrypted payload - * @param aad[in] Additional data (message header contents) - * @param nonce[in] Nonce (Security Flags | Message Counter | Source Node ID) - * @param mic[in] Incoming Message Integrity Check + * @param[in,out] ciphertext Incoming encrypted payload + * @param[in] aad Additional data (message header contents) + * @param[in] nonce Nonce (Security Flags | Message Counter | Source Node ID) + * @param[in] mic Incoming Message Integrity Check * @return CHIP_ERROR */ virtual CHIP_ERROR DecryptMessage(MutableByteSpan & ciphertext, const ByteSpan & aad, const ByteSpan & nonce, @@ -1376,10 +1376,10 @@ class SymmetricKeyContext /** * @brief Perform privacy encoding as described in 4.8.2. (Privacy Processing of Outgoing Messages) - * @param header[in/out] Message header to encrypt - * @param session_id[in] Outgoing SessionID - * @param payload[in] Encrypted payload - * @param mic[in] Outgoing Message Integrity Check + * @param[in,out] header Message header to encrypt + * @param[in] session_id Outgoing SessionID + * @param[in] payload Encrypted payload + * @param[in] mic Outgoing Message Integrity Check * @return CHIP_ERROR */ virtual CHIP_ERROR EncryptPrivacy(MutableByteSpan & header, uint16_t session_id, const ByteSpan & payload, @@ -1387,10 +1387,10 @@ class SymmetricKeyContext /** * @brief Perform privacy decoding as described in 4.8.3. (Privacy Processing of Incoming Messages) - * @param header[in/out] Message header to decrypt - * @param session_id[in] Incoming SessionID - * @param payload[in] Encrypted payload - * @param mic[in] Outgoing Message Integrity Check + * @param[in,out] header Message header to decrypt + * @param[in] session_id Incoming SessionID + * @param[in] payload Encrypted payload + * @param[in] mic Outgoing Message Integrity Check * @return CHIP_ERROR */ virtual CHIP_ERROR DecryptPrivacy(MutableByteSpan & header, uint16_t session_id, const ByteSpan & payload, diff --git a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m index 2b6bb8ca8be9ac..e0fb0a3439c100 100644 --- a/src/darwin/Framework/CHIPTests/CHIPClustersTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPClustersTests.m @@ -41752,7 +41752,9 @@ - (void)testSendClusterTestGroupKeyManagementCluster_000001_ReadAttribute { id actualValue = value; - XCTAssertEqual([actualValue unsignedShortValue], 1U); + if (actualValue != nil) { + XCTAssertGreaterThanOrEqual([actualValue unsignedShortValue], 2U); + } } [expectation fulfill]; @@ -41776,7 +41778,7 @@ - (void)testSendClusterTestGroupKeyManagementCluster_000002_ReadAttribute { id actualValue = value; - XCTAssertEqual([actualValue unsignedShortValue], 1U); + XCTAssertEqual([actualValue unsignedShortValue], 2U); } [expectation fulfill]; diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 107ac8c272a676..d0ea5681e0f314 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1503,7 +1503,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; * Binds to number of GroupState entries to support per fabric */ #ifndef CHIP_CONFIG_MAX_GROUPS_PER_FABRIC -#define CHIP_CONFIG_MAX_GROUPS_PER_FABRIC 1 +#define CHIP_CONFIG_MAX_GROUPS_PER_FABRIC 2 #endif /** @@ -1514,7 +1514,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; * Binds to number of GroupState entries to support per fabric */ #ifndef CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC -#define CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC 1 +#define CHIP_CONFIG_MAX_GROUP_KEYS_PER_FABRIC 2 #endif /** diff --git a/src/lib/support/TestGroupData.h b/src/lib/support/TestGroupData.h new file mode 100644 index 00000000000000..580b768d1d3aee --- /dev/null +++ b/src/lib/support/TestGroupData.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2022 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 +#include + +namespace { + +constexpr uint16_t kMaxGroupsPerFabric = 5; +constexpr uint16_t kMaxGroupKeysPerFabric = 8; + +static chip::TestPersistentStorageDelegate sDeviceStorage; +static chip::Credentials::GroupDataProviderImpl sGroupsProvider(sDeviceStorage, kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); + +static const chip::FabricIndex kFabric1 = 1; +static const chip::GroupId kGroup1 = 0x1234; +static const chip::GroupId kGroup2 = 0x0001; +static const chip::KeysetId kKeySet1 = 0x0101; + +} // namespace + +namespace chip { + +namespace GroupTesting { + +CHIP_ERROR InitGroupData() +{ + ReturnErrorOnFailure(sGroupsProvider.Init()); + chip::Credentials::SetGroupDataProvider(&sGroupsProvider); + + const chip::Credentials::GroupDataProvider::GroupInfo group1(kGroup1, "Group #1"); + ReturnErrorOnFailure(sGroupsProvider.SetGroupInfo(kFabric1, group1)); + ReturnErrorOnFailure(sGroupsProvider.AddEndpoint(kFabric1, group1.group_id, 1)); + + const chip::Credentials::GroupDataProvider::GroupInfo group2(kGroup2, "Group #2"); + ReturnErrorOnFailure(sGroupsProvider.SetGroupInfo(kFabric1, group2)); + ReturnErrorOnFailure(sGroupsProvider.AddEndpoint(kFabric1, group2.group_id, 0)); + + chip::Credentials::GroupDataProvider::KeySet keyset1( + kKeySet1, chip::Credentials::GroupDataProvider::KeySet::SecurityPolicy::kStandard, 3); + const chip::Credentials::GroupDataProvider::EpochKey epoch_keys[] = { + { 0xaaaaaaaaaaaaaaaa, { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf } }, + { 0xbbbbbbbbbbbbbbbb, { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf } }, + { 0xcccccccccccccccc, { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf } }, + }; + memcpy(keyset1.epoch_keys, epoch_keys, sizeof(epoch_keys)); + ReturnErrorOnFailure(sGroupsProvider.SetKeySet(kFabric1, keyset1)); + + sGroupsProvider.SetGroupKeyAt(kFabric1, 0, chip::Credentials::GroupDataProvider::GroupKey(kGroup1, kKeySet1)); + sGroupsProvider.SetGroupKeyAt(kFabric1, 1, chip::Credentials::GroupDataProvider::GroupKey(kGroup2, kKeySet1)); + + return CHIP_NO_ERROR; +} + +} // namespace GroupTesting + +} // namespace chip diff --git a/src/messaging/tests/MessagingContext.h b/src/messaging/tests/MessagingContext.h index cc99415e729029..2d3787d8787a68 100644 --- a/src/messaging/tests/MessagingContext.h +++ b/src/messaging/tests/MessagingContext.h @@ -120,7 +120,7 @@ class MessagingContext NodeId mAliceNodeId = 111222333; uint16_t mBobKeyId = 1; uint16_t mAliceKeyId = 2; - GroupId mFriendsGroupId = 517; + GroupId mFriendsGroupId = 1; Transport::PeerAddress mAliceAddress; Transport::PeerAddress mBobAddress; SecurePairingUsingTestSecret mPairingAliceToBob; diff --git a/src/transport/CryptoContext.cpp b/src/transport/CryptoContext.cpp index c78bf8b7872d8c..fd88f1bf123c8d 100644 --- a/src/transport/CryptoContext.cpp +++ b/src/transport/CryptoContext.cpp @@ -64,6 +64,7 @@ CryptoContext::~CryptoContext() { ClearSecretData(key, sizeof(CryptoKey)); } + mKeyContext = nullptr; } CHIP_ERROR CryptoContext::InitFromSecret(const ByteSpan & secret, const ByteSpan & salt, SessionInfoType infoType, SessionRole role) @@ -168,7 +169,6 @@ CHIP_ERROR CryptoContext::Encrypt(const uint8_t * input, size_t input_length, ui VerifyOrDie(taglen <= kMaxTagLen); - VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); VerifyOrReturnError(input != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(input_length > 0, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(output != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -181,19 +181,30 @@ CHIP_ERROR CryptoContext::Encrypt(const uint8_t * input, size_t input_length, ui ReturnErrorOnFailure(GetIV(header, IV, sizeof(IV))); ReturnErrorOnFailure(GetAdditionalAuthData(header, AAD, aadLen)); - KeyUsage usage = kR2IKey; + if (mKeyContext) + { + MutableByteSpan plaintext(output, input_length); // WARNING: ASSUMES IN-PLACE ENCRYPTION + MutableByteSpan mic(tag, taglen); - // Message is encrypted before sending. If the secure session was created by session - // initiator, we'll use I2R key to encrypt the message that's being transmitted. - // Otherwise, we'll use R2I key, as the responder is sending the message. - if (mSessionRole == SessionRole::kInitiator) + ReturnErrorOnFailure(mKeyContext->EncryptMessage(plaintext, ByteSpan(AAD, aadLen), ByteSpan(IV), mic)); + } + else { - usage = kI2RKey; + VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); + KeyUsage usage = kR2IKey; + + // Message is encrypted before sending. If the secure session was created by session + // initiator, we'll use I2R key to encrypt the message that's being transmitted. + // Otherwise, we'll use R2I key, as the responder is sending the message. + if (mSessionRole == SessionRole::kInitiator) + { + usage = kI2RKey; + } + + ReturnErrorOnFailure(AES_CCM_encrypt(input, input_length, AAD, aadLen, mKeys[usage], Crypto::kAES_CCM128_Key_Length, IV, + sizeof(IV), output, tag, taglen)); } - ReturnErrorOnFailure(AES_CCM_encrypt(input, input_length, AAD, aadLen, mKeys[usage], Crypto::kAES_CCM128_Key_Length, IV, - sizeof(IV), output, tag, taglen)); - mac.SetTag(&header, tag, taglen); return CHIP_NO_ERROR; @@ -208,7 +219,6 @@ CHIP_ERROR CryptoContext::Decrypt(const uint8_t * input, size_t input_length, ui uint8_t AAD[kMaxAADLen]; uint16_t aadLen = sizeof(AAD); - VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); VerifyOrReturnError(input != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(input_length > 0, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(output != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -216,18 +226,31 @@ CHIP_ERROR CryptoContext::Decrypt(const uint8_t * input, size_t input_length, ui ReturnErrorOnFailure(GetIV(header, IV, sizeof(IV))); ReturnErrorOnFailure(GetAdditionalAuthData(header, AAD, aadLen)); - KeyUsage usage = kI2RKey; + if (nullptr != mKeyContext) + { + MutableByteSpan ciphertext(output, input_length); // WARNING: ASSUMES input == output + ByteSpan mic(tag, taglen); - // Message is decrypted on receive. If the secure session was created by session - // initiator, we'll use R2I key to decrypt the message (as it was sent by responder). - // Otherwise, we'll use I2R key, as the responder is sending the message. - if (mSessionRole == SessionRole::kInitiator) + CHIP_ERROR err = mKeyContext->DecryptMessage(ciphertext, ByteSpan(AAD, aadLen), ByteSpan(IV), mic); + ReturnErrorOnFailure(err); + } + else { - usage = kR2IKey; + VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY); + KeyUsage usage = kI2RKey; + + // Message is decrypted on receive. If the secure session was created by session + // initiator, we'll use R2I key to decrypt the message (as it was sent by responder). + // Otherwise, we'll use I2R key, as the responder is sending the message. + if (mSessionRole == SessionRole::kInitiator) + { + usage = kR2IKey; + } + + ReturnErrorOnFailure(AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mKeys[usage], + Crypto::kAES_CCM128_Key_Length, IV, sizeof(IV), output)); } - - return AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mKeys[usage], Crypto::kAES_CCM128_Key_Length, IV, - sizeof(IV), output); + return CHIP_NO_ERROR; } } // namespace chip diff --git a/src/transport/CryptoContext.h b/src/transport/CryptoContext.h index 13771cb9af7c60..82f347e13d3376 100644 --- a/src/transport/CryptoContext.h +++ b/src/transport/CryptoContext.h @@ -39,6 +39,7 @@ class DLL_EXPORT CryptoContext ~CryptoContext(); CryptoContext(CryptoContext &&) = default; CryptoContext(const CryptoContext &) = default; + CryptoContext(Crypto::SymmetricKeyContext * context) : mKeyContext(context){}; CryptoContext & operator=(const CryptoContext &) = default; CryptoContext & operator=(CryptoContext &&) = default; @@ -140,6 +141,7 @@ class DLL_EXPORT CryptoContext bool mKeyAvailable; CryptoKey mKeys[KeyUsage::kNumCryptoKeys]; + Crypto::SymmetricKeyContext * mKeyContext = nullptr; static CHIP_ERROR GetIV(const PacketHeader & header, uint8_t * iv, size_t len); diff --git a/src/transport/SecureMessageCodec.cpp b/src/transport/SecureMessageCodec.cpp index 5ae7a56d3eee19..98547858a10515 100644 --- a/src/transport/SecureMessageCodec.cpp +++ b/src/transport/SecureMessageCodec.cpp @@ -36,7 +36,7 @@ using System::PacketBufferHandle; namespace SecureMessageCodec { -CHIP_ERROR Encrypt(Transport::SecureSession * session, PayloadHeader & payloadHeader, PacketHeader & packetHeader, +CHIP_ERROR Encrypt(const CryptoContext & context, PayloadHeader & payloadHeader, PacketHeader & packetHeader, System::PacketBufferHandle & msgBuf) { VerifyOrReturnError(!msgBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT); @@ -52,7 +52,7 @@ CHIP_ERROR Encrypt(Transport::SecureSession * session, PayloadHeader & payloadHe uint16_t totalLen = msgBuf->TotalLength(); MessageAuthenticationCode mac; - ReturnErrorOnFailure(session->EncryptBeforeSend(data, totalLen, data, packetHeader, mac)); + ReturnErrorOnFailure(context.Encrypt(data, totalLen, data, packetHeader, mac)); uint16_t taglen = 0; ReturnErrorOnFailure(mac.Encode(packetHeader, &data[totalLen], msgBuf->AvailableDataLength(), &taglen)); @@ -63,7 +63,7 @@ CHIP_ERROR Encrypt(Transport::SecureSession * session, PayloadHeader & payloadHe return CHIP_NO_ERROR; } -CHIP_ERROR Decrypt(Transport::SecureSession * session, PayloadHeader & payloadHeader, const PacketHeader & packetHeader, +CHIP_ERROR Decrypt(const CryptoContext & context, PayloadHeader & payloadHeader, const PacketHeader & packetHeader, System::PacketBufferHandle & msg) { ReturnErrorCodeIf(msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT); @@ -93,7 +93,7 @@ CHIP_ERROR Decrypt(Transport::SecureSession * session, PayloadHeader & payloadHe msg->SetDataLength(len); uint8_t * plainText = msg->Start(); - ReturnErrorOnFailure(session->DecryptOnReceive(data, len, plainText, packetHeader, mac)); + ReturnErrorOnFailure(context.Decrypt(data, len, plainText, packetHeader, mac)); ReturnErrorOnFailure(payloadHeader.DecodeAndConsume(msg)); return CHIP_NO_ERROR; diff --git a/src/transport/SecureMessageCodec.h b/src/transport/SecureMessageCodec.h index 2fa0700bb9a101..32460f0316944d 100644 --- a/src/transport/SecureMessageCodec.h +++ b/src/transport/SecureMessageCodec.h @@ -27,6 +27,7 @@ #pragma once +#include #include namespace chip { @@ -48,7 +49,7 @@ namespace SecureMessageCodec { * the encrypted message. * @return A CHIP_ERROR value consistent with the result of the encryption operation */ -CHIP_ERROR Encrypt(Transport::SecureSession * session, PayloadHeader & payloadHeader, PacketHeader & packetHeader, +CHIP_ERROR Encrypt(const CryptoContext & context, PayloadHeader & payloadHeader, PacketHeader & packetHeader, System::PacketBufferHandle & msgBuf); /** @@ -65,7 +66,7 @@ CHIP_ERROR Encrypt(Transport::SecureSession * session, PayloadHeader & payloadHe * the decrypted message. * @return A CHIP_ERROR value consistent with the result of the decryption operation */ -CHIP_ERROR Decrypt(Transport::SecureSession * session, PayloadHeader & payloadHeader, const PacketHeader & packetHeader, +CHIP_ERROR Decrypt(const CryptoContext & context, PayloadHeader & payloadHeader, const PacketHeader & packetHeader, System::PacketBufferHandle & msgBuf); } // namespace SecureMessageCodec diff --git a/src/transport/SecureSession.h b/src/transport/SecureSession.h index 5edcac726f96d2..d3aa6a9ed86b7b 100644 --- a/src/transport/SecureSession.h +++ b/src/transport/SecureSession.h @@ -136,18 +136,6 @@ class SecureSession : public Session CryptoContext & GetCryptoContext() { return mCryptoContext; } - CHIP_ERROR EncryptBeforeSend(const uint8_t * input, size_t input_length, uint8_t * output, PacketHeader & header, - MessageAuthenticationCode & mac) const - { - return mCryptoContext.Encrypt(input, input_length, output, header, mac); - } - - CHIP_ERROR DecryptOnReceive(const uint8_t * input, size_t input_length, uint8_t * output, const PacketHeader & header, - const MessageAuthenticationCode & mac) const - { - return mCryptoContext.Decrypt(input, input_length, output, header, mac); - } - SessionMessageCounter & GetSessionMessageCounter() { return mSessionMessageCounter; } private: diff --git a/src/transport/SessionManager.cpp b/src/transport/SessionManager.cpp index 8397aefe1b8c58..d15ec918535d3b 100644 --- a/src/transport/SessionManager.cpp +++ b/src/transport/SessionManager.cpp @@ -124,9 +124,13 @@ CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, P switch (sessionHandle->GetSessionType()) { case Transport::Session::SessionType::kGroup: { + auto groupSession = sessionHandle->AsGroupSession(); + auto * groups = Credentials::GetGroupDataProvider(); + VerifyOrReturnError(nullptr != groups, CHIP_ERROR_INTERNAL); + // TODO : #11911 // For now, just set the packetHeader with the correct data. - packetHeader.SetDestinationGroupId(sessionHandle->AsGroupSession()->GetGroupId()); + packetHeader.SetDestinationGroupId(groupSession->GetGroupId()); packetHeader.SetFlags(Header::SecFlagValues::kPrivacyFlag); packetHeader.SetSessionType(Header::SessionType::kGroupSession); // TODO : Replace the PeerNodeId with Our nodeId @@ -140,8 +144,14 @@ CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, P // Trace before any encryption CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, message->Start(), message->TotalLength()); - // TODO #11911 Update SecureMessageCodec::Encrypt for Group - ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(message)); + Crypto::SymmetricKeyContext * keyContext = + groups->GetKeyContext(groupSession->GetFabricIndex(), groupSession->GetGroupId()); + VerifyOrReturnError(nullptr != keyContext, CHIP_ERROR_INTERNAL); + + packetHeader.SetSessionId(keyContext->GetKeyHash()); + CHIP_ERROR err = SecureMessageCodec::Encrypt(CryptoContext(keyContext), payloadHeader, packetHeader, message); + keyContext->Release(); + ReturnErrorOnFailure(err); #if CHIP_PROGRESS_LOGGING destination = kUndefinedNodeId; @@ -166,7 +176,7 @@ CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, P // Trace before any encryption CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, message->Start(), message->TotalLength()); - ReturnErrorOnFailure(SecureMessageCodec::Encrypt(session, payloadHeader, packetHeader, message)); + ReturnErrorOnFailure(SecureMessageCodec::Encrypt(session->GetCryptoContext(), payloadHeader, packetHeader, message)); ReturnErrorOnFailure(counter.Advance()); #if CHIP_PROGRESS_LOGGING @@ -497,7 +507,7 @@ void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & packetHea Transport::SecureSession * secureSession = session.Value()->AsSecureSession(); // Decrypt and verify the message before message counter verification or any further processing. - if (SecureMessageCodec::Decrypt(secureSession, payloadHeader, packetHeader, msg) != CHIP_NO_ERROR) + if (SecureMessageCodec::Decrypt(secureSession->GetCryptoContext(), payloadHeader, packetHeader, msg) != CHIP_NO_ERROR) { ChipLogError(Inet, "Secure transport received message, but failed to decode/authenticate it, discarding"); return; @@ -553,7 +563,8 @@ void SessionManager::SecureGroupMessageDispatch(const PacketHeader & packetHeade { PayloadHeader payloadHeader; SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No; - // Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider(); + Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider(); + VerifyOrReturn(nullptr != groups); if (!packetHeader.GetDestinationGroupId().HasValue()) { @@ -573,12 +584,22 @@ void SessionManager::SecureGroupMessageDispatch(const PacketHeader & packetHeade return; } - // Trial decryption with GroupDataProvider. TODO: Implement the GroupDataProvider Class - // TODO retrieve also the fabricIndex with the GroupDataProvider. - // VerifyOrExit(CHIP_NO_ERROR == groups->DecryptMessage(packetHeader, payloadHeader, msg), - // ChipLogError(Inet, "Secure transport received group message, but failed to decode it, discarding")); + // Trial decryption with GroupDataProvider + Credentials::GroupDataProvider::GroupSession groupContext; + auto iter = groups->IterateGroupSessions(packetHeader.GetSessionId()); + VerifyOrReturn(nullptr != iter); - ReturnOnFailure(payloadHeader.DecodeAndConsume(msg)); + System::PacketBufferHandle msgCopy; + bool decrypted = false; + while (!decrypted && iter->Next(groupContext)) + { + msgCopy = msg.CloneData(); + decrypted = + (CHIP_NO_ERROR == SecureMessageCodec::Decrypt(CryptoContext(groupContext.key), payloadHeader, packetHeader, msgCopy)); + } + iter->Release(); + VerifyOrReturn(decrypted); + msg = std::move(msgCopy); // MCSP check if (packetHeader.IsValidMCSPMsg()) @@ -617,8 +638,7 @@ void SessionManager::SecureGroupMessageDispatch(const PacketHeader & packetHeade if (mCB != nullptr) { - // TODO : remove hard coded fabric index once GroupDataProvider->Decrypt is implemented - Optional session = CreateGroupSession(packetHeader.GetDestinationGroupId().Value(), 1); + Optional session = CreateGroupSession(groupContext.group_id, groupContext.fabric_index); VerifyOrReturn(session.HasValue(), ChipLogError(Inet, "Error when creating group session handle.")); Transport::GroupSession * groupSession = session.Value()->AsGroupSession(); diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 107c8eb95e9789..362568bfb453b6 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -83517,29 +83517,37 @@ class TestGroupMessaging : public TestCommand err = TestAddGroup2Endpoint0_2(); break; case 3: - ChipLogProgress(chipTool, " ***** Test Step 3 : Group Write Attribute\n"); - err = TestGroupWriteAttribute_3(); + ChipLogProgress(chipTool, " ***** Test Step 3 : KeySet Write\n"); + err = TestKeySetWrite_3(); break; case 4: - ChipLogProgress(chipTool, " ***** Test Step 4 : Read back Attribute\n"); - err = TestReadBackAttribute_4(); + ChipLogProgress(chipTool, " ***** Test Step 4 : Write Group Keys\n"); + err = TestWriteGroupKeys_4(); break; case 5: - ChipLogProgress(chipTool, " ***** Test Step 5 : Restore initial location value\n"); - err = TestRestoreInitialLocationValue_5(); + ChipLogProgress(chipTool, " ***** Test Step 5 : Group Write Attribute\n"); + err = TestGroupWriteAttribute_5(); break; case 6: ChipLogProgress(chipTool, " ***** Test Step 6 : Read back Attribute\n"); err = TestReadBackAttribute_6(); break; case 7: - ChipLogProgress(chipTool, " ***** Test Step 7 : Turn On the light to see attribute change\n"); - err = TestTurnOnTheLightToSeeAttributeChange_7(); + ChipLogProgress(chipTool, " ***** Test Step 7 : Restore initial location value\n"); + err = TestRestoreInitialLocationValue_7(); break; case 8: + ChipLogProgress(chipTool, " ***** Test Step 8 : Read back Attribute\n"); + err = TestReadBackAttribute_8(); + break; + case 9: + ChipLogProgress(chipTool, " ***** Test Step 9 : Turn On the light to see attribute change\n"); + err = TestTurnOnTheLightToSeeAttributeChange_9(); + break; + case 10: ChipLogProgress(chipTool, - " ***** Test Step 8 : Check on/off attribute value is true after on command for endpoint 1\n"); - err = TestCheckOnOffAttributeValueIsTrueAfterOnCommandForEndpoint1_8(); + " ***** Test Step 10 : Check on/off attribute value is true after on command for endpoint 1\n"); + err = TestCheckOnOffAttributeValueIsTrueAfterOnCommandForEndpoint1_10(); break; } @@ -83552,29 +83560,17 @@ class TestGroupMessaging : public TestCommand private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 9; + const uint16_t mTestCount = 11; chip::Optional mCluster; chip::Optional mEndpoint; - static void OnDoneCallback_3(void * context) { (static_cast(context))->OnDoneResponse_3(); } - - static void OnFailureCallback_3(void * context, CHIP_ERROR error) - { - (static_cast(context))->OnFailureResponse_3(error); - } - - static void OnSuccessCallback_3(void * context) { (static_cast(context))->OnSuccessResponse_3(); } - static void OnFailureCallback_4(void * context, CHIP_ERROR error) { (static_cast(context))->OnFailureResponse_4(error); } - static void OnSuccessCallback_4(void * context, chip::CharSpan location) - { - (static_cast(context))->OnSuccessResponse_4(location); - } + static void OnSuccessCallback_4(void * context) { (static_cast(context))->OnSuccessResponse_4(); } static void OnDoneCallback_5(void * context) { (static_cast(context))->OnDoneResponse_5(); } @@ -83595,14 +83591,33 @@ class TestGroupMessaging : public TestCommand (static_cast(context))->OnSuccessResponse_6(location); } + static void OnDoneCallback_7(void * context) { (static_cast(context))->OnDoneResponse_7(); } + + static void OnFailureCallback_7(void * context, CHIP_ERROR error) + { + (static_cast(context))->OnFailureResponse_7(error); + } + + static void OnSuccessCallback_7(void * context) { (static_cast(context))->OnSuccessResponse_7(); } + static void OnFailureCallback_8(void * context, CHIP_ERROR error) { (static_cast(context))->OnFailureResponse_8(error); } - static void OnSuccessCallback_8(void * context, bool onOff) + static void OnSuccessCallback_8(void * context, chip::CharSpan location) + { + (static_cast(context))->OnSuccessResponse_8(location); + } + + static void OnFailureCallback_10(void * context, CHIP_ERROR error) + { + (static_cast(context))->OnFailureResponse_10(error); + } + + static void OnSuccessCallback_10(void * context, bool onOff) { - (static_cast(context))->OnSuccessResponse_8(onOff); + (static_cast(context))->OnSuccessResponse_10(onOff); } // @@ -83687,7 +83702,85 @@ class TestGroupMessaging : public TestCommand NextTest(); } - CHIP_ERROR TestGroupWriteAttribute_3() + CHIP_ERROR TestKeySetWrite_3() + { + const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0; + using RequestType = chip::app::Clusters::GroupKeyManagement::Commands::KeySetWrite::Type; + + RequestType request; + + request.groupKeySet.groupKeySetID = 257U; + request.groupKeySet.securityPolicy = static_cast(0); + request.groupKeySet.epochKey0 = + chip::ByteSpan(chip::Uint8::from_const_char( + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xafgarbage: not in length on purpose"), + 16); + request.groupKeySet.epochStartTime0 = 1110000ULL; + request.groupKeySet.epochKey1 = + chip::ByteSpan(chip::Uint8::from_const_char( + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbfgarbage: not in length on purpose"), + 16); + request.groupKeySet.epochStartTime1 = 1110001ULL; + request.groupKeySet.epochKey2 = + chip::ByteSpan(chip::Uint8::from_const_char( + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcfgarbage: not in length on purpose"), + 16); + request.groupKeySet.epochStartTime2 = 1110002ULL; + + auto success = [](void * context, const typename RequestType::ResponseType & data) { + (static_cast(context))->OnSuccessResponse_3(); + }; + + auto failure = [](void * context, CHIP_ERROR error) { + (static_cast(context))->OnFailureResponse_3(error); + }; + + ReturnErrorOnFailure(chip::Controller::InvokeCommand(mDevices[kIdentityAlpha], this, success, failure, endpoint, request)); + return CHIP_NO_ERROR; + } + + void OnFailureResponse_3(CHIP_ERROR error) + { + chip::app::StatusIB status(error); + ThrowFailureResponse(); + } + + void OnSuccessResponse_3() { NextTest(); } + + CHIP_ERROR TestWriteGroupKeys_4() + { + const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0; + chip::Controller::GroupKeyManagementClusterTest cluster; + cluster.Associate(mDevices[kIdentityAlpha], endpoint); + + chip::app::DataModel::List groupKeyMapArgument; + + chip::app::Clusters::GroupKeyManagement::Structs::GroupKey::Type groupKeyMapList_0[2]; + + groupKeyMapList_0[0].fabricIndex = 1; + groupKeyMapList_0[0].groupId = 4660U; + groupKeyMapList_0[0].groupKeySetID = 257U; + + groupKeyMapList_0[1].fabricIndex = 1; + groupKeyMapList_0[1].groupId = 1U; + groupKeyMapList_0[1].groupKeySetID = 257U; + + groupKeyMapArgument = groupKeyMapList_0; + + ReturnErrorOnFailure(cluster.WriteAttribute( + groupKeyMapArgument, this, OnSuccessCallback_4, OnFailureCallback_4)); + return CHIP_NO_ERROR; + } + + void OnFailureResponse_4(CHIP_ERROR error) + { + chip::app::StatusIB status(error); + ThrowFailureResponse(); + } + + void OnSuccessResponse_4() { NextTest(); } + + CHIP_ERROR TestGroupWriteAttribute_5() { const chip::GroupId groupId = 1; chip::Controller::BasicClusterTest cluster; @@ -83697,45 +83790,45 @@ class TestGroupMessaging : public TestCommand locationArgument = chip::Span("USgarbage: not in length on purpose", 2); ReturnErrorOnFailure(cluster.WriteAttribute( - locationArgument, this, OnSuccessCallback_3, OnFailureCallback_3, OnDoneCallback_3)); + locationArgument, this, OnSuccessCallback_5, OnFailureCallback_5, OnDoneCallback_5)); return CHIP_NO_ERROR; } - void OnFailureResponse_3(CHIP_ERROR error) + void OnFailureResponse_5(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_3() { NextTest(); } + void OnSuccessResponse_5() { NextTest(); } - void OnDoneResponse_3() { NextTest(); } + void OnDoneResponse_5() { NextTest(); } - CHIP_ERROR TestReadBackAttribute_4() + CHIP_ERROR TestReadBackAttribute_6() { const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0; chip::Controller::BasicClusterTest cluster; cluster.Associate(mDevices[kIdentityAlpha], endpoint); ReturnErrorOnFailure(cluster.ReadAttribute( - this, OnSuccessCallback_4, OnFailureCallback_4)); + this, OnSuccessCallback_6, OnFailureCallback_6)); return CHIP_NO_ERROR; } - void OnFailureResponse_4(CHIP_ERROR error) + void OnFailureResponse_6(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_4(chip::CharSpan location) + void OnSuccessResponse_6(chip::CharSpan location) { VerifyOrReturn(CheckValueAsString("location", location, chip::CharSpan("US", 2))); NextTest(); } - CHIP_ERROR TestRestoreInitialLocationValue_5() + CHIP_ERROR TestRestoreInitialLocationValue_7() { const chip::GroupId groupId = 1; chip::Controller::BasicClusterTest cluster; @@ -83745,45 +83838,45 @@ class TestGroupMessaging : public TestCommand locationArgument = chip::Span("XXgarbage: not in length on purpose", 2); ReturnErrorOnFailure(cluster.WriteAttribute( - locationArgument, this, OnSuccessCallback_5, OnFailureCallback_5, OnDoneCallback_5)); + locationArgument, this, OnSuccessCallback_7, OnFailureCallback_7, OnDoneCallback_7)); return CHIP_NO_ERROR; } - void OnFailureResponse_5(CHIP_ERROR error) + void OnFailureResponse_7(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_5() { NextTest(); } + void OnSuccessResponse_7() { NextTest(); } - void OnDoneResponse_5() { NextTest(); } + void OnDoneResponse_7() { NextTest(); } - CHIP_ERROR TestReadBackAttribute_6() + CHIP_ERROR TestReadBackAttribute_8() { const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0; chip::Controller::BasicClusterTest cluster; cluster.Associate(mDevices[kIdentityAlpha], endpoint); ReturnErrorOnFailure(cluster.ReadAttribute( - this, OnSuccessCallback_6, OnFailureCallback_6)); + this, OnSuccessCallback_8, OnFailureCallback_8)); return CHIP_NO_ERROR; } - void OnFailureResponse_6(CHIP_ERROR error) + void OnFailureResponse_8(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_6(chip::CharSpan location) + void OnSuccessResponse_8(chip::CharSpan location) { VerifyOrReturn(CheckValueAsString("location", location, chip::CharSpan("XX", 2))); NextTest(); } - CHIP_ERROR TestTurnOnTheLightToSeeAttributeChange_7() + CHIP_ERROR TestTurnOnTheLightToSeeAttributeChange_9() { const chip::GroupId groupId = 4660; using RequestType = chip::app::Clusters::OnOff::Commands::On::Type; @@ -83791,48 +83884,48 @@ class TestGroupMessaging : public TestCommand RequestType request; auto success = [](void * context, const typename RequestType::ResponseType & data) { - (static_cast(context))->OnSuccessResponse_7(); + (static_cast(context))->OnSuccessResponse_9(); }; auto failure = [](void * context, CHIP_ERROR error) { - (static_cast(context))->OnFailureResponse_7(error); + (static_cast(context))->OnFailureResponse_9(error); }; - auto done = [](void * context) { (static_cast(context))->OnDoneResponse_7(); }; + auto done = [](void * context) { (static_cast(context))->OnDoneResponse_9(); }; ReturnErrorOnFailure( chip::Controller::InvokeGroupCommand(mDevices[kIdentityAlpha], this, success, failure, done, groupId, request)); return CHIP_NO_ERROR; } - void OnFailureResponse_7(CHIP_ERROR error) + void OnFailureResponse_9(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_7() { NextTest(); } + void OnSuccessResponse_9() { NextTest(); } - void OnDoneResponse_7() { NextTest(); } + void OnDoneResponse_9() { NextTest(); } - CHIP_ERROR TestCheckOnOffAttributeValueIsTrueAfterOnCommandForEndpoint1_8() + CHIP_ERROR TestCheckOnOffAttributeValueIsTrueAfterOnCommandForEndpoint1_10() { const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 1; chip::Controller::OnOffClusterTest cluster; cluster.Associate(mDevices[kIdentityAlpha], endpoint); ReturnErrorOnFailure(cluster.ReadAttribute( - this, OnSuccessCallback_8, OnFailureCallback_8)); + this, OnSuccessCallback_10, OnFailureCallback_10)); return CHIP_NO_ERROR; } - void OnFailureResponse_8(CHIP_ERROR error) + void OnFailureResponse_10(CHIP_ERROR error) { chip::app::StatusIB status(error); ThrowFailureResponse(); } - void OnSuccessResponse_8(bool onOff) + void OnSuccessResponse_10(bool onOff) { VerifyOrReturn(CheckValue("onOff", onOff, 1)); @@ -85387,8 +85480,7 @@ class TestGroupKeyManagementCluster : public TestCommand void OnSuccessResponse_1(uint16_t maxGroupsPerFabric) { - VerifyOrReturn(CheckValue("maxGroupsPerFabric", maxGroupsPerFabric, 1U)); - + VerifyOrReturn(CheckConstraintMinValue("maxGroupsPerFabric", maxGroupsPerFabric, 2U)); NextTest(); } @@ -85412,7 +85504,7 @@ class TestGroupKeyManagementCluster : public TestCommand void OnSuccessResponse_2(uint16_t maxGroupKeysPerFabric) { - VerifyOrReturn(CheckValue("maxGroupKeysPerFabric", maxGroupKeysPerFabric, 1U)); + VerifyOrReturn(CheckValue("maxGroupKeysPerFabric", maxGroupKeysPerFabric, 2U)); NextTest(); }