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