Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2025 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 :
18 : #pragma once
19 :
20 : #include <algorithm>
21 : #include <app-common/zap-generated/cluster-objects.h>
22 : #include <app/data-model-provider/MetadataTypes.h>
23 : #include <credentials/CHIPCert.h>
24 : #include <crypto/CHIPCryptoPAL.h>
25 : #include <functional>
26 : #include <lib/core/CHIPPersistentStorageDelegate.h>
27 : #include <lib/core/CHIPVendorIdentifiers.hpp>
28 : #include <lib/core/DataModelTypes.h>
29 : #include <lib/core/NodeId.h>
30 : #include <lib/support/ReadOnlyBuffer.h>
31 : #include <map>
32 : #include <type_traits>
33 : #include <unordered_map>
34 : #include <utility>
35 : #include <vector>
36 :
37 : namespace chip {
38 :
39 : // Forward declaration for friend class
40 : class JFAManager;
41 :
42 : namespace app {
43 :
44 : namespace datastore {
45 :
46 : struct AccessControlEntryStruct
47 : {
48 : Clusters::JointFabricDatastore::DatastoreAccessControlEntryPrivilegeEnum privilege =
49 : static_cast<Clusters::JointFabricDatastore::DatastoreAccessControlEntryPrivilegeEnum>(0);
50 : Clusters::JointFabricDatastore::DatastoreAccessControlEntryAuthModeEnum authMode =
51 : static_cast<Clusters::JointFabricDatastore::DatastoreAccessControlEntryAuthModeEnum>(0);
52 : std::vector<uint64_t> subjects;
53 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreAccessControlTargetStruct::Type> targets;
54 : };
55 :
56 : struct ACLEntryStruct
57 : {
58 : chip::NodeId nodeID = static_cast<chip::NodeId>(0);
59 : uint16_t listID = static_cast<uint16_t>(0);
60 : AccessControlEntryStruct ACLEntry;
61 : Clusters::JointFabricDatastore::Structs::DatastoreStatusEntryStruct::Type statusEntry;
62 : };
63 :
64 : } // namespace datastore
65 :
66 : namespace detail {
67 :
68 : /**
69 : * Searches `vec` for the first entry that returns true when passed to `pred`, then marks that entry as committed.
70 : *
71 : * @param [in,out] vec The vector to search; the matching entry is mutated in place to mark it committed.
72 : * @param [in] pred Predicate invoked as `bool(const T &)`; the first entry for which it returns true is marked.
73 : */
74 : template <typename T, typename Pred>
75 36 : void MarkEntryCommittedIfFound(std::vector<T> & vec, Pred pred)
76 : {
77 : static_assert(std::is_invocable_r_v<bool, Pred, const T &>,
78 : "MarkEntryCommittedIfFound predicate must accept a const T & and return bool");
79 36 : auto it = std::find_if(vec.begin(), vec.end(), pred);
80 36 : if (it != vec.end())
81 : {
82 34 : it->statusEntry.state = Clusters::JointFabricDatastore::DatastoreStateEnum::kCommitted;
83 : }
84 36 : }
85 :
86 : } // namespace detail
87 :
88 : enum RefreshState
89 : {
90 : kIdle,
91 : kRefreshingEndpoints,
92 : kRefreshingGroups,
93 : kRefreshingBindings,
94 : kFetchingGroupKeySetList,
95 : kFetchingGroupKeySets,
96 : kRefreshingGroupKeySets,
97 : kRefreshingACLs,
98 : };
99 :
100 : /**
101 : * A struct which extends the DatastoreNodeInformationEntry type with FriendlyName buffer reservation.
102 : */
103 : struct GenericDatastoreNodeInformationEntry
104 : : public Clusters::JointFabricDatastore::Structs::DatastoreNodeInformationEntryStruct::Type
105 : {
106 24 : GenericDatastoreNodeInformationEntry(NodeId nodeId = 0,
107 : Clusters::JointFabricDatastore::DatastoreStateEnum state =
108 : Clusters::JointFabricDatastore::DatastoreStateEnum::kUnknownEnumValue,
109 : Optional<CharSpan> label = NullOptional)
110 24 : {
111 24 : Set(nodeId, state, label);
112 24 : }
113 :
114 39 : GenericDatastoreNodeInformationEntry(const GenericDatastoreNodeInformationEntry & op) { *this = op; }
115 :
116 39 : GenericDatastoreNodeInformationEntry & operator=(const GenericDatastoreNodeInformationEntry & op)
117 : {
118 39 : Set(op.nodeID, op.commissioningStatusEntry.state, MakeOptional(op.friendlyName));
119 39 : return *this;
120 : }
121 :
122 63 : void Set(NodeId nodeId, Clusters::JointFabricDatastore::DatastoreStateEnum state, Optional<CharSpan> label = NullOptional)
123 : {
124 63 : this->nodeID = nodeId;
125 63 : this->commissioningStatusEntry.state = state;
126 63 : Set(label);
127 63 : }
128 :
129 64 : void Set(Optional<CharSpan> label = NullOptional)
130 : {
131 64 : if (label.HasValue())
132 : {
133 64 : memset(mFriendlyNameBuffer, 0, sizeof(mFriendlyNameBuffer));
134 64 : if (label.Value().size() > sizeof(mFriendlyNameBuffer))
135 : {
136 0 : memcpy(mFriendlyNameBuffer, label.Value().data(), sizeof(mFriendlyNameBuffer));
137 0 : this->friendlyName = CharSpan(mFriendlyNameBuffer, sizeof(mFriendlyNameBuffer));
138 : }
139 : else
140 : {
141 64 : memcpy(mFriendlyNameBuffer, label.Value().data(), label.Value().size());
142 64 : this->friendlyName = CharSpan(mFriendlyNameBuffer, label.Value().size());
143 : }
144 : }
145 : else
146 : {
147 0 : this->friendlyName = CharSpan();
148 : }
149 64 : }
150 :
151 : private:
152 : static constexpr size_t kFriendlyNameMaxSize = 32u;
153 :
154 : char mFriendlyNameBuffer[kFriendlyNameMaxSize];
155 : };
156 :
157 : class JointFabricDatastore
158 : {
159 : public:
160 : static JointFabricDatastore & GetInstance()
161 : {
162 : static JointFabricDatastore sInstance;
163 : return sInstance;
164 : }
165 :
166 : class Delegate
167 : {
168 : public:
169 16 : Delegate() {}
170 16 : virtual ~Delegate() {}
171 :
172 : virtual CHIP_ERROR
173 0 : SyncNode(NodeId nodeId,
174 : const Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type & endpointGroupIDEntry,
175 : std::function<void()> onSuccess)
176 : {
177 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
178 : }
179 :
180 : virtual CHIP_ERROR
181 0 : SyncNode(NodeId nodeId,
182 : const Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type & nodeKeySetEntry,
183 : std::function<void()> onSuccess)
184 : {
185 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
186 : }
187 :
188 : virtual CHIP_ERROR
189 0 : SyncNode(NodeId nodeId,
190 : const Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type & bindingEntry,
191 : std::function<void()> onSuccess)
192 : {
193 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
194 : }
195 :
196 : virtual CHIP_ERROR
197 0 : SyncNode(NodeId nodeId,
198 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type> & bindingEntries,
199 : std::function<void()> onSuccess)
200 : {
201 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
202 : }
203 :
204 0 : virtual CHIP_ERROR SyncNode(NodeId nodeId,
205 : const Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type & aclEntry,
206 : std::function<void()> onSuccess)
207 : {
208 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
209 : }
210 :
211 : virtual CHIP_ERROR
212 0 : SyncNode(NodeId nodeId,
213 : const std::vector<app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type> & aclEntries,
214 : std::function<void()> onSuccess)
215 : {
216 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
217 : }
218 :
219 0 : virtual CHIP_ERROR SyncNode(NodeId nodeId,
220 : const Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & groupKeySet,
221 : std::function<void()> onSuccess)
222 : {
223 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
224 : }
225 :
226 0 : virtual CHIP_ERROR FetchEndpointList(
227 : NodeId nodeId,
228 : std::function<void(CHIP_ERROR,
229 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointEntryStruct::Type> &)>
230 : onSuccess)
231 : {
232 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
233 : }
234 :
235 0 : virtual CHIP_ERROR FetchEndpointGroupList(
236 : NodeId nodeId, EndpointId endpointId,
237 : std::function<
238 : void(CHIP_ERROR,
239 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreGroupInformationEntryStruct::Type> &)>
240 : onSuccess)
241 : {
242 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
243 : }
244 :
245 0 : virtual CHIP_ERROR FetchEndpointBindingList(
246 : NodeId nodeId, EndpointId endpointId,
247 : std::function<
248 : void(CHIP_ERROR,
249 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type> &)>
250 : onSuccess)
251 : {
252 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
253 : }
254 :
255 0 : virtual CHIP_ERROR FetchGroupKeySetList(NodeId nodeId,
256 : std::function<void(CHIP_ERROR, const std::vector<uint16_t> &)> onSuccess)
257 : {
258 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
259 : }
260 :
261 0 : virtual CHIP_ERROR FetchGroupKeySet(
262 : NodeId nodeId, uint16_t groupKeySetID,
263 : std::function<void(CHIP_ERROR, const app::Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type &)>
264 : onSuccess)
265 : {
266 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
267 : }
268 :
269 0 : virtual CHIP_ERROR FetchACLList(
270 : NodeId nodeId,
271 : std::function<void(CHIP_ERROR,
272 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type> &)>
273 : onSuccess)
274 : {
275 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
276 : }
277 : };
278 :
279 : CHIP_ERROR SetAnchorRootCA(const ByteSpan & anchorRootCA)
280 : {
281 : if (anchorRootCA.size() >= sizeof(mAnchorRootCA))
282 : {
283 : return CHIP_ERROR_INVALID_ARGUMENT;
284 : }
285 : mAnchorRootCALength = anchorRootCA.size();
286 : memcpy(mAnchorRootCA, anchorRootCA.data(), mAnchorRootCALength);
287 : return CHIP_NO_ERROR;
288 : }
289 : ByteSpan GetAnchorRootCA() const { return ByteSpan(mAnchorRootCA, mAnchorRootCALength); }
290 :
291 1 : CHIP_ERROR SetAnchorNodeId(NodeId anchorNodeId)
292 : {
293 1 : mAnchorNodeId = anchorNodeId;
294 1 : return CHIP_NO_ERROR;
295 : }
296 1 : NodeId GetAnchorNodeId() { return mAnchorNodeId; }
297 :
298 : CHIP_ERROR SetAnchorVendorId(VendorId anchorVendorId)
299 : {
300 : mAnchorVendorId = anchorVendorId;
301 : return CHIP_NO_ERROR;
302 : }
303 : VendorId GetAnchorVendorId() { return mAnchorVendorId; }
304 :
305 : /**
306 : * We track the FabricIndex of the Joint Fabric so that the datastore can be wiped if the Joint Fabric is removed.
307 : */
308 1 : void SetAnchorFabricIndex(FabricIndex anchorFabricIndex) { mAnchorFabricIndex = anchorFabricIndex; }
309 2 : FabricIndex GetAnchorFabricIndex() const { return mAnchorFabricIndex; }
310 :
311 : /**
312 : * Runs when a fabric is removed from the node's FabricTable. If the removed fabric is the anchor fabric, the entire datastore
313 : * should be cleared. A no-op for any other fabric.
314 : */
315 2 : void OnFabricRemoved(FabricIndex fabricIndex)
316 : {
317 : // The datastore is the anchor's registry for a single joint fabric. Only act when that fabric is
318 : // removed; records for any other fabric are not stored here.
319 2 : if (mAnchorFabricIndex == kUndefinedFabricIndex || fabricIndex != mAnchorFabricIndex)
320 : {
321 1 : return;
322 : }
323 :
324 1 : ClearAllRecords();
325 :
326 1 : for (Listener * listener = mListeners; listener != nullptr; listener = listener->mNext)
327 : {
328 0 : listener->MarkNodeListChanged();
329 : }
330 : }
331 :
332 : CHIP_ERROR SetFriendlyName(const CharSpan & friendlyName)
333 : {
334 : if (friendlyName.size() >= sizeof(mFriendlyNameBuffer))
335 : {
336 : return CHIP_ERROR_INVALID_ARGUMENT;
337 : }
338 : mFriendlyNameBufferLength = friendlyName.size();
339 : memcpy(mFriendlyNameBuffer, friendlyName.data(), mFriendlyNameBufferLength);
340 : mFriendlyNameBuffer[mFriendlyNameBufferLength] = '\0'; // Ensure null-termination
341 : return CHIP_NO_ERROR;
342 : }
343 : CharSpan GetFriendlyName() const { return CharSpan(mFriendlyNameBuffer, mFriendlyNameBufferLength); }
344 :
345 17 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreGroupInformationEntryStruct::Type> & GetGroupEntries()
346 : {
347 17 : return mGroupInformationEntries;
348 : }
349 :
350 : void SetStatus(Clusters::JointFabricDatastore::DatastoreStateEnum state, uint32_t updateTimestamp, uint8_t failureCode)
351 : {
352 : mDatastoreStatusEntry.state = state;
353 : mDatastoreStatusEntry.updateTimestamp = updateTimestamp;
354 : mDatastoreStatusEntry.failureCode = failureCode;
355 : }
356 : Clusters::JointFabricDatastore::Structs::DatastoreStatusEntryStruct::Type & GetStatus() { return mDatastoreStatusEntry; }
357 :
358 2 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type> & GetEndpointGroupIDList()
359 : {
360 2 : return mEndpointGroupIDEntries;
361 : }
362 :
363 12 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type> & GetEndpointBindingList()
364 : {
365 12 : return mEndpointBindingEntries;
366 : }
367 :
368 2 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type> & GetNodeKeySetList()
369 : {
370 2 : return mNodeKeySetEntries;
371 : }
372 :
373 10 : std::vector<datastore::ACLEntryStruct> & GetNodeACLList() { return mACLEntries; }
374 :
375 5 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointEntryStruct::Type> & GetNodeEndpointList()
376 : {
377 5 : return mEndpointEntries;
378 : }
379 :
380 : CHIP_ERROR AddPendingNode(NodeId nodeId, const CharSpan & friendlyName);
381 : CHIP_ERROR UpdateNode(NodeId nodeId, const CharSpan & friendlyName);
382 : CHIP_ERROR RemoveNode(NodeId nodeId);
383 : CHIP_ERROR RefreshNode(NodeId nodeId);
384 : CHIP_ERROR ContinueRefresh();
385 :
386 : CHIP_ERROR SetNode(NodeId nodeId, Clusters::JointFabricDatastore::DatastoreStateEnum state);
387 :
388 : CHIP_ERROR AddGroupKeySetEntry(const Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & groupKeySet);
389 : bool IsGroupKeySetEntryPresent(uint16_t groupKeySetId);
390 : CHIP_ERROR RemoveGroupKeySetEntry(uint16_t groupKeySetId);
391 : CHIP_ERROR UpdateGroupKeySetEntry(Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & groupKeySet);
392 :
393 : CHIP_ERROR
394 : AddAdmin(const Clusters::JointFabricDatastore::Structs::DatastoreAdministratorInformationEntryStruct::Type & adminId);
395 : bool IsAdminEntryPresent(NodeId nodeId);
396 : CHIP_ERROR UpdateAdmin(NodeId nodeId, Optional<CharSpan> friendlyName, Optional<ByteSpan> icac);
397 : CHIP_ERROR RemoveAdmin(NodeId nodeId);
398 :
399 : CHIP_ERROR AddGroup(const Clusters::JointFabricDatastore::Commands::AddGroup::DecodableType & commandData);
400 : CHIP_ERROR UpdateGroup(const Clusters::JointFabricDatastore::Commands::UpdateGroup::DecodableType & commandData);
401 : CHIP_ERROR RemoveGroup(const Clusters::JointFabricDatastore::Commands::RemoveGroup::DecodableType & commandData);
402 :
403 : CHIP_ERROR UpdateEndpointForNode(NodeId nodeId, EndpointId endpointId, CharSpan friendlyName);
404 :
405 : CHIP_ERROR AddGroupIDToEndpointForNode(NodeId nodeId, EndpointId endpointId, GroupId groupId);
406 : CHIP_ERROR RemoveGroupIDFromEndpointForNode(NodeId nodeId, EndpointId endpointId, GroupId groupId);
407 :
408 : CHIP_ERROR
409 : AddBindingToEndpointForNode(NodeId nodeId, EndpointId endpointId,
410 : const Clusters::JointFabricDatastore::Structs::DatastoreBindingTargetStruct::Type & binding);
411 : CHIP_ERROR
412 : RemoveBindingFromEndpointForNode(uint16_t listId, NodeId nodeId, EndpointId endpointId);
413 :
414 : CHIP_ERROR
415 : AddACLToNode(NodeId nodeId,
416 : const Clusters::JointFabricDatastore::Structs::DatastoreAccessControlEntryStruct::DecodableType & aclEntry);
417 : CHIP_ERROR RemoveACLFromNode(uint16_t listId, NodeId nodeId);
418 :
419 : CHIP_ERROR TestAddNodeKeySetEntry(GroupId groupId, uint16_t groupKeySetId, NodeId nodeId);
420 : CHIP_ERROR TestAddEndpointEntry(EndpointId endpointId, NodeId nodeId, CharSpan friendlyName);
421 :
422 : CHIP_ERROR ForceAddNodeKeySetEntry(uint16_t groupKeySetId, NodeId nodeId);
423 :
424 6 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type> & GetGroupKeySetList()
425 : {
426 6 : return mGroupKeySetList;
427 : }
428 6 : const std::vector<GenericDatastoreNodeInformationEntry> & GetNodeInformationEntries() { return mNodeInformationEntries; }
429 : const std::vector<Clusters::JointFabricDatastore::Structs::DatastoreAdministratorInformationEntryStruct::Type> &
430 6 : GetAdminEntries()
431 : {
432 6 : return mAdminEntries;
433 : }
434 :
435 : /**
436 : * Used to notify of changes in the node list and more TODO.
437 : */
438 : class Listener
439 : {
440 : public:
441 3 : virtual ~Listener() = default;
442 :
443 : /**
444 : * Notifies of a change in the node list.
445 : */
446 : virtual void MarkNodeListChanged() = 0;
447 :
448 : private:
449 : Listener * mNext = nullptr;
450 :
451 : friend class JointFabricDatastore;
452 : };
453 :
454 : /**
455 : * Add a listener to be notified of changes in the Joint Fabric Datastore.
456 : *
457 : * @param [in] listener The listener to add.
458 : */
459 : void AddListener(Listener & listener);
460 :
461 : /**
462 : * Remove a listener from being notified of changes in the Joint Fabric Datastore.
463 : *
464 : * @param [in] listener The listener to remove.
465 : */
466 : void RemoveListener(Listener & listener);
467 :
468 16 : CHIP_ERROR SetDelegate(Delegate * delegate)
469 : {
470 16 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
471 16 : mDelegate = delegate;
472 :
473 16 : return CHIP_NO_ERROR;
474 : }
475 :
476 : private:
477 : // Epoch keys are raw group-key secret material. Hold them in a self-zeroizing buffer so they are
478 : // wiped on every deallocation path (per-record erase, overwrite, and whole-map/object destruction),
479 : // not just the explicit removal helpers.
480 : using EpochKeyStorage = Crypto::SensitiveDataBuffer<Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES>;
481 :
482 : struct GroupKeySetStorage
483 : {
484 : EpochKeyStorage epochKey0;
485 : EpochKeyStorage epochKey1;
486 : EpochKeyStorage epochKey2;
487 : };
488 :
489 : struct GroupInformationStorage
490 : {
491 : // Friendly names are surfaced as CharSpan and may come from non-null-terminated buffers.
492 : // Keep raw owned bytes in vector<char> to preserve exact length semantics for Span use.
493 : std::vector<char> friendlyName;
494 : };
495 :
496 : struct AdminEntryStorage
497 : {
498 : // Friendly names are stored as owned raw bytes for CharSpan (not C-string) semantics.
499 : std::vector<char> friendlyName;
500 : // ICAC DER is sensitive credential material; hold it in a self-zeroizing buffer (see EpochKeyStorage).
501 : Crypto::SensitiveDataBuffer<Credentials::kMaxDERCertLength> icac;
502 : };
503 :
504 : static constexpr size_t kMaxNodes = 256;
505 : static constexpr size_t kMaxAdminNodes = 32;
506 : static constexpr size_t kMaxGroups = kMaxNodes / 16;
507 : static constexpr size_t kMaxGroupKeySet = kMaxGroups * 16;
508 : static constexpr size_t kMaxFriendlyNameSize = 32;
509 : static constexpr size_t kMaxACLs = 64;
510 :
511 : uint8_t mAnchorRootCA[Credentials::kMaxDERCertLength] = { 0 };
512 : size_t mAnchorRootCALength = 0;
513 : char mFriendlyNameBuffer[kMaxFriendlyNameSize] = { 0 };
514 : size_t mFriendlyNameBufferLength = 0;
515 : NodeId mAnchorNodeId = kUndefinedNodeId;
516 : VendorId mAnchorVendorId = VendorId::NotSpecified;
517 : FabricIndex mAnchorFabricIndex = kUndefinedFabricIndex;
518 : Clusters::JointFabricDatastore::Structs::DatastoreStatusEntryStruct::Type mDatastoreStatusEntry;
519 :
520 : /**
521 : * Clears all stored records and resets anchor identity. Used by OnFabricRemoved() when the joint fabric is removed.
522 : * Self-zeroizing buffers wipe their secrets as the containers are cleared.
523 : */
524 1 : void ClearAllRecords()
525 : {
526 : // Erasing the secret-bearing maps destroys the self-zeroizing EpochKeyStorage / ICAC buffers,
527 : // wiping their contents.
528 1 : mGroupKeySetStorage.clear();
529 1 : mAdminEntryStorage.clear();
530 1 : mGroupInformationStorage.clear();
531 1 : mEndpointFriendlyNameStorage.clear();
532 :
533 1 : mNodeInformationEntries.clear();
534 1 : mGroupKeySetList.clear();
535 1 : mAdminEntries.clear();
536 1 : mGroupInformationEntries.clear();
537 1 : mEndpointGroupIDEntries.clear();
538 1 : mEndpointBindingEntries.clear();
539 1 : mNodeKeySetEntries.clear();
540 1 : mACLEntries.clear();
541 1 : mEndpointEntries.clear();
542 :
543 : // Reset anchor identity: with the joint fabric gone, the datastore no longer describes a fabric.
544 1 : memset(mAnchorRootCA, 0, sizeof(mAnchorRootCA));
545 1 : mAnchorRootCALength = 0;
546 1 : mFriendlyNameBuffer[0] = '\0';
547 1 : mFriendlyNameBufferLength = 0;
548 1 : mAnchorNodeId = kUndefinedNodeId;
549 1 : mAnchorVendorId = VendorId::NotSpecified;
550 1 : mAnchorFabricIndex = kUndefinedFabricIndex;
551 1 : mDatastoreStatusEntry = Clusters::JointFabricDatastore::Structs::DatastoreStatusEntryStruct::Type{};
552 1 : }
553 :
554 : // TODO: Persist these members to local storage
555 : std::vector<GenericDatastoreNodeInformationEntry> mNodeInformationEntries;
556 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type> mGroupKeySetList;
557 : std::unordered_map<uint16_t, GroupKeySetStorage> mGroupKeySetStorage;
558 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreAdministratorInformationEntryStruct::Type> mAdminEntries;
559 : std::unordered_map<NodeId, AdminEntryStorage> mAdminEntryStorage;
560 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreGroupInformationEntryStruct::Type> mGroupInformationEntries;
561 : std::unordered_map<GroupId, GroupInformationStorage> mGroupInformationStorage;
562 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type> mEndpointGroupIDEntries;
563 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type> mEndpointBindingEntries;
564 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type> mNodeKeySetEntries;
565 : std::vector<datastore::ACLEntryStruct> mACLEntries;
566 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointEntryStruct::Type> mEndpointEntries;
567 : std::map<std::pair<NodeId, EndpointId>, std::vector<char>> mEndpointFriendlyNameStorage;
568 :
569 : Listener * mListeners = nullptr;
570 :
571 : friend class chip::JFAManager;
572 :
573 : CHIP_ERROR
574 : ForceAddGroup(const Clusters::JointFabricDatastore::Commands::AddGroup::DecodableType & commandData);
575 :
576 : CHIP_ERROR IsNodeIDInDatastore(NodeId nodeId, size_t & index);
577 :
578 : CHIP_ERROR UpdateNodeKeySetList(Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & groupKeySet);
579 : CHIP_ERROR RemoveKeySet(uint16_t groupKeySetId);
580 :
581 : CHIP_ERROR IsGroupIDInDatastore(GroupId groupId, size_t & index);
582 : CHIP_ERROR IsNodeIdInNodeInformationEntries(NodeId nodeId, size_t & index);
583 : CHIP_ERROR IsNodeIdAndEndpointInEndpointInformationEntries(NodeId nodeId, EndpointId endpointId, size_t & index);
584 :
585 : CHIP_ERROR GenerateAndAssignAUniqueListID(uint16_t & listId);
586 : bool BindingMatches(const Clusters::JointFabricDatastore::Structs::DatastoreBindingTargetStruct::Type & binding1,
587 : const Clusters::JointFabricDatastore::Structs::DatastoreBindingTargetStruct::Type & binding2);
588 : bool ACLMatches(const datastore::AccessControlEntryStruct & acl1,
589 : const Clusters::JointFabricDatastore::Structs::DatastoreAccessControlEntryStruct::DecodableType & acl2);
590 : bool ACLTargetMatches(const Clusters::JointFabricDatastore::Structs::DatastoreAccessControlTargetStruct::Type & target1,
591 : const Clusters::JointFabricDatastore::Structs::DatastoreAccessControlTargetStruct::Type & target2);
592 :
593 : CHIP_ERROR AddNodeKeySetEntry(GroupId groupId, uint16_t groupKeySetId);
594 : CHIP_ERROR RemoveNodeKeySetEntry(GroupId groupId, uint16_t groupKeySetId);
595 :
596 : CHIP_ERROR
597 : CopyGroupKeySetWithOwnedSpans(const Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & source,
598 : Clusters::JointFabricDatastore::Structs::DatastoreGroupKeySetStruct::Type & destination);
599 : void RemoveGroupKeySetStorage(uint16_t groupKeySetId);
600 :
601 : void SetGroupInformationFriendlyNameWithOwnedStorage(
602 : GroupId groupId, const CharSpan & friendlyName,
603 : Clusters::JointFabricDatastore::Structs::DatastoreGroupInformationEntryStruct::Type & destination);
604 : void RemoveGroupInformationStorage(GroupId groupId);
605 :
606 : CHIP_ERROR SetAdminEntryWithOwnedStorage(
607 : NodeId nodeId, const CharSpan & friendlyName, const ByteSpan & icac,
608 : Clusters::JointFabricDatastore::Structs::DatastoreAdministratorInformationEntryStruct::Type & destination);
609 : void RemoveAdminEntryStorage(NodeId nodeId);
610 :
611 : void SetEndpointFriendlyNameWithOwnedStorage(
612 : NodeId nodeId, EndpointId endpointId, const CharSpan & friendlyName,
613 : Clusters::JointFabricDatastore::Structs::DatastoreEndpointEntryStruct::Type & destination);
614 : void RemoveEndpointFriendlyNameStorage(NodeId nodeId, EndpointId endpointId);
615 :
616 : // Helper methods for copying optional ByteSpan and simple nullable values
617 : void CopyByteSpanWithOwnedStorage(const DataModel::Nullable<ByteSpan> & source, EpochKeyStorage & storage,
618 : DataModel::Nullable<ByteSpan> & destination);
619 :
620 : template <typename T>
621 9 : void CopyNullableValue(const DataModel::Nullable<T> & source, DataModel::Nullable<T> & destination)
622 : {
623 : // Only update destination if source has a value; leave destination unchanged if source is null.
624 9 : if (!source.IsNull())
625 : {
626 0 : static_cast<void>(destination.Update(source));
627 : }
628 9 : }
629 :
630 : Delegate * mDelegate = nullptr;
631 :
632 : NodeId mRefreshingNodeId = kUndefinedNodeId;
633 : RefreshState mRefreshState = kIdle;
634 : size_t mRefreshingEndpointIndex = 0;
635 : size_t mRefreshingGroupKeySetIndex = 0;
636 :
637 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointEntryStruct::Type> mRefreshingEndpointsList;
638 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type> mRefreshingBindingEntries;
639 : std::vector<Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type> mRefreshingACLEntries;
640 : std::vector<uint16_t> mRefreshingGroupKeySetIDs;
641 : };
642 :
643 : } // namespace app
644 : } // namespace chip
|