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