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 <credentials/CHIPCert.h>
19 : #include <lib/core/CHIPError.h>
20 : #include <lib/core/CHIPPersistentStorageDelegate.h>
21 : #include <lib/core/DataModelTypes.h>
22 : #include <lib/core/TLV.h>
23 : #include <lib/support/CHIPMem.h>
24 : #include <lib/support/CodeUtils.h>
25 : #include <lib/support/DefaultStorageKeyAllocator.h>
26 : #include <lib/support/SafeInt.h>
27 : #include <lib/support/ScopedBuffer.h>
28 :
29 : #include "PersistentStorageOpCertStore.h"
30 :
31 : namespace chip {
32 : namespace Credentials {
33 :
34 : namespace {
35 :
36 : using CertChainElement = OperationalCertificateStore::CertChainElement;
37 :
38 4571 : StorageKeyName GetStorageKeyForCert(FabricIndex fabricIndex, CertChainElement element)
39 : {
40 4571 : switch (element)
41 : {
42 1530 : case CertChainElement::kNoc:
43 1530 : return DefaultStorageKeyAllocator::FabricNOC(fabricIndex);
44 : break;
45 1504 : case CertChainElement::kIcac:
46 1504 : return DefaultStorageKeyAllocator::FabricICAC(fabricIndex);
47 : break;
48 1537 : case CertChainElement::kRcac:
49 1537 : return DefaultStorageKeyAllocator::FabricRCAC(fabricIndex);
50 : break;
51 0 : default:
52 0 : break;
53 : }
54 :
55 0 : return StorageKeyName::Uninitialized();
56 : }
57 :
58 2256 : bool StorageHasCertificate(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element)
59 : {
60 2256 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
61 :
62 2256 : if (!storageKey)
63 : {
64 0 : return false;
65 : }
66 :
67 : // TODO(#16958): need to actually read the cert to know if it's there due to platforms not
68 : // properly enforcing CHIP_ERROR_BUFFER_TOO_SMALL behavior needed by
69 : // PersistentStorageDelegate.
70 : uint8_t placeHolderCertBuffer[kMaxCHIPCertLength];
71 :
72 2256 : uint16_t keySize = sizeof(placeHolderCertBuffer);
73 2256 : CHIP_ERROR err = storage->SyncGetKeyValue(storageKey.KeyName(), &placeHolderCertBuffer[0], keySize);
74 :
75 2256 : return (err == CHIP_NO_ERROR);
76 2256 : }
77 :
78 139 : CHIP_ERROR LoadCertFromStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element,
79 : MutableByteSpan & outCert)
80 : {
81 139 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
82 139 : if (!storageKey)
83 : {
84 0 : return CHIP_ERROR_INTERNAL;
85 : }
86 :
87 139 : uint16_t keySize = static_cast<uint16_t>(outCert.size());
88 139 : CHIP_ERROR err = storage->SyncGetKeyValue(storageKey.KeyName(), outCert.data(), keySize);
89 :
90 : // Not finding an ICAC means we don't have one, so adjust to meet the API contract, where
91 : // outCert.empty() will be true;
92 139 : if ((element == CertChainElement::kIcac) && (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
93 : {
94 2 : outCert.reduce_size(0);
95 2 : return CHIP_ERROR_NOT_FOUND;
96 : }
97 :
98 137 : if (err == CHIP_NO_ERROR)
99 : {
100 133 : outCert.reduce_size(keySize);
101 : }
102 4 : else if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
103 : {
104 : // Convert persisted storage error to CHIP_ERROR_NOT_FOUND so that
105 : // `PersistentStorageOpCertStore::GetCertificate` doesn't need to convert.
106 4 : err = CHIP_ERROR_NOT_FOUND;
107 : }
108 :
109 137 : return err;
110 139 : }
111 :
112 2128 : CHIP_ERROR SaveCertToStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element,
113 : const ByteSpan & cert)
114 : {
115 2128 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
116 2128 : if (!storageKey)
117 : {
118 0 : return CHIP_ERROR_INTERNAL;
119 : }
120 :
121 : // If provided an empty ICAC, we delete the ICAC key previously used. If not there, it's OK
122 2128 : if ((element == CertChainElement::kIcac) && (cert.empty()))
123 : {
124 9 : CHIP_ERROR err = storage->SyncDeleteKeyValue(storageKey.KeyName());
125 9 : if ((err == CHIP_NO_ERROR) || (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND))
126 : {
127 9 : return CHIP_NO_ERROR;
128 : }
129 0 : return err;
130 : }
131 :
132 2119 : return storage->SyncSetKeyValue(storageKey.KeyName(), cert.data(), static_cast<uint16_t>(cert.size()));
133 2128 : }
134 :
135 48 : CHIP_ERROR DeleteCertFromStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element)
136 : {
137 48 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
138 48 : if (!storageKey)
139 : {
140 0 : return CHIP_ERROR_INTERNAL;
141 : }
142 48 : return storage->SyncDeleteKeyValue(storageKey.KeyName());
143 48 : }
144 :
145 : } // namespace
146 :
147 1464 : bool PersistentStorageOpCertStore::HasPendingRootCert() const
148 : {
149 1464 : if (mStorage == nullptr)
150 : {
151 0 : return false;
152 : }
153 :
154 1464 : return (mPendingRcac.Get() != nullptr) && mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled);
155 : }
156 :
157 753 : bool PersistentStorageOpCertStore::HasPendingNocChain() const
158 : {
159 753 : if (mStorage == nullptr)
160 : {
161 0 : return false;
162 : }
163 :
164 753 : return (mPendingNoc.Get() != nullptr) && mStateFlags.HasAny(StateFlags::kAddNewOpCertsCalled, StateFlags::kUpdateOpCertsCalled);
165 : }
166 :
167 723 : bool PersistentStorageOpCertStore::HasCertificateForFabric(FabricIndex fabricIndex, CertChainElement element) const
168 : {
169 723 : if ((mStorage == nullptr) || !IsValidFabricIndex(fabricIndex))
170 : {
171 0 : return false;
172 : }
173 :
174 : // FabricIndex matches pending, we MAY have some pending data
175 723 : if (fabricIndex == mPendingFabricIndex)
176 : {
177 716 : switch (element)
178 : {
179 703 : case CertChainElement::kRcac:
180 703 : if (mPendingRcac.Get() != nullptr)
181 : {
182 703 : return true;
183 : }
184 0 : break;
185 2 : case CertChainElement::kIcac:
186 2 : if (mPendingIcac.Get() != nullptr)
187 : {
188 0 : return true;
189 : }
190 : // If we have a pending NOC and no pending ICAC, don't delegate to storage, return not found here
191 : // since in the pending state, there truly is nothing.
192 2 : if (mPendingNoc.Get() != nullptr)
193 : {
194 1 : return false;
195 : }
196 1 : break;
197 11 : case CertChainElement::kNoc:
198 11 : if (mPendingNoc.Get() != nullptr)
199 : {
200 10 : return true;
201 : }
202 1 : break;
203 0 : default:
204 0 : return false;
205 : }
206 : }
207 :
208 9 : return StorageHasCertificate(mStorage, fabricIndex, element);
209 : }
210 :
211 729 : CHIP_ERROR PersistentStorageOpCertStore::AddNewTrustedRootCertForFabric(FabricIndex fabricIndex, const ByteSpan & rcac)
212 : {
213 729 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
214 728 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
215 727 : VerifyOrReturnError(!rcac.empty() && (rcac.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
216 :
217 727 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kUpdateOpCertsCalled, StateFlags::kAddNewTrustedRootCalled,
218 : StateFlags::kAddNewOpCertsCalled),
219 : CHIP_ERROR_INCORRECT_STATE);
220 725 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
221 :
222 724 : Platform::ScopedMemoryBufferWithSize<uint8_t> rcacBuf;
223 724 : VerifyOrReturnError(rcacBuf.Alloc(rcac.size()), CHIP_ERROR_NO_MEMORY);
224 724 : memcpy(rcacBuf.Get(), rcac.data(), rcac.size());
225 :
226 724 : mPendingRcac = std::move(rcacBuf);
227 :
228 724 : mPendingFabricIndex = fabricIndex;
229 724 : mStateFlags.Set(StateFlags::kAddNewTrustedRootCalled);
230 :
231 724 : return CHIP_NO_ERROR;
232 724 : }
233 :
234 727 : CHIP_ERROR PersistentStorageOpCertStore::AddNewOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
235 : const ByteSpan & icac)
236 : {
237 727 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
238 727 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
239 727 : VerifyOrReturnError(!noc.empty() && (noc.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
240 727 : VerifyOrReturnError(icac.size() <= Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
241 :
242 : // Can't have called UpdateOpCertsForFabric first, or called with pending certs
243 727 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kUpdateOpCertsCalled, StateFlags::kAddNewOpCertsCalled),
244 : CHIP_ERROR_INCORRECT_STATE);
245 :
246 : // Need to have trusted roots installed to make the chain valid
247 724 : VerifyOrReturnError(mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled), CHIP_ERROR_INCORRECT_STATE);
248 :
249 : // fabricIndex must match the current pending fabric
250 724 : VerifyOrReturnError(fabricIndex == mPendingFabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
251 :
252 : // Can't have persisted NOC/ICAC for same fabric if adding
253 723 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc), CHIP_ERROR_INCORRECT_STATE);
254 722 : VerifyOrReturnError(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kIcac), CHIP_ERROR_INCORRECT_STATE);
255 :
256 722 : Platform::ScopedMemoryBufferWithSize<uint8_t> nocBuf;
257 722 : VerifyOrReturnError(nocBuf.Alloc(noc.size()), CHIP_ERROR_NO_MEMORY);
258 722 : memcpy(nocBuf.Get(), noc.data(), noc.size());
259 :
260 722 : Platform::ScopedMemoryBufferWithSize<uint8_t> icacBuf;
261 722 : if (icac.size() > 0)
262 : {
263 711 : VerifyOrReturnError(icacBuf.Alloc(icac.size()), CHIP_ERROR_NO_MEMORY);
264 711 : memcpy(icacBuf.Get(), icac.data(), icac.size());
265 : }
266 :
267 722 : mPendingNoc = std::move(nocBuf);
268 722 : mPendingIcac = std::move(icacBuf);
269 :
270 722 : mStateFlags.Set(StateFlags::kAddNewOpCertsCalled);
271 :
272 722 : return CHIP_NO_ERROR;
273 722 : }
274 :
275 12 : CHIP_ERROR PersistentStorageOpCertStore::UpdateOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
276 : const ByteSpan & icac)
277 : {
278 12 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
279 11 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
280 11 : VerifyOrReturnError(!noc.empty() && (noc.size() <= Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
281 11 : VerifyOrReturnError(icac.size() <= Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
282 :
283 : // Can't have called AddNewOpCertsForFabric first, and should never get here after AddNewTrustedRootCertForFabric.
284 11 : VerifyOrReturnError(!mStateFlags.HasAny(StateFlags::kAddNewOpCertsCalled, StateFlags::kAddNewTrustedRootCalled),
285 : CHIP_ERROR_INCORRECT_STATE);
286 :
287 : // Can't have already pending NOC from UpdateOpCerts not yet committed
288 10 : VerifyOrReturnError(!mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
289 :
290 : // Need to have trusted roots installed to make the chain valid
291 9 : VerifyOrReturnError(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
292 :
293 : // Must have persisted NOC for same fabric if updating
294 8 : VerifyOrReturnError(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc), CHIP_ERROR_INCORRECT_STATE);
295 :
296 : // Don't check for ICAC, we may not have had one before, but assume that if NOC is there, a
297 : // previous chain was at least partially there
298 :
299 8 : Platform::ScopedMemoryBufferWithSize<uint8_t> nocBuf;
300 8 : VerifyOrReturnError(nocBuf.Alloc(noc.size()), CHIP_ERROR_NO_MEMORY);
301 8 : memcpy(nocBuf.Get(), noc.data(), noc.size());
302 :
303 8 : Platform::ScopedMemoryBufferWithSize<uint8_t> icacBuf;
304 8 : if (icac.size() > 0)
305 : {
306 3 : VerifyOrReturnError(icacBuf.Alloc(icac.size()), CHIP_ERROR_NO_MEMORY);
307 3 : memcpy(icacBuf.Get(), icac.data(), icac.size());
308 : }
309 :
310 8 : mPendingNoc = std::move(nocBuf);
311 8 : mPendingIcac = std::move(icacBuf);
312 :
313 : // For NOC update, UpdateOpCertsForFabric is what determines the pending fabric index,
314 : // not a previous AddNewTrustedRootCertForFabric call.
315 8 : mPendingFabricIndex = fabricIndex;
316 :
317 8 : mStateFlags.Set(StateFlags::kUpdateOpCertsCalled);
318 :
319 8 : return CHIP_NO_ERROR;
320 8 : }
321 :
322 713 : CHIP_ERROR PersistentStorageOpCertStore::CommitOpCertsForFabric(FabricIndex fabricIndex)
323 : {
324 713 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
325 713 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
326 :
327 712 : VerifyOrReturnError(HasPendingNocChain(), CHIP_ERROR_INCORRECT_STATE);
328 711 : if (HasPendingRootCert())
329 : {
330 : // Neither of these conditions should have occurred based on other interlocks, but since
331 : // committing certificates is a dangerous operation, we absolutely validate our assumptions.
332 706 : VerifyOrReturnError(!mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
333 706 : VerifyOrReturnError(mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled), CHIP_ERROR_INCORRECT_STATE);
334 : }
335 :
336 : // TODO: Handle transaction marking to revert partial certs at next boot if we get interrupted by reboot.
337 :
338 : // Start committing NOC first so we don't have dangling roots if one was added.
339 711 : ByteSpan pendingNocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
340 711 : CHIP_ERROR nocErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kNoc, pendingNocSpan);
341 :
342 : // ICAC storage handles deleting on empty/missing
343 711 : ByteSpan pendingIcacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
344 711 : CHIP_ERROR icacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kIcac, pendingIcacSpan);
345 :
346 711 : CHIP_ERROR rcacErr = CHIP_NO_ERROR;
347 711 : if (HasPendingRootCert())
348 : {
349 706 : ByteSpan pendingRcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
350 706 : rcacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kRcac, pendingRcacSpan);
351 : }
352 :
353 : // Remember which was the first error, and if any error occurred.
354 711 : CHIP_ERROR stickyErr = nocErr;
355 711 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : icacErr;
356 711 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : rcacErr;
357 :
358 711 : if (stickyErr != CHIP_NO_ERROR)
359 : {
360 : // On Adds rather than updates, remove anything possibly stored for the new fabric on partial
361 : // failure.
362 0 : if (mStateFlags.Has(StateFlags::kAddNewOpCertsCalled))
363 : {
364 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kNoc);
365 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kIcac);
366 : }
367 0 : if (mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled))
368 : {
369 0 : (void) DeleteCertFromStorage(mStorage, mPendingFabricIndex, CertChainElement::kRcac);
370 : }
371 0 : if (mStateFlags.Has(StateFlags::kUpdateOpCertsCalled))
372 : {
373 : // Can't do anything to clean-up here, but pretty sure the fabric is broken now...
374 : // TODO: Handle transaction marking to revert certs if somehow failing store on update by pre-backing-up opcerts
375 : }
376 :
377 0 : return stickyErr;
378 : }
379 :
380 : // If we got here, we succeeded and can reset the pending certs: next `GetCertificate` will use the stored certs
381 711 : RevertPendingOpCerts();
382 711 : return CHIP_NO_ERROR;
383 : }
384 :
385 20 : bool PersistentStorageOpCertStore::HasAnyCertificateForFabric(FabricIndex fabricIndex) const
386 : {
387 20 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false);
388 :
389 20 : bool rcacMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac);
390 20 : bool icacMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kIcac);
391 20 : bool nocMissing = !StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc);
392 20 : bool anyPending = (mPendingRcac.Get() != nullptr) || (mPendingIcac.Get() != nullptr) || (mPendingNoc.Get() != nullptr);
393 :
394 20 : if (rcacMissing && icacMissing && nocMissing && !anyPending)
395 : {
396 4 : return false;
397 : }
398 :
399 16 : return true;
400 : }
401 :
402 21 : CHIP_ERROR PersistentStorageOpCertStore::RemoveOpCertsForFabric(FabricIndex fabricIndex)
403 : {
404 21 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
405 20 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
406 :
407 : // If there was *no* state, pending or persisted, we have an error
408 20 : VerifyOrReturnError(HasAnyCertificateForFabric(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
409 :
410 : // Clear any pending state
411 16 : RevertPendingOpCerts();
412 :
413 : // Remove all persisted certs for the given fabric, blindly
414 16 : CHIP_ERROR nocErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kNoc);
415 16 : CHIP_ERROR icacErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kIcac);
416 16 : CHIP_ERROR rcacErr = DeleteCertFromStorage(mStorage, fabricIndex, CertChainElement::kRcac);
417 :
418 : // Ignore missing cert errors
419 16 : nocErr = (nocErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : nocErr;
420 16 : icacErr = (icacErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : icacErr;
421 16 : rcacErr = (rcacErr == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) ? CHIP_NO_ERROR : rcacErr;
422 :
423 : // Find the first error and return that
424 16 : CHIP_ERROR stickyErr = nocErr;
425 16 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : icacErr;
426 16 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : rcacErr;
427 :
428 16 : return stickyErr;
429 : }
430 :
431 2364 : CHIP_ERROR PersistentStorageOpCertStore::GetPendingCertificate(FabricIndex fabricIndex, CertChainElement element,
432 : MutableByteSpan & outCertificate) const
433 : {
434 2364 : if (fabricIndex != mPendingFabricIndex)
435 : {
436 132 : return CHIP_ERROR_NOT_FOUND;
437 : }
438 :
439 : // FabricIndex matches pending, we MAY have some pending data
440 2232 : switch (element)
441 : {
442 778 : case CertChainElement::kRcac:
443 778 : if (mPendingRcac.Get() != nullptr)
444 : {
445 771 : ByteSpan rcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
446 771 : return CopySpanToMutableSpan(rcacSpan, outCertificate);
447 : }
448 7 : break;
449 727 : case CertChainElement::kIcac:
450 727 : if (mPendingIcac.Get() != nullptr)
451 : {
452 714 : ByteSpan icacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
453 714 : return CopySpanToMutableSpan(icacSpan, outCertificate);
454 : }
455 13 : break;
456 727 : case CertChainElement::kNoc:
457 727 : if (mPendingNoc.Get() != nullptr)
458 : {
459 727 : ByteSpan nocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
460 727 : return CopySpanToMutableSpan(nocSpan, outCertificate);
461 : }
462 0 : break;
463 0 : default:
464 0 : return CHIP_ERROR_INVALID_ARGUMENT;
465 : }
466 :
467 20 : return CHIP_ERROR_NOT_FOUND;
468 : }
469 :
470 2364 : CHIP_ERROR PersistentStorageOpCertStore::GetCertificate(FabricIndex fabricIndex, CertChainElement element,
471 : MutableByteSpan & outCertificate) const
472 : {
473 2364 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
474 2364 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
475 :
476 : // Handle case of pending data
477 2364 : CHIP_ERROR err = GetPendingCertificate(fabricIndex, element, outCertificate);
478 2364 : if ((err == CHIP_NO_ERROR) || (err != CHIP_ERROR_NOT_FOUND))
479 : {
480 : // Found in pending, or got a deeper error: return the pending cert status.
481 2212 : return err;
482 : }
483 :
484 : // If we have a pending NOC and no pending ICAC, don't delegate to storage, return not found here
485 : // since in the pending state, there truly is nothing.
486 :
487 152 : if ((err == CHIP_ERROR_NOT_FOUND) && (element == CertChainElement::kIcac) && (mPendingNoc.Get() != nullptr))
488 : {
489 : // Don't delegate to storage if we just have a pending NOC and are missing the ICAC
490 13 : return CHIP_ERROR_NOT_FOUND;
491 : }
492 :
493 : // Not found in pending, let's look in persisted
494 139 : return LoadCertFromStorage(mStorage, fabricIndex, element, outCertificate);
495 : }
496 :
497 : } // namespace Credentials
498 : } // namespace chip
|