Matter SDK Coverage Report
Current view: top level - credentials - OperationalCertificateStore.h (source / functions) Coverage Total Hit
Test: SHA:4cbce7f768f16e614f5a8ccb8cd93c92cbeae70d Lines: 11.1 % 9 1
Test Date: 2025-04-26 07:09:35 Functions: 16.7 % 6 1

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2022 Project CHIP Authors
       3              :  *    All rights reserved.
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : #pragma once
      19              : 
      20              : #include <lib/core/CHIPError.h>
      21              : #include <lib/core/DataModelTypes.h>
      22              : #include <lib/support/Span.h>
      23              : 
      24              : namespace chip {
      25              : namespace Credentials {
      26              : 
      27              : class OperationalCertificateStore
      28              : {
      29              : public:
      30              :     enum class CertChainElement : uint8_t
      31              :     {
      32              :         kRcac = 0,
      33              :         kIcac = 1,
      34              :         kNoc  = 2
      35              :     };
      36              : 
      37              :     enum class VidVerificationElement : uint8_t
      38              :     {
      39              :         kVidVerificationStatement = 0,
      40              :         kVvsc                     = 1,
      41              :     };
      42              : 
      43            2 :     virtual ~OperationalCertificateStore() {}
      44              : 
      45              :     // ==== API designed for commisionables to support fail-safe (although can be used by controllers) ====
      46              : 
      47              :     /**
      48              :      * @brief Returns true if a pending root certificate exists and is active from a previous
      49              :      *        `AddNewTrustedRootCertForFabric`.
      50              :      */
      51              :     virtual bool HasPendingRootCert() const = 0;
      52              : 
      53              :     /**
      54              :      * @brief Returns true if a pending operational certificate chain exists and is active from a previous
      55              :      *        `AddNewOpCertsForFabric` or `UpdateOpCertsForFabric`.
      56              :      */
      57              :     virtual bool HasPendingNocChain() const = 0;
      58              : 
      59              :     /**
      60              :      * @brief Returns true if either a pending VVSC or VIDVerificationStatement exists and is active.
      61              :      */
      62            0 :     virtual bool HasPendingVidVerificationElements() const
      63              :     {
      64              :         // Default false to match the CHIP_ERROR_NOT_IMPLEMENTED for default versions in this base class.
      65            0 :         return false;
      66              :     }
      67              : 
      68              :     /**
      69              :      * @brief Returns whether a usable operational certificates chain exists for the given fabric.
      70              :      *
      71              :      * Returns true even if the certificates are not persisted yet. Only returns true if a certificate
      72              :      * is presently usable such that `GetCertificate` would succeed for the fabric.
      73              :      *
      74              :      * @param fabricIndex - FabricIndex for which availability of certificate will be checked.
      75              :      * @param element - Element of the certificate chain whose presence needs to be checked
      76              :      * @return true if there an active obtainable operational certificate of the given type for the given FabricIndex,
      77              :      *         false otherwise.
      78              :      */
      79              :     virtual bool HasCertificateForFabric(FabricIndex fabricIndex, CertChainElement element) const = 0;
      80              : 
      81              :     /**
      82              :      * @brief Add and temporarily activate a new Trusted Root Certificate for the given fabric
      83              :      *
      84              :      * The certificate is temporary until committed or reverted.
      85              :      * The certificate is committed to storage only on `CommitOpCertsForFabric`.
      86              :      * The certificate is destroyed if `RevertPendingOpCerts` is called before `CommitOpCertsForFabric`.
      87              :      *
      88              :      * Only one pending trusted root certificate is supported at a time and it is illegal
      89              :      * to call this method if there is already a persisted root certificate for the given
      90              :      * fabric.
      91              :      *
      92              :      * Uniqueness constraints for roots (see AddTrustedRootCertificate command in spec) are not
      93              :      * enforced by this method and must be done as a more holistic check elsewhere. Cryptographic
      94              :      * signature verification or path validation are not enforced by this method.
      95              :      *
      96              :      * If `UpdateOpCertsForFabric` had been called before this method, this method will return
      97              :      * CHIP_ERROR_INCORRECT_STATE since it is illegal to update trusted roots when updating an
      98              :      * existing NOC chain.
      99              :      *
     100              :      * @param fabricIndex - FabricIndex for which a new trusted root certificate should be added
     101              :      * @param rcac - Buffer containing the root certificate to add.
     102              :      *
     103              :      * @retval CHIP_NO_ERROR on success
     104              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to maintain the temporary root cert
     105              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if the certificate is empty or too large
     106              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized, if this method
     107              :      *                                    is called after `UpdateOpCertsForFabric`, or if there was
     108              :      *                                    already a pending or persisted root certificate for the given `fabricIndex`.
     109              :      * @retval other CHIP_ERROR value on internal errors
     110              :      */
     111              :     virtual CHIP_ERROR AddNewTrustedRootCertForFabric(FabricIndex fabricIndex, const ByteSpan & rcac) = 0;
     112              : 
     113              :     /**
     114              :      * @brief Add and temporarily activate an operational certificate chain for the given fabric.
     115              :      *
     116              :      * The certificate chain is temporary until committed or reverted.
     117              :      * The certificate chain is committed to storage on `CommitOpCertsForFabric`.
     118              :      * The certificate chain is destroyed if `RevertPendingOpCerts` is called before `CommitOpCertsForFabric`.
     119              :      *
     120              :      * Only one pending operational certificate chain is supported at a time and it is illegal
     121              :      * to call this method if there is already a persisted certificate chain for the given
     122              :      * fabric.
     123              :      *
     124              :      * Cryptographic signature verification or path validation are not enforced by this method.
     125              :      *
     126              :      * If `UpdateOpCertsForFabric` had been called before this method, this method will return
     127              :      * CHIP_ERROR_INCORRECT_STATE since it is illegal to add a certificate chain after
     128              :      * updating an existing NOC and before committing or reverting the update.
     129              :      *
     130              :      * If `AddNewTrustedRootCertForFabric` had not been called before this method, this method will
     131              :      * return CHIP_ERROR_INCORRECT_STATE since it is illegal in this implementation to store an
     132              :      * NOC chain without associated root.
     133              :      *
     134              :      * NOTE: The Matter spec allows AddNOC without AddTrustedRootCertificate if the NOC
     135              :      * chains to an existing root, to support root reuse. In this implementation, we expect each
     136              :      * fabric to store the root with the rest of the chain. Because of this, callers must ensure
     137              :      * that if an AddNOC command is done and no trusted root was added, that the requisite existing
     138              :      * root be "copied over" to match.
     139              :      *
     140              :      * @param fabricIndex - FabricIndex for which to add a new operational certificate chain
     141              :      * @param noc - Buffer containing the NOC certificate to add
     142              :      * @param icac - Buffer containing the ICAC certificate to add. If no ICAC is needed, `icac.empty()` must be true.
     143              :      *
     144              :      * @retval CHIP_NO_ERROR on success
     145              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to maintain the temporary `noc` and `icac` cert copies
     146              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if either the noc or icac are invalid sizes
     147              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if `fabricIndex` mismatches the one from a previous successful
     148              :      *                                         `AddNewTrustedRootCertForFabric`.
     149              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized, if this method
     150              :      *                                    is called after `UpdateOpCertsForFabric`, if there was
     151              :      *                                    already a pending or persisted operational cert chain for the given `fabricIndex`, or
     152              :      *                                    if AddNewTrustedRootCertForFabric had not yet been called for the given `fabricIndex`.
     153              :      *
     154              :      * @retval other CHIP_ERROR value on internal errors
     155              :      */
     156              :     virtual CHIP_ERROR AddNewOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc, const ByteSpan & icac) = 0;
     157              : 
     158              :     /**
     159              :      * @brief Update and temporarily activate an existing operational certificate chain for the given fabric.
     160              :      *
     161              :      * The certificate chain is temporary until committed or reverted.
     162              :      * The certificate chain is committed to storage on `CommitOpCertsForFabric`.
     163              :      * The certificate chain is reverted to prior storage if `RevertPendingOpCerts` is called
     164              :      * before `CommitOpCertsForFabric`.
     165              :      *
     166              :      * Only one pending operational certificate chain is supported at a time and it is illegal
     167              :      * to call this method if there was not already a persisted certificate chain for the given
     168              :      * fabric.
     169              :      *
     170              :      * Cryptographic signature verification or path validation are not enforced by this method.
     171              :      *
     172              :      * If `AddNewOpCertsForFabric` had been called before this method, this method will return
     173              :      * CHIP_ERROR_INCORRECT_STATE since it is illegal to update a certificate chain after
     174              :      * adding an existing NOC and before committing or reverting the addition.
     175              :      *
     176              :      * If there is no existing persisted trusted root certificate and NOC chain for the given
     177              :      * fabricIndex, this method will return CHIP_ERROR_INCORRECT_STATE since it is
     178              :      * illegal in this implementation to store an NOC chain without associated root, and it is illegal
     179              :      * to update an opcert for a fabric not already configured.
     180              :      *
     181              :      * @param fabricIndex - FabricIndex for which to update the operational certificate chain
     182              :      * @param noc - Buffer containing the new NOC certificate to use
     183              :      * @param icac - Buffer containing the ICAC certificate to use. If no ICAC is needed, `icac.empty()` must be true.
     184              :      *
     185              :      * @retval CHIP_NO_ERROR on success
     186              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to maintain the temporary `noc` and `icac` cert copies
     187              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if either the noc or icac are invalid sizes
     188              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized, if this method
     189              :      *                                    is called after `AddNewOpCertsForFabric`, if there was
     190              :      *                                    already a pending cert chain for the given `fabricIndex`, if there are
     191              :      *                                    no associated persisted root and NOC chain for the given `fabricIndex`,
     192              :      *                                    or if a VVSC is present and `icac` is not empty.
     193              :      * @retval other CHIP_ERROR value on internal errors
     194              :      */
     195              :     virtual CHIP_ERROR UpdateOpCertsForFabric(FabricIndex fabricIndex, const ByteSpan & noc, const ByteSpan & icac) = 0;
     196              : 
     197              :     /**
     198              :      * @brief Permanently commit the certificate chain last configured via successful calls to
     199              :      *        legal combinations of `AddNewTrustedRootCertForFabric`, `AddNewOpCertsForFabric` or
     200              :      *        `UpdateOpCertsForFabric`, replacing previously committed data, if any.
     201              :      *
     202              :      * This is to be used when CommissioningComplete is successfully received
     203              :      *
     204              :      * @param fabricIndex - FabricIndex for which to commit the certificate chain, used for security cross-checking
     205              :      *
     206              :      * @retval CHIP_NO_ERROR on success
     207              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized,
     208              :      *                                    or if no valid pending state is available.
     209              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no pending certificate chain for `fabricIndex`
     210              :      * @retval other CHIP_ERROR value on internal storage errors
     211              :      */
     212              :     virtual CHIP_ERROR CommitOpCertsForFabric(FabricIndex fabricIndex) = 0;
     213              : 
     214              :     /**
     215              :      * @brief Permanently remove the certificate chain associated with a fabric.
     216              :      *
     217              :      * This is to be used for RemoveFabric. Removes both the pending operational cert chain
     218              :      * elements for the fabricIndex (if any) and the committed ones (if any).
     219              :      *
     220              :      * This must also remove any VID Verification statement elements, if they exist, since
     221              :      * those are associated with the opcerts.
     222              :      *
     223              :      * @param fabricIndex - FabricIndex for which to remove the operational cert chain
     224              :      *
     225              :      * @retval CHIP_NO_ERROR on success
     226              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized.
     227              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there was no operational certificate data at all for `fabricIndex`
     228              :      * @retval other CHIP_ERROR value on internal storage errors
     229              :      */
     230              :     virtual CHIP_ERROR RemoveOpCertsForFabric(FabricIndex fabricIndex) = 0;
     231              : 
     232              :     /**
     233              :      * @brief Permanently release the operational certificate chain made via successful calls to
     234              :      *        legal combinations of `AddNewTrustedRootCertForFabric`, `AddNewOpCertsForFabric` or
     235              :      *        `UpdateOpCertsForFabric`, if any.
     236              :      *
     237              :      * This is to be used when a fail-safe expires prior to CommissioningComplete.
     238              :      *
     239              :      * This method cannot error-out and must always succeed, even on a no-op. This should
     240              :      * be safe to do given that `CommitOpCertsForFabric` must succeed to make an operation
     241              :      * certificate chain usable.
     242              :      */
     243              :     virtual void RevertPendingOpCerts() = 0;
     244              : 
     245              :     /**
     246              :      * @brief Update the VidVerificationSigningCertificate (VVSC) for the given fabric, including
     247              :      *        possibly removing it (if an empty vvsc buffer is provided).
     248              :      *
     249              :      * If a fabric was pending, the certificate is temporary until committed by `CommitOpCertsForFabric`
     250              :      * or reverted by `RevertPendingOpCerts`. Otherwise it is immediately commited/erased.
     251              :      *
     252              :      * Only one pending VVSC certificate is supported at a time and it is illegal
     253              :      * to call this method if there was is not already an operational certificate chain
     254              :      * pending or committed for the given fabric.
     255              :      *
     256              :      * Cryptographic signature verification or path validation are not enforced by this method.
     257              :      *
     258              :      * If there is no existing persisted or pending trusted root certificate and NOC chain for the given
     259              :      * fabricIndex, this method will return CHIP_ERROR_INCORRECT_STATE since it is
     260              :      * illegal in this implementation to store a VVSC without a fabric already there.
     261              :      *
     262              :      * @param fabricIndex - FabricIndex for which to update the VidVerificationSigningCert
     263              :      * @param vvsc - Buffer containing the VVSC payload
     264              :      *
     265              :      * @retval CHIP_NO_ERROR on success
     266              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to maintain the temporary `vvsc` cert copy
     267              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if the VVSC is an invalid size
     268              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized, or if there are
     269              :      *                                    no associated root and NOC chain for the given `fabricIndex`.
     270              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if this method is not implemented (e.g. for simple controller-only cases).
     271              :      * @retval other CHIP_ERROR value on internal errors
     272              :      */
     273            0 :     virtual CHIP_ERROR UpdateVidVerificationSignerCertForFabric(FabricIndex fabricIndex, ByteSpan vvsc)
     274              :     {
     275            0 :         return CHIP_ERROR_NOT_IMPLEMENTED;
     276              :     }
     277              : 
     278              :     /**
     279              :      * @brief Update the VidVerificationStatement for the given fabric, including
     280              :      *        possibly removing it (if an empty `vidVerificationStatement` buffer is provided).
     281              :      *
     282              :      * If a fabric was pending, the statement is temporary until committed by `CommitOpCertsForFabric`
     283              :      * or reverted by `RevertPendingOpCerts`. Otherwise it is immediately commited/erased.
     284              :      *
     285              :      * Only one pending statement is supported at a time and it is illegal
     286              :      * to call this method if there was is not already an operational certificate chain
     287              :      * pending or committed for the given fabric.
     288              :      *
     289              :      * If there is no existing persisted or pending trusted root certificate and NOC chain for the given
     290              :      * fabricIndex, this method will return CHIP_ERROR_INCORRECT_STATE since it is
     291              :      * illegal in this implementation to store a VVSC without a fabric already there.
     292              :      *
     293              :      * @param fabricIndex - FabricIndex for which to update the VidVerificationSigningCert
     294              :      * @param vidVerificationStatement - Buffer containing the VidVerificationStatement payload
     295              :      *
     296              :      * @retval CHIP_NO_ERROR on success
     297              :      * @retval CHIP_ERROR_NO_MEMORY if there is insufficient memory to maintain the temporary `vidVerificatioNStatement` copy
     298              :      * @retval CHIP_ERROR_INVALID_ARGUMENT if the vidVerificationStatement is an invalid format
     299              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized, or if there are
     300              :      *                                    no associated root and NOC chain for the given `fabricIndex`.
     301              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if this method is not implemented (e.g. for simple controller-only cases).
     302              :      * @retval other CHIP_ERROR value on internal errors
     303              :      */
     304            0 :     virtual CHIP_ERROR UpdateVidVerificationStatementForFabric(FabricIndex fabricIndex, ByteSpan vidVerificationStatement)
     305              :     {
     306            0 :         return CHIP_ERROR_NOT_IMPLEMENTED;
     307              :     }
     308              : 
     309              :     /**
     310              :      * @brief Same as RevertPendingOpCerts(), but leaves pending Trusted Root certs if they had
     311              :      *        been added. This is is an operation to support the complex error handling of
     312              :      *        AddNOC, where we don't want to have "sticking" ICAC/NOC after validation
     313              :      *        problems, but don't want to lose the RCAC given in an AddTrustedRootCertificate
     314              :      *        command.
     315              :      */
     316              :     virtual void RevertPendingOpCertsExceptRoot() = 0;
     317              : 
     318              :     /**
     319              :      * @brief Get the operational certificate element requested, giving the pending data or committed
     320              :      *        data depending on prior `AddNewTrustedRootCertForFabric`, `AddNewOpCertsForFabric` or
     321              :      *        `UpdateOpCertsForFabric` calls.
     322              :      *
     323              :      * On success, the `outCertificate` span is resized to the size of the actual certificate read-back.
     324              :      *
     325              :      * @param fabricIndex - fabricIndex for which to get the certificate
     326              :      * @param element - which element of the cerficate chain to get
     327              :      * @param outCertificate - buffer to contain the certificate obtained from persistent or temporary storage
     328              :      *
     329              :      * @retval CHIP_NO_ERROR on success.
     330              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCertificate` is too small to fit the certificate found.
     331              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized.
     332              :      * @retval CHIP_ERROR_NOT_FOUND if the element cannot be found.
     333              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if the fabricIndex is invalid.
     334              :      * @retval other CHIP_ERROR value on internal storage errors.
     335              :      */
     336              :     virtual CHIP_ERROR GetCertificate(FabricIndex fabricIndex, CertChainElement element,
     337              :                                       MutableByteSpan & outCertificate) const = 0;
     338              : 
     339              :     /**
     340              :      * @brief Get the VidVerification element requested, giving the pending data or committed
     341              :      *        data depending on prior `UpdateVidVerificationSignerCertForFabric`, or
     342              :      *        `UpdateVidVerificationStatemmentForFabric` calls.
     343              :      *
     344              :      * If element is not found, outElement is resized to 0 bytes (empty).
     345              :      *
     346              :      * On success, the `outElement` span is resized to the size of the actual element read-back.
     347              :      *
     348              :      * @param fabricIndex - fabricIndex for which to get the certificate
     349              :      * @param element - which element to get
     350              :      * @param outElement- buffer to contain the element obtained from persistent or temporary storage
     351              :      *
     352              :      * @retval CHIP_NO_ERROR on success.
     353              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outElement` is too small to fit the certificate found.
     354              :      * @retval CHIP_ERROR_INCORRECT_STATE if the certificate store is not properly initialized.
     355              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if the fabricIndex is invalid.
     356              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if this method is not implemented (e.g. for simple controller-only cases).
     357              :      * @retval other CHIP_ERROR value on internal storage errors.
     358              :      */
     359            0 :     virtual CHIP_ERROR GetVidVerificationElement(FabricIndex fabricIndex, VidVerificationElement element,
     360              :                                                  MutableByteSpan & outElement) const
     361              :     {
     362            0 :         return CHIP_ERROR_NOT_IMPLEMENTED;
     363              :     }
     364              : };
     365              : 
     366              : /**
     367              :  * @brief RAII class to operate on an OperationalCertificateStore with auto-revert if not committed.
     368              :  *
     369              :  * Use as:
     370              :  *
     371              :  * CHIP_ERROR FunctionWillReturnWithPendingReverted(....)
     372              :  * {
     373              :  *     OpCertStoreTransaction transaction(opCertStore);
     374              :  *
     375              :  *     ReturnErrorOnFailure(transaction->AddNewTrustedRootCertForFabric(...));
     376              :  *     ReturnErrorOnFailure(transaction->AddNewOpCertsForFabric(...));
     377              :  *     ReturnErrorOnFailure(transaction->CommitOpCertsForFabric(...));
     378              :  *
     379              :  *     return CHIP_NO_ERROR;
     380              :  * }
     381              :  */
     382              : class OpCertStoreTransaction
     383              : {
     384              : public:
     385              :     explicit OpCertStoreTransaction(OperationalCertificateStore & store) : mStore(store) {}
     386              :     ~OpCertStoreTransaction()
     387              :     {
     388              :         // This is a no-op if CommitOpCertsForFabric had been called on the store
     389              :         mStore.RevertPendingOpCerts();
     390              :     }
     391              : 
     392              :     // Non-copyable
     393              :     OpCertStoreTransaction(OpCertStoreTransaction const &) = delete;
     394              :     void operator=(OpCertStoreTransaction const &)         = delete;
     395              : 
     396              :     OperationalCertificateStore * operator->() { return &mStore; }
     397              : 
     398              : private:
     399              :     OperationalCertificateStore & mStore;
     400              : };
     401              : 
     402              : } // namespace Credentials
     403              : } // namespace chip
        

Generated by: LCOV version 2.0-1