Line data Source code
1 : /*
2 : * Copyright (c) 2022 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 : /**
19 : * @file
20 : * This file defines the CHIP CASE Session object that provides
21 : * APIs for constructing a secure session using a certificate from the device's
22 : * operational credentials.
23 : */
24 :
25 : #include <protocols/secure_channel/SimpleSessionResumptionStorage.h>
26 :
27 : #include <lib/support/Base64.h>
28 : #include <lib/support/SafeInt.h>
29 :
30 : namespace chip {
31 :
32 : constexpr TLV::Tag SimpleSessionResumptionStorage::kFabricIndexTag;
33 : constexpr TLV::Tag SimpleSessionResumptionStorage::kPeerNodeIdTag;
34 : constexpr TLV::Tag SimpleSessionResumptionStorage::kResumptionIdTag;
35 : constexpr TLV::Tag SimpleSessionResumptionStorage::kSharedSecretTag;
36 : constexpr TLV::Tag SimpleSessionResumptionStorage::kCATTag;
37 :
38 883 : StorageKeyName SimpleSessionResumptionStorage::GetStorageKey(const ScopedNodeId & node)
39 : {
40 883 : return DefaultStorageKeyAllocator::FabricSession(node.GetFabricIndex(), node.GetNodeId());
41 : }
42 :
43 683 : StorageKeyName SimpleSessionResumptionStorage::GetStorageKey(ConstResumptionIdView resumptionId)
44 : {
45 : char resumptionIdBase64[BASE64_ENCODED_LEN(resumptionId.size()) + 1];
46 683 : auto len = Base64Encode(resumptionId.data(), resumptionId.size(), resumptionIdBase64);
47 683 : resumptionIdBase64[len] = '\0';
48 683 : return DefaultStorageKeyAllocator::SessionResumption(resumptionIdBase64);
49 : }
50 :
51 216 : CHIP_ERROR SimpleSessionResumptionStorage::SaveIndex(const SessionIndex & index)
52 : {
53 : std::array<uint8_t, MaxIndexSize()> buf;
54 216 : TLV::TLVWriter writer;
55 216 : writer.Init(buf);
56 :
57 : TLV::TLVType arrayType;
58 216 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Array, arrayType));
59 :
60 5336 : for (size_t i = 0; i < index.mSize; ++i)
61 : {
62 : TLV::TLVType innerType;
63 5120 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, innerType));
64 5120 : ReturnErrorOnFailure(writer.Put(kFabricIndexTag, index.mNodes[i].GetFabricIndex()));
65 5120 : ReturnErrorOnFailure(writer.Put(kPeerNodeIdTag, index.mNodes[i].GetNodeId()));
66 5120 : ReturnErrorOnFailure(writer.EndContainer(innerType));
67 : }
68 :
69 216 : ReturnErrorOnFailure(writer.EndContainer(arrayType));
70 :
71 216 : const auto len = writer.GetLengthWritten();
72 216 : VerifyOrReturnError(CanCastTo<uint16_t>(len), CHIP_ERROR_BUFFER_TOO_SMALL);
73 :
74 216 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(DefaultStorageKeyAllocator::SessionResumptionIndex().KeyName(), buf.data(),
75 : static_cast<uint16_t>(len)));
76 :
77 216 : return CHIP_NO_ERROR;
78 : }
79 :
80 275 : CHIP_ERROR SimpleSessionResumptionStorage::LoadIndex(SessionIndex & index)
81 : {
82 : std::array<uint8_t, MaxIndexSize()> buf;
83 275 : uint16_t len = static_cast<uint16_t>(buf.size());
84 :
85 275 : if (mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::SessionResumptionIndex().KeyName(), buf.data(), len) != CHIP_NO_ERROR)
86 : {
87 4 : index.mSize = 0;
88 4 : return CHIP_NO_ERROR;
89 : }
90 :
91 271 : TLV::ContiguousBufferTLVReader reader;
92 271 : reader.Init(buf.data(), len);
93 :
94 271 : ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::AnonymousTag()));
95 : TLV::TLVType arrayType;
96 271 : ReturnErrorOnFailure(reader.EnterContainer(arrayType));
97 :
98 271 : size_t count = 0;
99 : CHIP_ERROR err;
100 5565 : while ((err = reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())) == CHIP_NO_ERROR)
101 : {
102 5294 : if (count >= ArraySize(index.mNodes))
103 : {
104 0 : return CHIP_ERROR_NO_MEMORY;
105 : }
106 :
107 : TLV::TLVType containerType;
108 5294 : ReturnErrorOnFailure(reader.EnterContainer(containerType));
109 :
110 : FabricIndex fabricIndex;
111 5294 : ReturnErrorOnFailure(reader.Next(kFabricIndexTag));
112 5294 : ReturnErrorOnFailure(reader.Get(fabricIndex));
113 :
114 : NodeId peerNodeId;
115 5294 : ReturnErrorOnFailure(reader.Next(kPeerNodeIdTag));
116 5294 : ReturnErrorOnFailure(reader.Get(peerNodeId));
117 :
118 5294 : index.mNodes[count++] = ScopedNodeId(peerNodeId, fabricIndex);
119 :
120 5294 : ReturnErrorOnFailure(reader.ExitContainer(containerType));
121 : }
122 :
123 271 : if (err != CHIP_END_OF_TLV)
124 : {
125 0 : return err;
126 : }
127 :
128 271 : ReturnErrorOnFailure(reader.ExitContainer(arrayType));
129 271 : ReturnErrorOnFailure(reader.VerifyEndOfContainer());
130 :
131 271 : index.mSize = count;
132 :
133 271 : return CHIP_NO_ERROR;
134 : }
135 :
136 207 : CHIP_ERROR SimpleSessionResumptionStorage::SaveLink(ConstResumptionIdView resumptionId, const ScopedNodeId & node)
137 : {
138 : // Save a link from resumptionId to node, in key: /g/s/<resumptionId>
139 : std::array<uint8_t, MaxScopedNodeIdSize()> buf;
140 207 : TLV::TLVWriter writer;
141 207 : writer.Init(buf);
142 :
143 : TLV::TLVType outerType;
144 207 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
145 207 : ReturnErrorOnFailure(writer.Put(kFabricIndexTag, node.GetFabricIndex()));
146 207 : ReturnErrorOnFailure(writer.Put(kPeerNodeIdTag, node.GetNodeId()));
147 207 : ReturnErrorOnFailure(writer.EndContainer(outerType));
148 :
149 207 : const auto len = writer.GetLengthWritten();
150 207 : VerifyOrDie(CanCastTo<uint16_t>(len));
151 :
152 207 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(GetStorageKey(resumptionId).KeyName(), buf.data(), static_cast<uint16_t>(len)));
153 207 : return CHIP_NO_ERROR;
154 : }
155 :
156 163 : CHIP_ERROR SimpleSessionResumptionStorage::LoadLink(ConstResumptionIdView resumptionId, ScopedNodeId & node)
157 : {
158 : std::array<uint8_t, MaxScopedNodeIdSize()> buf;
159 163 : uint16_t len = static_cast<uint16_t>(buf.size());
160 :
161 163 : ReturnErrorOnFailure(mStorage->SyncGetKeyValue(GetStorageKey(resumptionId).KeyName(), buf.data(), len));
162 :
163 56 : TLV::ContiguousBufferTLVReader reader;
164 56 : reader.Init(buf.data(), len);
165 :
166 56 : ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
167 : TLV::TLVType containerType;
168 56 : ReturnErrorOnFailure(reader.EnterContainer(containerType));
169 :
170 : FabricIndex fabricIndex;
171 56 : ReturnErrorOnFailure(reader.Next(kFabricIndexTag));
172 56 : ReturnErrorOnFailure(reader.Get(fabricIndex));
173 :
174 : NodeId peerNodeId;
175 56 : ReturnErrorOnFailure(reader.Next(kPeerNodeIdTag));
176 56 : ReturnErrorOnFailure(reader.Get(peerNodeId));
177 :
178 56 : ReturnErrorOnFailure(reader.ExitContainer(containerType));
179 56 : ReturnErrorOnFailure(reader.VerifyEndOfContainer());
180 :
181 56 : node = ScopedNodeId(peerNodeId, fabricIndex);
182 :
183 56 : return CHIP_NO_ERROR;
184 : }
185 :
186 159 : CHIP_ERROR SimpleSessionResumptionStorage::DeleteLink(ConstResumptionIdView resumptionId)
187 : {
188 159 : ReturnErrorOnFailure(mStorage->SyncDeleteKeyValue(GetStorageKey(resumptionId).KeyName()));
189 159 : return CHIP_NO_ERROR;
190 : }
191 :
192 208 : CHIP_ERROR SimpleSessionResumptionStorage::SaveState(const ScopedNodeId & node, ConstResumptionIdView resumptionId,
193 : const Crypto::P256ECDHDerivedSecret & sharedSecret, const CATValues & peerCATs)
194 : {
195 : // Save session state into key: /f/<fabricIndex>/s/<nodeId>
196 : std::array<uint8_t, MaxStateSize()> buf;
197 208 : TLV::TLVWriter writer;
198 208 : writer.Init(buf);
199 :
200 : TLV::TLVType outerType;
201 208 : ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
202 :
203 208 : ReturnErrorOnFailure(writer.Put(kResumptionIdTag, resumptionId));
204 :
205 208 : ReturnErrorOnFailure(writer.Put(kSharedSecretTag, ByteSpan(sharedSecret.ConstBytes(), sharedSecret.Length())));
206 :
207 : CATValues::Serialized cat;
208 208 : peerCATs.Serialize(cat);
209 208 : ReturnErrorOnFailure(writer.Put(kCATTag, ByteSpan(cat)));
210 :
211 208 : ReturnErrorOnFailure(writer.EndContainer(outerType));
212 :
213 208 : const auto len = writer.GetLengthWritten();
214 208 : VerifyOrDie(CanCastTo<uint16_t>(len));
215 :
216 208 : ReturnErrorOnFailure(mStorage->SyncSetKeyValue(GetStorageKey(node).KeyName(), buf.data(), static_cast<uint16_t>(len)));
217 208 : return CHIP_NO_ERROR;
218 : }
219 :
220 474 : CHIP_ERROR SimpleSessionResumptionStorage::LoadState(const ScopedNodeId & node, ResumptionIdStorage & resumptionId,
221 : Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
222 : {
223 : std::array<uint8_t, MaxStateSize()> buf;
224 474 : uint16_t len = static_cast<uint16_t>(buf.size());
225 :
226 474 : ReturnErrorOnFailure(mStorage->SyncGetKeyValue(GetStorageKey(node).KeyName(), buf.data(), len));
227 :
228 318 : TLV::ContiguousBufferTLVReader reader;
229 318 : reader.Init(buf.data(), len);
230 :
231 318 : ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
232 : TLV::TLVType containerType;
233 318 : ReturnErrorOnFailure(reader.EnterContainer(containerType));
234 :
235 318 : ByteSpan resumptionIdSpan;
236 318 : ReturnErrorOnFailure(reader.Next(kResumptionIdTag));
237 318 : ReturnErrorOnFailure(reader.Get(resumptionIdSpan));
238 318 : VerifyOrReturnError(resumptionIdSpan.size() == resumptionId.size(), CHIP_ERROR_KEY_NOT_FOUND);
239 318 : std::copy(resumptionIdSpan.begin(), resumptionIdSpan.end(), resumptionId.begin());
240 :
241 318 : ByteSpan sharedSecretSpan;
242 318 : ReturnErrorOnFailure(reader.Next(kSharedSecretTag));
243 318 : ReturnErrorOnFailure(reader.Get(sharedSecretSpan));
244 318 : VerifyOrReturnError(sharedSecretSpan.size() <= sharedSecret.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL);
245 318 : ::memcpy(sharedSecret.Bytes(), sharedSecretSpan.data(), sharedSecretSpan.size());
246 318 : sharedSecret.SetLength(sharedSecretSpan.size());
247 :
248 318 : ByteSpan catSpan;
249 318 : ReturnErrorOnFailure(reader.Next(kCATTag));
250 318 : ReturnErrorOnFailure(reader.Get(catSpan));
251 : CATValues::Serialized cat;
252 318 : VerifyOrReturnError(sizeof(cat) == catSpan.size(), CHIP_ERROR_INVALID_TLV_ELEMENT);
253 318 : ::memcpy(cat, catSpan.data(), catSpan.size());
254 318 : peerCATs.Deserialize(cat);
255 :
256 318 : ReturnErrorOnFailure(reader.ExitContainer(containerType));
257 318 : ReturnErrorOnFailure(reader.VerifyEndOfContainer());
258 :
259 318 : return CHIP_NO_ERROR;
260 : }
261 :
262 102 : CHIP_ERROR SimpleSessionResumptionStorage::DeleteState(const ScopedNodeId & node)
263 : {
264 102 : ReturnErrorOnFailure(mStorage->SyncDeleteKeyValue(GetStorageKey(node).KeyName()));
265 102 : return CHIP_NO_ERROR;
266 : }
267 :
268 : } // namespace chip
|