Matter SDK Coverage Report
Current view: top level - credentials - PersistentStorageOpCertStore.cpp (source / functions) Coverage Total Hit
Test: SHA:4cbce7f768f16e614f5a8ccb8cd93c92cbeae70d Lines: 71.7 % 350 251
Test Date: 2025-04-26 07:09:35 Functions: 84.6 % 26 22

            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
        

Generated by: LCOV version 2.0-1