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