Matter SDK Coverage Report
Current view: top level - credentials - FabricTable.h (source / functions) Coverage Total Hit
Test: SHA:4cbce7f768f16e614f5a8ccb8cd93c92cbeae70d Lines: 59.4 % 106 63
Test Date: 2025-04-26 07:09:35 Functions: 60.8 % 51 31

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-2022 Project CHIP Authors
       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              : /**
      19              :  * @brief Defines a table of fabrics that have provisioned the device.
      20              :  */
      21              : 
      22              : #pragma once
      23              : 
      24              : #include <algorithm>
      25              : 
      26              : #include <app/util/basic-types.h>
      27              : #include <credentials/CHIPCert.h>
      28              : #include <credentials/CHIPCertificateSet.h>
      29              : #include <credentials/CertificateValidityPolicy.h>
      30              : #include <credentials/LastKnownGoodTime.h>
      31              : #include <credentials/OperationalCertificateStore.h>
      32              : #include <crypto/CHIPCryptoPAL.h>
      33              : #include <crypto/OperationalKeystore.h>
      34              : #include <lib/core/CHIPEncoding.h>
      35              : #include <lib/core/CHIPPersistentStorageDelegate.h>
      36              : #include <lib/core/CHIPSafeCasts.h>
      37              : #include <lib/core/Optional.h>
      38              : #include <lib/core/ScopedNodeId.h>
      39              : #include <lib/core/TLV.h>
      40              : #include <lib/support/BitFlags.h>
      41              : #include <lib/support/CHIPMem.h>
      42              : #include <lib/support/DLLUtil.h>
      43              : #include <lib/support/ScopedBuffer.h>
      44              : #include <lib/support/Span.h>
      45              : 
      46              : namespace chip {
      47              : 
      48              : static constexpr uint8_t kFabricLabelMaxLengthInBytes = 32;
      49              : 
      50              : static_assert(kUndefinedFabricIndex < chip::kMinValidFabricIndex, "Undefined fabric index should not be valid");
      51              : 
      52              : /**
      53              :  * Provides access to the core metadata for a given fabric to which a node is joined.
      54              :  *
      55              :  * This metadata includes:
      56              :  *
      57              :  * - FabricIndex within the local set of fabrics
      58              :  * - Operational Identity
      59              :  *   - NodeId
      60              :  *   - Fabric Id
      61              :  *   - Public key of operational root CA (to avoid keeping/reloading RCAC (Root CA Certificate) too often)
      62              :  *   - Pre-computed "Compressed Fabric ID" used for discovery
      63              :  * - Operational public key (if externally injected as opposed to present in an OperationalKeystore)
      64              :  * - Fabric Label
      65              :  * - VendorID allocated at fabric joining by commissioner
      66              :  *
      67              :  * NOTE: All the setters of this class are private and only accessible by FabricTable, the
      68              :  *       friend class that owns these. The reason is that there are data dependencies between
      69              :  *       fabrics that require FabricTable to be the single entrypoint for all mutations, rather
      70              :  *       than directly on a FabricInfo instance.
      71              :  */
      72              : class DLL_EXPORT FabricInfo
      73              : {
      74              : public:
      75            0 :     FabricInfo() { Reset(); }
      76            0 :     ~FabricInfo() { Reset(); }
      77              : 
      78              :     // Non-copyable
      79              :     FabricInfo(FabricInfo const &)     = delete;
      80              :     void operator=(FabricInfo const &) = delete;
      81              : 
      82              :     // Returns a span into our internal storage.
      83            0 :     CharSpan GetFabricLabel() const { return CharSpan(mFabricLabel, strnlen(mFabricLabel, kFabricLabelMaxLengthInBytes)); }
      84              :     CHIP_ERROR SetFabricLabel(const CharSpan & fabricLabel);
      85              : 
      86         1317 :     NodeId GetNodeId() const { return mNodeId; }
      87              :     ScopedNodeId GetScopedNodeId() const { return ScopedNodeId(mNodeId, mFabricIndex); }
      88            0 :     ScopedNodeId GetScopedNodeIdForNode(const NodeId node) const { return ScopedNodeId(node, mFabricIndex); }
      89              : 
      90              :     // TODO(#15049): Refactor/rename PeerId to OperationalId or OpId throughout source
      91            0 :     PeerId GetPeerId() const { return PeerId(mCompressedFabricId, mNodeId); }
      92              :     PeerId GetPeerIdForNode(const NodeId node) const { return PeerId(mCompressedFabricId, node); }
      93              : 
      94           37 :     FabricId GetFabricId() const { return mFabricId; }
      95        49113 :     FabricIndex GetFabricIndex() const { return mFabricIndex; }
      96              : 
      97        28844 :     CompressedFabricId GetCompressedFabricId() const { return mCompressedFabricId; }
      98            0 :     CHIP_ERROR GetCompressedFabricIdBytes(MutableByteSpan & compressedFabricId) const
      99              :     {
     100            0 :         VerifyOrReturnError(compressedFabricId.size() == sizeof(uint64_t), CHIP_ERROR_INVALID_ARGUMENT);
     101            0 :         Encoding::BigEndian::Put64(compressedFabricId.data(), GetCompressedFabricId());
     102            0 :         return CHIP_NO_ERROR;
     103              :     }
     104              : 
     105              :     CHIP_ERROR FetchRootPubkey(Crypto::P256PublicKey & outPublicKey) const;
     106              : 
     107            0 :     void SetVendorId(VendorId vendorId) { mVendorId = vendorId; }
     108            0 :     VendorId GetVendorId() const { return mVendorId; }
     109              : 
     110       101666 :     bool IsInitialized() const { return (mFabricIndex != kUndefinedFabricIndex) && IsOperationalNodeId(mNodeId); }
     111              : 
     112          776 :     bool HasOperationalKey() const { return mOperationalKey != nullptr; }
     113              : 
     114            0 :     bool ShouldAdvertiseIdentity() const { return mShouldAdvertiseIdentity; }
     115              : 
     116              :     friend class FabricTable;
     117              : 
     118              : private:
     119              :     struct InitParams
     120              :     {
     121              :         CompressedFabricId compressedFabricId    = kUndefinedCompressedFabricId;
     122              :         NodeId nodeId                            = kUndefinedNodeId;
     123              :         FabricIndex fabricIndex                  = kUndefinedFabricIndex;
     124              :         Crypto::P256Keypair * operationalKeypair = nullptr;
     125              :         FabricId fabricId                        = kUndefinedFabricId;
     126              :         Crypto::P256PublicKey rootPublicKey;
     127              :         VendorId vendorId              = VendorId::NotSpecified; /**< Vendor ID for commissioner of fabric */
     128              :         bool hasExternallyOwnedKeypair = false;
     129              :         bool advertiseIdentity         = false;
     130              : 
     131          749 :         CHIP_ERROR AreValid() const
     132              :         {
     133          749 :             VerifyOrReturnError((fabricId != kUndefinedFabricId) && (fabricIndex != kUndefinedFabricIndex),
     134              :                                 CHIP_ERROR_INVALID_ARGUMENT);
     135          749 :             VerifyOrReturnError(IsOperationalNodeId(nodeId), CHIP_ERROR_INVALID_ARGUMENT);
     136              :             // We don't check the root public key validity or the compressed fabric ID, since in the
     137              :             // very small usage that exists in private use, the rest should be OK.
     138          749 :             return CHIP_NO_ERROR;
     139              :         }
     140              :     };
     141              : 
     142              :     // Move assignment operator to support setting from pending on fabric table commit
     143              :     void operator=(FabricInfo && other);
     144              : 
     145              :     /**
     146              :      * @brief Initialize a FabricInfo object's metadata given init parameters.
     147              :      *
     148              :      * Note that certificates are never owned by this object and are assumed pre-validated
     149              :      *
     150              :      * @param initParams Init parameters to use to initialize the given fabric.
     151              :      * @return CHIP_NO_ERROR on success or another internal CHIP_ERROR_* value on failure
     152              :      */
     153              :     CHIP_ERROR Init(const InitParams & initParams);
     154              : 
     155              :     /**
     156              :      * Sets the P256Keypair used for this fabric.  This will make a copy of the keypair
     157              :      * via the P256Keypair::Serialize and P256Keypair::Deserialize methods.
     158              :      *
     159              :      * The keyPair argument is safe to deallocate once this method returns.
     160              :      *
     161              :      * If your P256Keypair does not support serialization, use the
     162              :      * `SetExternallyOwnedOperationalKeypair` method instead.
     163              :      */
     164              :     CHIP_ERROR SetOperationalKeypair(const Crypto::P256Keypair * keyPair);
     165              : 
     166              :     /**
     167              :      * Sets the P256Keypair used for this fabric, delegating ownership of the
     168              :      * key to the caller. The P256Keypair provided here must be freed later by
     169              :      * the caller of this method if it was allocated dynamically.
     170              :      *
     171              :      * This should be used if your P256Keypair does not support serialization
     172              :      * and deserialization (e.g. your private key is held in a secure element
     173              :      * and cannot be accessed directly), or if you back your operational
     174              :      * private keys by external implementation of the cryptographic interfaces.
     175              :      *
     176              :      * To have the ownership of the key managed for you, use
     177              :      * SetOperationalKeypair instead.
     178              :      */
     179              :     CHIP_ERROR SetExternallyOwnedOperationalKeypair(Crypto::P256Keypair * keyPair);
     180              : 
     181              :     /**
     182              :      * @brief Sign a message with the fabric's operational private key. This ONLY
     183              :      *        works if `SetOperationalKeypair` or `SetExternallyOwnedOperationalKeypair`
     184              :      *        had been called and is an API that is present ONLY to be called by FabricTable.
     185              :      *
     186              :      * @param message - message to sign
     187              :      * @param outSignature - buffer to hold the signature
     188              :      * @return CHIP_NO_ERROR on success or another CHIP_ERROR on crypto internal errors
     189              :      */
     190              :     CHIP_ERROR SignWithOpKeypair(ByteSpan message, Crypto::P256ECDSASignature & outSignature) const;
     191              : 
     192              :     /**
     193              :      *  Reset the state to a completely uninitialized status.
     194              :      */
     195            0 :     void Reset()
     196              :     {
     197            0 :         mNodeId             = kUndefinedNodeId;
     198            0 :         mFabricId           = kUndefinedFabricId;
     199            0 :         mFabricIndex        = kUndefinedFabricIndex;
     200            0 :         mCompressedFabricId = kUndefinedCompressedFabricId;
     201              : 
     202            0 :         mVendorId       = VendorId::NotSpecified;
     203            0 :         mFabricLabel[0] = '\0';
     204              : 
     205            0 :         if (!mHasExternallyOwnedOperationalKey && mOperationalKey != nullptr)
     206              :         {
     207            0 :             chip::Platform::Delete(mOperationalKey);
     208              :         }
     209            0 :         mOperationalKey                   = nullptr;
     210            0 :         mHasExternallyOwnedOperationalKey = false;
     211            0 :         mShouldAdvertiseIdentity          = true;
     212              : 
     213            0 :         mFabricIndex = kUndefinedFabricIndex;
     214            0 :         mNodeId      = kUndefinedNodeId;
     215            0 :     }
     216              : 
     217            4 :     void SetShouldAdvertiseIdentity(bool advertiseIdentity) { mShouldAdvertiseIdentity = advertiseIdentity; }
     218              : 
     219              :     static constexpr size_t MetadataTLVMaxSize()
     220              :     {
     221              :         return TLV::EstimateStructOverhead(sizeof(uint16_t), kFabricLabelMaxLengthInBytes);
     222              :     }
     223              : 
     224              :     static constexpr size_t OpKeyTLVMaxSize()
     225              :     {
     226              :         return TLV::EstimateStructOverhead(sizeof(uint16_t), Crypto::P256SerializedKeypair::Capacity());
     227              :     }
     228              : 
     229              :     NodeId mNodeId     = kUndefinedNodeId;
     230              :     FabricId mFabricId = kUndefinedFabricId;
     231              :     // We cache the compressed fabric id since it's used so often and costly to get.
     232              :     CompressedFabricId mCompressedFabricId = kUndefinedCompressedFabricId;
     233              :     // We cache the root public key since it's used so often and costly to get.
     234              :     Crypto::P256PublicKey mRootPublicKey;
     235              : 
     236              :     // mFabricLabel is 33 bytes, so ends on a 1 mod 4 byte boundary.
     237              :     char mFabricLabel[kFabricLabelMaxLengthInBytes + 1] = { '\0' };
     238              : 
     239              :     // mFabricIndex, mVendorId, mHasExternallyOwnedOperationalKey,
     240              :     // mShouldAdvertiseIdentity are 5 bytes and do not include any padding if
     241              :     // they come after the 33-byte mFabricLabel, so end on a 2 mod 4 byte
     242              :     // boundary.
     243              :     FabricIndex mFabricIndex               = kUndefinedFabricIndex;
     244              :     VendorId mVendorId                     = VendorId::NotSpecified;
     245              :     bool mHasExternallyOwnedOperationalKey = false;
     246              :     bool mShouldAdvertiseIdentity          = true;
     247              : 
     248              :     // 2 bytes of padding here, since mOperationalKey needs to be void*-aligned,
     249              :     // so has to be at a 0 mod 4 byte location.
     250              : 
     251              :     mutable Crypto::P256Keypair * mOperationalKey = nullptr;
     252              : 
     253              :     CHIP_ERROR CommitToStorage(PersistentStorageDelegate * storage) const;
     254              :     CHIP_ERROR LoadFromStorage(PersistentStorageDelegate * storage, FabricIndex newFabricIndex, const ByteSpan & rcac,
     255              :                                const ByteSpan & noc);
     256              : };
     257              : 
     258              : /**
     259              :  * Iterates over valid fabrics within a list
     260              :  */
     261              : 
     262              : class ConstFabricIterator
     263              : {
     264              : public:
     265              :     using value_type = FabricInfo;
     266              :     using pointer    = FabricInfo *;
     267              :     using reference  = FabricInfo &;
     268              : 
     269         1514 :     ConstFabricIterator(const FabricInfo * start, const FabricInfo * pending, size_t index, size_t maxSize) :
     270         1514 :         mStart(start), mPending(pending), mIndex(index), mMaxSize(maxSize)
     271              :     {
     272         1514 :         if (mIndex >= maxSize)
     273              :         {
     274          757 :             mIndex = maxSize;
     275              :         }
     276          757 :         else if (!mStart[mIndex].IsInitialized())
     277              :         {
     278           26 :             Advance();
     279              :         }
     280         1514 :     }
     281              :     ConstFabricIterator(const ConstFabricIterator &)             = default;
     282              :     ConstFabricIterator & operator=(const ConstFabricIterator &) = default;
     283              : 
     284         1068 :     ConstFabricIterator & operator++() { return Advance(); }
     285              :     ConstFabricIterator operator++(int)
     286              :     {
     287              :         ConstFabricIterator other(*this);
     288              :         Advance();
     289              :         return other;
     290              :     }
     291              : 
     292         1094 :     const FabricInfo & operator*() const
     293              :     {
     294         1094 :         VerifyOrDie(!IsAtEnd());
     295              : 
     296         1094 :         return *GetCurrent();
     297              :     }
     298            0 :     const FabricInfo * operator->() const
     299              :     {
     300            0 :         VerifyOrDie(!IsAtEnd());
     301              : 
     302            0 :         return GetCurrent();
     303              :     }
     304              : 
     305         1825 :     bool operator==(const ConstFabricIterator & other) const
     306              :     {
     307         1825 :         if (IsAtEnd())
     308              :         {
     309          731 :             return other.IsAtEnd();
     310              :         }
     311              : 
     312              :         // Pending entry does not participate in finding this.
     313         1094 :         return (mStart == other.mStart) && (mIndex == other.mIndex) && (mMaxSize == other.mMaxSize);
     314              :     }
     315         1825 :     bool operator!=(const ConstFabricIterator & other) const { return !(*this == other); }
     316              : 
     317        15353 :     bool IsAtEnd() const { return (mIndex == mMaxSize); }
     318              : 
     319              : private:
     320              :     const FabricInfo * mStart;
     321              :     const FabricInfo * mPending; ///< Pointer to the shadow pending entry, nullptr if none
     322              :     size_t mIndex;
     323              :     size_t mMaxSize;
     324              : 
     325              :     // Helper to get either a given entry of the fabric table, or its pending shadow if
     326              :     // a fabric update is currently pending.
     327         1094 :     const FabricInfo * GetCurrent() const
     328              :     {
     329         1094 :         const auto * current = mStart + mIndex;
     330              : 
     331              :         // If we reached the pending entry, return that instead of the underlying entry from the mStates.
     332         1094 :         if ((mPending != nullptr) && mPending->IsInitialized() && (current->GetFabricIndex() == mPending->GetFabricIndex()))
     333              :         {
     334            0 :             current = mPending;
     335              :         }
     336              : 
     337         1094 :         return current;
     338              :     }
     339              : 
     340        11703 :     ConstFabricIterator & Advance()
     341              :     {
     342              :         do
     343              :         {
     344        11703 :             if (mIndex < mMaxSize)
     345              :             {
     346        11703 :                 mIndex++;
     347              :             }
     348        11703 :         } while (!IsAtEnd() && !mStart[mIndex].IsInitialized());
     349              : 
     350         1094 :         return *this;
     351              :     }
     352              : };
     353              : 
     354              : class DLL_EXPORT FabricTable
     355              : {
     356              : public:
     357              :     struct DLL_EXPORT InitParams
     358              :     {
     359              :         // PersistentStorageDelegate for Fabric Info metadata storage and Fabric Table index (MANDATORY).
     360              :         PersistentStorageDelegate * storage = nullptr;
     361              :         // Operational Keystore to abstract access to key. Mandatory for commissionable devices  (e.g.
     362              :         // chip::Server-based things) and recommended for controllers. With this set to false, FabricInfo
     363              :         // added as new fabrics need to have directly injected operational keys with FabricInfo::Set*OperationalKey.
     364              :         Crypto::OperationalKeystore * operationalKeystore = nullptr;
     365              :         // Operational Certificate store to hold the NOC/ICAC/RCAC chains (MANDATORY).
     366              :         Credentials::OperationalCertificateStore * opCertStore = nullptr;
     367              :     };
     368              : 
     369              :     class DLL_EXPORT Delegate
     370              :     {
     371              :     public:
     372          494 :         Delegate() {}
     373          494 :         virtual ~Delegate() {}
     374              : 
     375              :         /**
     376              :          * Gets called when a fabric is about to be deleted, such as on
     377              :          * FabricTable::Delete().  This allows actions to be taken that need the
     378              :          * fabric to still be around before we delete it.
     379              :          **/
     380           14 :         virtual void FabricWillBeRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) {}
     381              : 
     382              :         /**
     383              :          * Gets called when a fabric is deleted, such as on FabricTable::Delete().
     384              :          **/
     385            0 :         virtual void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) {}
     386              : 
     387              :         /**
     388              :          * Gets called when a fabric in Fabric Table is persisted to storage, by CommitPendingFabricData.
     389              :          **/
     390          702 :         virtual void OnFabricCommitted(const FabricTable & fabricTable, FabricIndex fabricIndex){};
     391              : 
     392              :         /**
     393              :          * Gets called when operational credentials are changed, which may not be persistent.
     394              :          *
     395              :          * Can be used to affect what is needed for UpdateNOC prior to commit.
     396              :          **/
     397          702 :         virtual void OnFabricUpdated(const FabricTable & fabricTable, FabricIndex fabricIndex){};
     398              : 
     399              :         // Intrusive list pointer for FabricTable to manage the entries.
     400              :         Delegate * next = nullptr;
     401              :     };
     402              : 
     403              :     /** Data to convey whenever a SignVIDVerificationRequest is executed. */
     404              :     struct SignVIDVerificationResponseData
     405              :     {
     406              :         FabricIndex fabricIndex;
     407              :         uint8_t fabricBindingVersion;
     408              :         // The next field is a variable size buffer to account for different signature
     409              :         // algorithms over time, which may have different sizes.
     410              :         Platform::ScopedMemoryBufferWithSize<uint8_t> signature;
     411              :     };
     412              : 
     413              : public:
     414            0 :     FabricTable()  = default;
     415            0 :     ~FabricTable() = default;
     416              : 
     417              :     // Non-copyable
     418              :     FabricTable(FabricTable const &)    = delete;
     419              :     void operator=(FabricTable const &) = delete;
     420              : 
     421              :     enum class AdvertiseIdentity : uint8_t
     422              :     {
     423              :         Yes,
     424              :         No
     425              :     };
     426              : 
     427              :     /**
     428              :      * @brief Delete the fabric with given `fabricIndex`.
     429              :      *
     430              :      * @param fabricIndex - Index of fabric for deletion
     431              :      * @retval CHIP_NO_ERROR on success
     432              :      * @retval CHIP_ERROR_NOT_FOUND if there is no fabric for that index
     433              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if any of the arguments are invalid such as too large or out of bounds
     434              :      * @retval other CHIP_ERROR on internal errors
     435              :      */
     436              :     CHIP_ERROR Delete(FabricIndex fabricIndex);
     437              :     void DeleteAllFabrics();
     438              : 
     439              :     // TODO this #if CONFIG_BUILD_FOR_HOST_UNIT_TEST is temporary. There is a change incoming soon
     440              :     // that will allow triggering NOC update directly.
     441              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     442              :     void SendUpdateFabricNotificationForTest(FabricIndex fabricIndex) { NotifyFabricUpdated(fabricIndex); }
     443              : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
     444              : 
     445              :     /**
     446              :      * Collection of methods to help find a matching FabricInfo instance given a set of query criteria
     447              :      *
     448              :      */
     449              : 
     450              :     /**
     451              :      * Finds a matching FabricInfo instance given a root public key and fabric ID that uniquely identifies the fabric in any scope.
     452              :      *
     453              :      * Returns nullptr if no matching instance is found.
     454              :      *
     455              :      */
     456              :     const FabricInfo * FindFabric(const Crypto::P256PublicKey & rootPubKey, FabricId fabricId) const;
     457              : 
     458              :     /**
     459              :      * Finds a matching FabricInfo instance given a locally-scoped fabric index.
     460              :      *
     461              :      * Returns nullptr if no matching instance is found.
     462              :      *
     463              :      */
     464              :     const FabricInfo * FindFabricWithIndex(FabricIndex fabricIndex) const;
     465              : 
     466              :     /**
     467              :      * Finds a matching FabricInfo instance given a root public key, fabric ID AND a matching NodeId. This variant of find
     468              :      * is only to be used when it is possible to have colliding fabrics in the table that are on the same logical fabric
     469              :      * but may be associated with different node identities.
     470              :      *
     471              :      * Returns nullptr if no matching instance is found.
     472              :      *
     473              :      */
     474              :     const FabricInfo * FindIdentity(const Crypto::P256PublicKey & rootPubKey, FabricId fabricId, NodeId nodeId) const;
     475              : 
     476              :     /**
     477              :      * Finds a matching FabricInfo instance given a compressed fabric ID. If there are multiple
     478              :      * matching FabricInfo instances given the low but non-zero probability of collision, there is no guarantee
     479              :      * on which instance will be returned.
     480              :      *
     481              :      * Returns nullptr if no matching instance is found.
     482              :      */
     483              :     const FabricInfo * FindFabricWithCompressedId(CompressedFabricId compressedFabricId) const;
     484              : 
     485              :     CHIP_ERROR Init(const FabricTable::InitParams & initParams);
     486              :     void Shutdown();
     487              : 
     488              :     /**
     489              :      * @brief If `Init()` caused a Delete due to partial commit, the fabric index at play is returned.
     490              :      *
     491              :      * Allows caller to schedule more clean-up. This is because at Init() time, none of the delegates
     492              :      * are registered yet, so no other modules would learn of the removal.
     493              :      *
     494              :      * The value is auto-reset to `kUndefinedFabricIndex` on being returned, so that subsequent
     495              :      * `GetDeletedFabricFromCommitMarker()` after one that has a fabric index to give will provide
     496              :      * `kUndefinedFabricIndex`.
     497              :      *
     498              :      * @return the fabric index of a just-deleted fabric, or kUndefinedFabricIndex if none were deleted.
     499              :      */
     500              :     FabricIndex GetDeletedFabricFromCommitMarker();
     501              : 
     502              :     /**
     503              :      * @brief Clear the commit marker when we are sure we have proceeded with any remaining clean-up
     504              :      */
     505              :     void ClearCommitMarker();
     506              : 
     507              :     // Forget a fabric in memory: doesn't delete any persistent state, just
     508              :     // reverts any pending state (blindly) and then resets the fabric table
     509              :     // entry.
     510              :     //
     511              :     // TODO: We have to determine if we should remove this call.
     512              :     void Forget(FabricIndex fabricIndex);
     513              : 
     514              :     CHIP_ERROR AddFabricDelegate(FabricTable::Delegate * delegate);
     515              :     void RemoveFabricDelegate(FabricTable::Delegate * delegate);
     516              : 
     517              :     /**
     518              :      * @brief Set the Fabric Label for the fabric referred by `fabricIndex`.
     519              :      *
     520              :      * If a fabric add/update is pending, only the pending version will be updated,
     521              :      * so that on fail-safe expiry, you would actually see the only fabric label if
     522              :      * Update fails. If the fabric label is set before UpdateNOC, then the change is immediate.
     523              :      *
     524              :      * @param fabricIndex - Fabric Index for which to set the label
     525              :      * @param fabricLabel - Label to set on the fabric
     526              :      * @retval CHIP_NO_ERROR on success
     527              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if fabricIndex does not refer to an fabric in the table
     528              :      * @retval CHIP_ERROR_INVALID_ARGUMENT on fabric label error (e.g. too large)
     529              :      * @retval other CHIP_ERROR on internal errors
     530              :      */
     531              :     CHIP_ERROR SetFabricLabel(FabricIndex fabricIndex, const CharSpan & fabricLabel);
     532              : 
     533              :     /**
     534              :      * @brief Get the Fabric Label for a given fabric
     535              :      *
     536              :      * NOTE: The outFabricLabel argument points to internal memory of the fabric info.
     537              :      *       It may become invalid on the next FabricTable API call due to shadow
     538              :      *       storage of data.
     539              :      *
     540              :      * @param fabricIndex - Fabric index for which to get the label
     541              :      * @param outFabricLabel - char span that will be set to the label value
     542              :      * @retval CHIP_NO_ERROR on success
     543              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX on error
     544              :      * @retval other CHIP_ERROR on internal errors
     545              :      */
     546              :     CHIP_ERROR GetFabricLabel(FabricIndex fabricIndex, CharSpan & outFabricLabel);
     547              : 
     548              :     /**
     549              :      * Get the current Last Known Good Time.
     550              :      *
     551              :      * @param lastKnownGoodChipEpochTime (out) the current last known good time, if any is known
     552              :      * @return CHIP_NO_ERROR on success, else an appropriate CHIP_ERROR
     553              :      */
     554            0 :     CHIP_ERROR GetLastKnownGoodChipEpochTime(System::Clock::Seconds32 & lastKnownGoodChipEpochTime) const
     555              :     {
     556            0 :         return mLastKnownGoodTime.GetLastKnownGoodChipEpochTime(lastKnownGoodChipEpochTime);
     557              :     }
     558              : 
     559              :     /**
     560              :      * Validate that the passed Last Known Good Time is within bounds and then
     561              :      * store this and write back to storage.  Legal values are those which are
     562              :      * not earlier than firmware build time or any of our stored certificates'
     563              :      * NotBefore times:
     564              :      *
     565              :      *    3.5.6.1. Last Known Good UTC Time
     566              :      *
     567              :      *    A Node MAY adjust the Last Known Good UTC Time backwards if it
     568              :      *    believes the current Last Known Good UTC Time is incorrect and it has
     569              :      *    a good time value from a trusted source. The Node SHOULD NOT adjust
     570              :      *    the Last Known Good UTC to a time before the later of:
     571              :      *      • The build timestamp of its currently running software image
     572              :      *      • The not-before timestamp of any of its operational certificates
     573              :      *
     574              :      * @param lastKnownGoodChipEpochTime Last Known Good Time in seconds since CHIP epoch
     575              :      * @return CHIP_NO_ERROR on success, else an appopriate CHIP_ERROR
     576              :      */
     577              :     CHIP_ERROR SetLastKnownGoodChipEpochTime(System::Clock::Seconds32 lastKnownGoodChipEpochTime);
     578              : 
     579              :     /**
     580              :      * @return the number of fabrics currently accessible/usable/iterable.
     581              :      */
     582            8 :     uint8_t FabricCount() const { return mFabricCount; }
     583              : 
     584          757 :     ConstFabricIterator cbegin() const
     585              :     {
     586          757 :         const FabricInfo * pending = GetShadowPendingFabricEntry();
     587          757 :         return ConstFabricIterator(mStates, pending, 0, CHIP_CONFIG_MAX_FABRICS);
     588              :     }
     589          757 :     ConstFabricIterator cend() const
     590              :     {
     591          757 :         return ConstFabricIterator(mStates, nullptr, CHIP_CONFIG_MAX_FABRICS, CHIP_CONFIG_MAX_FABRICS);
     592              :     }
     593          757 :     ConstFabricIterator begin() const { return cbegin(); }
     594          757 :     ConstFabricIterator end() const { return cend(); }
     595              : 
     596              :     /**
     597              :      * @brief Get the RCAC (operational root certificate) associated with a fabric.
     598              :      *
     599              :      * If a root is pending for `fabricIndex` from `AddNewPendingTrustedRootCert`, it is returned.
     600              :      *
     601              :      * @param fabricIndex - Fabric for which to get the RCAC
     602              :      * @param outCert - MutableByteSpan to receive the certificate. Resized to actual size.
     603              :      * @retval CHIP_NO_ERROR on success
     604              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCert` is too small
     605              :      * @retval CHIP_ERROR_NOT_FOUND if not found/available
     606              :      * @retval other CHIP_ERROR values on invalid arguments or internal errors.
     607              :      */
     608              :     CHIP_ERROR FetchRootCert(FabricIndex fabricIndex, MutableByteSpan & outCert) const;
     609              : 
     610              :     /**
     611              :      * @brief Get the pending root certificate which is not associated with a fabric, if there is one.
     612              :      *
     613              :      * If a root is pending from `AddNewPendingTrustedRootCert`, and there is no
     614              :      * fabric associated with the corresponding fabric index yet
     615              :      * (i.e. `AddNewPendingFabric*` has not been called yet) it is returned.
     616              :      *
     617              :      * @param outCert - MutableByteSpan to receive the certificate. Resized to actual size.
     618              :      * @retval CHIP_NO_ERROR on success
     619              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCert` is too small.
     620              :      * @retval CHIP_ERROR_NOT_FOUND if there is no pending root certificate
     621              :      *                              that's not yet associated with a fabric.
     622              :      * @retval other CHIP_ERROR values on invalid arguments or internal errors.
     623              :      */
     624              :     CHIP_ERROR FetchPendingNonFabricAssociatedRootCert(MutableByteSpan & outCert) const;
     625              : 
     626              :     /**
     627              :      * @brief Get the ICAC (operational intermediate certificate) associated with a fabric.
     628              :      *
     629              :      * If a fabric is pending from add/update operation for the given `fabricIndex`, its
     630              :      * ICAC is returned.
     631              :      *
     632              :      * If an NOC exists, but the ICAC is not present in the chain, CHIP_NO_ERROR is
     633              :      * returned and `outCert` is resized to 0 length so that its `empty()` method returns true.
     634              :      *
     635              :      * @param fabricIndex - Fabric for which to get the ICAC
     636              :      * @param outCert - MutableByteSpan to receive the certificate. Resized to actual size.
     637              :      * @retval CHIP_NO_ERROR on success, including if absent within an existing chain
     638              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCert` is too small
     639              :      * @retval CHIP_ERROR_NOT_FOUND if not found/available
     640              :      * @retval other CHIP_ERROR values on invalid arguments or internal errors.
     641              :      */
     642              :     CHIP_ERROR FetchICACert(FabricIndex fabricIndex, MutableByteSpan & outCert) const;
     643              : 
     644              :     /**
     645              :      * @brief Get the NOC (Node Operational Certificate) associated with a fabric.
     646              :      *
     647              :      * If a fabric is pending from add/update operation for the given `fabricIndex`, its
     648              :      * NOC is returned.
     649              :      *
     650              :      * @param fabricIndex - Fabric for which to get the NOC
     651              :      * @param outCert - MutableByteSpan to receive the certificate. Resized to actual size.
     652              :      * @retval CHIP_NO_ERROR on success
     653              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCert` is too small
     654              :      * @retval CHIP_ERROR_NOT_FOUND if not found/available
     655              :      * @retval other CHIP_ERROR values on invalid arguments or internal errors.
     656              :      */
     657              :     CHIP_ERROR FetchNOCCert(FabricIndex fabricIndex, MutableByteSpan & outCert) const;
     658              : 
     659              :     /**
     660              :      * @brief Recover the VIDVerificationStatement for a fabric, if any exists.
     661              :      *
     662              :      * This includes returning a pending one if one exists.
     663              :      *
     664              :      * @param fabricIndex - Fabric index for which to find a VIDVerificationStatement
     665              :      * @param outVIDVerificationStatement - Buffer to receive the VIDVerificationstatement. Must be large enough for the maximum
     666              :      * size.
     667              :      *
     668              :      * @retval CHIP_NO_ERROR on success, **including if missing**.
     669              :      * @retval other CHIP_ERROR value on internal errors
     670              :      */
     671              :     CHIP_ERROR FetchVIDVerificationStatement(FabricIndex fabricIndex, MutableByteSpan & outVIDVerificationStatement) const;
     672              : 
     673              :     /**
     674              :      * @brief Recover the VVSC (VID Verification Signing Certificate) for a fabric, if any exists.
     675              :      *
     676              :      * This includes returning a pending one if one exists.
     677              :      *
     678              :      * @param fabricIndex - Fabric index for which to find a VVSC
     679              :      * @param outVIDVerificationStatement - Buffer to receive the VVSC in Matter TLV certificate format.
     680              :      *
     681              :      * @retval CHIP_NO_ERROR on success, **including if missing**.
     682              :      * @retval other CHIP_ERROR value on internal errors
     683              :      */
     684              :     CHIP_ERROR FetchVVSC(FabricIndex fabricIndex, MutableByteSpan & outVVSC) const;
     685              : 
     686              :     /**
     687              :      * @brief Get the root public key by value for the given `fabricIndex`.
     688              :      *
     689              :      * @param fabricIndex - Fabric for which to get the root public key (subject public key of RCAC)
     690              :      * @param outPublicKey - PublicKey instance to receive the public key contents
     691              :      * @retval CHIP_NO_ERROR on success
     692              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCert` is too small
     693              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if not found/available, or `fabricIndex` has a bad value
     694              :      * @retval other CHIP_ERROR values on other invalid arguments or internal errors.
     695              :      */
     696              :     CHIP_ERROR FetchRootPubkey(FabricIndex fabricIndex, Crypto::P256PublicKey & outPublicKey) const;
     697              : 
     698              :     /**
     699              :      * @brief Get the CASE Authenticated Tags from the NOC for the given `fabricIndex`.
     700              :      *
     701              :      * @param fabricIndex - Fabric for which to get the root public key (subject public key of RCAC)
     702              :      * @param cats - CATValues struct to write the NOC CATs for the given fabric index
     703              :      * @retval CHIP_NO_ERROR on success
     704              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if not found/available, or `fabricIndex` has a bad value
     705              :      * @retval other CHIP_ERROR values on other invalid arguments or internal errors.
     706              :      */
     707              :     CHIP_ERROR FetchCATs(const FabricIndex fabricIndex, CATValues & cats) const;
     708              : 
     709              :     /**
     710              :      * @brief Sign a message with a given fabric's operational keypair. This is used for
     711              :      *        CASE and the only way the key should be used.
     712              :      *
     713              :      * This will use a pending key activated with `ActivatePendingOperationalKey` but
     714              :      * not yet persisted, if one is available for the fabric.
     715              :      *
     716              :      * @param fabricIndex - Fabric index whose operational key to use
     717              :      * @param message - Message to sign
     718              :      * @param outSignature - Signature object to receive the signature
     719              :      *
     720              :      * @retval CHIP_NO_ERROR on success
     721              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if no active key is found for the given `fabricIndex` or if
     722              :      *                                         `fabricIndex` is invalid.
     723              :      * @retval other CHIP_ERROR value on internal errors
     724              :      */
     725              :     CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, ByteSpan message, Crypto::P256ECDSASignature & outSignature) const;
     726              : 
     727              :     /**
     728              :      * @brief Create an ephemeral keypair for use in session establishment.
     729              :      *
     730              :      * WARNING: The return value MUST be released by `ReleaseEphemeralKeypair`. This is because
     731              :      *          Matter CHIPMem.h does not properly support UniquePtr in a way that would
     732              :      *          safely allow classes derived from Crypto::P256Keypair to be released properly.
     733              :      *
     734              :      * This delegates to the OperationalKeystore if one exists, otherwise it directly allocates a base
     735              :      * Crypto::P256Keypair instance
     736              :      *
     737              :      * @return a pointer to a dynamically P256Keypair (or derived class thereof), which may evaluate to nullptr
     738              :      *         if running out of memory.
     739              :      */
     740              :     Crypto::P256Keypair * AllocateEphemeralKeypairForCASE();
     741              : 
     742              :     /**
     743              :      * @brief Release an ephemeral keypair previously created by `AllocateEphemeralKeypairForCASE()`
     744              :      */
     745              :     void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair);
     746              : 
     747              :     /**
     748              :      * This initializes a new keypair for the given fabric and generates a CSR for it,
     749              :      * so that it can be passed in a CSRResponse.
     750              :      *
     751              :      * The keypair is temporary and becomes usable for `SignWithOpKeypair` only after either
     752              :      * `ActivatePendingOperationalKey` is called. It is destroyed if
     753              :      * `RevertPendingFabricData` is called before `CommitPendingFabricData`.
     754              :      *  If a pending keypair for the provided fabricIndex (if present) already existed, it is replaced by this call.
     755              :      *
     756              :      *  Only one pending operational keypair is supported at a time.
     757              :      *
     758              :      * @param fabricIndex - Existing FabricIndex for which a new keypair must be made available. If it
     759              :      *                      doesn't have a value, the key will be marked pending for the next available
     760              :      *                      fabric index that would apply for `AddNewFabric`.
     761              :      * @param outputCsr - Buffer to contain the CSR. Must be at least `kMIN_CSR_Buffer_Size` large.
     762              :      *
     763              :      * @retval CHIP_NO_ERROR on success
     764              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outputCsr` buffer is too small
     765              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is already a pending keypair for another `fabricIndex` value
     766              :      *                                         or if fabricIndex is an invalid value.
     767              :      * @retval other CHIP_ERROR value on internal errors
     768              :      */
     769              :     CHIP_ERROR AllocatePendingOperationalKey(Optional<FabricIndex> fabricIndex, MutableByteSpan & outputCsr);
     770              : 
     771              :     /**
     772              :      * @brief Returns whether an operational key is pending (true if `AllocatePendingOperationalKey` was
     773              :      *        previously successfully called, false otherwise).
     774              :      *
     775              :      * @param outIsPendingKeyForUpdateNoc this is set to true if the `AllocatePendingOperationalKey` had an
     776              :      *                                    associated fabric index attached, indicating it's for UpdateNoc
     777              :      */
     778              :     bool HasPendingOperationalKey(bool & outIsPendingKeyForUpdateNoc) const;
     779              : 
     780              :     /**
     781              :      * @brief Returns whether an operational key can be used to sign for given FabricIndex
     782              :      *
     783              :      * @param fabricIndex - Fabric index for which an operational key must be found
     784              :      * @return true if a pending fabric or committed fabric for fabricIndex has an operational key, false otherwise.
     785              :      */
     786              :     bool HasOperationalKeyForFabric(FabricIndex fabricIndex) const;
     787              : 
     788              :     /**
     789              :      * @brief If a newly-added fabric is pending, this returns its index, or kUndefinedFabricIndex if none are pending.
     790              :      *
     791              :      * A newly-added fabric is pending if AddNOC has been previously called successfully but the
     792              :      * fabric is not yet fully committed by CommissioningComplete.
     793              :      *
     794              :      * NOTE: that this never returns a value other than kUndefinedFabricIndex when UpdateNOC is pending.
     795              :      *
     796              :      * @return the fabric index of the pending fabric, or kUndefinedFabricIndex if no fabrics are pending.
     797              :      */
     798              :     FabricIndex GetPendingNewFabricIndex() const;
     799              : 
     800              :     /**
     801              :      * @brief Returns the operational keystore. This is used for
     802              :      *        CASE and the only way the keystore should be used.
     803              :      *
     804              :      * @return The operational keystore, nullptr otherwise.
     805              :      */
     806            7 :     const Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; }
     807              : 
     808              :     /**
     809              :      * @brief Add a pending trusted root certificate for the next fabric created with `AddNewPendingFabric*` methods.
     810              :      *
     811              :      * The root only becomes actually pending when the `AddNewPendingFabric*` is called afterwards. It is reverted
     812              :      * if `RevertPendingFabricData` is called.
     813              :      *
     814              :      * This method with fail with CHIP_ERROR_INCORRECT_STATE in a variety of illogical/inconsistent conditions,
     815              :      * which always can be cleared with `RevertPendingFabricData`. Such a situation is calling this method after
     816              :      * `UpdatePendingFabric` which would mean logical collision of an addition and an update.
     817              :      *
     818              :      * @param rcac - Root certificate in Matter Operational Certificate Encoding (TLV) format
     819              :      * @retval CHIP_NO_ERROR on success
     820              :      * @retval CHIP_ERROR_INCORRECT_STATE if this is called in an inconsistent order
     821              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to make the root pending
     822              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if the RCAC is too large (further checks are done on `AddNewPendingFabric*`)
     823              :      * @retval other CHIP_ERROR on internal errors.
     824              :      */
     825              :     CHIP_ERROR AddNewPendingTrustedRootCert(const ByteSpan & rcac);
     826              : 
     827              :     /**
     828              :      * @brief Use an NOC and optional ICAC chaining back to the pending RCAC to activate a new fabric
     829              :      *
     830              :      * Operational key is assumed to be pending or committed in the associated mOperationalKeystore.
     831              :      *
     832              :      * The fabric becomes temporarily active for purposes of `Fetch*` and `SignWithOpKeyPair`, etc.
     833              :      * The new fabric becomes permanent/persisted on successful `CommitPendingFabricData`. It disappears
     834              :      * on `RevertPendingFabricData` or `RevertPendingOpCertsExceptRoot`.
     835              :      *
     836              :      * This method with fail with CHIP_ERROR_INCORRECT_STATE in a variety of illogical/inconsistent conditions,
     837              :      * which always can be cleared with `RevertPendingFabricData`. Such a situation is calling this method after
     838              :      * `UpdatePendingFabric*` which would mean logical collision of an addition and an update.
     839              :      *
     840              :      * If a pending key was present in the OperationalKeystore associated with this FabricTable,
     841              :      * it is activated on success.
     842              :      *
     843              :      *
     844              :      * @param noc - NOC for the fabric. Must match an existing or pending operational keypair in the mOperationalKeystore.
     845              :      * @param icac - ICAC for the fabric. Can be empty if absent from the chain.
     846              :      * @param vendorId - VendorID to use for the new fabric
     847              :      * @param outNewFabricIndex - Pointer where the new fabric index for the fabric just added will be set. Cannot be nullptr.
     848              :      *
     849              :      * @retval CHIP_NO_ERROR on success.
     850              :      * @retval CHIP_ERROR_INCORRECT_STATE if this is called in an inconsistent order.
     851              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to make the fabric pending.
     852              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if any of the arguments are invalid such as too large or out of bounds.
     853              :      * @retval CHIP_ERROR_FABRIC_EXISTS if operational identity collides with one already present.
     854              :      * @retval other CHIP_ERROR_* on internal errors or certificate validation errors.
     855              :      */
     856            0 :     CHIP_ERROR AddNewPendingFabricWithOperationalKeystore(const ByteSpan & noc, const ByteSpan & icac, uint16_t vendorId,
     857              :                                                           FabricIndex * outNewFabricIndex,
     858              :                                                           AdvertiseIdentity advertiseIdentity = AdvertiseIdentity::Yes)
     859              :     {
     860            0 :         return AddNewPendingFabricCommon(noc, icac, vendorId, nullptr, false, advertiseIdentity, outNewFabricIndex);
     861              :     };
     862              : 
     863              :     /**
     864              :      * @brief Use an NOC and optional ICAC chaining back to the pending RCAC to activate a new fabric
     865              :      *
     866              :      * Operational key is injected, and then owned by the fabric (!isExistingOpKeyExternallyOwned) or
     867              :      * owned externally if `isExistingOpKeyExternallyOwned` is true).
     868              :      *
     869              :      * WARNING: Copying keypairs is unsafe and not recommended. Consider using
     870              :      *          AddNewPendingFabricWithOperationalKeystore and an associated OperationalKeystore
     871              :      *          or always using `isExistingOpKeyExternallyOwned`, with `existingOpKey` being a safe
     872              :      *          class derived from P256Keypair that avoids the true private key persisting in memory.
     873              :      *
     874              :      * For rest of semantics outside of operational key, @see AddNewPendingFabricWithOperationalKeystore
     875              :      *
     876              :      * @param noc - NOC for the fabric. Public key must match the `existingOpKey`'s public key
     877              :      * @param icac - ICAC for the fabric. Can be empty if absent from the chain.
     878              :      * @param vendorId - VendorID to use for the new fabric
     879              :      * @param existingOpKey - Existing operational key to ingest for use in the fabric. Cannot be nullptr.
     880              :      * @param isExistingOpKeyExternallyOwned - if true, operational key must outlive the fabric. If false, the key is
     881              :      *                                         copied using P256Keypair::Serialize/Deserialize and owned in heap of a FabricInfo.
     882              :      * @param outNewFabricIndex - Pointer where the new fabric index for the fabric just added will be set. Cannot be nullptr.
     883              :      *
     884              :      * @retval CHIP_NO_ERROR on success.
     885              :      * @retval CHIP_ERROR_INCORRECT_STATE if this is called in an inconsistent order.
     886              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to make the fabric pending.
     887              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if any of the arguments are invalid such as too large or out of bounds.
     888              :      * @retval CHIP_ERROR_FABRIC_EXISTS if operational identity collides with one already present.
     889              :      * @retval other CHIP_ERROR_* on internal errors or certificate validation errors.
     890              :      */
     891          699 :     CHIP_ERROR AddNewPendingFabricWithProvidedOpKey(const ByteSpan & noc, const ByteSpan & icac, uint16_t vendorId,
     892              :                                                     Crypto::P256Keypair * existingOpKey, bool isExistingOpKeyExternallyOwned,
     893              :                                                     FabricIndex * outNewFabricIndex,
     894              :                                                     AdvertiseIdentity advertiseIdentity = AdvertiseIdentity::Yes)
     895              :     {
     896          699 :         return AddNewPendingFabricCommon(noc, icac, vendorId, existingOpKey, isExistingOpKeyExternallyOwned, advertiseIdentity,
     897          699 :                                          outNewFabricIndex);
     898              :     };
     899              : 
     900              :     /**
     901              :      * @brief Use an NOC and optional ICAC to update an existing fabric
     902              :      *
     903              :      * Operational key is assumed to be pending or committed in the associated mOperationalKeystore.
     904              :      *
     905              :      * The new NOC chain becomes temporarily active for purposes of `Fetch*` and `SignWithOpKeyPair`, etc.
     906              :      * The RCAC remains as before. For this method call to succeed, NOC chain must chain back to the existing RCAC.
     907              :      * The update fabric becomes permanent/persisted on successful `CommitPendingFabricData`. Changes revert
     908              :      * on `RevertPendingFabricData` or `RevertPendingOpCertsExceptRoot`. FabricId CANNOT be updated, but
     909              :      * CAT tags and Node ID in NOC can change between previous and new NOC for a given FabricId.
     910              :      *
     911              :      * This method with fail with CHIP_ERROR_INCORRECT_STATE in a variety of illogical/inconsistent conditions,
     912              :      * which always can be cleared with `RevertPendingFabricData`. Such a situation is calling this method after
     913              :      * `AddNewPending*` which would mean logical collision of an addition and an update.
     914              :      *
     915              :      * If a pending key was present in the OperationalKeystore associated with this FabricTable,
     916              :      * it is activated on success.
     917              :      *
     918              :      * @param fabricIndex - fabricIndex of the existing fabric to update
     919              :      * @param noc - Updated NOC for the fabric. Must match an existing or pending operational keypair in the mOperationalKeystore.
     920              :      * @param icac - Update ICAC for the fabric. Can be empty if absent from the chain.
     921              :      *
     922              :      * @retval CHIP_NO_ERROR on success
     923              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if the `fabricIndex` is not an existing fabric
     924              :      * @retval CHIP_ERROR_INCORRECT_STATE if this is called in an inconsistent order
     925              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to store the pending updates
     926              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if any of the arguments are invalid such as too large or out of bounds.
     927              :      * @retval other CHIP_ERROR_* on internal errors or certificate validation errors.
     928              :      */
     929            0 :     CHIP_ERROR UpdatePendingFabricWithOperationalKeystore(FabricIndex fabricIndex, const ByteSpan & noc, const ByteSpan & icac,
     930              :                                                           AdvertiseIdentity advertiseIdentity = AdvertiseIdentity::Yes)
     931              :     {
     932            0 :         return UpdatePendingFabricCommon(fabricIndex, noc, icac, nullptr, false, advertiseIdentity);
     933              :     }
     934              : 
     935              :     /**
     936              :      * @brief Use an NOC and optional ICAC to update an existing fabric
     937              :      *
     938              :      * Operational key is injected, and then owned by the fabric (!isExistingOpKeyExternallyOwned) or
     939              :      * owned externally if `isExistingOpKeyExternallyOwned` is true).
     940              :      *
     941              :      * WARNING: Copying keypairs is unsafe and not recommended. Consider using
     942              :      *          AddNewPendingFabricWithOperationalKeystore and an associated OperationalKeystore
     943              :      *          or always using `isExistingOpKeyExternallyOwned`, with `existingOpKey` being a safe
     944              :      *          class derived from P256Keypair that avoids the true private key persisting in memory.
     945              :      *
     946              :      * For rest of semantics outside of operational key, @see UpdatePendingFabricWithOperationalKeystore
     947              :      *
     948              :      * @param fabricIndex - fabricIndex of the existing fabric to update
     949              :      * @param noc - Updated NOC for the fabric. Must match an existing or pending operational keypair in the mOperationalKeystore.
     950              :      * @param icac - Update ICAC for the fabric. Can be empty if absent from the chain.
     951              :      * @param existingOpKey - Existing operational key to ingest for use in the fabric with new NOC. Cannot be nullptr.
     952              :      * @param isExistingOpKeyExternallyOwned - if true, operational key must outlive the fabric. If false, the key is
     953              :      *                                         copied using P256Keypair::Serialize/Deserialize and owned in heap of a FabricInfo.
     954              :      *
     955              :      * @retval CHIP_NO_ERROR on success
     956              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if the `fabricIndex` is not an existing fabric
     957              :      * @retval CHIP_ERROR_INCORRECT_STATE if this is called in an inconsistent order
     958              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to store the pending updates
     959              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if any of the arguments are invalid such as too large or out of bounds.
     960              :      * @retval other CHIP_ERROR_* on internal errors or certificate validation errors.
     961              :      */
     962              : 
     963            0 :     CHIP_ERROR UpdatePendingFabricWithProvidedOpKey(FabricIndex fabricIndex, const ByteSpan & noc, const ByteSpan & icac,
     964              :                                                     Crypto::P256Keypair * existingOpKey, bool isExistingOpKeyExternallyOwned,
     965              :                                                     AdvertiseIdentity advertiseIdentity = AdvertiseIdentity::Yes)
     966              :     {
     967            0 :         return UpdatePendingFabricCommon(fabricIndex, noc, icac, existingOpKey, isExistingOpKeyExternallyOwned, advertiseIdentity);
     968              :     }
     969              : 
     970              :     /**
     971              :      * @brief Commit any pending temporary FabricTable state. This is used mostly for affecting
     972              :      *        CommissioningComplete.
     973              :      *
     974              :      * On success, any pending information is committed such that after a restart, it would
     975              :      * be found to be the same in persistent storage.
     976              :      *
     977              :      * If no changes were pending and state is internally consistent, this appears as a no-op and returns
     978              :      * CHIP_NO_ERROR.
     979              :      *
     980              :      * If there is any internally inconsistent state, this methods acts the same as RevertPendingFabricData(),
     981              :      * and all state is lost.
     982              :      *
     983              :      * In rare circumstances, and depending on the storage backend for opcerts and operational keys,
     984              :      * an inconsistent state could be left, such as if restarting during storage writes of
     985              :      * CommitPendingFabricData(). If this happens, the next FabricTable::Init() will attempt
     986              :      * to clean-up the pieces.
     987              :      *
     988              :      * @return CHIP_NO_ERROR on success or any other CHIP_ERROR value on internal errors
     989              :      */
     990              :     CHIP_ERROR CommitPendingFabricData();
     991              : 
     992              :     /**
     993              :      * @brief Revert any pending state.
     994              :      *
     995              :      * This is used to handle fail-safe expiry of partially configured fabrics, or to recover
     996              :      * from situations where partial state was written and configuration cannot continue properly.
     997              :      *
     998              :      * All pending certificates and operational keys and pending fabric metadata are cleared.
     999              :      */
    1000              :     void RevertPendingFabricData();
    1001              : 
    1002              :     /**
    1003              :      * @brief Revert only the pending NOC/ICAC and pending added fabric, not RCAC. Used for error handling
    1004              :      *        during commissioning.
    1005              :      */
    1006              :     void RevertPendingOpCertsExceptRoot();
    1007              : 
    1008              :     // Verifies credentials, using the root certificate of the provided fabric index.
    1009              :     CHIP_ERROR VerifyCredentials(FabricIndex fabricIndex, ByteSpan noc, ByteSpan icac, Credentials::ValidationContext & context,
    1010              :                                  CompressedFabricId & outCompressedFabricId, FabricId & outFabricId, NodeId & outNodeId,
    1011              :                                  Crypto::P256PublicKey & outNocPubkey, Crypto::P256PublicKey * outRootPublicKey = nullptr) const;
    1012              : 
    1013              :     // Verifies credentials, using the provided root certificate.
    1014              :     static CHIP_ERROR VerifyCredentials(ByteSpan noc, ByteSpan icac, ByteSpan rcac, Credentials::ValidationContext & context,
    1015              :                                         CompressedFabricId & outCompressedFabricId, FabricId & outFabricId, NodeId & outNodeId,
    1016              :                                         Crypto::P256PublicKey & outNocPubkey, Crypto::P256PublicKey * outRootPublicKey = nullptr);
    1017              :     /**
    1018              :      * @brief Enables FabricInfo instances to collide and reference the same logical fabric (i.e Root Public Key + FabricId).
    1019              :      *
    1020              :      * *WARNING* This is ONLY to be used when creating multiple controllers on the same fabric OR for test.
    1021              :      *
    1022              :      */
    1023            0 :     void PermitCollidingFabrics() { mStateFlags.Set(StateFlags::kAreCollidingFabricsIgnored); }
    1024              : 
    1025              :     // Add a new fabric for testing. The Operational Key is a raw P256Keypair (public key and private key raw bits) that will
    1026              :     // get copied (directly) into the fabric table.
    1027              :     CHIP_ERROR AddNewFabricForTest(ByteSpan rootCert, ByteSpan icacCert, ByteSpan nocCert, ByteSpan opKeySpan,
    1028              :                                    FabricIndex * outFabricIndex);
    1029              : 
    1030              :     // Add a new fabric for testing. The Operational Key is a raw P256Keypair (public key and private key raw bits) that will
    1031              :     // get copied (directly) into the fabric table. The fabric will NOT be committed, and will remain pending.
    1032              :     CHIP_ERROR AddNewUncommittedFabricForTest(ByteSpan rootCert, ByteSpan icacCert, ByteSpan nocCert, ByteSpan opKeySpan,
    1033              :                                               FabricIndex * outFabricIndex);
    1034              : 
    1035              :     // Same as AddNewFabricForTest, but ignore if we are colliding with same <Root Public Key, Fabric Id>, so
    1036              :     // that a single fabric table can have N nodes for same fabric. This usually works, but is bad form.
    1037              :     CHIP_ERROR AddNewFabricForTestIgnoringCollisions(ByteSpan rootCert, ByteSpan icacCert, ByteSpan nocCert, ByteSpan opKeySpan,
    1038              :                                                      FabricIndex * outFabricIndex)
    1039              :     {
    1040              :         PermitCollidingFabrics();
    1041              :         CHIP_ERROR err = AddNewFabricForTest(rootCert, icacCert, nocCert, opKeySpan, outFabricIndex);
    1042              :         mStateFlags.Clear(StateFlags::kAreCollidingFabricsIgnored);
    1043              :         return err;
    1044              :     }
    1045              : 
    1046              :     // For test only. See definition of `StateFlags::kAbortCommitForTest`.
    1047              :     void SetForceAbortCommitForTest(bool abortCommitForTest)
    1048              :     {
    1049              :         (void) abortCommitForTest;
    1050              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
    1051              :         if (abortCommitForTest)
    1052              :         {
    1053              :             mStateFlags.Set(StateFlags::kAbortCommitForTest);
    1054              :         }
    1055              :         else
    1056              :         {
    1057              :             mStateFlags.Clear(StateFlags::kAbortCommitForTest);
    1058              :         }
    1059              : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
    1060              :     }
    1061              : 
    1062              :     /**
    1063              :      * Get the fabric index that will be used for the next fabric that will be
    1064              :      * added.  Returns error if no more fabrics can be added, otherwise writes
    1065              :      * the fabric index that will be used for the next addition into the
    1066              :      * outparam.
    1067              :      */
    1068              :     CHIP_ERROR PeekFabricIndexForNextAddition(FabricIndex & outIndex);
    1069              : 
    1070              :     /**
    1071              :      * Set the fabric index that will be used fo the next fabric added.
    1072              :      *
    1073              :      * Returns an error if the |fabricIndex| is already in use.
    1074              :      */
    1075              :     CHIP_ERROR SetFabricIndexForNextAddition(FabricIndex fabricIndex);
    1076              : 
    1077              :     /**
    1078              :      * @brief Set the advertising behavior for the fabric identified by `fabricIndex`.
    1079              :      *
    1080              :      * It is the caller's responsibility to actually restart DNS-SD advertising
    1081              :      * as needed after updating this state.
    1082              :      *
    1083              :      * @param fabricIndex - Fabric Index for which to set the label
    1084              :      * @param advertiseIdentity - whether the identity for this fabric should be advertised.
    1085              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if fabricIndex does not refer to a fabric in the table
    1086              :      */
    1087              :     CHIP_ERROR SetShouldAdvertiseIdentity(FabricIndex fabricIndex, AdvertiseIdentity advertiseIdentity);
    1088              : 
    1089              :     /**
    1090              :      * @brief Request a VID verification signature to be generated for a specific fabric in the FabricTable.
    1091              :      *
    1092              :      * @param[in] fabricIndex - Fabric Index for which to produce the response.
    1093              :      * @param[in] clientChallenge - Client-provided challenge.
    1094              :      * @param[in] attestationChallenge - Attestation challenge from the secure session.
    1095              :      * @param[out] outResponse - Reference to a pre-allocated response object that will be populated on success.
    1096              :      * @retval CHIP_NO_ERROR on success
    1097              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if the fabricIndex or clientChallenge is incorrectly formatted.
    1098              :      */
    1099              :     CHIP_ERROR SignVIDVerificationRequest(FabricIndex fabricIndex, ByteSpan clientChallenge, ByteSpan attestationChallenge,
    1100              :                                           SignVIDVerificationResponseData & outResponse);
    1101              : 
    1102              :     /**
    1103              :      * @brief Handle setting data related to Fabric Table VID Verification.
    1104              :      *
    1105              :      * This is on purpose structured to mirror the SetVIDVerificationStatement Operational Credentials Cluster command
    1106              :      *
    1107              :      * @param[in] fabricIndex - Fabric Index for which to produce the response.
    1108              :      * @param[in] vendorID - New VendorID to set on the Fabric (ignored if missing)
    1109              :      * @param[in] VIDVerificationStatement - VID Verification Statement to add/remove (ignored if missing)
    1110              :      * @param[in] VVSC - VID Verification Signing Certificate to add/remove (ignored if missing)
    1111              :      * @param[out] outFabricTableWasChanged - This is set to true if FabricTable saw a change from prior value, even if
    1112              :      *                                        method returns an error (appies to VIDVerificationStatement and VendorID)
    1113              :      * @retval CHIP_NO_ERROR on success
    1114              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if vendorID, VVSC or VIDVerificationStatement are not correct (maps to CONSTRAINT_ERROR)
    1115              :      * @retval CHIP_ERROR_INCORRECT_STATE if VVSC cannot be set due to ICAC presence (maps to INVALID_COMMAND)
    1116              :      */
    1117              :     CHIP_ERROR SetVIDVerificationStatementElements(FabricIndex fabricIndex, Optional<uint16_t> vendorId,
    1118              :                                                    Optional<ByteSpan> VIDVerificationStatement, Optional<ByteSpan> VVSC,
    1119              :                                                    bool & outFabricTableWasChanged);
    1120              : 
    1121              : private:
    1122              :     enum class StateFlags : uint16_t
    1123              :     {
    1124              :         // If true, we are in the process of a fail-safe and there was at least one
    1125              :         // operation that caused partial data in the fabric table.
    1126              :         kIsPendingFabricDataPresent = (1u << 0),
    1127              :         kIsTrustedRootPending       = (1u << 1),
    1128              :         kIsUpdatePending            = (1u << 2),
    1129              :         kIsAddPending               = (1u << 3),
    1130              : 
    1131              :         // Only true when `AllocatePendingOperationalKey` has been called
    1132              :         kIsOperationalKeyPending = (1u << 4),
    1133              :         // True if `AllocatePendingOperationalKey` was for an existing fabric
    1134              :         kIsPendingKeyForUpdateNoc = (1u << 5),
    1135              : 
    1136              :         // True if we allow more than one fabric with same root and fabricId in the fabric table
    1137              :         // for test purposes. This disables a collision check.
    1138              :         kAreCollidingFabricsIgnored = (1u << 6),
    1139              : 
    1140              :         // If set to true (only possible on test builds), will cause `CommitPendingFabricData()` to early
    1141              :         // return during commit, skipping clean-ups, so that we can validate commit marker fabric removal.
    1142              :         kAbortCommitForTest = (1u << 7),
    1143              :     };
    1144              : 
    1145              :     // Stored to indicate a commit is in progress, so that it can be cleaned-up on next boot
    1146              :     // if stopped in the middle.
    1147              :     struct CommitMarker
    1148              :     {
    1149              :         CommitMarker() = default;
    1150          738 :         CommitMarker(FabricIndex fabricIndex_, bool isAddition_)
    1151          738 :         {
    1152          738 :             this->fabricIndex = fabricIndex_;
    1153          738 :             this->isAddition  = isAddition_;
    1154          738 :         }
    1155              :         FabricIndex fabricIndex = kUndefinedFabricIndex;
    1156              :         bool isAddition         = false;
    1157              :     };
    1158              : 
    1159              :     /**
    1160              :      * @brief Get a mutable FabricInfo entry from the table by FabricIndex.
    1161              :      *
    1162              :      * NOTE: This is private for use within the FabricTable itself. All mutations have to go through the
    1163              :      *       FabricTable public methods that take a FabricIndex so that there are no mutations about which
    1164              :      *       the FabricTable is unaware, since this would break expectations regarding shadow/pending
    1165              :      *       entries used during fail-safe.
    1166              :      *
    1167              :      * @param fabricIndex - fabric index for which to get a mutable FabricInfo entry
    1168              :      * @return the FabricInfo entry for the fabricIndex if found, or nullptr if not found
    1169              :      */
    1170              :     FabricInfo * GetMutableFabricByIndex(FabricIndex fabricIndex);
    1171              : 
    1172              :     // Load a FabricInfo metatada item from storage for a given new fabric index. Returns internal error on failure.
    1173              :     CHIP_ERROR LoadFromStorage(FabricInfo * fabric, FabricIndex newFabricIndex);
    1174              : 
    1175              :     // Store a given fabric metadata directly/immediately. Used by internal operations.
    1176              :     CHIP_ERROR StoreFabricMetadata(const FabricInfo * fabricInfo) const;
    1177              : 
    1178              :     // Tries to set `mFabricIndexWithPendingState` and returns false if there's a clash.
    1179              :     bool SetPendingDataFabricIndex(FabricIndex fabricIndex);
    1180              : 
    1181              :     // Core validation logic for fabric additions/updates
    1182              :     CHIP_ERROR AddOrUpdateInner(FabricIndex fabricIndex, bool isAddition, Crypto::P256Keypair * existingOpKey,
    1183              :                                 bool isExistingOpKeyExternallyOwned, uint16_t vendorId, AdvertiseIdentity advertiseIdentity);
    1184              : 
    1185              :     // Common code for fabric addition, for either OperationalKeystore or injected key scenarios.
    1186              :     CHIP_ERROR AddNewPendingFabricCommon(const ByteSpan & noc, const ByteSpan & icac, uint16_t vendorId,
    1187              :                                          Crypto::P256Keypair * existingOpKey, bool isExistingOpKeyExternallyOwned,
    1188              :                                          AdvertiseIdentity advertiseIdentity, FabricIndex * outNewFabricIndex);
    1189              : 
    1190              :     // Common code for fabric updates, for either OperationalKeystore or injected key scenarios.
    1191              :     CHIP_ERROR UpdatePendingFabricCommon(FabricIndex fabricIndex, const ByteSpan & noc, const ByteSpan & icac,
    1192              :                                          Crypto::P256Keypair * existingOpKey, bool isExistingOpKeyExternallyOwned,
    1193              :                                          AdvertiseIdentity advertiseIdentity);
    1194              : 
    1195              :     // Common code for looking up a fabric given a root public key, a fabric ID and an optional node id scoped to that fabric.
    1196              :     const FabricInfo * FindFabricCommon(const Crypto::P256PublicKey & rootPubKey, FabricId fabricId,
    1197              :                                         NodeId nodeId = kUndefinedNodeId) const;
    1198              : 
    1199              :     /**
    1200              :      * UpdateNextAvailableFabricIndex should only be called when
    1201              :      * mNextAvailableFabricIndex has a value and that value stops being
    1202              :      * available.  It will set mNextAvailableFabricIndex to the next available
    1203              :      * value, or no value if there is none available.
    1204              :      */
    1205              :     void UpdateNextAvailableFabricIndex();
    1206              : 
    1207              :     /**
    1208              :      * Ensure that we have a valid next available fabric index, if that's at all possible.  This covers
    1209              :      * some FabricIndex allocation corner cases.  After this is called, the only way we can fail to have
    1210              :      * a next available fabric index is if our fabric table is max-sized (254 entries) and full.
    1211              :      */
    1212              :     void EnsureNextAvailableFabricIndexUpdated();
    1213              : 
    1214              :     /**
    1215              :      * Store our current fabric index state: what our next available index is
    1216              :      * and what indices we're using right now.
    1217              :      */
    1218              :     CHIP_ERROR StoreFabricIndexInfo() const;
    1219              : 
    1220              :     /**
    1221              :      * @brief Delete all metadata from storage for the given fabric
    1222              :      *
    1223              :      * @param fabricIndex FabricIndex for which to delete the metadadata
    1224              :      * @return CHIP_NO_ERROR on success or another CHIP_ERROR on failure
    1225              :      */
    1226              :     CHIP_ERROR DeleteMetadataFromStorage(FabricIndex fabricIndex);
    1227              : 
    1228              :     /**
    1229              :      * @brief Determine if a collision (undesired on AddNOC, necessary on UpdateNOC) exists
    1230              :      *        between the FabricID in the given noc, and the RCAC found for `currentFabricIndex`
    1231              :      *        in the op cert store, against an existing fabric in the FabricTable (which could be pending)
    1232              :      *
    1233              :      * @param currentFabricIndex - pending fabricIndex for which we are trying to Add/Update a NOC
    1234              :      * @param noc - NOC cert received that contains FabricID whose collision we care to validate
    1235              :      * @param outMatchingFabricIndex - set to the FabricIndex matching the collision or kUndefinedFabricIndex on no collision found
    1236              :      * @return CHIP_NO_ERROR on successful update of outMatchingFabricIndex or other CHIP_ERROR on internal errors
    1237              :      */
    1238              :     CHIP_ERROR FindExistingFabricByNocChaining(FabricIndex currentFabricIndex, const ByteSpan & noc,
    1239              :                                                FabricIndex & outMatchingFabricIndex) const;
    1240              : 
    1241              :     /**
    1242              :      * @brief Get the shadow FabricInfo entry that is pending for updates, if an
    1243              :      *        update is in progress.
    1244              :      *
    1245              :      * @return a pointer to the shadow pending fabric or nullptr if none is active.
    1246              :      */
    1247          757 :     const FabricInfo * GetShadowPendingFabricEntry() const { return HasPendingFabricUpdate() ? &mPendingFabric : nullptr; }
    1248              : 
    1249              :     // Returns true if we have a shadow entry pending for a fabric update.
    1250        31975 :     bool HasPendingFabricUpdate() const
    1251              :     {
    1252        31975 :         return mPendingFabric.IsInitialized() &&
    1253        31975 :             mStateFlags.HasAll(StateFlags::kIsPendingFabricDataPresent, StateFlags::kIsUpdatePending);
    1254              :     }
    1255              : 
    1256              :     // Validate an NOC chain at time of adding/updating a fabric (uses VerifyCredentials with additional checks).
    1257              :     // The `existingFabricId` is passed for UpdateNOC, and must match the Fabric, to make sure that we are
    1258              :     // not trying to change FabricID with UpdateNOC. If set to kUndefinedFabricId, we are doing AddNOC and
    1259              :     // we don't need to check match to pre-existing fabric.
    1260              :     static CHIP_ERROR ValidateIncomingNOCChain(const ByteSpan & noc, const ByteSpan & icac, const ByteSpan & rcac,
    1261              :                                                FabricId existingFabricId, Credentials::CertificateValidityPolicy * policy,
    1262              :                                                CompressedFabricId & outCompressedFabricId, FabricId & outFabricId,
    1263              :                                                NodeId & outNodeId, Crypto::P256PublicKey & outNocPubkey,
    1264              :                                                Crypto::P256PublicKey & outRootPubkey);
    1265              : 
    1266              :     /**
    1267              :      * Read our fabric index info from the given TLV reader and set up the
    1268              :      * fabric table accordingly.
    1269              :      */
    1270              :     CHIP_ERROR ReadFabricInfo(TLV::ContiguousBufferTLVReader & reader);
    1271              : 
    1272              :     CHIP_ERROR NotifyFabricUpdated(FabricIndex fabricIndex);
    1273              :     CHIP_ERROR NotifyFabricCommitted(FabricIndex fabricIndex);
    1274              : 
    1275              :     // Commit management clean-up APIs
    1276              :     CHIP_ERROR StoreCommitMarker(const CommitMarker & commitMarker);
    1277              :     CHIP_ERROR GetCommitMarker(CommitMarker & outCommitMarker);
    1278              : 
    1279              :     FabricInfo mStates[CHIP_CONFIG_MAX_FABRICS];
    1280              :     // Used for UpdateNOC pending fabric updates
    1281              :     FabricInfo mPendingFabric;
    1282              :     PersistentStorageDelegate * mStorage                    = nullptr;
    1283              :     Crypto::OperationalKeystore * mOperationalKeystore      = nullptr;
    1284              :     Credentials::OperationalCertificateStore * mOpCertStore = nullptr;
    1285              : 
    1286              :     // FabricTable::Delegate link to first node, since FabricTable::Delegate is a form
    1287              :     // of intrusive linked-list item.
    1288              :     FabricTable::Delegate * mDelegateListRoot = nullptr;
    1289              : 
    1290              :     // When mStateFlags.Has(kIsPendingFabricDataPresent) is true, this holds the index of the fabric
    1291              :     // for which there is currently pending data.
    1292              :     FabricIndex mFabricIndexWithPendingState = kUndefinedFabricIndex;
    1293              : 
    1294              :     // For when a revert occurs during init, so that more clean-up can be scheduled by caller.
    1295              :     FabricIndex mDeletedFabricIndexFromInit = kUndefinedFabricIndex;
    1296              : 
    1297              :     LastKnownGoodTime mLastKnownGoodTime;
    1298              : 
    1299              :     // We may not have an mNextAvailableFabricIndex if our table is as large as
    1300              :     // it can go and is full.
    1301              :     Optional<FabricIndex> mNextAvailableFabricIndex;
    1302              :     uint8_t mFabricCount = 0;
    1303              : 
    1304              :     BitFlags<StateFlags> mStateFlags;
    1305              : };
    1306              : 
    1307              : } // namespace chip
        

Generated by: LCOV version 2.0-1