Line data Source code
1 : /*
2 : * Copyright (c) 2023 Project CHIP Authors
3 : * All rights reserved.
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 : // Do not use the DefaultICDClientStorage class in settings where fabric indices are not stable.
19 : // This class relies on the stability of fabric indices for efficient storage and retrieval of ICD client information.
20 : // If fabric indices are not stable, the functionality of this class will be compromised and can lead to unexpected behavior.
21 :
22 : #pragma once
23 :
24 : #include <app/icd/client/ICDClientStorage.h>
25 : #include <lib/core/CHIPCore.h>
26 :
27 : #include <crypto/CHIPCryptoPAL.h>
28 : #include <crypto/SessionKeystore.h>
29 : #include <lib/core/CHIPConfig.h>
30 : #include <lib/core/CHIPPersistentStorageDelegate.h>
31 : #include <lib/core/DataModelTypes.h>
32 : #include <lib/core/ScopedNodeId.h>
33 : #include <lib/core/TLV.h>
34 : #include <lib/support/CommonIterator.h>
35 : #include <lib/support/Pool.h>
36 : #include <vector>
37 :
38 : // TODO: SymmetricKeystore is an alias for SessionKeystore, replace the below when sdk supports SymmetricKeystore
39 : namespace chip {
40 : namespace Crypto {
41 : using SymmetricKeystore = SessionKeystore;
42 : } // namespace Crypto
43 : } // namespace chip
44 :
45 : namespace chip {
46 : namespace app {
47 :
48 : /**
49 : * A DefaultICDClientStorage implementation of ICDClientStorage.
50 : */
51 : class DefaultICDClientStorage : public ICDClientStorage
52 : {
53 : public:
54 : using ICDClientInfoIterator = CommonIterator<ICDClientInfo>;
55 :
56 : // ICDClientInfoIterator wrapper to release ICDClientInfoIterator when it is out of scope
57 : class ICDClientInfoIteratorWrapper
58 : {
59 : public:
60 2 : ICDClientInfoIteratorWrapper(ICDClientInfoIterator * apICDClientInfoIterator)
61 2 : {
62 2 : mpICDClientInfoIterator = apICDClientInfoIterator;
63 2 : }
64 :
65 2 : ~ICDClientInfoIteratorWrapper()
66 : {
67 2 : if (mpICDClientInfoIterator != nullptr)
68 : {
69 2 : mpICDClientInfoIterator->Release();
70 2 : mpICDClientInfoIterator = nullptr;
71 : }
72 2 : }
73 :
74 : private:
75 : ICDClientInfoIterator * mpICDClientInfoIterator = nullptr;
76 : };
77 :
78 : static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_ICD_CLIENTS_INFO_STORAGE_CONCURRENT_ITERATORS;
79 :
80 : CHIP_ERROR Init(PersistentStorageDelegate * clientInfoStore, Crypto::SymmetricKeystore * keyStore);
81 :
82 : /**
83 : * Iterate through persisted ICD Client Info
84 : *
85 : * @return A valid iterator on success. Use CommonIterator accessor to retrieve ICDClientInfo
86 : */
87 : ICDClientInfoIterator * IterateICDClientInfo();
88 :
89 : /**
90 : * When decrypting check-in messages, the system needs to iterate through all keys
91 : * from all ICD clientInfos. In DefaultICDClientStorage, ICDClientInfos for the same fabric are stored in
92 : * storage using the fabricIndex as the key. To retrieve all relevant ICDClientInfos
93 : * from storage, the system needs to know all fabricIndices in advance. The
94 : * `UpdateFabricList` function provides a way to inject newly created fabricIndices
95 : * into a dedicated table. It is recommended to call this function whenever a controller is created
96 : * with a new fabric index.
97 : *
98 : * @param[in] fabricIndex The newly created fabric index.
99 : */
100 : CHIP_ERROR UpdateFabricList(FabricIndex fabricIndex);
101 :
102 : CHIP_ERROR SetKey(ICDClientInfo & clientInfo, const ByteSpan keyData) override;
103 :
104 : void RemoveKey(ICDClientInfo & clientInfo) override;
105 :
106 : CHIP_ERROR StoreEntry(const ICDClientInfo & clientInfo) override;
107 :
108 : CHIP_ERROR DeleteEntry(const ScopedNodeId & peerNode) override;
109 :
110 : /**
111 : * Remove all ICDClient persistent information associated with the specified
112 : * fabric index. If no entries for the fabric index exist, this is a no-op
113 : * and is considered successful.
114 : * When the whole fabric is removed, all entries from persistent storage in current fabric index are removed.
115 : *
116 : * @param[in] fabricIndex the index of the fabric for which to remove ICDClient persistent information
117 : */
118 : CHIP_ERROR DeleteAllEntries(FabricIndex fabricIndex);
119 :
120 : CHIP_ERROR ProcessCheckInPayload(const ByteSpan & payload, ICDClientInfo & clientInfo,
121 : Protocols::SecureChannel::CounterType & counter) override;
122 :
123 : /**
124 : * Shut down DefaultICDClientStorage
125 : *
126 : */
127 : void Shutdown();
128 :
129 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
130 2 : size_t GetFabricListSize() { return mFabricList.size(); }
131 :
132 11 : PersistentStorageDelegate * GetClientInfoStore() { return mpClientInfoStore; }
133 : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
134 :
135 : protected:
136 : enum class ClientInfoTag : uint8_t
137 : {
138 : kPeerNodeId = 1,
139 : kCheckInNodeId = 2,
140 : kFabricIndex = 3,
141 : kStartICDCounter = 4,
142 : kOffset = 5,
143 : kMonitoredSubject = 6,
144 : kAesKeyHandle = 7,
145 : kHmacKeyHandle = 8,
146 : kClientType = 9,
147 : };
148 :
149 : enum class CounterTag : uint8_t
150 : {
151 : kCount = 1,
152 : kSize = 2,
153 : };
154 :
155 : class ICDClientInfoIteratorImpl : public ICDClientInfoIterator
156 : {
157 : public:
158 : ICDClientInfoIteratorImpl(DefaultICDClientStorage & manager);
159 : size_t Count() override;
160 : bool Next(ICDClientInfo & info) override;
161 : void Release() override;
162 :
163 : private:
164 : DefaultICDClientStorage & mManager;
165 : size_t mFabricListIndex = 0;
166 : size_t mClientInfoIndex = 0;
167 : std::vector<ICDClientInfo> mClientInfoVector;
168 : };
169 :
170 : static constexpr size_t MaxICDClientInfoSize()
171 : {
172 : // All the fields added together
173 : return TLV::EstimateStructOverhead(
174 : sizeof(NodeId), sizeof(NodeId), sizeof(FabricIndex), sizeof(uint32_t) /*start_icd_counter*/,
175 : sizeof(uint32_t) /*offset*/, sizeof(uint64_t) /*monitored_subject*/,
176 : sizeof(Crypto::Symmetric128BitsKeyByteArray) /*aes_key_handle*/,
177 : sizeof(Crypto::Symmetric128BitsKeyByteArray) /*hmac_key_handle*/, sizeof(uint8_t) /*client_type*/);
178 : }
179 :
180 : static constexpr size_t MaxICDCounterSize()
181 : {
182 : // All the fields added together
183 : return TLV::EstimateStructOverhead(sizeof(size_t), sizeof(size_t));
184 : }
185 :
186 : private:
187 : friend class ICDClientInfoIteratorImpl;
188 : CHIP_ERROR StoreFabricList();
189 : CHIP_ERROR LoadFabricList();
190 : CHIP_ERROR LoadCounter(FabricIndex fabricIndex, size_t & count, size_t & clientInfoSize);
191 :
192 : bool FabricExists(FabricIndex fabricIndex);
193 :
194 : CHIP_ERROR IncreaseEntryCountForFabric(FabricIndex fabricIndex);
195 : CHIP_ERROR DecreaseEntryCountForFabric(FabricIndex fabricIndex);
196 : CHIP_ERROR UpdateEntryCountForFabric(FabricIndex fabricIndex, bool increase);
197 :
198 : CHIP_ERROR SerializeToTlv(TLV::TLVWriter & writer, const std::vector<ICDClientInfo> & clientInfoVector);
199 : CHIP_ERROR Load(FabricIndex fabricIndex, std::vector<ICDClientInfo> & clientInfoVector, size_t & clientInfoSize);
200 :
201 : ObjectPool<ICDClientInfoIteratorImpl, kIteratorsMax> mICDClientInfoIterators;
202 :
203 : PersistentStorageDelegate * mpClientInfoStore = nullptr;
204 : Crypto::SymmetricKeystore * mpKeyStore = nullptr;
205 : std::vector<FabricIndex> mFabricList;
206 : };
207 : } // namespace app
208 : } // namespace chip
|