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

Generated by: LCOV version 2.0-1