From e3a3afa44e61f9417fc55c9250b37ad11d9268af Mon Sep 17 00:00:00 2001 From: C Freeman Date: Wed, 4 Jan 2023 16:16:07 -0500 Subject: [PATCH] Remove GroupKeyMap entries for removed KeySet (#23864) * Remove GroupKeyMap entries for removed KeySet Per Core spec 11.2.9.4, If there exist any entries for the accessing fabric within the GroupKeyMap attribute that refer to the GroupKeySetID just removed, then these entries SHALL be removed from that list. Fixes #23862 * Restyled by clang-format * Restyled by prettier-yaml * Update src/credentials/GroupDataProviderImpl.cpp Co-authored-by: Boris Zbarsky Co-authored-by: Restyled.io Co-authored-by: Boris Zbarsky --- .../suites/TestGroupKeyManagementCluster.yaml | 74 +++++ src/credentials/GroupDataProviderImpl.cpp | 51 +++- .../chip-tool/zap-generated/test/Commands.h | 174 ++++++++++- .../zap-generated/test/Commands.h | 286 +++++++++++++++++- 4 files changed, 582 insertions(+), 3 deletions(-) diff --git a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml index f388434370cb6a..62fbfe4e1cb7c4 100644 --- a/src/app/tests/suites/TestGroupKeyManagementCluster.yaml +++ b/src/app/tests/suites/TestGroupKeyManagementCluster.yaml @@ -295,3 +295,77 @@ tests: value: 0x01a2 response: error: NOT_FOUND + + - label: "KeySet Write 1" + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a1, + GroupKeySecurityPolicy: 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, + } + + - label: "KeySet Write 2" + command: "KeySetWrite" + arguments: + values: + - name: "GroupKeySet" + value: + { + GroupKeySetID: 0x01a2, + GroupKeySecurityPolicy: 1, + EpochKey0: "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf", + EpochStartTime0: 2110000, + EpochKey1: "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef", + EpochStartTime1: 2110001, + EpochKey2: "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + EpochStartTime2: 2110002, + } + + - label: "Map Group 1 and Group 2 to KeySet 1 and group 2 to KeySet 2" + command: "writeAttribute" + attribute: "GroupKeyMap" + arguments: + value: + [ + { FabricIndex: 1, GroupId: 0x0101, GroupKeySetID: 0x01a1 }, + { FabricIndex: 1, GroupId: 0x0102, GroupKeySetID: 0x01a2 }, + { FabricIndex: 1, GroupId: 0x0102, GroupKeySetID: 0x01a1 }, + ] + + - label: "Remove keyset 1" + command: "KeySetRemove" + arguments: + values: + - name: "GroupKeySetID" + value: 0x01a1 + + - label: "TH verifies GroupKeyMap entries for KeySet 1 have been removed" + cluster: "Group Key Management" + endpoint: 0 + command: "readAttribute" + attribute: "GroupKeyMap" + response: + value: [{ FabricIndex: 1, GroupId: 0x0102, GroupKeySetID: 0x01a2 }] + - label: "Remove keyset 2" + command: "KeySetRemove" + arguments: + values: + - name: "GroupKeySetID" + value: 0x01a2 + + - label: "TH verifies GroupKeyMap entries for KeySet 2 have been removed" + cluster: "Group Key Management" + endpoint: 0 + command: "readAttribute" + attribute: "GroupKeyMap" + response: + value: [] diff --git a/src/credentials/GroupDataProviderImpl.cpp b/src/credentials/GroupDataProviderImpl.cpp index 95764967dab051..fde6cec2343ad8 100644 --- a/src/credentials/GroupDataProviderImpl.cpp +++ b/src/credentials/GroupDataProviderImpl.cpp @@ -503,6 +503,37 @@ struct KeyMapData : public GroupDataProvider::GroupKey, LinkedData id = static_cast(max_id + 1); return false; } + + // returns index if the find_id is found, otherwise std::numeric_limits::max + size_t Find(PersistentStorageDelegate * storage, const FabricData & fabric, const KeysetId find_id) + { + fabric_index = fabric.fabric_index; + id = fabric.first_map; + max_id = 0; + index = 0; + first = true; + + while (index < fabric.map_count) + { + if (CHIP_NO_ERROR != Load(storage)) + { + break; + } + if (keyset_id == find_id) + { + // Match found + return index; + } + max_id = std::max(id, max_id); + first = false; + prev = id; + id = next; + index++; + } + + id = static_cast(max_id + 1); + return std::numeric_limits::max(); + } }; struct EndpointData : GroupDataProvider::GroupEndpoint, PersistentData @@ -1574,7 +1605,25 @@ CHIP_ERROR GroupDataProviderImpl::RemoveKeySet(chip::FabricIndex fabric_index, u fabric.keyset_count--; } // Update fabric info - return fabric.Save(mStorage); + ReturnErrorOnFailure(fabric.Save(mStorage)); + + // Removing a key set also removes the associated group mappings + KeyMapData map; + uint16_t original_count = fabric.map_count; + for (uint16_t i = 0; i < original_count; ++i) + { + fabric.Load(mStorage); + size_t idx = map.Find(mStorage, fabric, target_id); + if (idx == std::numeric_limits::max()) + { + break; + } + // NOTE: It's unclear what should happen here if we have removed the key set + // and possibly some mappings before failing. For now, ignoring errors, but + // open to suggestsions for the correct behavior. + RemoveGroupKeyAt(fabric_index, idx); + } + return CHIP_NO_ERROR; } GroupDataProvider::KeySetIterator * GroupDataProviderImpl::IterateKeySets(chip::FabricIndex fabric_index) diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index d6f7eef25da072..a4c3223b511588 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -78695,7 +78695,7 @@ class TestGroupKeyManagementClusterSuite : public TestCommand { public: TestGroupKeyManagementClusterSuite(CredentialIssuerCommands * credsIssuerConfig) : - TestCommand("TestGroupKeyManagementCluster", 22, credsIssuerConfig) + TestCommand("TestGroupKeyManagementCluster", 29, credsIssuerConfig) { AddArgument("nodeId", 0, UINT64_MAX, &mNodeId); AddArgument("cluster", &mCluster); @@ -78929,6 +78929,51 @@ class TestGroupKeyManagementClusterSuite : public TestCommand case 21: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_NOT_FOUND)); break; + case 22: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 23: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 24: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 25: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 26: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::DecodableList< + chip::app::Clusters::GroupKeyManagement::Structs::GroupKeyMapStruct::DecodableType> + value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + { + auto iter_0 = value.begin(); + VerifyOrReturn(CheckNextListItemDecodes("groupKeyMap", iter_0, 0)); + VerifyOrReturn(CheckValue("groupKeyMap[0].groupId", iter_0.GetValue().groupId, 258U)); + VerifyOrReturn(CheckValue("groupKeyMap[0].groupKeySetID", iter_0.GetValue().groupKeySetID, 418U)); + VerifyOrReturn(CheckValue("groupKeyMap[0].fabricIndex", iter_0.GetValue().fabricIndex, 1U)); + VerifyOrReturn(CheckNoMoreListItems("groupKeyMap", iter_0, 1)); + } + } + break; + case 27: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 28: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + { + chip::app::DataModel::DecodableList< + chip::app::Clusters::GroupKeyManagement::Structs::GroupKeyMapStruct::DecodableType> + value; + VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); + { + auto iter_0 = value.begin(); + VerifyOrReturn(CheckNoMoreListItems("groupKeyMap", iter_0, 0)); + } + } + break; default: LogErrorOnFailure(ContinueOnChipMainThread(CHIP_ERROR_INVALID_ARGUMENT)); } @@ -79227,6 +79272,133 @@ class TestGroupKeyManagementClusterSuite : public TestCommand ); } + case 22: { + LogStep(22, "KeySet Write 1"); + ListFreer listFreer; + chip::app::Clusters::GroupKeyManagement::Commands::KeySetWrite::Type value; + + value.groupKeySet.groupKeySetID = 417U; + value.groupKeySet.groupKeySecurityPolicy = + static_cast(0); + value.groupKeySet.epochKey0.SetNonNull(); + value.groupKeySet.epochKey0.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime0.SetNonNull(); + value.groupKeySet.epochStartTime0.Value() = 1110000ULL; + value.groupKeySet.epochKey1.SetNonNull(); + value.groupKeySet.epochKey1.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime1.SetNonNull(); + value.groupKeySet.epochStartTime1.Value() = 1110001ULL; + value.groupKeySet.epochKey2.SetNonNull(); + value.groupKeySet.epochKey2.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime2.SetNonNull(); + value.groupKeySet.epochStartTime2.Value() = 1110002ULL; + + return SendCommand(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Commands::KeySetWrite::Id, value, chip::NullOptional + + ); + } + case 23: { + LogStep(23, "KeySet Write 2"); + ListFreer listFreer; + chip::app::Clusters::GroupKeyManagement::Commands::KeySetWrite::Type value; + + value.groupKeySet.groupKeySetID = 418U; + value.groupKeySet.groupKeySecurityPolicy = + static_cast(1); + value.groupKeySet.epochKey0.SetNonNull(); + value.groupKeySet.epochKey0.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime0.SetNonNull(); + value.groupKeySet.epochStartTime0.Value() = 2110000ULL; + value.groupKeySet.epochKey1.SetNonNull(); + value.groupKeySet.epochKey1.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime1.SetNonNull(); + value.groupKeySet.epochStartTime1.Value() = 2110001ULL; + value.groupKeySet.epochKey2.SetNonNull(); + value.groupKeySet.epochKey2.Value() = chip::ByteSpan( + chip::Uint8::from_const_char( + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377garbage: not in length on purpose"), + 16); + value.groupKeySet.epochStartTime2.SetNonNull(); + value.groupKeySet.epochStartTime2.Value() = 2110002ULL; + + return SendCommand(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Commands::KeySetWrite::Id, value, chip::NullOptional + + ); + } + case 24: { + LogStep(24, "Map Group 1 and Group 2 to KeySet 1 and group 2 to KeySet 2"); + ListFreer listFreer; + chip::app::DataModel::List value; + + { + auto * listHolder_0 = new ListHolder(3); + listFreer.add(listHolder_0); + + listHolder_0->mList[0].groupId = 257U; + listHolder_0->mList[0].groupKeySetID = 417U; + listHolder_0->mList[0].fabricIndex = 1U; + + listHolder_0->mList[1].groupId = 258U; + listHolder_0->mList[1].groupKeySetID = 418U; + listHolder_0->mList[1].fabricIndex = 1U; + + listHolder_0->mList[2].groupId = 258U; + listHolder_0->mList[2].groupKeySetID = 417U; + listHolder_0->mList[2].fabricIndex = 1U; + + value = chip::app::DataModel::List( + listHolder_0->mList, 3); + } + return WriteAttribute(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Attributes::GroupKeyMap::Id, value, chip::NullOptional, chip::NullOptional); + } + case 25: { + LogStep(25, "Remove keyset 1"); + ListFreer listFreer; + chip::app::Clusters::GroupKeyManagement::Commands::KeySetRemove::Type value; + value.groupKeySetID = 417U; + return SendCommand(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Commands::KeySetRemove::Id, value, chip::NullOptional + + ); + } + case 26: { + LogStep(26, "TH verifies GroupKeyMap entries for KeySet 1 have been removed"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Attributes::GroupKeyMap::Id, true, chip::NullOptional); + } + case 27: { + LogStep(27, "Remove keyset 2"); + ListFreer listFreer; + chip::app::Clusters::GroupKeyManagement::Commands::KeySetRemove::Type value; + value.groupKeySetID = 418U; + return SendCommand(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Commands::KeySetRemove::Id, value, chip::NullOptional + + ); + } + case 28: { + LogStep(28, "TH verifies GroupKeyMap entries for KeySet 2 have been removed"); + return ReadAttribute(kIdentityAlpha, GetEndpoint(0), GroupKeyManagement::Id, + GroupKeyManagement::Attributes::GroupKeyMap::Id, true, chip::NullOptional); + } } return CHIP_NO_ERROR; } diff --git a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h index 6e5987315647ea..896ae2a97537f1 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -127760,6 +127760,34 @@ class TestGroupKeyManagementCluster : public TestCommandBridge { ChipLogProgress(chipTool, " ***** Test Step 21 : KeySet Read (also removed)\n"); err = TestKeySetReadAlsoRemoved_21(); break; + case 22: + ChipLogProgress(chipTool, " ***** Test Step 22 : KeySet Write 1\n"); + err = TestKeySetWrite1_22(); + break; + case 23: + ChipLogProgress(chipTool, " ***** Test Step 23 : KeySet Write 2\n"); + err = TestKeySetWrite2_23(); + break; + case 24: + ChipLogProgress(chipTool, " ***** Test Step 24 : Map Group 1 and Group 2 to KeySet 1 and group 2 to KeySet 2\n"); + err = TestMapGroup1AndGroup2ToKeySet1AndGroup2ToKeySet2_24(); + break; + case 25: + ChipLogProgress(chipTool, " ***** Test Step 25 : Remove keyset 1\n"); + err = TestRemoveKeyset1_25(); + break; + case 26: + ChipLogProgress(chipTool, " ***** Test Step 26 : TH verifies GroupKeyMap entries for KeySet 1 have been removed\n"); + err = TestThVerifiesGroupKeyMapEntriesForKeySet1HaveBeenRemoved_26(); + break; + case 27: + ChipLogProgress(chipTool, " ***** Test Step 27 : Remove keyset 2\n"); + err = TestRemoveKeyset2_27(); + break; + case 28: + ChipLogProgress(chipTool, " ***** Test Step 28 : TH verifies GroupKeyMap entries for KeySet 2 have been removed\n"); + err = TestThVerifiesGroupKeyMapEntriesForKeySet2HaveBeenRemoved_28(); + break; } if (CHIP_NO_ERROR != err) { @@ -127837,6 +127865,27 @@ class TestGroupKeyManagementCluster : public TestCommandBridge { case 21: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), EMBER_ZCL_STATUS_NOT_FOUND)); break; + case 22: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 23: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 24: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 25: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 26: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 27: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; + case 28: + VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); + break; } // Go on to the next test. @@ -127850,7 +127899,7 @@ class TestGroupKeyManagementCluster : public TestCommandBridge { private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 22; + const uint16_t mTestCount = 29; chip::Optional mNodeId; chip::Optional mCluster; @@ -128594,6 +128643,241 @@ class TestGroupKeyManagementCluster : public TestCommandBridge { return CHIP_NO_ERROR; } + + CHIP_ERROR TestKeySetWrite1_22() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetWriteParams alloc] init]; + params.groupKeySet = [[MTRGroupKeyManagementClusterGroupKeySetStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySetID = + [NSNumber numberWithUnsignedShort:417U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySecurityPolicy = + [NSNumber numberWithUnsignedChar:0U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey0 = + [[NSData alloc] initWithBytes:"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime0 = + [NSNumber numberWithUnsignedLongLong:1110000ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey1 = + [[NSData alloc] initWithBytes:"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime1 = + [NSNumber numberWithUnsignedLongLong:1110001ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey2 = + [[NSData alloc] initWithBytes:"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime2 = + [NSNumber numberWithUnsignedLongLong:1110002ULL]; + + [cluster keySetWriteWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"KeySet Write 1 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestKeySetWrite2_23() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetWriteParams alloc] init]; + params.groupKeySet = [[MTRGroupKeyManagementClusterGroupKeySetStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySetID = + [NSNumber numberWithUnsignedShort:418U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).groupKeySecurityPolicy = + [NSNumber numberWithUnsignedChar:1U]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey0 = + [[NSData alloc] initWithBytes:"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime0 = + [NSNumber numberWithUnsignedLongLong:2110000ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey1 = + [[NSData alloc] initWithBytes:"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime1 = + [NSNumber numberWithUnsignedLongLong:2110001ULL]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochKey2 = + [[NSData alloc] initWithBytes:"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" length:16]; + ((MTRGroupKeyManagementClusterGroupKeySetStruct *) params.groupKeySet).epochStartTime2 = + [NSNumber numberWithUnsignedLongLong:2110002ULL]; + + [cluster keySetWriteWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"KeySet Write 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestMapGroup1AndGroup2ToKeySet1AndGroup2ToKeySet2_24() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + id groupKeyMapArgument; + { + NSMutableArray * temp_0 = [[NSMutableArray alloc] init]; + temp_0[0] = [[MTRGroupKeyManagementClusterGroupKeyMapStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupId = [NSNumber numberWithUnsignedShort:257U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).groupKeySetID = [NSNumber numberWithUnsignedShort:417U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[0]).fabricIndex = [NSNumber numberWithUnsignedChar:1U]; + + temp_0[1] = [[MTRGroupKeyManagementClusterGroupKeyMapStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[1]).groupId = [NSNumber numberWithUnsignedShort:258U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[1]).groupKeySetID = [NSNumber numberWithUnsignedShort:418U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[1]).fabricIndex = [NSNumber numberWithUnsignedChar:1U]; + + temp_0[2] = [[MTRGroupKeyManagementClusterGroupKeyMapStruct alloc] init]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[2]).groupId = [NSNumber numberWithUnsignedShort:258U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[2]).groupKeySetID = [NSNumber numberWithUnsignedShort:417U]; + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) temp_0[2]).fabricIndex = [NSNumber numberWithUnsignedChar:1U]; + + groupKeyMapArgument = temp_0; + } + [cluster writeAttributeGroupKeyMapWithValue:groupKeyMapArgument + completion:^(NSError * _Nullable err) { + NSLog(@"Map Group 1 and Group 2 to KeySet 1 and group 2 to KeySet 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestRemoveKeyset1_25() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetRemoveParams alloc] init]; + params.groupKeySetID = [NSNumber numberWithUnsignedShort:417U]; + [cluster keySetRemoveWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"Remove keyset 1 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestThVerifiesGroupKeyMapEntriesForKeySet1HaveBeenRemoved_26() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRReadParams alloc] init]; + params.filterByFabric = true; + [cluster + readAttributeGroupKeyMapWithParams:params + completion:^(NSArray * _Nullable value, NSError * _Nullable err) { + NSLog(@"TH verifies GroupKeyMap entries for KeySet 1 have been removed Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn( + CheckValue("GroupKeyMap", [actualValue count], static_cast(1))); + VerifyOrReturn(CheckValue("GroupId", + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) actualValue[0]).groupId, 258U)); + VerifyOrReturn(CheckValue("GroupKeySetID", + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) actualValue[0]).groupKeySetID, + 418U)); + VerifyOrReturn(CheckValue("FabricIndex", + ((MTRGroupKeyManagementClusterGroupKeyMapStruct *) actualValue[0]).fabricIndex, + 1U)); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestRemoveKeyset2_27() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRGroupKeyManagementClusterKeySetRemoveParams alloc] init]; + params.groupKeySetID = [NSNumber numberWithUnsignedShort:418U]; + [cluster keySetRemoveWithParams:params + completion:^(NSError * _Nullable err) { + NSLog(@"Remove keyset 2 Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR TestThVerifiesGroupKeyMapEntriesForKeySet2HaveBeenRemoved_28() + { + + MTRBaseDevice * device = GetDevice("alpha"); + __auto_type * cluster = [[MTRBaseClusterGroupKeyManagement alloc] initWithDevice:device + endpointID:@(0) + queue:mCallbackQueue]; + VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); + + __auto_type * params = [[MTRReadParams alloc] init]; + params.filterByFabric = true; + [cluster + readAttributeGroupKeyMapWithParams:params + completion:^(NSArray * _Nullable value, NSError * _Nullable err) { + NSLog(@"TH verifies GroupKeyMap entries for KeySet 2 have been removed Error: %@", err); + + VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); + + { + id actualValue = value; + VerifyOrReturn( + CheckValue("GroupKeyMap", [actualValue count], static_cast(0))); + } + + NextTest(); + }]; + + return CHIP_NO_ERROR; + } }; class Test_TC_G_1_1 : public TestCommandBridge {