Matter SDK Coverage Report
Current view: top level - credentials - PersistentStorageOpCertStore.cpp (source / functions) Coverage Total Hit
Test: SHA:09f6fdf93a7e847a42518c076e487f336877a722 Lines: 84.9 % 338 287
Test Date: 2025-06-07 07:10:33 Functions: 100.0 % 25 25

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

Generated by: LCOV version 2.0-1