Matter SDK Coverage Report
Current view: top level - credentials - GroupDataProviderImpl.cpp (source / functions) Coverage Total Hit
Test: SHA:3f9cd168e84cd831b7699126f5296f5c5498690f Lines: 97.6 % 1125 1098
Test Date: 2026-04-27 19:52:19 Functions: 99.2 % 129 128

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : #include <credentials/GroupDataProviderImpl.h>
      18              : #include <crypto/CHIPCryptoPAL.h>
      19              : #include <lib/core/TLV.h>
      20              : #include <lib/support/CodeUtils.h>
      21              : #include <lib/support/CommonPersistentData.h>
      22              : #include <lib/support/DefaultStorageKeyAllocator.h>
      23              : #include <lib/support/PersistentData.h>
      24              : #include <lib/support/Pool.h>
      25              : #include <stdlib.h>
      26              : 
      27              : namespace chip {
      28              : namespace Credentials {
      29              : 
      30              : using GroupInfo     = GroupDataProvider::GroupInfo;
      31              : using GroupKey      = GroupDataProvider::GroupKey;
      32              : using GroupEndpoint = GroupDataProvider::GroupEndpoint;
      33              : using EpochKey      = GroupDataProvider::EpochKey;
      34              : using KeySet        = GroupDataProvider::KeySet;
      35              : using GroupSession  = GroupDataProvider::GroupSession;
      36              : 
      37              : struct FabricList : public CommonPersistentData::FabricList
      38              : {
      39         1169 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      40              :     {
      41         1169 :         key = DefaultStorageKeyAllocator::GroupFabricList();
      42         1169 :         return CHIP_NO_ERROR;
      43              :     }
      44              : };
      45              : 
      46              : constexpr size_t kPersistentBufferMax = 128;
      47              : 
      48              : struct LinkedData : public PersistableData<kPersistentBufferMax>
      49              : {
      50              :     static constexpr uint16_t kMinLinkId = 1;
      51              : 
      52           68 :     LinkedData() = default;
      53          780 :     LinkedData(uint16_t linked_id) : id(linked_id) {}
      54              :     uint16_t id     = kMinLinkId;
      55              :     uint16_t index  = 0;
      56              :     uint16_t next   = 0;
      57              :     uint16_t prev   = 0;
      58              :     uint16_t max_id = 0;
      59              :     bool first      = true;
      60              : };
      61              : 
      62              : struct FabricData : public PersistableData<kPersistentBufferMax>
      63              : {
      64         7681 :     static constexpr TLV::Tag TagFirstGroup() { return TLV::ContextTag(1); }
      65         7681 :     static constexpr TLV::Tag TagGroupCount() { return TLV::ContextTag(2); }
      66         7681 :     static constexpr TLV::Tag TagFirstMap() { return TLV::ContextTag(3); }
      67         7681 :     static constexpr TLV::Tag TagMapCount() { return TLV::ContextTag(4); }
      68         7681 :     static constexpr TLV::Tag TagFirstKeyset() { return TLV::ContextTag(5); }
      69         7681 :     static constexpr TLV::Tag TagKeysetCount() { return TLV::ContextTag(6); }
      70         7681 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(7); }
      71              : 
      72              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
      73              :     chip::GroupId first_group      = kUndefinedGroupId;
      74              :     uint16_t group_count           = 0;
      75              :     uint16_t first_map             = 0;
      76              :     uint16_t map_count             = 0;
      77              :     chip::KeysetId first_keyset    = kInvalidKeysetId;
      78              :     uint16_t keyset_count          = 0;
      79              :     chip::FabricIndex next         = kUndefinedFabricIndex;
      80              : 
      81           29 :     FabricData() = default;
      82         7262 :     FabricData(chip::FabricIndex fabric) : fabric_index(fabric) {}
      83              : 
      84         8316 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
      85              :     {
      86         8316 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
      87         8314 :         key = DefaultStorageKeyAllocator::FabricGroups(fabric_index);
      88         8314 :         return CHIP_NO_ERROR;
      89              :     }
      90              : 
      91         7311 :     void Clear() override
      92              :     {
      93         7311 :         first_group  = kUndefinedGroupId;
      94         7311 :         group_count  = 0;
      95         7311 :         first_keyset = kInvalidKeysetId;
      96         7311 :         keyset_count = 0;
      97         7311 :         next         = kUndefinedFabricIndex;
      98         7311 :     }
      99              : 
     100          978 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     101              :     {
     102              :         TLV::TLVType container;
     103          978 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     104              : 
     105          978 :         ReturnErrorOnFailure(writer.Put(TagFirstGroup(), static_cast<uint16_t>(first_group)));
     106          978 :         ReturnErrorOnFailure(writer.Put(TagGroupCount(), static_cast<uint16_t>(group_count)));
     107          978 :         ReturnErrorOnFailure(writer.Put(TagFirstMap(), static_cast<uint16_t>(first_map)));
     108          978 :         ReturnErrorOnFailure(writer.Put(TagMapCount(), static_cast<uint16_t>(map_count)));
     109          978 :         ReturnErrorOnFailure(writer.Put(TagFirstKeyset(), static_cast<uint16_t>(first_keyset)));
     110          978 :         ReturnErrorOnFailure(writer.Put(TagKeysetCount(), static_cast<uint16_t>(keyset_count)));
     111          978 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     112              : 
     113          978 :         return writer.EndContainer(container);
     114              :     }
     115         6703 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     116              :     {
     117         6703 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     118         6703 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     119              : 
     120              :         TLV::TLVType container;
     121         6703 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     122              : 
     123              :         // first_group
     124         6703 :         ReturnErrorOnFailure(reader.Next(TagFirstGroup()));
     125         6703 :         ReturnErrorOnFailure(reader.Get(first_group));
     126              :         // group_count
     127         6703 :         ReturnErrorOnFailure(reader.Next(TagGroupCount()));
     128         6703 :         ReturnErrorOnFailure(reader.Get(group_count));
     129              :         // first_map
     130         6703 :         ReturnErrorOnFailure(reader.Next(TagFirstMap()));
     131         6703 :         ReturnErrorOnFailure(reader.Get(first_map));
     132              :         // map_count
     133         6703 :         ReturnErrorOnFailure(reader.Next(TagMapCount()));
     134         6703 :         ReturnErrorOnFailure(reader.Get(map_count));
     135              :         // first_keyset
     136         6703 :         ReturnErrorOnFailure(reader.Next(TagFirstKeyset()));
     137         6703 :         ReturnErrorOnFailure(reader.Get(first_keyset));
     138              :         // keyset_count
     139         6703 :         ReturnErrorOnFailure(reader.Next(TagKeysetCount()));
     140         6703 :         ReturnErrorOnFailure(reader.Get(keyset_count));
     141              :         // next
     142         6703 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     143         6703 :         ReturnErrorOnFailure(reader.Get(next));
     144              : 
     145         6703 :         return reader.ExitContainer(container);
     146              :     }
     147              : 
     148              :     // Register the fabric in the fabrics' linked-list
     149          978 :     CHIP_ERROR Register(PersistentStorageDelegate * storage)
     150              :     {
     151          978 :         FabricList fabric_list;
     152          978 :         CHIP_ERROR err = fabric_list.Load(storage);
     153         1956 :         if (CHIP_ERROR_NOT_FOUND == err)
     154              :         {
     155              :             // New fabric list
     156          100 :             fabric_list.first_entry = fabric_index;
     157          100 :             fabric_list.entry_count = 1;
     158          100 :             return fabric_list.Save(storage);
     159              :         }
     160          878 :         ReturnErrorOnFailure(err);
     161              : 
     162              :         // Existing fabric list, search for existing entry
     163          878 :         FabricData fabric(fabric_list.first_entry);
     164          945 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     165              :         {
     166          917 :             err = fabric.Load(storage);
     167         1834 :             if (CHIP_NO_ERROR != err)
     168              :             {
     169            0 :                 break;
     170              :             }
     171          917 :             if (fabric.fabric_index == this->fabric_index)
     172              :             {
     173              :                 // Fabric already registered
     174          850 :                 return CHIP_NO_ERROR;
     175              :             }
     176           67 :             fabric.fabric_index = fabric.next;
     177              :         }
     178              :         // Add this fabric to the fabric list
     179           28 :         this->next              = fabric_list.first_entry;
     180           28 :         fabric_list.first_entry = this->fabric_index;
     181           28 :         fabric_list.entry_count++;
     182           28 :         return fabric_list.Save(storage);
     183          978 :     }
     184              : 
     185              :     // Remove the fabric from the fabrics' linked list
     186           29 :     CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const
     187              :     {
     188           29 :         FabricList fabric_list;
     189           29 :         CHIP_ERROR err = fabric_list.Load(storage);
     190           60 :         VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     191              : 
     192              :         // Existing fabric list, search for existing entry
     193           29 :         FabricData fabric(fabric_list.first_entry);
     194           29 :         FabricData prev;
     195              : 
     196           42 :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     197              :         {
     198           38 :             err = fabric.Load(storage);
     199           76 :             if (CHIP_NO_ERROR != err)
     200              :             {
     201            0 :                 break;
     202              :             }
     203           38 :             if (fabric.fabric_index == this->fabric_index)
     204              :             {
     205              :                 // Fabric found
     206           25 :                 if (i == 0)
     207              :                 {
     208              :                     // Remove first fabric
     209           13 :                     fabric_list.first_entry = this->next;
     210              :                 }
     211              :                 else
     212              :                 {
     213              :                     // Remove intermediate fabric
     214           12 :                     prev.next = this->next;
     215           12 :                     ReturnErrorOnFailure(prev.Save(storage));
     216              :                 }
     217           25 :                 VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL);
     218           25 :                 fabric_list.entry_count--;
     219           25 :                 return fabric_list.Save(storage);
     220              :             }
     221           13 :             prev                = fabric;
     222           13 :             fabric.fabric_index = fabric.next;
     223              :         }
     224              :         // Fabric not in the list
     225            4 :         return CHIP_ERROR_NOT_FOUND;
     226           29 :     }
     227              : 
     228              :     // Check the fabric is registered in the fabrics' linked list
     229              :     CHIP_ERROR Validate(PersistentStorageDelegate * storage) const
     230              :     {
     231              :         FabricList fabric_list;
     232              :         ReturnErrorOnFailure(fabric_list.Load(storage));
     233              : 
     234              :         // Existing fabric list, search for existing entry
     235              :         FabricData fabric(fabric_list.first_entry);
     236              : 
     237              :         for (size_t i = 0; i < fabric_list.entry_count; i++)
     238              :         {
     239              :             ReturnErrorOnFailure(fabric.Load(storage));
     240              :             if (fabric.fabric_index == this->fabric_index)
     241              :             {
     242              :                 return CHIP_NO_ERROR;
     243              :             }
     244              :             fabric.fabric_index = fabric.next;
     245              :         }
     246              :         // Fabric not in the list
     247              :         return CHIP_ERROR_NOT_FOUND;
     248              :     }
     249              : 
     250          978 :     CHIP_ERROR Save(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     251              :     {
     252          978 :         ReturnErrorOnFailure(Register(storage));
     253          978 :         return PersistableData::Save(storage);
     254              :     }
     255              : 
     256           29 :     CHIP_ERROR Delete(PersistentStorageDelegate * storage) // NOLINT(bugprone-derived-method-shadowing-base-method)
     257              :     {
     258           29 :         ReturnErrorOnFailure(Unregister(storage));
     259           25 :         return PersistableData::Delete(storage);
     260              :     }
     261              : };
     262              : 
     263              : struct GroupData : public GroupDataProvider::GroupInfo, PersistableData<kPersistentBufferMax>
     264              : {
     265        10747 :     static constexpr TLV::Tag TagName() { return TLV::ContextTag(1); }
     266        10747 :     static constexpr TLV::Tag TagFirstEndpoint() { return TLV::ContextTag(2); }
     267        10747 :     static constexpr TLV::Tag TagEndpointCount() { return TLV::ContextTag(3); }
     268        10747 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(4); }
     269        10747 :     static constexpr TLV::Tag TagFlags() { return TLV::ContextTag(5); }
     270              : 
     271              :     chip::FabricIndex fabric_index  = kUndefinedFabricIndex;
     272              :     chip::EndpointId first_endpoint = kInvalidEndpointId;
     273              :     uint16_t endpoint_count         = 0;
     274              :     uint16_t index                  = 0;
     275              :     chip::GroupId next              = 0;
     276              :     chip::GroupId prev              = 0;
     277              :     bool first                      = true;
     278              : 
     279         2374 :     GroupData() : GroupInfo(nullptr){};
     280              :     GroupData(chip::FabricIndex fabric) : fabric_index(fabric) {}
     281         5644 :     GroupData(chip::FabricIndex fabric, chip::GroupId group) : GroupInfo(group, nullptr), fabric_index(fabric) {}
     282              : 
     283        10815 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     284              :     {
     285        10815 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     286        10815 :         key = DefaultStorageKeyAllocator::FabricGroup(fabric_index, group_id);
     287        10815 :         return CHIP_NO_ERROR;
     288              :     }
     289              : 
     290         8937 :     void Clear() override
     291              :     {
     292         8937 :         SetName(CharSpan());
     293         8937 :         first_endpoint = kInvalidEndpointId;
     294         8937 :         endpoint_count = 0;
     295         8937 :         next           = 0;
     296         8937 :         flags          = 0;
     297         8937 :     }
     298              : 
     299         1811 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     300              :     {
     301              :         TLV::TLVType container;
     302         1811 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     303              : 
     304         1811 :         size_t name_size = strnlen(name, GroupDataProvider::GroupInfo::kGroupNameMax);
     305         1811 :         ReturnErrorOnFailure(writer.PutString(TagName(), name, static_cast<uint32_t>(name_size)));
     306         1811 :         ReturnErrorOnFailure(writer.Put(TagFirstEndpoint(), static_cast<uint16_t>(first_endpoint)));
     307         1811 :         ReturnErrorOnFailure(writer.Put(TagEndpointCount(), static_cast<uint16_t>(endpoint_count)));
     308         1811 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     309         1811 :         ReturnErrorOnFailure(writer.Put(TagFlags(), static_cast<uint8_t>(flags)));
     310         1811 :         return writer.EndContainer(container);
     311              :     }
     312              : 
     313         8936 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     314              :     {
     315         8936 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     316         8936 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     317              : 
     318              :         TLV::TLVType container;
     319         8936 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     320              : 
     321              :         // name
     322         8936 :         ReturnErrorOnFailure(reader.Next(TagName()));
     323         8936 :         ReturnErrorOnFailure(reader.GetString(name, sizeof(name)));
     324         8936 :         size_t size = strnlen(name, kGroupNameMax);
     325         8936 :         name[size]  = 0;
     326              :         // first_endpoint
     327         8936 :         ReturnErrorOnFailure(reader.Next(TagFirstEndpoint()));
     328         8936 :         ReturnErrorOnFailure(reader.Get(first_endpoint));
     329              :         // endpoint_count
     330         8936 :         ReturnErrorOnFailure(reader.Next(TagEndpointCount()));
     331         8936 :         ReturnErrorOnFailure(reader.Get(endpoint_count));
     332              :         // next
     333         8936 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     334         8936 :         ReturnErrorOnFailure(reader.Get(next));
     335              : 
     336              :         // Groupcast
     337         8936 :         CHIP_ERROR err = reader.Next(TagFlags());
     338        17872 :         if (CHIP_NO_ERROR == err)
     339              :         {
     340              :             // flags
     341         8936 :             uint8_t value = 0;
     342         8936 :             ReturnErrorOnFailure(reader.Get(value));
     343         8936 :             flags = value;
     344              :         }
     345              : 
     346         8936 :         return reader.ExitContainer(container);
     347              :     }
     348              : 
     349          115 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     350              :     {
     351          115 :         fabric_index = fabric.fabric_index;
     352          115 :         group_id     = fabric.first_group;
     353          115 :         index        = 0;
     354          115 :         first        = true;
     355              : 
     356          181 :         while (index < fabric.group_count)
     357              :         {
     358          318 :             if (CHIP_NO_ERROR != Load(storage))
     359              :             {
     360            0 :                 break;
     361              :             }
     362          159 :             if (index == target_index)
     363              :             {
     364              :                 // Target index found
     365           93 :                 return true;
     366              :             }
     367              : 
     368           66 :             first    = false;
     369           66 :             prev     = group_id;
     370           66 :             group_id = next;
     371           66 :             index++;
     372              :         }
     373              : 
     374           22 :         return false;
     375              :     }
     376              : 
     377         2223 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, chip::GroupId target_group)
     378              :     {
     379         2223 :         fabric_index = fabric.fabric_index;
     380         2223 :         group_id     = fabric.first_group;
     381         2223 :         index        = 0;
     382         2223 :         first        = true;
     383              : 
     384         3784 :         while (index < fabric.group_count)
     385              :         {
     386         6258 :             if (CHIP_NO_ERROR != Load(storage))
     387              :             {
     388            0 :                 break;
     389              :             }
     390         3129 :             if (group_id == target_group)
     391              :             {
     392              :                 // Target index found
     393         1568 :                 return true;
     394              :             }
     395         1561 :             first    = false;
     396         1561 :             prev     = group_id;
     397         1561 :             group_id = next;
     398         1561 :             index++;
     399              :         }
     400          655 :         return false;
     401              :     }
     402              : };
     403              : 
     404              : struct KeyMapData : public GroupDataProvider::GroupKey, LinkedData
     405              : {
     406         1811 :     static constexpr TLV::Tag TagGroupId() { return TLV::ContextTag(1); }
     407         1811 :     static constexpr TLV::Tag TagKeysetId() { return TLV::ContextTag(2); }
     408         1811 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(3); }
     409              : 
     410              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     411              :     chip::GroupId group_id         = kUndefinedGroupId;
     412              :     chip::KeysetId keyset_id       = 0;
     413              : 
     414           68 :     KeyMapData(){};
     415          780 :     KeyMapData(chip::FabricIndex fabric, uint16_t link_id = 0, chip::GroupId group = kUndefinedGroupId, chip::KeysetId keyset = 0) :
     416          780 :         GroupKey(group, keyset), LinkedData(link_id), fabric_index(fabric)
     417          780 :     {}
     418              : 
     419         1834 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     420              :     {
     421         1834 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     422         1834 :         key = DefaultStorageKeyAllocator::FabricGroupKey(fabric_index, id);
     423         1834 :         return CHIP_NO_ERROR;
     424              :     }
     425              : 
     426         1262 :     void Clear() override {}
     427              : 
     428          549 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     429              :     {
     430              :         TLV::TLVType container;
     431          549 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     432              : 
     433          549 :         ReturnErrorOnFailure(writer.Put(TagGroupId(), static_cast<uint16_t>(group_id)));
     434          549 :         ReturnErrorOnFailure(writer.Put(TagKeysetId(), static_cast<uint16_t>(keyset_id)));
     435          549 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     436          549 :         return writer.EndContainer(container);
     437              :     }
     438              : 
     439         1262 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     440              :     {
     441         1262 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     442         1262 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     443              : 
     444              :         TLV::TLVType container;
     445         1262 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     446              : 
     447              :         // first_endpoint
     448         1262 :         ReturnErrorOnFailure(reader.Next(TagGroupId()));
     449         1262 :         ReturnErrorOnFailure(reader.Get(group_id));
     450              :         // endpoint_count
     451         1262 :         ReturnErrorOnFailure(reader.Next(TagKeysetId()));
     452         1262 :         ReturnErrorOnFailure(reader.Get(keyset_id));
     453              :         // next
     454         1262 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     455         1262 :         ReturnErrorOnFailure(reader.Get(next));
     456              : 
     457         1262 :         return reader.ExitContainer(container);
     458              :     }
     459              : 
     460          341 :     bool Get(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_index)
     461              :     {
     462          341 :         fabric_index = fabric.fabric_index;
     463          341 :         id           = fabric.first_map;
     464          341 :         max_id       = 0;
     465          341 :         index        = 0;
     466          341 :         first        = true;
     467              : 
     468          711 :         while (index < fabric.map_count)
     469              :         {
     470          824 :             if (CHIP_NO_ERROR != Load(storage))
     471              :             {
     472            0 :                 break;
     473              :             }
     474          412 :             if (index == target_index)
     475              :             {
     476              :                 // Target index found
     477           42 :                 return true;
     478              :             }
     479          370 :             max_id = std::max(id, max_id);
     480          370 :             first  = false;
     481          370 :             prev   = id;
     482          370 :             id     = next;
     483          370 :             index++;
     484              :         }
     485              : 
     486          299 :         id = static_cast<uint16_t>(max_id + 1);
     487          299 :         return false;
     488              :     }
     489              : 
     490          305 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupKey & map)
     491              :     {
     492          305 :         fabric_index = fabric.fabric_index;
     493          305 :         id           = fabric.first_map;
     494          305 :         max_id       = 0;
     495          305 :         index        = 0;
     496          305 :         first        = true;
     497              : 
     498          633 :         while (index < fabric.map_count)
     499              :         {
     500          676 :             if (CHIP_NO_ERROR != Load(storage))
     501              :             {
     502            0 :                 break;
     503              :             }
     504          338 :             if ((group_id == map.group_id) && (keyset_id == map.keyset_id))
     505              :             {
     506              :                 // Match found
     507           10 :                 return true;
     508              :             }
     509          328 :             max_id = std::max(id, max_id);
     510          328 :             first  = false;
     511          328 :             prev   = id;
     512          328 :             id     = next;
     513          328 :             index++;
     514              :         }
     515              : 
     516          295 :         id = static_cast<uint16_t>(max_id + 1);
     517          295 :         return false;
     518              :     }
     519              : 
     520              :     // returns index if the find_id is found, otherwise std::numeric_limits<size_t>::max
     521            2 :     size_t Find(PersistentStorageDelegate * storage, const FabricData & fabric, const KeysetId find_id)
     522              :     {
     523            2 :         fabric_index = fabric.fabric_index;
     524            2 :         id           = fabric.first_map;
     525            2 :         max_id       = 0;
     526            2 :         index        = 0;
     527            2 :         first        = true;
     528              : 
     529            6 :         while (index < fabric.map_count)
     530              :         {
     531           10 :             if (CHIP_NO_ERROR != Load(storage))
     532              :             {
     533            0 :                 break;
     534              :             }
     535            5 :             if (keyset_id == find_id)
     536              :             {
     537              :                 // Match found
     538            1 :                 return index;
     539              :             }
     540            4 :             max_id = std::max(id, max_id);
     541            4 :             first  = false;
     542            4 :             prev   = id;
     543            4 :             id     = next;
     544            4 :             index++;
     545              :         }
     546              : 
     547            1 :         id = static_cast<uint16_t>(max_id + 1);
     548            1 :         return std::numeric_limits<size_t>::max();
     549              :     }
     550              : };
     551              : 
     552              : struct EndpointData : GroupDataProvider::GroupEndpoint, PersistableData<kPersistentBufferMax>
     553              : {
     554        67069 :     static constexpr TLV::Tag TagEndpoint() { return TLV::ContextTag(1); }
     555        67069 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(2); }
     556              : 
     557              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     558              :     uint16_t index                 = 0;
     559              :     chip::EndpointId next          = 0;
     560              :     chip::EndpointId prev          = 0;
     561              :     bool first                     = true;
     562              : 
     563         1427 :     EndpointData() = default;
     564         2205 :     EndpointData(chip::FabricIndex fabric, chip::GroupId group = kUndefinedGroupId,
     565         2205 :                  chip::EndpointId endpoint = kInvalidEndpointId) :
     566              :         GroupEndpoint(group, endpoint),
     567         2205 :         fabric_index(fabric)
     568         2205 :     {}
     569              : 
     570        67532 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     571              :     {
     572        67532 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     573        67532 :         key = DefaultStorageKeyAllocator::FabricGroupEndpoint(fabric_index, group_id, endpoint_id);
     574        67532 :         return CHIP_NO_ERROR;
     575              :     }
     576              : 
     577        64248 :     void Clear() override { next = kInvalidEndpointId; }
     578              : 
     579         2842 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     580              :     {
     581              :         TLV::TLVType container;
     582         2842 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     583              : 
     584         2842 :         ReturnErrorOnFailure(writer.Put(TagEndpoint(), static_cast<uint16_t>(endpoint_id)));
     585         2842 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     586              : 
     587         2842 :         return writer.EndContainer(container);
     588              :     }
     589        64227 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     590              :     {
     591        64227 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     592        64227 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     593              : 
     594              :         TLV::TLVType container;
     595        64227 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     596              : 
     597              :         // endpoint_id
     598        64227 :         ReturnErrorOnFailure(reader.Next(TagEndpoint()));
     599        64227 :         ReturnErrorOnFailure(reader.Get(endpoint_id));
     600              :         // next
     601        64227 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     602        64227 :         ReturnErrorOnFailure(reader.Get(next));
     603              : 
     604        64227 :         return reader.ExitContainer(container);
     605              :     }
     606              : 
     607         1412 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, const GroupData & group, chip::EndpointId target_id)
     608              :     {
     609         1412 :         fabric_index = fabric.fabric_index;
     610         1412 :         group_id     = group.group_id;
     611         1412 :         endpoint_id  = group.first_endpoint;
     612         1412 :         index        = 0;
     613         1412 :         first        = true;
     614              : 
     615        61748 :         while (index < group.endpoint_count)
     616              :         {
     617       121228 :             if (CHIP_NO_ERROR != Load(storage))
     618              :             {
     619            0 :                 break;
     620              :             }
     621        60614 :             if (this->endpoint_id == target_id)
     622              :             {
     623              :                 // Match found
     624          278 :                 return true;
     625              :             }
     626              : 
     627        60336 :             first       = false;
     628        60336 :             prev        = endpoint_id;
     629        60336 :             endpoint_id = next;
     630        60336 :             index++;
     631              :         }
     632              : 
     633         1134 :         return false;
     634              :     }
     635              : };
     636              : 
     637              : struct KeySetData : PersistableData<kPersistentBufferMax>
     638              : {
     639          847 :     static constexpr TLV::Tag TagPolicy() { return TLV::ContextTag(1); }
     640          847 :     static constexpr TLV::Tag TagNumKeys() { return TLV::ContextTag(2); }
     641          847 :     static constexpr TLV::Tag TagGroupCredentials() { return TLV::ContextTag(3); }
     642         2541 :     static constexpr TLV::Tag TagStartTime() { return TLV::ContextTag(4); }
     643         2541 :     static constexpr TLV::Tag TagKeyHash() { return TLV::ContextTag(5); }
     644         2541 :     static constexpr TLV::Tag TagKeyValue() { return TLV::ContextTag(6); }
     645          847 :     static constexpr TLV::Tag TagNext() { return TLV::ContextTag(7); }
     646              : 
     647              :     chip::FabricIndex fabric_index = kUndefinedFabricIndex;
     648              :     chip::KeysetId next            = kInvalidKeysetId;
     649              :     chip::KeysetId prev            = kInvalidKeysetId;
     650              :     bool first                     = true;
     651              : 
     652              :     uint16_t keyset_id                       = 0;
     653              :     GroupDataProvider::SecurityPolicy policy = GroupDataProvider::SecurityPolicy::kCacheAndSync;
     654              :     uint8_t keys_count                       = 0;
     655              :     Crypto::GroupOperationalCredentials operational_keys[KeySet::kEpochKeysMax];
     656              : 
     657          530 :     KeySetData() = default;
     658           40 :     KeySetData(chip::FabricIndex fabric, chip::KeysetId id) : fabric_index(fabric) { keyset_id = id; }
     659              :     KeySetData(chip::FabricIndex fabric, chip::KeysetId id, GroupDataProvider::SecurityPolicy policy_id, uint8_t num_keys) :
     660              :         fabric_index(fabric), keyset_id(id), policy(policy_id), keys_count(num_keys)
     661              :     {}
     662              : 
     663          872 :     CHIP_ERROR UpdateKey(StorageKeyName & key) const override
     664              :     {
     665          872 :         VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX);
     666          872 :         VerifyOrReturnError(kInvalidKeysetId != keyset_id, CHIP_ERROR_INVALID_KEY_ID);
     667          872 :         key = DefaultStorageKeyAllocator::FabricKeyset(fabric_index, keyset_id);
     668          872 :         return CHIP_NO_ERROR;
     669              :     }
     670              : 
     671          588 :     void Clear() override
     672              :     {
     673          588 :         policy     = GroupDataProvider::SecurityPolicy::kCacheAndSync;
     674          588 :         keys_count = 0;
     675          588 :         memset(operational_keys, 0x00, sizeof(operational_keys));
     676          588 :         next = kInvalidKeysetId;
     677          588 :     }
     678              : 
     679            4 :     Crypto::GroupOperationalCredentials * GetCurrentGroupCredentials()
     680              :     {
     681              :         // An epoch key update SHALL order the keys from oldest to newest,
     682              :         // the current epoch key having the second newest time if time
     683              :         // synchronization is not achieved or guaranteed.
     684            4 :         switch (this->keys_count)
     685              :         {
     686            1 :         case 1:
     687              :         case 2:
     688            1 :             return &operational_keys[0];
     689            3 :         case 3:
     690            3 :             return &operational_keys[1];
     691            0 :         default:
     692            0 :             return nullptr;
     693              :         }
     694              :     }
     695              : 
     696          259 :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override
     697              :     {
     698              :         TLV::TLVType container;
     699          259 :         ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container));
     700              : 
     701              :         // policy
     702          259 :         ReturnErrorOnFailure(writer.Put(TagPolicy(), static_cast<uint16_t>(policy)));
     703              :         // keys_count
     704          259 :         ReturnErrorOnFailure(writer.Put(TagNumKeys(), static_cast<uint16_t>(keys_count)));
     705              :         // operational_keys
     706              :         {
     707              :             TLV::TLVType array, item;
     708          259 :             ReturnErrorOnFailure(writer.StartContainer(TagGroupCredentials(), TLV::kTLVType_Array, array));
     709          259 :             uint8_t keyCount   = 0;
     710          259 :             uint64_t startTime = 0;
     711          259 :             uint16_t hash      = 0;
     712              :             uint8_t encryptionKey[Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES];
     713         1036 :             for (auto & key : operational_keys)
     714              :             {
     715          777 :                 startTime = 0;
     716          777 :                 hash      = 0;
     717          777 :                 memset(encryptionKey, 0, sizeof(encryptionKey));
     718          777 :                 ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, item));
     719              : 
     720          777 :                 if (keyCount++ < keys_count)
     721              :                 {
     722          655 :                     startTime = key.start_time;
     723          655 :                     hash      = key.hash;
     724          655 :                     memcpy(encryptionKey, key.encryption_key, sizeof(encryptionKey));
     725              :                 }
     726          777 :                 ReturnErrorOnFailure(writer.Put(TagStartTime(), static_cast<uint64_t>(startTime)));
     727          777 :                 ReturnErrorOnFailure(writer.Put(TagKeyHash(), hash));
     728          777 :                 ReturnErrorOnFailure(writer.Put(TagKeyValue(), ByteSpan(encryptionKey)));
     729              : 
     730          777 :                 ReturnErrorOnFailure(writer.EndContainer(item));
     731              :             }
     732          259 :             ReturnErrorOnFailure(writer.EndContainer(array));
     733              :         }
     734              :         // next keyset
     735          259 :         ReturnErrorOnFailure(writer.Put(TagNext(), static_cast<uint16_t>(next)));
     736              : 
     737          259 :         return writer.EndContainer(container);
     738              :     }
     739              : 
     740          588 :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override
     741              :     {
     742          588 :         ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     743          588 :         VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     744              : 
     745              :         TLV::TLVType container;
     746          588 :         ReturnErrorOnFailure(reader.EnterContainer(container));
     747              : 
     748              :         // policy
     749          588 :         ReturnErrorOnFailure(reader.Next(TagPolicy()));
     750          588 :         ReturnErrorOnFailure(reader.Get(policy));
     751              :         // keys_count
     752          588 :         ReturnErrorOnFailure(reader.Next(TagNumKeys()));
     753          588 :         ReturnErrorOnFailure(reader.Get(keys_count));
     754              :         // TODO(#21614): Enforce maximum number of 3 keys in a keyset
     755              :         {
     756              :             // operational_keys
     757          588 :             ReturnErrorOnFailure(reader.Next(TagGroupCredentials()));
     758          588 :             VerifyOrReturnError(TLV::kTLVType_Array == reader.GetType(), CHIP_ERROR_INTERNAL);
     759              : 
     760              :             TLV::TLVType array, item;
     761          588 :             ReturnErrorOnFailure(reader.EnterContainer(array));
     762         2352 :             for (auto & key : operational_keys)
     763              :             {
     764         1764 :                 ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
     765         1764 :                 VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL);
     766              : 
     767         1764 :                 ReturnErrorOnFailure(reader.EnterContainer(item));
     768              :                 // start_time
     769         1764 :                 ReturnErrorOnFailure(reader.Next(TagStartTime()));
     770         1764 :                 ReturnErrorOnFailure(reader.Get(key.start_time));
     771              :                 // key hash
     772         1764 :                 ReturnErrorOnFailure(reader.Next(TagKeyHash()));
     773         1764 :                 ReturnErrorOnFailure(reader.Get(key.hash));
     774              :                 // key value
     775         1764 :                 ByteSpan encryption_key;
     776         1764 :                 ReturnErrorOnFailure(reader.Next(TagKeyValue()));
     777         1764 :                 ReturnErrorOnFailure(reader.Get(encryption_key));
     778         1764 :                 VerifyOrReturnError(Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES == encryption_key.size(), CHIP_ERROR_INTERNAL);
     779         1764 :                 memcpy(key.encryption_key, encryption_key.data(), encryption_key.size());
     780              :                 // Re-derive privacy key from encryption key when loading from storage to save on storage size.
     781         1764 :                 MutableByteSpan privacy_key(key.privacy_key);
     782         1764 :                 ReturnErrorOnFailure(Crypto::DeriveGroupPrivacyKey(encryption_key, privacy_key));
     783         1764 :                 ReturnErrorOnFailure(reader.ExitContainer(item));
     784              :             }
     785          588 :             ReturnErrorOnFailure(reader.ExitContainer(array));
     786              :         }
     787              :         // next keyset
     788          588 :         ReturnErrorOnFailure(reader.Next(TagNext()));
     789          588 :         ReturnErrorOnFailure(reader.Get(next));
     790              : 
     791          588 :         return reader.ExitContainer(container);
     792              :     }
     793              : 
     794          512 :     bool Find(PersistentStorageDelegate * storage, const FabricData & fabric, size_t target_id)
     795              :     {
     796          512 :         uint16_t count = 0;
     797              : 
     798          512 :         fabric_index = fabric.fabric_index;
     799          512 :         keyset_id    = fabric.first_keyset;
     800          512 :         first        = true;
     801              : 
     802          838 :         while (count++ < fabric.keyset_count)
     803              :         {
     804         1124 :             if (CHIP_NO_ERROR != Load(storage))
     805              :             {
     806            0 :                 break;
     807              :             }
     808              : 
     809          562 :             if (keyset_id == target_id)
     810              :             {
     811              :                 // Target id found
     812          236 :                 return true;
     813              :             }
     814              : 
     815          326 :             first     = false;
     816          326 :             prev      = keyset_id;
     817          326 :             keyset_id = next;
     818              :         }
     819              : 
     820          276 :         return false;
     821              :     }
     822              : };
     823              : 
     824              : //
     825              : // General
     826              : //
     827              : 
     828              : constexpr size_t GroupDataProvider::GroupInfo::kGroupNameMax;
     829              : constexpr size_t GroupDataProviderImpl::kIteratorsMax;
     830              : 
     831          117 : CHIP_ERROR GroupDataProviderImpl::Init()
     832              : {
     833          117 :     if (mStorage == nullptr || mSessionKeystore == nullptr)
     834              :     {
     835            0 :         return CHIP_ERROR_INCORRECT_STATE;
     836              :     }
     837          117 :     return CHIP_NO_ERROR;
     838              : }
     839              : 
     840          111 : void GroupDataProviderImpl::Finish()
     841              : {
     842          111 :     mGroupInfoIterators.ReleaseAll();
     843          111 :     mGroupKeyIterators.ReleaseAll();
     844          111 :     mEndpointIterators.ReleaseAll();
     845          111 :     mKeySetIterators.ReleaseAll();
     846          111 :     mGroupSessionsIterator.ReleaseAll();
     847          111 :     mGroupKeyContexPool.ReleaseAll();
     848          111 : }
     849              : 
     850          117 : void GroupDataProviderImpl::SetStorageDelegate(PersistentStorageDelegate * storage)
     851              : {
     852          117 :     VerifyOrDie(storage != nullptr);
     853          117 :     mStorage = storage;
     854          117 : }
     855              : 
     856              : //
     857              : // Group Info
     858              : //
     859              : 
     860          326 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfo(chip::FabricIndex fabric_index, const GroupInfo & info)
     861              : {
     862          326 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     863              : 
     864          326 :     FabricData fabric(fabric_index);
     865          326 :     GroupData group;
     866              : 
     867              :     // Load fabric data (defaults to zero)
     868          326 :     CHIP_ERROR err = fabric.Load(mStorage);
     869          718 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     870              : 
     871          326 :     if (group.Find(mStorage, fabric, info.group_id))
     872              :     {
     873              :         // Existing group_id
     874           46 :         if (IsGroupcastEnabled() && group.endpoint_count > 0 && (group.HasAuxiliaryACL() != info.HasAuxiliaryACL()))
     875              :         {
     876            4 :             mAuxAclNotificationNeeded = true;
     877              :         }
     878              : 
     879           46 :         group.Copy(info);
     880           46 :         ReturnErrorOnFailure(group.Save(mStorage));
     881           46 :         GroupModified(fabric_index, info.group_id);
     882           46 :         return CHIP_NO_ERROR;
     883              :     }
     884              : 
     885              :     // New group_id
     886          280 :     group.Copy(info);
     887          280 :     return SetGroupInfoAt(fabric_index, fabric.group_count, group);
     888          326 : }
     889              : 
     890          157 : CHIP_ERROR GroupDataProviderImpl::GetGroupInfo(chip::FabricIndex fabric_index, chip::GroupId group_id, GroupInfo & info)
     891              : {
     892          157 :     FabricData fabric(fabric_index);
     893          157 :     GroupData group;
     894              : 
     895          157 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     896          141 :     info.count = fabric.group_count;
     897          141 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
     898              : 
     899           95 :     info.Copy(group);
     900           95 :     return CHIP_NO_ERROR;
     901          157 : }
     902              : 
     903            9 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupInfo(chip::FabricIndex fabric_index, chip::GroupId group_id)
     904              : {
     905            9 :     FabricData fabric(fabric_index);
     906            9 :     GroupData group;
     907              : 
     908            9 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     909            9 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
     910              : 
     911            9 :     return RemoveGroupInfoAt(fabric_index, group.index);
     912            9 : }
     913              : 
     914          321 : CHIP_ERROR GroupDataProviderImpl::SetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, const GroupInfo & info)
     915              : {
     916          321 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     917              : 
     918          321 :     FabricData fabric(fabric_index);
     919          321 :     GroupData group;
     920              : 
     921              :     // Load fabric, defaults to zero
     922          321 :     CHIP_ERROR err = fabric.Load(mStorage);
     923          718 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
     924              : 
     925              :     // If the group exists, the index must match
     926          321 :     bool found = group.Find(mStorage, fabric, info.group_id);
     927          321 :     VerifyOrReturnError(!found || (group.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
     928              : 
     929          317 :     group.Copy(info);
     930          317 :     group.endpoint_count = 0;
     931              : 
     932          317 :     if (found)
     933              :     {
     934              :         // Update existing entry
     935            6 :         if (IsGroupcastEnabled() && group.endpoint_count > 0 && (group.HasAuxiliaryACL() != info.HasAuxiliaryACL()))
     936              :         {
     937            0 :             mAuxAclNotificationNeeded = true;
     938              :         }
     939            6 :         return group.Save(mStorage);
     940              :     }
     941          311 :     if (index < fabric.group_count)
     942              :     {
     943              :         // Replace existing entry with a new group
     944            1 :         GroupData old_group;
     945            1 :         old_group.Get(mStorage, fabric, index);
     946            1 :         group.first = old_group.first;
     947            1 :         group.prev  = old_group.prev;
     948            1 :         group.next  = old_group.next;
     949              : 
     950            1 :         ReturnErrorOnFailure(RemoveEndpoints(fabric_index, old_group.group_id));
     951            1 :         ReturnErrorOnFailure(old_group.Delete(mStorage));
     952            1 :         GroupRemoved(fabric_index, old_group);
     953            1 :     }
     954              :     else
     955              :     {
     956              :         // Insert last
     957          310 :         VerifyOrReturnError(fabric.group_count == index, CHIP_ERROR_INVALID_ARGUMENT);
     958          309 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
     959          307 :         fabric.group_count++;
     960              :     }
     961              : 
     962          308 :     ReturnErrorOnFailure(group.Save(mStorage));
     963              : 
     964          308 :     if (group.first)
     965              :     {
     966              :         // First group, update fabric
     967          114 :         fabric.first_group = group.group_id;
     968              :     }
     969              :     else
     970              :     {
     971              :         // Second to last group, update previous
     972          194 :         GroupData prev(fabric_index, group.prev);
     973          194 :         ReturnErrorOnFailure(prev.Load(mStorage));
     974          194 :         prev.next = group.group_id;
     975          194 :         ReturnErrorOnFailure(prev.Save(mStorage));
     976          194 :     }
     977              :     // Update fabric
     978          308 :     ReturnErrorOnFailure(fabric.Save(mStorage));
     979          308 :     GroupAdded(fabric_index, group);
     980          308 :     return CHIP_NO_ERROR;
     981          321 : }
     982              : 
     983           57 : CHIP_ERROR GroupDataProviderImpl::GetGroupInfoAt(chip::FabricIndex fabric_index, size_t index, GroupInfo & info)
     984              : {
     985           57 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
     986              : 
     987           57 :     FabricData fabric(fabric_index);
     988           57 :     GroupData group;
     989              : 
     990           57 :     ReturnErrorOnFailure(fabric.Load(mStorage));
     991           48 :     VerifyOrReturnError(group.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
     992              : 
     993              :     // Target group found
     994           26 :     info.Copy(group);
     995           26 :     return CHIP_NO_ERROR;
     996           57 : }
     997              : 
     998           66 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupInfoAt(chip::FabricIndex fabric_index, size_t index)
     999              : {
    1000           66 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1001              : 
    1002           66 :     FabricData fabric(fabric_index);
    1003           66 :     GroupData group;
    1004              : 
    1005           66 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1006           66 :     VerifyOrReturnError(group.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
    1007              : 
    1008           66 :     bool notifyNeeded = (IsGroupcastEnabled() && group.HasAuxiliaryACL() && group.endpoint_count > 0);
    1009              : 
    1010              :     // Remove endpoints
    1011           66 :     EndpointData endpoint(fabric_index, group.group_id, group.first_endpoint);
    1012           66 :     size_t count = 0;
    1013          334 :     while (count++ < group.endpoint_count)
    1014              :     {
    1015          578 :         if (CHIP_NO_ERROR != endpoint.Load(mStorage))
    1016              :         {
    1017           21 :             break;
    1018              :         }
    1019          268 :         TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1020          268 :         endpoint.endpoint_id = endpoint.next;
    1021              :     }
    1022              : 
    1023           66 :     ReturnErrorOnFailure(group.Delete(mStorage));
    1024              : 
    1025           66 :     if (notifyNeeded)
    1026              :     {
    1027           23 :         mAuxAclNotificationNeeded = true;
    1028              :     }
    1029              : 
    1030           66 :     if (group.first)
    1031              :     {
    1032              :         // Remove first group
    1033           41 :         fabric.first_group = group.next;
    1034              :     }
    1035              :     else
    1036              :     {
    1037              :         // Remove intermediate group, update previous
    1038           25 :         GroupData prev_data(fabric_index, group.prev);
    1039           25 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1040           25 :         prev_data.next = group.next;
    1041           25 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1042           25 :     }
    1043           66 :     if (fabric.group_count > 0)
    1044              :     {
    1045           66 :         fabric.group_count--;
    1046              :     }
    1047              :     // Update fabric info
    1048           66 :     ReturnErrorOnFailure(fabric.Save(mStorage));
    1049           66 :     GroupRemoved(fabric_index, group);
    1050           66 :     return CHIP_NO_ERROR;
    1051           66 : }
    1052              : 
    1053          175 : bool GroupDataProviderImpl::HasEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id)
    1054              : {
    1055          175 :     VerifyOrReturnError(IsInitialized(), false);
    1056              : 
    1057          175 :     FabricData fabric(fabric_index);
    1058          175 :     GroupData group;
    1059          175 :     EndpointData endpoint;
    1060              : 
    1061          350 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), false);
    1062          164 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), false);
    1063          156 :     return endpoint.Find(mStorage, fabric, group, endpoint_id);
    1064          175 : }
    1065              : 
    1066         1140 : CHIP_ERROR GroupDataProviderImpl::AddEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id, chip::EndpointId endpoint_id)
    1067              : {
    1068         1140 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1069              : 
    1070         1140 :     FabricData fabric(fabric_index);
    1071         1140 :     GroupData group;
    1072              : 
    1073              :     // Load fabric data (defaults to zero)
    1074         1140 :     CHIP_ERROR err = fabric.Load(mStorage);
    1075         2284 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1076              : 
    1077         1140 :     if (!group.Find(mStorage, fabric, group_id))
    1078              :     {
    1079              :         // New group
    1080            9 :         VerifyOrReturnError(fabric.group_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1081            9 :         ReturnErrorOnFailure(EndpointData(fabric_index, group_id, endpoint_id).Save(mStorage));
    1082              :         // Save the new group into the fabric
    1083            9 :         group.group_id       = group_id;
    1084            9 :         group.name[0]        = 0;
    1085            9 :         group.first_endpoint = endpoint_id;
    1086            9 :         group.endpoint_count = 1;
    1087            9 :         group.next           = fabric.first_group;
    1088            9 :         group.prev           = kUndefinedGroupId;
    1089            9 :         ReturnErrorOnFailure(group.Save(mStorage));
    1090              : 
    1091            9 :         if (IsGroupcastEnabled() && group.HasAuxiliaryACL())
    1092              :         {
    1093            0 :             mAuxAclNotificationNeeded = true;
    1094              :         }
    1095              : 
    1096              :         // Update fabric
    1097            9 :         fabric.first_group = group.group_id;
    1098            9 :         fabric.group_count++;
    1099            9 :         ReturnErrorOnFailure(fabric.Save(mStorage));
    1100            9 :         GroupAdded(fabric_index, group);
    1101            9 :         return CHIP_NO_ERROR;
    1102              :     }
    1103              : 
    1104              :     // Existing group
    1105         1131 :     EndpointData endpoint;
    1106         1131 :     VerifyOrReturnError(!endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_NO_ERROR);
    1107              : 
    1108              :     // New endpoint, insert last
    1109         1124 :     endpoint.endpoint_id = endpoint_id;
    1110         1124 :     ReturnErrorOnFailure(endpoint.Save(mStorage));
    1111              : 
    1112         1124 :     if (IsGroupcastEnabled() && group.HasAuxiliaryACL())
    1113              :     {
    1114          720 :         mAuxAclNotificationNeeded = true;
    1115              :     }
    1116              : 
    1117         1124 :     if (endpoint.first)
    1118              :     {
    1119              :         // First endpoint of group
    1120          283 :         group.first_endpoint = endpoint.endpoint_id;
    1121              :     }
    1122              :     else
    1123              :     {
    1124              :         // Previous endpoint(s)
    1125          841 :         ReturnErrorOnFailure(endpoint.Save(mStorage));
    1126          841 :         EndpointData prev(fabric_index, group.group_id, endpoint.prev);
    1127          841 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1128          841 :         prev.next = endpoint.endpoint_id;
    1129          841 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1130          841 :     }
    1131         1124 :     group.endpoint_count++;
    1132         1124 :     ReturnErrorOnFailure(group.Save(mStorage));
    1133         1124 :     GroupModified(fabric_index, group.group_id);
    1134         1124 :     return CHIP_NO_ERROR;
    1135         1140 : }
    1136              : 
    1137          118 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id,
    1138              :                                                  chip::EndpointId endpoint_id, GroupCleanupPolicy cleanupPolicy)
    1139              : {
    1140          118 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1141              : 
    1142          118 :     FabricData fabric(fabric_index);
    1143          118 :     GroupData group;
    1144          118 :     EndpointData endpoint;
    1145              : 
    1146          118 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1147          118 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_NOT_FOUND);
    1148          117 :     VerifyOrReturnError(endpoint.Find(mStorage, fabric, group, endpoint_id), CHIP_ERROR_NOT_FOUND);
    1149              : 
    1150              :     // Existing endpoint
    1151          116 :     TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1152              : 
    1153          116 :     if (IsGroupcastEnabled() && group.HasAuxiliaryACL())
    1154              :     {
    1155           89 :         mAuxAclNotificationNeeded = true;
    1156              :     }
    1157              : 
    1158          116 :     if (endpoint.first)
    1159              :     {
    1160              :         // Remove first
    1161           89 :         group.first_endpoint = endpoint.next;
    1162              :     }
    1163              :     else
    1164              :     {
    1165              :         // Remove middle
    1166           27 :         EndpointData prev(fabric_index, group.group_id, endpoint.prev);
    1167           27 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1168           27 :         prev.next = endpoint.next;
    1169           27 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1170           27 :     }
    1171              : 
    1172              :     // Check if we should keep the group with no endpoints or not(Groupcast Sender usecase)
    1173          116 :     uint16_t kGroupEndpointCountMin = (cleanupPolicy == GroupCleanupPolicy::kKeepGroupIfEmpty) ? 0 : 1;
    1174          116 :     if (group.endpoint_count > kGroupEndpointCountMin)
    1175              :     {
    1176           95 :         group.endpoint_count--;
    1177           95 :         ReturnErrorOnFailure(group.Save(mStorage));
    1178           95 :         GroupModified(fabric_index, group.group_id);
    1179           95 :         return CHIP_NO_ERROR;
    1180              :     }
    1181              : 
    1182              :     // No more endpoints and empty groups are not allowed: remove the group.
    1183           21 :     return RemoveGroupInfoAt(fabric_index, group.index);
    1184          118 : }
    1185              : 
    1186           10 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::GroupId group_id,
    1187              :                                                  chip::EndpointId endpoint_id)
    1188              : {
    1189           10 :     return RemoveEndpoint(fabric_index, group_id, endpoint_id, GroupCleanupPolicy::kDeleteGroupIfEmpty);
    1190              : }
    1191              : 
    1192            4 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpointAllGroups(chip::FabricIndex fabric_index, chip::EndpointId endpoint_id,
    1193              :                                                           GroupCleanupPolicy cleanupPolicy)
    1194              : {
    1195            4 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1196              : 
    1197            4 :     FabricData fabric(fabric_index);
    1198              : 
    1199            4 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1200              : 
    1201            3 :     GroupData group(fabric_index, fabric.first_group);
    1202            3 :     size_t group_index = 0;
    1203            3 :     EndpointData endpoint;
    1204              : 
    1205              :     // Loop through all the groups
    1206           11 :     while (group_index < fabric.group_count)
    1207              :     {
    1208           16 :         if (CHIP_NO_ERROR != group.Load(mStorage))
    1209              :         {
    1210            0 :             break;
    1211              :         }
    1212            8 :         if (endpoint.Find(mStorage, fabric, group, endpoint_id))
    1213              :         {
    1214              :             // Endpoint found in group
    1215            8 :             ReturnErrorOnFailure(RemoveEndpoint(fabric_index, group.group_id, endpoint_id, cleanupPolicy));
    1216              :         }
    1217              : 
    1218            8 :         group.group_id = group.next;
    1219            8 :         group_index++;
    1220              :     }
    1221              : 
    1222            3 :     return CHIP_NO_ERROR;
    1223            4 : }
    1224              : 
    1225            4 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoint(chip::FabricIndex fabric_index, chip::EndpointId endpoint_id)
    1226              : {
    1227            4 :     return RemoveEndpointAllGroups(fabric_index, endpoint_id, GroupCleanupPolicy::kDeleteGroupIfEmpty);
    1228              : }
    1229              : 
    1230         2828 : GroupDataProvider::GroupInfoIterator * GroupDataProviderImpl::IterateGroupInfo(chip::FabricIndex fabric_index)
    1231              : {
    1232         2828 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1233         2828 :     return mGroupInfoIterators.CreateObject(*this, fabric_index);
    1234              : }
    1235              : 
    1236         2828 : GroupDataProviderImpl::GroupInfoIteratorImpl::GroupInfoIteratorImpl(GroupDataProviderImpl & provider,
    1237         2828 :                                                                     chip::FabricIndex fabric_index) :
    1238         2828 :     mProvider(provider),
    1239         2828 :     mFabric(fabric_index)
    1240              : {
    1241         2828 :     FabricData fabric(fabric_index);
    1242         5656 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1243              :     {
    1244         2483 :         mNextId = fabric.first_group;
    1245         2483 :         mTotal  = fabric.group_count;
    1246         2483 :         mCount  = 0;
    1247              :     }
    1248         2828 : }
    1249              : 
    1250           87 : size_t GroupDataProviderImpl::GroupInfoIteratorImpl::Count()
    1251              : {
    1252           87 :     return mTotal;
    1253              : }
    1254              : 
    1255         6793 : bool GroupDataProviderImpl::GroupInfoIteratorImpl::Next(GroupInfo & output)
    1256              : {
    1257         6793 :     VerifyOrReturnError(mCount < mTotal, false);
    1258              : 
    1259         4047 :     GroupData group(mFabric, mNextId);
    1260         4047 :     CHIP_ERROR err = group.Load(mProvider.mStorage);
    1261         8094 :     VerifyOrReturnError(CHIP_NO_ERROR == err, false);
    1262              : 
    1263         4047 :     mCount++;
    1264         4047 :     mNextId = group.next;
    1265         4047 :     output.Copy(group);
    1266         4047 :     return true;
    1267         4047 : }
    1268              : 
    1269         2828 : void GroupDataProviderImpl::GroupInfoIteratorImpl::Release()
    1270              : {
    1271         2828 :     mProvider.mGroupInfoIterators.ReleaseObject(this);
    1272         2828 : }
    1273              : 
    1274           57 : GroupDataProvider::EndpointIterator * GroupDataProviderImpl::IterateEndpoints(chip::FabricIndex fabric_index,
    1275              :                                                                               std::optional<GroupId> group_id)
    1276              : {
    1277           57 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1278           57 :     return mEndpointIterators.CreateObject(*this, fabric_index, group_id);
    1279              : }
    1280              : 
    1281           57 : GroupDataProviderImpl::EndpointIteratorImpl::EndpointIteratorImpl(GroupDataProviderImpl & provider, chip::FabricIndex fabric_index,
    1282           57 :                                                                   std::optional<GroupId> group_id) :
    1283           57 :     mProvider(provider),
    1284           57 :     mFabric(fabric_index)
    1285              : {
    1286           57 :     FabricData fabric(fabric_index);
    1287          114 :     VerifyOrReturn(CHIP_NO_ERROR == fabric.Load(provider.mStorage));
    1288              : 
    1289           55 :     if (group_id.has_value())
    1290              :     {
    1291           45 :         GroupData group(fabric_index, *group_id);
    1292           90 :         VerifyOrReturn(CHIP_NO_ERROR == group.Load(provider.mStorage));
    1293              : 
    1294           44 :         mGroup         = *group_id;
    1295           44 :         mFirstGroup    = *group_id;
    1296           44 :         mGroupCount    = 1;
    1297           44 :         mEndpoint      = group.first_endpoint;
    1298           44 :         mEndpointCount = group.endpoint_count;
    1299           45 :     }
    1300              :     else
    1301              :     {
    1302           10 :         GroupData group(fabric_index, fabric.first_group);
    1303           20 :         VerifyOrReturn(CHIP_NO_ERROR == group.Load(provider.mStorage));
    1304              : 
    1305           10 :         mGroup         = fabric.first_group;
    1306           10 :         mFirstGroup    = fabric.first_group;
    1307           10 :         mGroupCount    = fabric.group_count;
    1308           10 :         mEndpoint      = group.first_endpoint;
    1309           10 :         mEndpointCount = group.endpoint_count;
    1310           10 :     }
    1311           57 : }
    1312              : 
    1313           43 : size_t GroupDataProviderImpl::EndpointIteratorImpl::Count()
    1314              : {
    1315           43 :     GroupData group(mFabric, mFirstGroup);
    1316           43 :     size_t group_index    = 0;
    1317           43 :     size_t endpoint_index = 0;
    1318           43 :     size_t count          = 0;
    1319              : 
    1320           86 :     while (group_index++ < mGroupCount)
    1321              :     {
    1322           86 :         if (CHIP_NO_ERROR != group.Load(mProvider.mStorage))
    1323              :         {
    1324            0 :             break;
    1325              :         }
    1326           43 :         EndpointData endpoint(mFabric, group.group_id, group.first_endpoint);
    1327         1247 :         while (endpoint_index++ < group.endpoint_count)
    1328              :         {
    1329         2408 :             if (CHIP_NO_ERROR != endpoint.Load(mProvider.mStorage))
    1330              :             {
    1331            0 :                 break;
    1332              :             }
    1333         1204 :             endpoint.endpoint_id = endpoint.next;
    1334         1204 :             count++;
    1335              :         }
    1336           43 :         group.group_id = group.next;
    1337           43 :         endpoint_index = 0;
    1338           43 :     }
    1339           86 :     return count;
    1340           43 : }
    1341              : 
    1342         1267 : bool GroupDataProviderImpl::EndpointIteratorImpl::Next(GroupEndpoint & output)
    1343              : {
    1344         1329 :     while (mGroupIndex < mGroupCount)
    1345              :     {
    1346         1277 :         GroupData group(mFabric, mGroup);
    1347         2554 :         if (CHIP_NO_ERROR != group.Load(mProvider.mStorage))
    1348              :         {
    1349            0 :             mGroupIndex = mGroupCount;
    1350            0 :             return false;
    1351              :         }
    1352         1277 :         if (mFirstEndpoint)
    1353              :         {
    1354           62 :             mEndpoint      = group.first_endpoint;
    1355           62 :             mEndpointIndex = 0;
    1356           62 :             mEndpointCount = group.endpoint_count;
    1357           62 :             mFirstEndpoint = false;
    1358              :         }
    1359         1277 :         if (mEndpointIndex < mEndpointCount)
    1360              :         {
    1361         1215 :             EndpointData endpoint(mFabric, mGroup, mEndpoint);
    1362         2430 :             if (CHIP_NO_ERROR == endpoint.Load(mProvider.mStorage))
    1363              :             {
    1364         1215 :                 output.group_id    = group.group_id;
    1365         1215 :                 output.endpoint_id = endpoint.endpoint_id;
    1366         1215 :                 mEndpoint          = endpoint.next;
    1367         1215 :                 mEndpointIndex++;
    1368         1215 :                 return true;
    1369              :             }
    1370         1215 :         }
    1371           62 :         mGroup = group.next;
    1372           62 :         mGroupIndex++;
    1373           62 :         mFirstEndpoint = true;
    1374         1277 :     }
    1375           52 :     return false;
    1376              : }
    1377              : 
    1378           57 : void GroupDataProviderImpl::EndpointIteratorImpl::Release()
    1379              : {
    1380           57 :     mProvider.mEndpointIterators.ReleaseObject(this);
    1381           57 : }
    1382              : 
    1383            4 : CHIP_ERROR GroupDataProviderImpl::RemoveEndpoints(chip::FabricIndex fabric_index, chip::GroupId group_id)
    1384              : {
    1385            4 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1386              : 
    1387            4 :     FabricData fabric(fabric_index);
    1388            4 :     GroupData group;
    1389              : 
    1390            8 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_INVALID_FABRIC_INDEX);
    1391            4 :     VerifyOrReturnError(group.Find(mStorage, fabric, group_id), CHIP_ERROR_KEY_NOT_FOUND);
    1392              : 
    1393            4 :     bool notifyNeeded = (IsGroupcastEnabled() && group.HasAuxiliaryACL() && group.endpoint_count > 0);
    1394              : 
    1395            4 :     EndpointData endpoint(fabric_index, group.group_id, group.first_endpoint);
    1396            4 :     size_t endpoint_index = 0;
    1397           62 :     while (endpoint_index < group.endpoint_count)
    1398              :     {
    1399           58 :         ReturnErrorOnFailure(endpoint.Load(mStorage));
    1400           58 :         TEMPORARY_RETURN_IGNORED endpoint.Delete(mStorage);
    1401           58 :         endpoint.endpoint_id = endpoint.next;
    1402           58 :         endpoint_index++;
    1403              :     }
    1404            4 :     group.first_endpoint = kInvalidEndpointId;
    1405            4 :     group.endpoint_count = 0;
    1406            4 :     ReturnErrorOnFailure(group.Save(mStorage));
    1407              : 
    1408            4 :     if (notifyNeeded)
    1409              :     {
    1410            3 :         mAuxAclNotificationNeeded = true;
    1411              :     }
    1412              : 
    1413            4 :     GroupModified(fabric_index, group.group_id);
    1414            4 :     return CHIP_NO_ERROR;
    1415            4 : }
    1416              : 
    1417              : //
    1418              : // Group-Key map
    1419              : //
    1420              : 
    1421           98 : CHIP_ERROR GroupDataProviderImpl::SetGroupKey(FabricIndex fabric_index, GroupId group_id, KeysetId keyset_id)
    1422              : {
    1423           98 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1424              : 
    1425           98 :     FabricData fabric(fabric_index);
    1426           98 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1427              : 
    1428              :     // Search for an existing mapping
    1429           98 :     size_t count = 0;
    1430           98 :     KeyMapData map(fabric_index, fabric.first_map);
    1431          180 :     while (count++ < fabric.map_count)
    1432              :     {
    1433          139 :         ReturnErrorOnFailure(map.Load(mStorage));
    1434          139 :         if (map.group_id == group_id)
    1435              :         {
    1436              :             // Existing group, replace keyset
    1437              : 
    1438           57 :             map.keyset_id = keyset_id;
    1439           57 :             ReturnErrorOnFailure(map.Save(mStorage));
    1440           57 :             GroupModified(fabric_index, group_id);
    1441           57 :             return CHIP_NO_ERROR;
    1442              :         }
    1443           82 :         map.id = map.next;
    1444              :     }
    1445              : 
    1446              :     // New group, insert last
    1447           41 :     GroupKey entry(group_id, keyset_id);
    1448           41 :     return SetGroupKeyAt(fabric_index, fabric.map_count, entry);
    1449           98 : }
    1450              : 
    1451          305 : CHIP_ERROR GroupDataProviderImpl::SetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, const GroupKey & in_map)
    1452              : {
    1453          305 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1454              : 
    1455          305 :     FabricData fabric(fabric_index);
    1456          305 :     KeyMapData map(fabric_index);
    1457              : 
    1458              :     // Load fabric, defaults to zero
    1459          305 :     CHIP_ERROR err = fabric.Load(mStorage);
    1460          618 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1461              : 
    1462              :     // If the group exists, the index must match
    1463          305 :     bool found = map.Find(mStorage, fabric, in_map);
    1464          305 :     VerifyOrReturnError(!found || (map.index == index), CHIP_ERROR_DUPLICATE_KEY_ID);
    1465              : 
    1466          299 :     found         = map.Get(mStorage, fabric, index);
    1467          299 :     map.group_id  = in_map.group_id;
    1468          299 :     map.keyset_id = in_map.keyset_id;
    1469              : 
    1470          299 :     if (found)
    1471              :     {
    1472              :         // Update existing map
    1473            8 :         ReturnErrorOnFailure(map.Save(mStorage));
    1474            8 :         GroupModified(fabric_index, in_map.group_id);
    1475            8 :         return CHIP_NO_ERROR;
    1476              :     }
    1477              : 
    1478              :     // Insert last
    1479          291 :     VerifyOrReturnError(fabric.map_count == index, CHIP_ERROR_INVALID_ARGUMENT);
    1480          290 :     VerifyOrReturnError(fabric.map_count < mMaxGroupsPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1481              : 
    1482          289 :     map.next = 0;
    1483          289 :     ReturnErrorOnFailure(map.Save(mStorage));
    1484              : 
    1485          289 :     if (map.first)
    1486              :     {
    1487              :         // First map, update fabric
    1488          105 :         fabric.first_map = map.id;
    1489              :     }
    1490              :     else
    1491              :     {
    1492              :         // Last map, update previous
    1493          184 :         KeyMapData prev(fabric_index, map.prev);
    1494          184 :         ReturnErrorOnFailure(prev.Load(mStorage));
    1495          184 :         prev.next = map.id;
    1496          184 :         ReturnErrorOnFailure(prev.Save(mStorage));
    1497          184 :     }
    1498              :     // Update fabric
    1499          289 :     fabric.map_count++;
    1500          289 :     GroupModified(fabric_index, in_map.group_id);
    1501          289 :     return fabric.Save(mStorage);
    1502          305 : }
    1503              : 
    1504           29 : CHIP_ERROR GroupDataProviderImpl::GetGroupKey(FabricIndex fabric_index, GroupId group_id, KeysetId & keyset_id)
    1505              : {
    1506           29 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1507              : 
    1508           29 :     FabricData fabric(fabric_index);
    1509           29 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1510              : 
    1511           29 :     size_t count = 0;
    1512           29 :     KeyMapData map(fabric_index, fabric.first_map);
    1513           42 :     while (count++ < fabric.map_count)
    1514              :     {
    1515           41 :         ReturnErrorOnFailure(map.Load(mStorage));
    1516           41 :         if (map.group_id == group_id)
    1517              :         {
    1518           28 :             keyset_id = map.keyset_id;
    1519           28 :             return CHIP_NO_ERROR;
    1520              :         }
    1521           13 :         map.id = map.next;
    1522              :     }
    1523            1 :     return CHIP_ERROR_NOT_FOUND;
    1524           29 : }
    1525              : 
    1526           28 : CHIP_ERROR GroupDataProviderImpl::GetGroupKeyAt(chip::FabricIndex fabric_index, size_t index, GroupKey & out_map)
    1527              : {
    1528           28 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1529              : 
    1530           28 :     FabricData fabric(fabric_index);
    1531           28 :     KeyMapData map;
    1532              : 
    1533           28 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1534           27 :     VerifyOrReturnError(map.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
    1535              : 
    1536              :     // Target map found
    1537           19 :     out_map.group_id  = map.group_id;
    1538           19 :     out_map.keyset_id = map.keyset_id;
    1539           19 :     return CHIP_NO_ERROR;
    1540           28 : }
    1541              : 
    1542           15 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupKeyAt(chip::FabricIndex fabric_index, size_t index)
    1543              : {
    1544           15 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1545              : 
    1546           15 :     FabricData fabric(fabric_index);
    1547           15 :     KeyMapData map;
    1548              : 
    1549           15 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1550           15 :     VerifyOrReturnError(map.Get(mStorage, fabric, index), CHIP_ERROR_NOT_FOUND);
    1551              : 
    1552           15 :     ReturnErrorOnFailure(map.Delete(mStorage));
    1553           15 :     if (map.first)
    1554              :     {
    1555              :         // Remove first map
    1556            4 :         fabric.first_map = map.next;
    1557              :     }
    1558              :     else
    1559              :     {
    1560              :         // Remove intermediate map, update previous
    1561           11 :         KeyMapData prev_data(fabric_index, map.prev);
    1562           11 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1563           11 :         prev_data.next = map.next;
    1564           11 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1565           11 :     }
    1566           15 :     if (fabric.map_count > 0)
    1567              :     {
    1568           15 :         fabric.map_count--;
    1569              :     }
    1570              :     // Update fabric
    1571           15 :     GroupModified(fabric_index, map.group_id);
    1572           15 :     return fabric.Save(mStorage);
    1573           15 : }
    1574              : 
    1575            8 : CHIP_ERROR GroupDataProviderImpl::RemoveGroupKeys(chip::FabricIndex fabric_index)
    1576              : {
    1577            8 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1578              : 
    1579            8 :     FabricData fabric(fabric_index);
    1580           16 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_INVALID_FABRIC_INDEX);
    1581              : 
    1582            4 :     size_t count = 0;
    1583            4 :     KeyMapData map(fabric_index, fabric.first_map);
    1584           12 :     while (count++ < fabric.map_count)
    1585              :     {
    1586           16 :         if (CHIP_NO_ERROR != map.Load(mStorage))
    1587              :         {
    1588            0 :             break;
    1589              :         }
    1590            8 :         TEMPORARY_RETURN_IGNORED map.Delete(mStorage);
    1591            8 :         map.id = map.next;
    1592              :     }
    1593              : 
    1594            4 :     GroupModified(fabric_index, 0 /* all groups affected*/);
    1595              :     // Update fabric
    1596            4 :     fabric.first_map = 0;
    1597            4 :     fabric.map_count = 0;
    1598            4 :     return fabric.Save(mStorage);
    1599            8 : }
    1600              : 
    1601           50 : GroupDataProvider::GroupKeyIterator * GroupDataProviderImpl::IterateGroupKeys(chip::FabricIndex fabric_index)
    1602              : {
    1603           50 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1604           50 :     return mGroupKeyIterators.CreateObject(*this, fabric_index);
    1605              : }
    1606              : 
    1607           50 : GroupDataProviderImpl::GroupKeyIteratorImpl::GroupKeyIteratorImpl(GroupDataProviderImpl & provider,
    1608           50 :                                                                   chip::FabricIndex fabric_index) :
    1609           50 :     mProvider(provider),
    1610           50 :     mFabric(fabric_index)
    1611              : {
    1612           50 :     FabricData fabric(fabric_index);
    1613          100 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1614              :     {
    1615           48 :         mNextId = fabric.first_map;
    1616           48 :         mTotal  = fabric.map_count;
    1617           48 :         mCount  = 0;
    1618              :     }
    1619           50 : }
    1620              : 
    1621           16 : size_t GroupDataProviderImpl::GroupKeyIteratorImpl::Count()
    1622              : {
    1623           16 :     return mTotal;
    1624              : }
    1625              : 
    1626           93 : bool GroupDataProviderImpl::GroupKeyIteratorImpl::Next(GroupKey & output)
    1627              : {
    1628           93 :     VerifyOrReturnError(mCount < mTotal, false);
    1629              : 
    1630           82 :     KeyMapData map(mFabric, mNextId);
    1631          164 :     VerifyOrReturnError(CHIP_NO_ERROR == map.Load(mProvider.mStorage), false);
    1632              : 
    1633           82 :     mCount++;
    1634           82 :     mNextId          = map.next;
    1635           82 :     output.group_id  = map.group_id;
    1636           82 :     output.keyset_id = map.keyset_id;
    1637           82 :     return true;
    1638           82 : }
    1639              : 
    1640           50 : void GroupDataProviderImpl::GroupKeyIteratorImpl::Release()
    1641              : {
    1642           50 :     mProvider.mGroupKeyIterators.ReleaseObject(this);
    1643           50 : }
    1644              : 
    1645              : //
    1646              : // Key Sets
    1647              : //
    1648              : 
    1649              : constexpr size_t GroupDataProvider::EpochKey::kLengthBytes;
    1650              : 
    1651          257 : CHIP_ERROR GroupDataProviderImpl::SetKeySet(chip::FabricIndex fabric_index, const ByteSpan & compressed_fabric_id,
    1652              :                                             const KeySet & in_keyset)
    1653              : {
    1654          257 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1655              : 
    1656          257 :     FabricData fabric(fabric_index);
    1657          257 :     KeySetData keyset;
    1658              : 
    1659              :     // Load fabric, defaults to zero
    1660          257 :     CHIP_ERROR err = fabric.Load(mStorage);
    1661          556 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1662              : 
    1663              :     // Search existing keyset
    1664          257 :     bool found = keyset.Find(mStorage, fabric, in_keyset.keyset_id);
    1665              : 
    1666          257 :     keyset.keyset_id  = in_keyset.keyset_id;
    1667          257 :     keyset.policy     = in_keyset.policy;
    1668          257 :     keyset.keys_count = in_keyset.num_keys_used;
    1669          257 :     memset(keyset.operational_keys, 0x00, sizeof(keyset.operational_keys));
    1670          257 :     keyset.operational_keys[0].start_time = in_keyset.epoch_keys[0].start_time;
    1671          257 :     keyset.operational_keys[1].start_time = in_keyset.epoch_keys[1].start_time;
    1672          257 :     keyset.operational_keys[2].start_time = in_keyset.epoch_keys[2].start_time;
    1673              : 
    1674              :     // Store the operational keys and hash instead of the epoch keys
    1675          905 :     for (size_t i = 0; i < in_keyset.num_keys_used; ++i)
    1676              :     {
    1677          648 :         ByteSpan epoch_key(in_keyset.epoch_keys[i].key, Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
    1678          648 :         ReturnErrorOnFailure(
    1679              :             Crypto::DeriveGroupOperationalCredentials(epoch_key, compressed_fabric_id, keyset.operational_keys[i]));
    1680              :     }
    1681              : 
    1682          257 :     if (found)
    1683              :     {
    1684              :         // Update existing keyset info, keep next
    1685            5 :         return keyset.Save(mStorage);
    1686              :     }
    1687              : 
    1688              :     // New keyset
    1689          252 :     VerifyOrReturnError(fabric.keyset_count < mMaxGroupKeysPerFabric, CHIP_ERROR_INVALID_LIST_LENGTH);
    1690              : 
    1691              :     // Insert first
    1692          250 :     keyset.next = fabric.first_keyset;
    1693          250 :     ReturnErrorOnFailure(keyset.Save(mStorage));
    1694              :     // Update fabric
    1695          250 :     fabric.keyset_count++;
    1696          250 :     fabric.first_keyset = in_keyset.keyset_id;
    1697          250 :     return fabric.Save(mStorage);
    1698          257 : }
    1699              : 
    1700          173 : CHIP_ERROR GroupDataProviderImpl::GetKeySet(chip::FabricIndex fabric_index, uint16_t target_id, KeySet & out_keyset)
    1701              : {
    1702          173 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1703              : 
    1704          173 :     FabricData fabric(fabric_index);
    1705          173 :     KeySetData keyset;
    1706              : 
    1707          173 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1708          155 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, target_id), CHIP_ERROR_NOT_FOUND);
    1709              : 
    1710              :     // Target keyset found
    1711          137 :     out_keyset.ClearKeys();
    1712          137 :     out_keyset.keyset_id     = keyset.keyset_id;
    1713          137 :     out_keyset.policy        = keyset.policy;
    1714          137 :     out_keyset.num_keys_used = keyset.keys_count;
    1715              :     // Epoch keys are not read back, only start times
    1716          137 :     out_keyset.epoch_keys[0].start_time = keyset.operational_keys[0].start_time;
    1717          137 :     out_keyset.epoch_keys[1].start_time = keyset.operational_keys[1].start_time;
    1718          137 :     out_keyset.epoch_keys[2].start_time = keyset.operational_keys[2].start_time;
    1719              : 
    1720          137 :     return CHIP_NO_ERROR;
    1721          173 : }
    1722              : 
    1723           29 : CHIP_ERROR GroupDataProviderImpl::RemoveKeySet(chip::FabricIndex fabric_index, uint16_t target_id)
    1724              : {
    1725           29 :     VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL);
    1726              : 
    1727           29 :     FabricData fabric(fabric_index);
    1728           29 :     KeySetData keyset;
    1729              : 
    1730           29 :     ReturnErrorOnFailure(fabric.Load(mStorage));
    1731           29 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, target_id), CHIP_ERROR_NOT_FOUND);
    1732           25 :     ReturnErrorOnFailure(keyset.Delete(mStorage));
    1733              : 
    1734           25 :     if (keyset.first)
    1735              :     {
    1736              :         // Remove first keyset
    1737           21 :         fabric.first_keyset = keyset.next;
    1738              :     }
    1739              :     else
    1740              :     {
    1741              :         // Remove intermediate keyset, update previous
    1742            4 :         KeySetData prev_data(fabric_index, keyset.prev);
    1743            4 :         ReturnErrorOnFailure(prev_data.Load(mStorage));
    1744            4 :         prev_data.next = keyset.next;
    1745            4 :         ReturnErrorOnFailure(prev_data.Save(mStorage));
    1746            4 :     }
    1747           25 :     if (fabric.keyset_count > 0)
    1748              :     {
    1749           25 :         fabric.keyset_count--;
    1750              :     }
    1751              :     // Update fabric info
    1752           25 :     ReturnErrorOnFailure(fabric.Save(mStorage));
    1753              : 
    1754              :     // Removing a key set also removes the associated group mappings
    1755           25 :     KeyMapData map;
    1756           25 :     uint16_t original_count = fabric.map_count;
    1757           26 :     for (uint16_t i = 0; i < original_count; ++i)
    1758              :     {
    1759            2 :         TEMPORARY_RETURN_IGNORED fabric.Load(mStorage);
    1760            2 :         size_t idx = map.Find(mStorage, fabric, target_id);
    1761            2 :         if (idx == std::numeric_limits<size_t>::max())
    1762              :         {
    1763            1 :             break;
    1764              :         }
    1765              :         // NOTE: It's unclear what should happen here if we have removed the key set
    1766              :         // and possibly some mappings before failing. For now, ignoring errors, but
    1767              :         // open to suggestsions for the correct behavior.
    1768            1 :         TEMPORARY_RETURN_IGNORED RemoveGroupKeyAt(fabric_index, idx);
    1769              :     }
    1770           25 :     return CHIP_NO_ERROR;
    1771           29 : }
    1772              : 
    1773            2 : GroupDataProvider::KeySetIterator * GroupDataProviderImpl::IterateKeySets(chip::FabricIndex fabric_index)
    1774              : {
    1775            2 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1776            2 :     return mKeySetIterators.CreateObject(*this, fabric_index);
    1777              : }
    1778              : 
    1779            2 : GroupDataProviderImpl::KeySetIteratorImpl::KeySetIteratorImpl(GroupDataProviderImpl & provider, chip::FabricIndex fabric_index) :
    1780            2 :     mProvider(provider), mFabric(fabric_index)
    1781              : {
    1782            2 :     FabricData fabric(fabric_index);
    1783            4 :     if (CHIP_NO_ERROR == fabric.Load(provider.mStorage))
    1784              :     {
    1785            2 :         mNextId = fabric.first_keyset;
    1786            2 :         mTotal  = fabric.keyset_count;
    1787            2 :         mCount  = 0;
    1788              :     }
    1789            2 : }
    1790              : 
    1791            2 : size_t GroupDataProviderImpl::KeySetIteratorImpl::Count()
    1792              : {
    1793            2 :     return mTotal;
    1794              : }
    1795              : 
    1796            9 : bool GroupDataProviderImpl::KeySetIteratorImpl::Next(KeySet & output)
    1797              : {
    1798            9 :     VerifyOrReturnError(mCount < mTotal, false);
    1799              : 
    1800            7 :     KeySetData keyset(mFabric, mNextId);
    1801           14 :     VerifyOrReturnError(CHIP_NO_ERROR == keyset.Load(mProvider.mStorage), false);
    1802              : 
    1803            7 :     mCount++;
    1804            7 :     mNextId = keyset.next;
    1805            7 :     output.ClearKeys();
    1806            7 :     output.keyset_id     = keyset.keyset_id;
    1807            7 :     output.policy        = keyset.policy;
    1808            7 :     output.num_keys_used = keyset.keys_count;
    1809              :     // Epoch keys are not read back, only start times
    1810            7 :     output.epoch_keys[0].start_time = keyset.operational_keys[0].start_time;
    1811            7 :     output.epoch_keys[1].start_time = keyset.operational_keys[1].start_time;
    1812            7 :     output.epoch_keys[2].start_time = keyset.operational_keys[2].start_time;
    1813            7 :     return true;
    1814            7 : }
    1815              : 
    1816            2 : void GroupDataProviderImpl::KeySetIteratorImpl::Release()
    1817              : {
    1818            2 :     mProvider.mKeySetIterators.ReleaseObject(this);
    1819            2 : }
    1820              : 
    1821              : //
    1822              : // Fabrics
    1823              : //
    1824              : 
    1825           29 : CHIP_ERROR GroupDataProviderImpl::RemoveFabric(chip::FabricIndex fabric_index)
    1826              : {
    1827           29 :     FabricData fabric(fabric_index);
    1828              : 
    1829              :     // Fabric data defaults to zero, so if not entry is found, no mappings, or keys are removed
    1830              :     // However, states has a separate list, and needs to be removed regardless
    1831           29 :     CHIP_ERROR err = fabric.Load(mStorage);
    1832           62 :     VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err);
    1833              : 
    1834              :     // Remove Group mappings
    1835              : 
    1836           41 :     for (size_t i = 0; i < fabric.map_count; i++)
    1837              :     {
    1838           12 :         TEMPORARY_RETURN_IGNORED RemoveGroupKeyAt(fabric_index, fabric.map_count - i - 1);
    1839              :     }
    1840              : 
    1841              :     // Remove group info
    1842              : 
    1843           64 :     for (size_t i = 0; i < fabric.group_count; i++)
    1844              :     {
    1845           35 :         TEMPORARY_RETURN_IGNORED RemoveGroupInfoAt(fabric_index, fabric.group_count - i - 1);
    1846              :     }
    1847              : 
    1848              :     // Remove Keysets
    1849              : 
    1850           29 :     KeySetData keyset(fabric_index, fabric.first_keyset);
    1851           29 :     size_t keyset_count = 0;
    1852              : 
    1853              :     // Loop the keysets associated with the target fabric
    1854           44 :     while (keyset_count < fabric.keyset_count)
    1855              :     {
    1856           30 :         if (CHIP_NO_ERROR != keyset.Load(mStorage))
    1857              :         {
    1858            0 :             break;
    1859              :         }
    1860           15 :         TEMPORARY_RETURN_IGNORED RemoveKeySet(fabric_index, keyset.keyset_id);
    1861           15 :         keyset.keyset_id = keyset.next;
    1862           15 :         keyset_count++;
    1863              :     }
    1864              : 
    1865              :     // Remove fabric, and ensure no auxiliary acl changed
    1866              :     // event will be emitted from this action
    1867           29 :     err                       = fabric.Delete(mStorage);
    1868           29 :     mAuxAclNotificationNeeded = false;
    1869           29 :     return err;
    1870           29 : }
    1871              : 
    1872              : //
    1873              : // Cryptography
    1874              : //
    1875              : 
    1876            4 : Crypto::SymmetricKeyContext * GroupDataProviderImpl::GetKeyContext(FabricIndex fabric_index, GroupId group_id)
    1877              : {
    1878            4 :     FabricData fabric(fabric_index);
    1879            8 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), nullptr);
    1880              : 
    1881            4 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1882              : 
    1883              :     // Look for the target group in the fabric's keyset-group pairs
    1884            4 :     for (uint16_t i = 0; i < fabric.map_count; ++i, mapping.id = mapping.next)
    1885              :     {
    1886            8 :         VerifyOrReturnError(CHIP_NO_ERROR == mapping.Load(mStorage), nullptr);
    1887              :         // GroupKeySetID of 0 is reserved for the Identity Protection Key (IPK),
    1888              :         // it cannot be used for operational group communication.
    1889            4 :         if (mapping.keyset_id > 0 && mapping.group_id == group_id)
    1890              :         {
    1891              :             // Group found, get the keyset
    1892            4 :             KeySetData keyset;
    1893            4 :             VerifyOrReturnError(keyset.Find(mStorage, fabric, mapping.keyset_id), nullptr);
    1894            4 :             Crypto::GroupOperationalCredentials * creds = keyset.GetCurrentGroupCredentials();
    1895            4 :             if (nullptr != creds)
    1896              :             {
    1897            4 :                 return mGroupKeyContexPool.CreateObject(*this, creds->encryption_key, creds->hash, creds->privacy_key);
    1898              :             }
    1899            4 :         }
    1900              :     }
    1901            0 :     return nullptr;
    1902            4 : }
    1903              : 
    1904           30 : CHIP_ERROR GroupDataProviderImpl::GetIpkKeySet(FabricIndex fabric_index, KeySet & out_keyset)
    1905              : {
    1906           30 :     FabricData fabric(fabric_index);
    1907           60 :     VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mStorage), CHIP_ERROR_NOT_FOUND);
    1908              : 
    1909           29 :     KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    1910              : 
    1911              :     // Fabric found, get the keyset
    1912           29 :     KeySetData keyset;
    1913           29 :     VerifyOrReturnError(keyset.Find(mStorage, fabric, kIdentityProtectionKeySetId), CHIP_ERROR_NOT_FOUND);
    1914              : 
    1915              :     // If the keyset ID doesn't match, we have a ... problem.
    1916           27 :     VerifyOrReturnError(keyset.keyset_id == kIdentityProtectionKeySetId, CHIP_ERROR_INTERNAL);
    1917              : 
    1918           27 :     out_keyset.keyset_id     = keyset.keyset_id;
    1919           27 :     out_keyset.num_keys_used = keyset.keys_count;
    1920           27 :     out_keyset.policy        = keyset.policy;
    1921              : 
    1922          108 :     for (size_t key_idx = 0; key_idx < MATTER_ARRAY_SIZE(out_keyset.epoch_keys); ++key_idx)
    1923              :     {
    1924           81 :         out_keyset.epoch_keys[key_idx].Clear();
    1925           81 :         if (key_idx < keyset.keys_count)
    1926              :         {
    1927           27 :             out_keyset.epoch_keys[key_idx].start_time = keyset.operational_keys[key_idx].start_time;
    1928           27 :             memcpy(&out_keyset.epoch_keys[key_idx].key[0], keyset.operational_keys[key_idx].encryption_key, EpochKey::kLengthBytes);
    1929              :         }
    1930              :     }
    1931              : 
    1932           27 :     return CHIP_NO_ERROR;
    1933           30 : }
    1934              : 
    1935            4 : void GroupDataProviderImpl::GroupKeyContext::Release()
    1936              : {
    1937            4 :     ReleaseKeys();
    1938            4 :     mProvider.mGroupKeyContexPool.ReleaseObject(this);
    1939            4 : }
    1940              : 
    1941            4 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageEncrypt(const ByteSpan & plaintext, const ByteSpan & aad,
    1942              :                                                                   const ByteSpan & nonce, MutableByteSpan & mic,
    1943              :                                                                   MutableByteSpan & ciphertext) const
    1944              : {
    1945            4 :     uint8_t * output = ciphertext.data();
    1946            4 :     return Crypto::AES_CCM_encrypt(plaintext.data(), plaintext.size(), aad.data(), aad.size(), mEncryptionKey, nonce.data(),
    1947            4 :                                    nonce.size(), output, mic.data(), mic.size());
    1948              : }
    1949              : 
    1950            8 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::MessageDecrypt(const ByteSpan & ciphertext, const ByteSpan & aad,
    1951              :                                                                   const ByteSpan & nonce, const ByteSpan & mic,
    1952              :                                                                   MutableByteSpan & plaintext) const
    1953              : {
    1954            8 :     uint8_t * output = plaintext.data();
    1955           16 :     return Crypto::AES_CCM_decrypt(ciphertext.data(), ciphertext.size(), aad.data(), aad.size(), mic.data(), mic.size(),
    1956           16 :                                    mEncryptionKey, nonce.data(), nonce.size(), output);
    1957              : }
    1958              : 
    1959            0 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyEncrypt(const ByteSpan & input, const ByteSpan & nonce,
    1960              :                                                                   MutableByteSpan & output) const
    1961              : {
    1962            0 :     return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data());
    1963              : }
    1964              : 
    1965            3 : CHIP_ERROR GroupDataProviderImpl::GroupKeyContext::PrivacyDecrypt(const ByteSpan & input, const ByteSpan & nonce,
    1966              :                                                                   MutableByteSpan & output) const
    1967              : {
    1968            3 :     return Crypto::AES_CTR_crypt(input.data(), input.size(), mPrivacyKey, nonce.data(), nonce.size(), output.data());
    1969              : }
    1970              : 
    1971            9 : GroupDataProviderImpl::GroupSessionIterator * GroupDataProviderImpl::IterateGroupSessions(uint16_t session_id)
    1972              : {
    1973            9 :     VerifyOrReturnError(IsInitialized(), nullptr);
    1974            9 :     return mGroupSessionsIterator.CreateObject(*this, session_id);
    1975              : }
    1976              : 
    1977            9 : GroupDataProviderImpl::GroupSessionIteratorImpl::GroupSessionIteratorImpl(GroupDataProviderImpl & provider, uint16_t session_id) :
    1978            9 :     mProvider(provider), mSessionId(session_id), mGroupKeyContext(provider)
    1979              : {
    1980            9 :     FabricList fabric_list;
    1981            9 :     ReturnOnFailure(fabric_list.Load(provider.mStorage));
    1982            9 :     mFirstFabric = fabric_list.first_entry;
    1983            9 :     mFabric      = fabric_list.first_entry;
    1984            9 :     mFabricCount = 0;
    1985            9 :     mFabricTotal = fabric_list.entry_count;
    1986            9 :     mMapCount    = 0;
    1987            9 :     mFirstMap    = true;
    1988            9 : }
    1989              : 
    1990            1 : size_t GroupDataProviderImpl::GroupSessionIteratorImpl::Count()
    1991              : {
    1992            1 :     FabricData fabric(mFirstFabric);
    1993            1 :     size_t count = 0;
    1994              : 
    1995            3 :     for (size_t i = 0; i < mFabricTotal; i++, fabric.fabric_index = fabric.next)
    1996              :     {
    1997            4 :         if (CHIP_NO_ERROR != fabric.Load(mProvider.mStorage))
    1998              :         {
    1999            0 :             break;
    2000              :         }
    2001              : 
    2002              :         // Iterate key sets
    2003            2 :         KeyMapData mapping(fabric.fabric_index, fabric.first_map);
    2004              : 
    2005              :         // Look for the target group in the fabric's keyset-group pairs
    2006            8 :         for (uint16_t j = 0; j < fabric.map_count; ++j, mapping.id = mapping.next)
    2007              :         {
    2008           12 :             if (CHIP_NO_ERROR != mapping.Load(mProvider.mStorage))
    2009              :             {
    2010            0 :                 break;
    2011              :             }
    2012              : 
    2013              :             // Group found, get the keyset
    2014            6 :             KeySetData keyset;
    2015            6 :             if (!keyset.Find(mProvider.mStorage, fabric, mapping.keyset_id))
    2016              :             {
    2017            0 :                 break;
    2018              :             }
    2019           20 :             for (uint16_t k = 0; k < keyset.keys_count; ++k)
    2020              :             {
    2021           14 :                 if (keyset.operational_keys[k].hash == mSessionId)
    2022              :                 {
    2023            1 :                     count++;
    2024              :                 }
    2025              :             }
    2026            6 :         }
    2027            2 :     }
    2028            2 :     return count;
    2029            1 : }
    2030              : 
    2031           11 : bool GroupDataProviderImpl::GroupSessionIteratorImpl::Next(GroupSession & output)
    2032              : {
    2033           37 :     while (mFabricCount < mFabricTotal)
    2034              :     {
    2035           35 :         FabricData fabric(mFabric);
    2036           70 :         VerifyOrReturnError(CHIP_NO_ERROR == fabric.Load(mProvider.mStorage), false);
    2037              : 
    2038           35 :         if (mMapCount >= fabric.map_count)
    2039              :         {
    2040              :             // No more keyset/group mappings on the current fabric, try next fabric
    2041            3 :             mFabric = fabric.next;
    2042            3 :             mFabricCount++;
    2043            3 :             mFirstMap = true;
    2044            3 :             mMapCount = 0;
    2045            3 :             continue;
    2046              :         }
    2047              : 
    2048           32 :         if (mFirstMap)
    2049              :         {
    2050           10 :             mMapping  = fabric.first_map;
    2051           10 :             mFirstMap = false;
    2052              :         }
    2053              : 
    2054           32 :         KeyMapData mapping(mFabric, mMapping);
    2055           64 :         VerifyOrReturnError(CHIP_NO_ERROR == mapping.Load(mProvider.mStorage), false);
    2056              : 
    2057              :         // Group found, get the keyset
    2058           32 :         KeySetData keyset;
    2059           32 :         VerifyOrReturnError(keyset.Find(mProvider.mStorage, fabric, mapping.keyset_id), false);
    2060              : 
    2061           32 :         if (mKeyIndex >= keyset.keys_count || (mKeyIndex >= KeySet::kEpochKeysMax))
    2062              :         {
    2063              :             // No more keys in current keyset, try next
    2064            7 :             mMapping = mapping.next;
    2065            7 :             mMapCount++;
    2066            7 :             mKeyIndex = 0;
    2067            7 :             continue;
    2068              :         }
    2069              : 
    2070           25 :         Crypto::GroupOperationalCredentials & creds = keyset.operational_keys[mKeyIndex++];
    2071           25 :         if (creds.hash == mSessionId)
    2072              :         {
    2073            9 :             TEMPORARY_RETURN_IGNORED mGroupKeyContext.Initialize(creds.encryption_key, mSessionId, creds.privacy_key);
    2074            9 :             output.fabric_index    = fabric.fabric_index;
    2075            9 :             output.group_id        = mapping.group_id;
    2076            9 :             output.security_policy = keyset.policy;
    2077            9 :             output.keyContext      = &mGroupKeyContext;
    2078            9 :             return true;
    2079              :         }
    2080           67 :     }
    2081              : 
    2082            2 :     return false;
    2083              : }
    2084              : 
    2085            9 : void GroupDataProviderImpl::GroupSessionIteratorImpl::Release()
    2086              : {
    2087            9 :     mGroupKeyContext.ReleaseKeys();
    2088            9 :     mProvider.mGroupSessionsIterator.ReleaseObject(this);
    2089            9 : }
    2090              : 
    2091              : namespace {
    2092              : 
    2093              : GroupDataProvider * gGroupsProvider = nullptr;
    2094              : 
    2095              : } // namespace
    2096              : 
    2097          107 : GroupDataProvider * GetGroupDataProvider()
    2098              : {
    2099          107 :     return gGroupsProvider;
    2100              : }
    2101              : 
    2102          164 : void SetGroupDataProvider(GroupDataProvider * provider)
    2103              : {
    2104          164 :     gGroupsProvider = provider;
    2105          164 : }
    2106              : 
    2107              : } // namespace Credentials
    2108              : } // namespace chip
        

Generated by: LCOV version 2.0-1