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 : #include <string.h>
19 :
20 : #include <crypto/CHIPCryptoPAL.h>
21 : #include <lib/core/CHIPError.h>
22 : #include <lib/core/CHIPPersistentStorageDelegate.h>
23 : #include <lib/core/DataModelTypes.h>
24 : #include <lib/core/TLV.h>
25 : #include <lib/support/CHIPMem.h>
26 : #include <lib/support/CodeUtils.h>
27 : #include <lib/support/DefaultStorageKeyAllocator.h>
28 : #include <lib/support/SafeInt.h>
29 : #include <lib/support/ScopedBuffer.h>
30 :
31 : #include <credentials/CHIPCert.h>
32 :
33 : #include "PersistentStorageOpCertStore.h"
34 :
35 : namespace chip {
36 : namespace Credentials {
37 :
38 : namespace {
39 :
40 : using CertChainElement = OperationalCertificateStore::CertChainElement;
41 : using VidVerificationElement = OperationalCertificateStore::VidVerificationElement;
42 :
43 4888 : StorageKeyName GetStorageKeyForCert(FabricIndex fabricIndex, CertChainElement element)
44 : {
45 4888 : switch (element)
46 : {
47 1645 : case CertChainElement::kNoc:
48 1645 : return DefaultStorageKeyAllocator::FabricNOC(fabricIndex);
49 : break;
50 1598 : case CertChainElement::kIcac:
51 1598 : return DefaultStorageKeyAllocator::FabricICAC(fabricIndex);
52 : break;
53 1645 : case CertChainElement::kRcac:
54 1645 : return DefaultStorageKeyAllocator::FabricRCAC(fabricIndex);
55 : break;
56 0 : default:
57 0 : break;
58 : }
59 :
60 0 : return StorageKeyName::Uninitialized();
61 : }
62 :
63 2427 : bool StorageHasCertificate(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element)
64 : {
65 2427 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
66 :
67 2427 : if (!storageKey)
68 : {
69 0 : return false;
70 : }
71 :
72 : // TODO(#16958): need to actually read the cert to know if it's there due to platforms not
73 : // properly enforcing CHIP_ERROR_BUFFER_TOO_SMALL behavior needed by
74 : // PersistentStorageDelegate.
75 : uint8_t placeHolderCertBuffer[kMaxCHIPCertLength];
76 :
77 2427 : uint16_t keySize = sizeof(placeHolderCertBuffer);
78 2427 : CHIP_ERROR err = storage->SyncGetKeyValue(storageKey.KeyName(), &placeHolderCertBuffer[0], keySize);
79 :
80 2427 : return (err == CHIP_NO_ERROR);
81 2427 : }
82 :
83 162 : CHIP_ERROR LoadCertFromStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element,
84 : MutableByteSpan & outCert)
85 : {
86 162 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
87 162 : if (!storageKey)
88 : {
89 0 : return CHIP_ERROR_INTERNAL;
90 : }
91 :
92 162 : uint16_t keySize = static_cast<uint16_t>(outCert.size());
93 162 : CHIP_ERROR err = storage->SyncGetKeyValue(storageKey.KeyName(), outCert.data(), keySize);
94 :
95 : // Not finding an ICAC means we don't have one, so adjust to meet the API contract, where
96 : // outCert.empty() will be true;
97 162 : if ((element == CertChainElement::kIcac) && (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
98 : {
99 10 : outCert.reduce_size(0);
100 10 : return CHIP_ERROR_NOT_FOUND;
101 : }
102 :
103 152 : if (err == CHIP_NO_ERROR)
104 : {
105 148 : outCert.reduce_size(keySize);
106 : }
107 4 : else if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
108 : {
109 : // Convert persisted storage error to CHIP_ERROR_NOT_FOUND so that
110 : // `PersistentStorageOpCertStore::GetCertificate` doesn't need to convert.
111 4 : err = CHIP_ERROR_NOT_FOUND;
112 : }
113 :
114 152 : return err;
115 162 : }
116 :
117 2242 : CHIP_ERROR SaveCertToStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element,
118 : const ByteSpan & cert)
119 : {
120 2242 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
121 2242 : if (!storageKey)
122 : {
123 0 : return CHIP_ERROR_INTERNAL;
124 : }
125 :
126 : // If provided an empty ICAC, we delete the ICAC key previously used. If not there, it's OK
127 2242 : if ((element == CertChainElement::kIcac) && (cert.empty()))
128 : {
129 14 : CHIP_ERROR err = storage->SyncDeleteKeyValue(storageKey.KeyName());
130 14 : if ((err == CHIP_NO_ERROR) || (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
131 : {
132 14 : return CHIP_NO_ERROR;
133 : }
134 0 : return err;
135 : }
136 :
137 2228 : return storage->SyncSetKeyValue(storageKey.KeyName(), cert.data(), static_cast<uint16_t>(cert.size()));
138 2242 : }
139 :
140 57 : CHIP_ERROR DeleteCertFromStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element)
141 : {
142 57 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
143 57 : if (!storageKey)
144 : {
145 0 : return CHIP_ERROR_INTERNAL;
146 : }
147 57 : return storage->SyncDeleteKeyValue(storageKey.KeyName());
148 57 : }
149 :
150 49 : CHIP_ERROR SaveVidVerificationElementToStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex,
151 : VidVerificationElement element, ByteSpan elementData)
152 : {
153 49 : StorageKeyName storageKey = StorageKeyName::FromConst("");
154 :
155 49 : switch (element)
156 : {
157 23 : case VidVerificationElement::kVidVerificationStatement:
158 23 : storageKey = DefaultStorageKeyAllocator::FabricVidVerificationStatement(fabricIndex);
159 23 : break;
160 26 : case VidVerificationElement::kVvsc:
161 26 : storageKey = DefaultStorageKeyAllocator::FabricVVSC(fabricIndex);
162 26 : break;
163 0 : default:
164 0 : return CHIP_ERROR_INTERNAL;
165 : }
166 :
167 49 : if (!storageKey)
168 : {
169 0 : return CHIP_ERROR_INTERNAL;
170 : }
171 :
172 49 : if (elementData.empty())
173 : {
174 41 : CHIP_ERROR err = storage->SyncDeleteKeyValue(storageKey.KeyName());
175 41 : if ((err == CHIP_NO_ERROR) || (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
176 : {
177 41 : return CHIP_NO_ERROR;
178 : }
179 0 : return err;
180 : }
181 :
182 8 : return storage->SyncSetKeyValue(storageKey.KeyName(), elementData.data(), static_cast<uint16_t>(elementData.size()));
183 49 : }
184 :
185 41 : CHIP_ERROR DeleteVidVerificationElementFromStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex,
186 : VidVerificationElement element)
187 : {
188 : // Saving an empty bytespan actually deletes the element.
189 41 : return SaveVidVerificationElementToStorage(storage, fabricIndex, element, ByteSpan{});
190 : }
191 :
192 : } // namespace
193 :
194 1542 : bool PersistentStorageOpCertStore::HasPendingRootCert() const
195 : {
196 1542 : if (mStorage == nullptr)
197 : {
198 0 : return false;
199 : }
200 :
201 1542 : return (mPendingRcac.Get() != nullptr) && mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled);
202 : }
203 :
204 792 : bool PersistentStorageOpCertStore::HasPendingNocChain() const
205 : {
206 792 : if (mStorage == nullptr)
207 : {
208 0 : return false;
209 : }
210 :
211 792 : return (mPendingNoc.Get() != nullptr) && mStateFlags.HasAny(StateFlags::kAddNewOpCertsCalled, StateFlags::kUpdateOpCertsCalled);
212 : }
213 :
214 808 : bool PersistentStorageOpCertStore::HasCertificateForFabric(FabricIndex fabricIndex, CertChainElement element) const
215 : {
216 808 : if ((mStorage == nullptr) || !IsValidFabricIndex(fabricIndex))
217 : {
218 0 : return false;
219 : }
220 :
221 : // FabricIndex matches pending, we MAY have some pending data
222 808 : if (fabricIndex == mPendingFabricIndex)
223 : {
224 763 : switch (element)
225 : {
226 741 : case CertChainElement::kRcac:
227 741 : if (mPendingRcac.Get() != nullptr)
228 : {
229 739 : return true;
230 : }
231 2 : break;
232 3 : case CertChainElement::kIcac:
233 3 : if (mPendingIcac.Get() != nullptr)
234 : {
235 0 : return true;
236 : }
237 : // If we have a pending NOC and no pending ICAC, don't delegate to storage, return not found here
238 : // since in the pending state, there truly is nothing.
239 3 : if (mPendingNoc.Get() != nullptr)
240 : {
241 2 : return false;
242 : }
243 1 : break;
244 19 : case CertChainElement::kNoc:
245 19 : if (mPendingNoc.Get() != nullptr)
246 : {
247 18 : return true;
248 : }
249 1 : break;
250 0 : default:
251 0 : return false;
252 : }
253 : }
254 :
255 49 : return StorageHasCertificate(mStorage, fabricIndex, element);
256 : }
257 :
258 13 : bool PersistentStorageOpCertStore::HasNocChainForFabric(FabricIndex fabricIndex) const
259 : {
260 : // If we have at least RCAC and NOC, we are good. Chain may be invalid without ICAC, but caller is to ensure that.
261 26 : return (HasCertificateForFabric(fabricIndex, CertChainElement::kRcac) &&
262 26 : HasCertificateForFabric(fabricIndex, CertChainElement::kNoc));
263 : }
264 :
265 750 : bool PersistentStorageOpCertStore::HasPendingVidVerificationElements() const
266 : {
267 : // If any VID verifications statement data has been touched, we may need to store or erase data on commit.
268 750 : return mStateFlags.HasAny(StateFlags::kVidVerificationStatementUpdated, StateFlags::kVvscUpdated);
269 : }
270 :
271 766 : CHIP_ERROR PersistentStorageOpCertStore::AddNewTrustedRootCertForFabric(FabricIndex fabricIndex, const ByteSpan & rcac)
272 : {
273 766 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
274 765 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
275 764 : VerifyOrReturnError(!rcac.empty() && (rcac.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
276 :
277 764 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kUpdateOpCertsCalled, StateFlags::kAddNewTrustedRootCalled,
278 : StateFlags::kAddNewOpCertsCalled),
279 : CHIP_ERROR_INCORRECT_STATE);
280 762 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
281 :
282 761 : Platform::ScopedMemoryBufferWithSize<uint8_t> rcacBuf;
283 761 : VerifyOrReturnError(rcacBuf.Alloc(rcac.size()), CHIP_ERROR_NO_MEMORY);
284 761 : memcpy(rcacBuf.Get(), rcac.data(), rcac.size());
285 :
286 761 : mPendingRcac = std::move(rcacBuf);
287 :
288 761 : mPendingFabricIndex = fabricIndex;
289 761 : mStateFlags.Set(StateFlags::kAddNewTrustedRootCalled);
290 :
291 761 : return CHIP_NO_ERROR;
292 761 : }
293 :
294 764 : CHIP_ERROR PersistentStorageOpCertStore::AddNewOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
295 : const ByteSpan & icac)
296 : {
297 764 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
298 764 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
299 764 : VerifyOrReturnError(!noc.empty() && (noc.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
300 764 : VerifyOrReturnError(icac.size() <= Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
301 : // Can't have called UpdateOpCertsForFabric first, or called with pending certs
302 764 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kUpdateOpCertsCalled, StateFlags::kAddNewOpCertsCalled),
303 : CHIP_ERROR_INCORRECT_STATE);
304 :
305 : // Need to have trusted roots installed to make the chain valid
306 761 : VerifyOrReturnError(mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled), CHIP_ERROR_INCORRECT_STATE);
307 :
308 : // fabricIndex must match the current pending fabric
309 761 : VerifyOrReturnError(fabricIndex == mPendingFabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
310 :
311 : // Can't have persisted NOC/ICAC for same fabric if adding
312 760 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc), CHIP_ERROR_INCORRECT_STATE);
313 759 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kIcac), CHIP_ERROR_INCORRECT_STATE);
314 :
315 759 : Platform::ScopedMemoryBufferWithSize<uint8_t> nocBuf;
316 759 : VerifyOrReturnError(nocBuf.Alloc(noc.size()), CHIP_ERROR_NO_MEMORY);
317 759 : memcpy(nocBuf.Get(), noc.data(), noc.size());
318 :
319 759 : Platform::ScopedMemoryBufferWithSize<uint8_t> icacBuf;
320 759 : if (icac.size() > 0)
321 : {
322 745 : VerifyOrReturnError(icacBuf.Alloc(icac.size()), CHIP_ERROR_NO_MEMORY);
323 745 : memcpy(icacBuf.Get(), icac.data(), icac.size());
324 : }
325 :
326 759 : mPendingNoc = std::move(nocBuf);
327 759 : mPendingIcac = std::move(icacBuf);
328 :
329 759 : mStateFlags.Set(StateFlags::kAddNewOpCertsCalled);
330 :
331 759 : return CHIP_NO_ERROR;
332 759 : }
333 :
334 16 : CHIP_ERROR PersistentStorageOpCertStore::UpdateOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
335 : const ByteSpan & icac)
336 : {
337 16 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
338 15 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
339 15 : VerifyOrReturnError(!noc.empty() && (noc.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
340 15 : VerifyOrReturnError(icac.size() <= Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
341 :
342 : // Can't have called AddNewOpCertsForFabric first, and should never get here after AddNewTrustedRootCertForFabric.
343 15 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kAddNewOpCertsCalled, StateFlags::kAddNewTrustedRootCalled),
344 : CHIP_ERROR_INCORRECT_STATE);
345 :
346 : // Can't have already pending NOC from UpdateOpCerts not yet committed
347 14 : VerifyOrReturnError(!mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
348 :
349 : // Need to have trusted roots installed to make the chain valid
350 13 : VerifyOrReturnError(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
351 :
352 : // Must have persisted NOC for same fabric if updating
353 12 : VerifyOrReturnError(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc), CHIP_ERROR_INCORRECT_STATE);
354 :
355 : // Don't check for ICAC, we may not have had one before, but assume that if NOC is there, a
356 : // previous chain was at least partially there
357 :
358 12 : Platform::ScopedMemoryBufferWithSize<uint8_t> nocBuf;
359 12 : VerifyOrReturnError(nocBuf.Alloc(noc.size()), CHIP_ERROR_NO_MEMORY);
360 12 : memcpy(nocBuf.Get(), noc.data(), noc.size());
361 :
362 12 : Platform::ScopedMemoryBufferWithSize<uint8_t> icacBuf;
363 12 : if (icac.size() > 0)
364 : {
365 4 : VerifyOrReturnError(icacBuf.Alloc(icac.size()), CHIP_ERROR_NO_MEMORY);
366 4 : memcpy(icacBuf.Get(), icac.data(), icac.size());
367 : }
368 :
369 12 : mPendingNoc = std::move(nocBuf);
370 12 : mPendingIcac = std::move(icacBuf);
371 :
372 : // For NOC update, UpdateOpCertsForFabric is what determines the pending fabric index,
373 : // not a previous AddNewTrustedRootCertForFabric call.
374 12 : mPendingFabricIndex = fabricIndex;
375 :
376 12 : mStateFlags.Set(StateFlags::kUpdateOpCertsCalled);
377 :
378 12 : return CHIP_NO_ERROR;
379 12 : }
380 :
381 13 : CHIP_ERROR PersistentStorageOpCertStore::BasicVidVerificationAssumptionsAreMet(FabricIndex fabricIndex) const
382 : {
383 13 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
384 13 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
385 : // Must already have a valid NOC chain.
386 13 : VerifyOrReturnError(HasNocChainForFabric(fabricIndex), CHIP_ERROR_INCORRECT_STATE);
387 :
388 13 : return CHIP_NO_ERROR;
389 : }
390 :
391 8 : CHIP_ERROR PersistentStorageOpCertStore::UpdateVidVerificationSignerCertForFabric(FabricIndex fabricIndex, ByteSpan vvsc)
392 : {
393 8 : ReturnErrorOnFailure(BasicVidVerificationAssumptionsAreMet(fabricIndex));
394 8 : VerifyOrReturnError(vvsc.empty() || vvsc.size() <= Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
395 :
396 8 : CHIP_ERROR vvscErr = CHIP_NO_ERROR;
397 :
398 8 : if (vvsc.empty())
399 : {
400 2 : if (fabricIndex == mPendingFabricIndex)
401 : {
402 0 : mPendingVvsc.Free();
403 0 : mStateFlags.Set(StateFlags::kVvscUpdated);
404 : }
405 : else
406 : {
407 2 : vvscErr = DeleteVidVerificationElementFromStorage(mStorage, fabricIndex, VidVerificationElement::kVvsc);
408 : }
409 : }
410 : else
411 : {
412 6 : if (fabricIndex == mPendingFabricIndex)
413 : {
414 1 : VerifyOrReturnError(mPendingVvsc.Alloc(vvsc.size()), CHIP_ERROR_NO_MEMORY);
415 1 : memcpy(mPendingVvsc.Get(), vvsc.data(), vvsc.size());
416 1 : mStateFlags.Set(StateFlags::kVvscUpdated);
417 : }
418 : else
419 : {
420 5 : vvscErr = SaveVidVerificationElementToStorage(mStorage, fabricIndex, VidVerificationElement::kVvsc, vvsc);
421 : }
422 : }
423 :
424 8 : return vvscErr;
425 : }
426 :
427 5 : CHIP_ERROR PersistentStorageOpCertStore::UpdateVidVerificationStatementForFabric(FabricIndex fabricIndex,
428 : ByteSpan vidVerificationStatement)
429 : {
430 5 : ReturnErrorOnFailure(BasicVidVerificationAssumptionsAreMet(fabricIndex));
431 5 : VerifyOrReturnError(vidVerificationStatement.empty() ||
432 : vidVerificationStatement.size() == Crypto::kVendorIdVerificationStatementV1Size,
433 : CHIP_ERROR_INVALID_ARGUMENT);
434 :
435 5 : CHIP_ERROR vvsErr = CHIP_NO_ERROR;
436 :
437 5 : if (vidVerificationStatement.empty())
438 : {
439 1 : if (fabricIndex == mPendingFabricIndex)
440 : {
441 0 : mPendingVidVerificationStatement.Free();
442 0 : mStateFlags.Set(StateFlags::kVidVerificationStatementUpdated);
443 : }
444 : else
445 : {
446 1 : vvsErr =
447 1 : DeleteVidVerificationElementFromStorage(mStorage, fabricIndex, VidVerificationElement::kVidVerificationStatement);
448 : }
449 : }
450 : else
451 : {
452 4 : if (fabricIndex == mPendingFabricIndex)
453 : {
454 1 : VerifyOrReturnError(mPendingVidVerificationStatement.Alloc(vidVerificationStatement.size()), CHIP_ERROR_NO_MEMORY);
455 1 : memcpy(mPendingVidVerificationStatement.Get(), vidVerificationStatement.data(), vidVerificationStatement.size());
456 1 : mStateFlags.Set(StateFlags::kVidVerificationStatementUpdated);
457 : }
458 : else
459 : {
460 3 : vvsErr = SaveVidVerificationElementToStorage(mStorage, fabricIndex, VidVerificationElement::kVidVerificationStatement,
461 : vidVerificationStatement);
462 : }
463 : }
464 :
465 5 : return vvsErr;
466 : }
467 :
468 752 : CHIP_ERROR PersistentStorageOpCertStore::CommitOpCertsForFabric(FabricIndex fabricIndex)
469 : {
470 752 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
471 752 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
472 :
473 751 : VerifyOrReturnError(HasPendingNocChain(), CHIP_ERROR_INCORRECT_STATE);
474 750 : if (HasPendingRootCert())
475 : {
476 : // Neither of these conditions should have occurred based on other interlocks, but since
477 : // committing certificates is a dangerous operation, we absolutely validate our assumptions.
478 742 : VerifyOrReturnError(!mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
479 742 : VerifyOrReturnError(mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled), CHIP_ERROR_INCORRECT_STATE);
480 : }
481 :
482 : // TODO: Handle transaction marking to revert partial certs at next boot if we get interrupted by reboot.
483 :
484 : // Start committing NOC first so we don't have dangling roots if one was added.
485 750 : ByteSpan pendingNocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
486 750 : CHIP_ERROR nocErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kNoc, pendingNocSpan);
487 :
488 : // ICAC storage handles deleting on empty/missing
489 750 : ByteSpan pendingIcacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
490 750 : CHIP_ERROR icacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kIcac, pendingIcacSpan);
491 :
492 750 : CHIP_ERROR rcacErr = CHIP_NO_ERROR;
493 750 : if (HasPendingRootCert())
494 : {
495 742 : ByteSpan pendingRcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
496 742 : rcacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kRcac, pendingRcacSpan);
497 : }
498 :
499 750 : CHIP_ERROR vidVerifyErr = CommitVidVerificationForFabric(mPendingFabricIndex);
500 :
501 : // Remember which was the first error, and if any error occurred.
502 750 : CHIP_ERROR stickyErr = nocErr;
503 750 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : icacErr;
504 750 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : rcacErr;
505 750 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : vidVerifyErr;
506 :
507 750 : if (stickyErr != CHIP_NO_ERROR)
508 : {
509 : // On Adds rather than updates, remove anything possibly stored for the new fabric on partial
510 : // failure.
511 0 : if (mStateFlags.Has(StateFlags::kAddNewOpCertsCalled))
512 : {
513 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kNoc);
514 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kIcac);
515 0 : (void) DeleteVidVerificationElementFromStorage(mStorage, mPendingFabricIndex, VidVerificationElement::kVvsc);
516 0 : (void) DeleteVidVerificationElementFromStorage(mStorage, mPendingFabricIndex,
517 : VidVerificationElement::kVidVerificationStatement);
518 : }
519 0 : if (mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled))
520 : {
521 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kRcac);
522 : }
523 0 : if (mStateFlags.Has(StateFlags::kUpdateOpCertsCalled))
524 : {
525 : // Can't do anything to clean-up here, but pretty sure the fabric is broken now...
526 : // TODO: Handle transaction marking to revert certs if somehow failing store on update by pre-backing-up opcerts
527 : }
528 :
529 0 : return stickyErr;
530 : }
531 :
532 : // If we got here, we succeeded and can reset the pending certs: next `GetCertificate` will use the stored certs
533 750 : RevertPendingOpCerts();
534 750 : return CHIP_NO_ERROR;
535 : }
536 :
537 24 : bool PersistentStorageOpCertStore::HasAnyCertificateForFabric(FabricIndex fabricIndex) const
538 : {
539 24 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
540 :
541 24 : bool rcacMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac);
542 24 : bool icacMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kIcac);
543 24 : bool nocMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc);
544 24 : bool anyPending = (mPendingRcac.Get() != nullptr) || (mPendingIcac.Get() != nullptr) || (mPendingNoc.Get() != nullptr);
545 :
546 24 : if (rcacMissing && icacMissing && nocMissing && !anyPending)
547 : {
548 5 : return false;
549 : }
550 :
551 19 : return true;
552 : }
553 :
554 25 : CHIP_ERROR PersistentStorageOpCertStore::RemoveOpCertsForFabric(FabricIndex fabricIndex)
555 : {
556 25 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
557 24 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
558 :
559 : // If there was *no* state, pending or persisted, we have an error
560 24 : VerifyOrReturnError(HasAnyCertificateForFabric(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
561 :
562 : // Clear any pending state
563 19 : RevertPendingOpCerts();
564 :
565 : // Remove all persisted certs for the given fabric, blindly
566 19 : CHIP_ERROR nocErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kNoc);
567 19 : CHIP_ERROR icacErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kIcac);
568 19 : CHIP_ERROR rcacErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kRcac);
569 :
570 19 : CHIP_ERROR vvscErr = DeleteVidVerificationElementFromStorage(mStorage, fabricIndex, VidVerificationElement::kVvsc);
571 : CHIP_ERROR vvsErr =
572 19 : DeleteVidVerificationElementFromStorage(mStorage, fabricIndex, VidVerificationElement::kVidVerificationStatement);
573 :
574 : // Ignore missing data errors
575 19 : nocErr = (nocErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : nocErr;
576 19 : icacErr = (icacErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : icacErr;
577 19 : rcacErr = (rcacErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : rcacErr;
578 19 : vvscErr = (vvscErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : vvscErr;
579 19 : vvsErr = (vvsErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : vvsErr;
580 :
581 : // Find the first error and return that
582 19 : CHIP_ERROR stickyErr = nocErr;
583 19 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : icacErr;
584 19 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : rcacErr;
585 19 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : vvscErr;
586 19 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : vvsErr;
587 :
588 19 : return stickyErr;
589 : }
590 :
591 750 : CHIP_ERROR PersistentStorageOpCertStore::CommitVidVerificationForFabric(FabricIndex fabricIndex)
592 : {
593 750 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
594 750 : if (!HasPendingVidVerificationElements())
595 : {
596 750 : return CHIP_NO_ERROR;
597 : }
598 :
599 0 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
600 :
601 0 : CHIP_ERROR vvscErr = CHIP_NO_ERROR;
602 0 : CHIP_ERROR vvsErr = CHIP_NO_ERROR;
603 :
604 0 : if (mStateFlags.Has(StateFlags::kVvscUpdated))
605 : {
606 0 : ByteSpan pendingVvscSpan{ mPendingVvsc.Get(), mPendingVvsc.AllocatedSize() };
607 0 : vvscErr =
608 0 : SaveVidVerificationElementToStorage(mStorage, mPendingFabricIndex, VidVerificationElement::kVvsc, pendingVvscSpan);
609 : }
610 :
611 0 : if (mStateFlags.Has(StateFlags::kVidVerificationStatementUpdated))
612 : {
613 0 : ByteSpan pendingVidVerificationStatementSpan{ mPendingVidVerificationStatement.Get(),
614 0 : mPendingVidVerificationStatement.AllocatedSize() };
615 0 : vvsErr = SaveVidVerificationElementToStorage(
616 0 : mStorage, mPendingFabricIndex, VidVerificationElement::kVidVerificationStatement, pendingVidVerificationStatementSpan);
617 : }
618 :
619 : // Remember which was the first error, and if any error occurred.
620 0 : CHIP_ERROR stickyErr = vvscErr;
621 0 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : vvsErr;
622 :
623 0 : return stickyErr;
624 : }
625 :
626 2511 : CHIP_ERROR PersistentStorageOpCertStore::GetPendingCertificate(FabricIndex fabricIndex, CertChainElement element,
627 : MutableByteSpan & outCertificate) const
628 : {
629 2511 : if (fabricIndex != mPendingFabricIndex)
630 : {
631 151 : return CHIP_ERROR_NOT_FOUND;
632 : }
633 :
634 : // FabricIndex matches pending, we MAY have some pending data
635 2360 : switch (element)
636 : {
637 824 : case CertChainElement::kRcac:
638 824 : if (mPendingRcac.Get() != nullptr)
639 : {
640 813 : ByteSpan rcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
641 813 : return CopySpanToMutableSpan(rcacSpan, outCertificate);
642 : }
643 11 : break;
644 768 : case CertChainElement::kIcac:
645 768 : if (mPendingIcac.Get() != nullptr)
646 : {
647 749 : ByteSpan icacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
648 749 : return CopySpanToMutableSpan(icacSpan, outCertificate);
649 : }
650 19 : break;
651 768 : case CertChainElement::kNoc:
652 768 : if (mPendingNoc.Get() != nullptr)
653 : {
654 768 : ByteSpan nocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
655 768 : return CopySpanToMutableSpan(nocSpan, outCertificate);
656 : }
657 0 : break;
658 0 : default:
659 0 : return CHIP_ERROR_INVALID_ARGUMENT;
660 : }
661 :
662 30 : return CHIP_ERROR_NOT_FOUND;
663 : }
664 :
665 2511 : CHIP_ERROR PersistentStorageOpCertStore::GetCertificate(FabricIndex fabricIndex, CertChainElement element,
666 : MutableByteSpan & outCertificate) const
667 : {
668 2511 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
669 2511 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
670 :
671 : // Handle case of pending data
672 2511 : CHIP_ERROR err = GetPendingCertificate(fabricIndex, element, outCertificate);
673 2511 : if ((err == CHIP_NO_ERROR) || (err != CHIP_ERROR_NOT_FOUND))
674 : {
675 : // Found in pending, or got a deeper error: return the pending cert status.
676 2330 : return err;
677 : }
678 :
679 : // If we have a pending NOC and no pending ICAC, don't delegate to storage, return not found here
680 : // since in the pending state, there truly is nothing.
681 :
682 181 : if ((err == CHIP_ERROR_NOT_FOUND) && (element == CertChainElement::kIcac) && (mPendingNoc.Get() != nullptr))
683 : {
684 : // Don't delegate to storage if we just have a pending NOC and are missing the ICAC
685 19 : return CHIP_ERROR_NOT_FOUND;
686 : }
687 :
688 : // Not found in pending, let's look in persisted
689 162 : return LoadCertFromStorage(mStorage, fabricIndex, element, outCertificate);
690 : }
691 :
692 27 : CHIP_ERROR PersistentStorageOpCertStore::GetVidVerificationElement(FabricIndex fabricIndex, VidVerificationElement element,
693 : MutableByteSpan & outElement) const
694 : {
695 27 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
696 27 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
697 :
698 27 : StorageKeyName keyName = StorageKeyName::FromConst("");
699 27 : if (element == VidVerificationElement::kVidVerificationStatement)
700 : {
701 16 : if (mStateFlags.Has(StateFlags::kVidVerificationStatementUpdated) && (fabricIndex == mPendingFabricIndex))
702 : {
703 2 : return CopySpanToMutableSpan(
704 1 : ByteSpan{ mPendingVidVerificationStatement.Get(), mPendingVidVerificationStatement.AllocatedSize() }, outElement);
705 : }
706 :
707 15 : keyName = DefaultStorageKeyAllocator::FabricVidVerificationStatement(fabricIndex);
708 : }
709 :
710 26 : if (element == VidVerificationElement::kVvsc)
711 : {
712 11 : if (mStateFlags.Has(StateFlags::kVvscUpdated) && (fabricIndex == mPendingFabricIndex))
713 : {
714 1 : return CopySpanToMutableSpan(ByteSpan{ mPendingVvsc.Get(), mPendingVvsc.AllocatedSize() }, outElement);
715 : }
716 :
717 10 : keyName = DefaultStorageKeyAllocator::FabricVVSC(fabricIndex);
718 : }
719 :
720 25 : if (!keyName)
721 : {
722 0 : return CHIP_ERROR_INVALID_ARGUMENT;
723 : }
724 :
725 : uint8_t storageBuffer[kMaxCHIPCertLength];
726 25 : uint16_t keySize = sizeof(storageBuffer);
727 : static_assert(kMaxCHIPCertLength > (2 * (Crypto::kVendorIdVerificationStatementV1Size)),
728 : "Assuming that at least two VidVerificationStatement fit in a CHIP Cert to give space for future growth and "
729 : "upgrade/downgrade scenarios.");
730 :
731 25 : CHIP_ERROR err = mStorage->SyncGetKeyValue(keyName.KeyName(), &storageBuffer[0], keySize);
732 25 : if ((err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) || (err == CHIP_ERROR_NOT_FOUND))
733 : {
734 15 : outElement.reduce_size(0);
735 15 : return CHIP_NO_ERROR;
736 : }
737 :
738 10 : if (err == CHIP_NO_ERROR)
739 : {
740 10 : return CopySpanToMutableSpan(ByteSpan{ &storageBuffer[0], static_cast<size_t>(keySize) }, outElement);
741 : }
742 :
743 0 : return err;
744 27 : }
745 :
746 : } // namespace Credentials
747 : } // namespace chip
|