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 4120 : StorageKeyName GetStorageKeyForCert(FabricIndex fabricIndex, CertChainElement element)
39 : {
40 4120 : switch (element)
41 : {
42 1380 : case CertChainElement::kNoc:
43 1380 : return DefaultStorageKeyAllocator::FabricNOC(fabricIndex);
44 : break;
45 1354 : case CertChainElement::kIcac:
46 1354 : return DefaultStorageKeyAllocator::FabricICAC(fabricIndex);
47 : break;
48 1386 : case CertChainElement::kRcac:
49 1386 : return DefaultStorageKeyAllocator::FabricRCAC(fabricIndex);
50 : break;
51 0 : default:
52 0 : break;
53 : }
54 :
55 0 : return StorageKeyName::Uninitialized();
56 : }
57 :
58 2030 : bool StorageHasCertificate(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element)
59 : {
60 2030 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
61 :
62 2030 : 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 2030 : uint16_t keySize = sizeof(placeHolderCertBuffer);
73 2030 : CHIP_ERROR err = storage->SyncGetKeyValue(storageKey.KeyName(), &placeHolderCertBuffer[0], keySize);
74 :
75 2030 : return (err == CHIP_NO_ERROR);
76 2030 : }
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 1903 : CHIP_ERROR SaveCertToStorage(PersistentStorageDelegate * storage, FabricIndex fabricIndex, CertChainElement element,
113 : const ByteSpan & cert)
114 : {
115 1903 : StorageKeyName storageKey = GetStorageKeyForCert(fabricIndex, element);
116 1903 : 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 1903 : 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 1894 : return storage->SyncSetKeyValue(storageKey.KeyName(), cert.data(), static_cast<uint16_t>(cert.size()));
133 1903 : }
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 1314 : bool PersistentStorageOpCertStore::HasPendingRootCert() const
148 : {
149 1314 : if (mStorage == nullptr)
150 : {
151 0 : return false;
152 : }
153 :
154 1314 : return (mPendingRcac.Get() != nullptr) && mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled);
155 : }
156 :
157 678 : bool PersistentStorageOpCertStore::HasPendingNocChain() const
158 : {
159 678 : if (mStorage == nullptr)
160 : {
161 0 : return false;
162 : }
163 :
164 678 : return (mPendingNoc.Get() != nullptr) && mStateFlags.HasAny(StateFlags::kAddNewOpCertsCalled, StateFlags::kUpdateOpCertsCalled);
165 : }
166 :
167 648 : bool PersistentStorageOpCertStore::HasCertificateForFabric(FabricIndex fabricIndex, CertChainElement element) const
168 : {
169 648 : if ((mStorage == nullptr) || !IsValidFabricIndex(fabricIndex))
170 : {
171 0 : return false;
172 : }
173 :
174 : // FabricIndex matches pending, we MAY have some pending data
175 648 : if (fabricIndex == mPendingFabricIndex)
176 : {
177 641 : switch (element)
178 : {
179 628 : case CertChainElement::kRcac:
180 628 : if (mPendingRcac.Get() != nullptr)
181 : {
182 628 : 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 653 : CHIP_ERROR PersistentStorageOpCertStore::AddNewTrustedRootCertForFabric(FabricIndex fabricIndex, const ByteSpan & rcac)
212 : {
213 653 : ReturnErrorCodeIf(mStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
214 652 : ReturnErrorCodeIf(!IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
215 651 : ReturnErrorCodeIf(rcac.empty() || (rcac.size() > Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
216 :
217 651 : ReturnErrorCodeIf(mStateFlags.HasAny(StateFlags::kUpdateOpCertsCalled, StateFlags::kAddNewTrustedRootCalled,
218 : StateFlags::kAddNewOpCertsCalled),
219 : CHIP_ERROR_INCORRECT_STATE);
220 649 : ReturnErrorCodeIf(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
221 :
222 648 : Platform::ScopedMemoryBufferWithSize<uint8_t> rcacBuf;
223 648 : ReturnErrorCodeIf(!rcacBuf.Alloc(rcac.size()), CHIP_ERROR_NO_MEMORY);
224 648 : memcpy(rcacBuf.Get(), rcac.data(), rcac.size());
225 :
226 648 : mPendingRcac = std::move(rcacBuf);
227 :
228 648 : mPendingFabricIndex = fabricIndex;
229 648 : mStateFlags.Set(StateFlags::kAddNewTrustedRootCalled);
230 :
231 648 : return CHIP_NO_ERROR;
232 648 : }
233 :
234 652 : CHIP_ERROR PersistentStorageOpCertStore::AddNewOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
235 : const ByteSpan & icac)
236 : {
237 652 : ReturnErrorCodeIf(mStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
238 652 : ReturnErrorCodeIf(!IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
239 652 : ReturnErrorCodeIf(noc.empty() || (noc.size() > Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
240 652 : ReturnErrorCodeIf(icac.size() > Credentials::kMaxCHIPCertLength, CHIP_ERROR_INVALID_ARGUMENT);
241 :
242 : // Can't have called UpdateOpCertsForFabric first, or called with pending certs
243 652 : ReturnErrorCodeIf(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 649 : ReturnErrorCodeIf(!mStateFlags.Has(StateFlags::kAddNewTrustedRootCalled), CHIP_ERROR_INCORRECT_STATE);
248 :
249 : // fabricIndex must match the current pending fabric
250 649 : ReturnErrorCodeIf(fabricIndex != mPendingFabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
251 :
252 : // Can't have persisted NOC/ICAC for same fabric if adding
253 648 : ReturnErrorCodeIf(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kNoc), CHIP_ERROR_INCORRECT_STATE);
254 647 : ReturnErrorCodeIf(StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kIcac), CHIP_ERROR_INCORRECT_STATE);
255 :
256 647 : Platform::ScopedMemoryBufferWithSize<uint8_t> nocBuf;
257 647 : ReturnErrorCodeIf(!nocBuf.Alloc(noc.size()), CHIP_ERROR_NO_MEMORY);
258 647 : memcpy(nocBuf.Get(), noc.data(), noc.size());
259 :
260 647 : Platform::ScopedMemoryBufferWithSize<uint8_t> icacBuf;
261 647 : if (icac.size() > 0)
262 : {
263 636 : ReturnErrorCodeIf(!icacBuf.Alloc(icac.size()), CHIP_ERROR_NO_MEMORY);
264 636 : memcpy(icacBuf.Get(), icac.data(), icac.size());
265 : }
266 :
267 647 : mPendingNoc = std::move(nocBuf);
268 647 : mPendingIcac = std::move(icacBuf);
269 :
270 647 : mStateFlags.Set(StateFlags::kAddNewOpCertsCalled);
271 :
272 647 : return CHIP_NO_ERROR;
273 647 : }
274 :
275 12 : CHIP_ERROR PersistentStorageOpCertStore::UpdateOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc,
276 : const ByteSpan & icac)
277 : {
278 12 : ReturnErrorCodeIf(mStorage == nullptr, CHIP_ERROR_INCORRECT_STATE);
279 11 : ReturnErrorCodeIf(!IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
280 11 : ReturnErrorCodeIf(noc.empty() || (noc.size() > Credentials::kMaxCHIPCertLength), CHIP_ERROR_INVALID_ARGUMENT);
281 11 : ReturnErrorCodeIf(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 : ReturnErrorCodeIf(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 : ReturnErrorCodeIf(mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
289 :
290 : // Need to have trusted roots installed to make the chain valid
291 9 : ReturnErrorCodeIf(!StorageHasCertificate(mStorage, fabricIndex, CertChainElement::kRcac), CHIP_ERROR_INCORRECT_STATE);
292 :
293 : // Must have persisted NOC for same fabric if updating
294 8 : ReturnErrorCodeIf(!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 : ReturnErrorCodeIf(!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 : ReturnErrorCodeIf(!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 638 : CHIP_ERROR PersistentStorageOpCertStore::CommitOpCertsForFabric(FabricIndex fabricIndex)
323 : {
324 638 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
325 638 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
326 :
327 637 : VerifyOrReturnError(HasPendingNocChain(), CHIP_ERROR_INCORRECT_STATE);
328 636 : 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 631 : ReturnErrorCodeIf(mStateFlags.Has(StateFlags::kUpdateOpCertsCalled), CHIP_ERROR_INCORRECT_STATE);
333 631 : ReturnErrorCodeIf(!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 636 : ByteSpan pendingNocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
340 636 : CHIP_ERROR nocErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kNoc, pendingNocSpan);
341 :
342 : // ICAC storage handles deleting on empty/missing
343 636 : ByteSpan pendingIcacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
344 636 : CHIP_ERROR icacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kIcac, pendingIcacSpan);
345 :
346 636 : CHIP_ERROR rcacErr = CHIP_NO_ERROR;
347 636 : if (HasPendingRootCert())
348 : {
349 631 : ByteSpan pendingRcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
350 631 : rcacErr = SaveCertToStorage(mStorage, mPendingFabricIndex, CertChainElement::kRcac, pendingRcacSpan);
351 : }
352 :
353 : // Remember which was the first error, and if any error occurred.
354 636 : CHIP_ERROR stickyErr = nocErr;
355 636 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : icacErr;
356 636 : stickyErr = (stickyErr != CHIP_NO_ERROR) ? stickyErr : rcacErr;
357 :
358 636 : 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 636 : RevertPendingOpCerts();
382 636 : 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 : ReturnErrorCodeIf(!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 2136 : CHIP_ERROR PersistentStorageOpCertStore::GetPendingCertificate(FabricIndex fabricIndex, CertChainElement element,
432 : MutableByteSpan & outCertificate) const
433 : {
434 2136 : if (fabricIndex != mPendingFabricIndex)
435 : {
436 132 : return CHIP_ERROR_NOT_FOUND;
437 : }
438 :
439 : // FabricIndex matches pending, we MAY have some pending data
440 2004 : switch (element)
441 : {
442 700 : case CertChainElement::kRcac:
443 700 : if (mPendingRcac.Get() != nullptr)
444 : {
445 693 : ByteSpan rcacSpan{ mPendingRcac.Get(), mPendingRcac.AllocatedSize() };
446 693 : return CopySpanToMutableSpan(rcacSpan, outCertificate);
447 : }
448 7 : break;
449 652 : case CertChainElement::kIcac:
450 652 : if (mPendingIcac.Get() != nullptr)
451 : {
452 639 : ByteSpan icacSpan{ mPendingIcac.Get(), mPendingIcac.AllocatedSize() };
453 639 : return CopySpanToMutableSpan(icacSpan, outCertificate);
454 : }
455 13 : break;
456 652 : case CertChainElement::kNoc:
457 652 : if (mPendingNoc.Get() != nullptr)
458 : {
459 652 : ByteSpan nocSpan{ mPendingNoc.Get(), mPendingNoc.AllocatedSize() };
460 652 : 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 2136 : CHIP_ERROR PersistentStorageOpCertStore::GetCertificate(FabricIndex fabricIndex, CertChainElement element,
471 : MutableByteSpan & outCertificate) const
472 : {
473 2136 : VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
474 2136 : VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX);
475 :
476 : // Handle case of pending data
477 2136 : CHIP_ERROR err = GetPendingCertificate(fabricIndex, element, outCertificate);
478 2136 : 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 1984 : 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
|