Matter SDK Coverage Report
Current view: top level - crypto - OperationalKeystore.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 16.7 % 6 1
Test Date: 2025-01-17 19:00:11 Functions: 20.0 % 5 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 <crypto/CHIPCryptoPAL.h>
      21              : #include <lib/core/CHIPError.h>
      22              : #include <lib/core/DataModelTypes.h>
      23              : #include <lib/support/Span.h>
      24              : 
      25              : namespace chip {
      26              : namespace Crypto {
      27              : 
      28              : class OperationalKeystore
      29              : {
      30              : public:
      31            1 :     virtual ~OperationalKeystore() {}
      32              : 
      33              :     // ==== API designed for commisionables to support fail-safe (although can be used by controllers) ====
      34              : 
      35              :     /**
      36              :      * @brief Returns true if a pending operational key exists from a previous
      37              :      *        `NewOpKeypairForFabric` before any `CommitOpKeypairForFabric` or
      38              :      *        `RevertOpKeypairForFabric`. This returns true even if the key is
      39              :      *        NOT ACTIVE (i.e after `NewOpKeypairForFabric` but before
      40              :      *        `ActivateOpKeypairForFabric`).
      41              :      */
      42              :     virtual bool HasPendingOpKeypair() const = 0;
      43              : 
      44              :     /**
      45              :      * @brief Returns whether a usable operational key exists for the given fabric.
      46              :      *
      47              :      * Returns true even if the key is not persisted, such as if `ActivateOpKeypairForFabric`
      48              :      * had been successfully called for a given fabric. Only returns true if a key
      49              :      * is presently usable such that `SignWithOpKeypair` would succeed for the fabric. Therefore
      50              :      * if there was no previously persisted key and `NewOpKeypairForFabric` had been called
      51              :      * but not `ActivateOpKeypairForFabric`, there is only an inactive key, and this would return false.
      52              :      *
      53              :      * @param fabricIndex - FabricIndex for which availability of keypair will be checked.
      54              :      * @return true if there an active operational keypair for the given FabricIndex, false otherwise.
      55              :      */
      56              :     virtual bool HasOpKeypairForFabric(FabricIndex fabricIndex) const = 0;
      57              : 
      58              :     /**
      59              :      * @brief This initializes a new keypair for the given fabric and generates a CSR for it,
      60              :      *        so that it can be passed in a CSRResponse.
      61              :      *
      62              :      * The keypair is temporary and becomes usable for `SignWithOpKeypair` only after either
      63              :      * `ActivateOpKeypairForFabric` is called. It is destroyed if
      64              :      * `RevertPendingKeypair` is called before `CommitOpKeypairForFabric`.
      65              :      *  If a pending keypair already existed for the given `fabricIndex`, it is replaced by this call.
      66              :      *
      67              :      *  Only one pending operational keypair is supported at a time.
      68              :      *
      69              :      * @param fabricIndex - FabricIndex for which a new keypair must be made available
      70              :      * @param outCertificateSigningRequest - Buffer to contain the CSR. Must have size at least `kMIN_CSR_Buffer_Size`.
      71              :      *
      72              :      * @retval CHIP_NO_ERROR on success
      73              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outCertificateSigningRequest` buffer is too small
      74              :      * @retval CHIP_ERROR_INCORRECT_STATE if the key store is not properly initialized.
      75              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is already a pending keypair for another `fabricIndex` value
      76              :      *                                         or if fabricIndex is an invalid value.
      77              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if only `SignWithOpKeypair` is supported
      78              :      * @retval other CHIP_ERROR value on internal crypto engine errors
      79              :      */
      80              :     virtual CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) = 0;
      81              : 
      82              :     /**
      83              :      * @brief Temporarily activates the operational keypair last generated with `NewOpKeypairForFabric`, so
      84              :      *        that `SignWithOpKeypair` starts using it, but only if it matches the public key associated
      85              :      *        with the last NewOpKeypairForFabric.
      86              :      *
      87              :      * This is to be used by AddNOC and UpdateNOC so that a prior key generated by NewOpKeypairForFabric
      88              :      * can be used for CASE while not committing it yet to permanent storage to remain after fail-safe.
      89              :      *
      90              :      * @param fabricIndex - FabricIndex for which to activate the keypair, used for security cross-checking
      91              :      * @param nocPublicKey - Subject public key associated with an incoming NOC
      92              :      *
      93              :      * @retval CHIP_NO_ERROR on success
      94              :      * @retval CHIP_ERROR_INCORRECT_STATE if the key store is not properly initialized.
      95              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no operational keypair for `fabricIndex` from a previous
      96              :      *                                         matching `NewOpKeypairForFabric`.
      97              :      * @retval CHIP_ERROR_INVALID_PUBLIC_KEY if `nocPublicKey` does not match the public key associated with the
      98              :      *                                       key pair from last `NewOpKeypairForFabric`.
      99              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if only `SignWithOpKeypair` is supported
     100              :      * @retval other CHIP_ERROR value on internal storage or crypto engine errors
     101              :      */
     102              :     virtual CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey) = 0;
     103              : 
     104              :     /**
     105              :      * @brief Permanently commit the operational keypair last generated with `NewOpKeypairForFabric`,
     106              :      *        replacing a prior one previously committed, if any, so that `SignWithOpKeypair` for the
     107              :      *        given `FabricIndex` permanently uses the key that was pending.
     108              :      *
     109              :      * This is to be used when CommissioningComplete is successfully received
     110              :      *
     111              :      * @param fabricIndex - FabricIndex for which to commit the keypair, used for security cross-checking
     112              :      *
     113              :      * @retval CHIP_NO_ERROR on success
     114              :      * @retval CHIP_ERROR_INCORRECT_STATE if the key store is not properly initialized,
     115              :      *                                    or ActivateOpKeypairForFabric not yet called
     116              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no pending operational keypair for `fabricIndex`
     117              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if only `SignWithOpKeypair` is supported
     118              :      * @retval other CHIP_ERROR value on internal storage or crypto engine errors
     119              :      */
     120              :     virtual CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) = 0;
     121              : 
     122              :     /**
     123              :      * @brief Try to read out the permanently committed operational keypair and save it to the buffer.
     124              :      *
     125              :      * @param fabricIndex - FabricIndex from which the keypair will be exported
     126              :      * @param outKeypair - a reference to P256SerializedKeypair object to store the exported key.
     127              :      * @retval CHIP_ERROR on success.
     128              :      * @retval CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if the key cannot be exported due to security restrictions.
     129              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if the exporting is not implemented for the cryptography backend.
     130              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if provided wrong value of `fabricIndex`.
     131              :      * @retval CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND if there is no keypair found for `fabricIndex`.
     132              :      * @retval CHIP_ERROR_BUFFER_TOO_SMALL if `outKeyPair` buffer is too small to store the read out keypair.
     133              :      * @retval other CHIP_ERROR value on internal storage or cryptography backend errors.
     134              :      */
     135            0 :     virtual CHIP_ERROR ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair)
     136              :     {
     137            0 :         return CHIP_ERROR_NOT_IMPLEMENTED;
     138              :     };
     139              : 
     140              :     /**
     141              :      * @brief Migrate the operational keypair from another Operational keystore (`operationalKeystore`) implementation to this one.
     142              :      *
     143              :      * This method assumes that the operational key for given `fabricIndex` exists in the `operationalKeystore` storage or it has
     144              :      * been already migrated to the new Operational Storage. If a key for the given `fabricIndex` does not exist in any of those
     145              :      * keystores, then the method retuns CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND.
     146              :      *
     147              :      * @param fabricIndex - FabricIndex for which to migrate the operational key
     148              :      * @param operationalKeystore - a reference to the operationalKeystore implementation that may contain saved operational key
     149              :      * for Fabric
     150              :      * @retval CHIP_ERROR on success
     151              :      * @retval CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if the key cannot be exported due to security restrictions.
     152              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if the exporting is not implemented for the cryptography backend.
     153              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no keypair found for `fabricIndex`.
     154              :      * @retval CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND if there is no keypair found for `fabricIndex`.
     155              :      * @retval other CHIP_ERROR value on internal storage or crypto engine errors.
     156              :      */
     157            0 :     virtual CHIP_ERROR MigrateOpKeypairForFabric(FabricIndex fabricIndex, OperationalKeystore & operationalKeystore) const
     158              :     {
     159            0 :         return CHIP_ERROR_NOT_IMPLEMENTED;
     160              :     };
     161              : 
     162              :     /**
     163              :      * @brief Permanently remove the keypair associated with a fabric
     164              :      *
     165              :      * This is to be used for fail-safe handling and RemoveFabric.  Removes both the
     166              :      * pending operational keypair for the fabricIndex (if any) and the committed one (if any).
     167              :      *
     168              :      * @param fabricIndex - FabricIndex for which to remove the keypair
     169              :      *
     170              :      * @retval CHIP_NO_ERROR on success
     171              :      * @retval CHIP_ERROR_INCORRECT_STATE if the key store is not properly initialized.
     172              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if there is no operational keypair for `fabricIndex`
     173              :      * @retval CHIP_ERROR_NOT_IMPLEMENTED if only `SignWithOpKeypair` is supported
     174              :      * @retval other CHIP_ERROR value on internal storage errors
     175              :      */
     176              :     virtual CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) = 0;
     177              : 
     178              :     /**
     179              :      * @brief Permanently release the operational keypair last generated with `NewOpKeypairForFabric`,
     180              :      *        such that `SignWithOpKeypair` uses the previously committed key (if one existed).
     181              :      *
     182              :      * This is to be used when a fail-safe expires prior to CommissioningComplete.
     183              :      *
     184              :      * This method cannot error-out and must always succeed, even on a no-op. This should
     185              :      * be safe to do given that `CommitOpKeypairForFabric` must succeed to make a new operational
     186              :      * keypair usable.
     187              :      */
     188              :     virtual void RevertPendingKeypair() = 0;
     189              : 
     190              :     // ==== Primary operation required: signature
     191              :     /**
     192              :      * @brief Whether `SignWithOpKeypair` may be performed in the background.
     193              :      *
     194              :      * If true, `CASESession` may attempt to perform `SignWithOpKeypair` in the
     195              :      * background. In this case, `OperationalKeystore` should protect itself,
     196              :      * e.g. with a mutex, as the signing could occur at any time during session
     197              :      * establishment.
     198              :      *
     199              :      * @retval true if `SignWithOpKeypair` may be performed in the background
     200              :      * @retval false if `SignWithOpKeypair` may NOT be performed in the background
     201              :      */
     202            0 :     virtual bool SupportsSignWithOpKeypairInBackground() const { return false; }
     203              : 
     204              :     /**
     205              :      * @brief Sign a message with a fabric's currently-active operational keypair.
     206              :      *
     207              :      * If a Keypair was successfully made temporarily active for the given `fabricIndex` with `ActivateOpKeypairForFabric`,
     208              :      * then that is the keypair whose private key is used. Otherwise, the last committed private key
     209              :      * is used, if one exists
     210              :      *
     211              :      * @param fabricIndex - FabricIndex whose operational keypair will be used to sign the `message`
     212              :      * @param message - Message to sign with the currently active operational keypair
     213              :      * @param outSignature - Buffer to contain the signature
     214              :      *
     215              :      * @retval CHIP_NO_ERROR on success
     216              :      * @retval CHIP_ERROR_INCORRECT_STATE if the key store is not properly initialized.
     217              :      * @retval CHIP_ERROR_INVALID_FABRIC_INDEX if no active key is found for the given `fabricIndex` or if
     218              :      *                                         `fabricIndex` is invalid.
     219              :      * @retval other CHIP_ERROR value on internal crypto engine errors
     220              :      */
     221              :     virtual CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message,
     222              :                                          Crypto::P256ECDSASignature & outSignature) const = 0;
     223              : 
     224              :     /**
     225              :      * @brief Create an ephemeral keypair for use in session establishment.
     226              :      *
     227              :      * The caller must Initialize() the P256Keypair if needed. It is not done by this method.
     228              :      *
     229              :      * This method MUST ONLY be used for CASESession ephemeral keys.
     230              :      *
     231              :      * NOTE: The stack will allocate as many of these as there are CASE sessions which
     232              :      *       can be concurrently in the process of establishment. Implementations must
     233              :      *       support more than one such keypair, or be implemented to match the limitations
     234              :      *       enforced by a given product on its concurrent CASE session establishment limits.
     235              :      *
     236              :      * WARNING: The return value MUST be released by `ReleaseEphemeralKeypair`. This is because
     237              :      *          Matter CHIPMem.h does not properly support UniquePtr in a way that would
     238              :      *          safely allow classes derived from Crypto::P256Keypair to be released properly.
     239              :      *
     240              :      * @return a pointer to a P256Keypair (or derived class thereof), which may evaluate to nullptr
     241              :      *         if running out of memory.
     242              :      */
     243              :     virtual Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() = 0;
     244              : 
     245              :     /**
     246              :      * @brief Release an ephemeral keypair previously provided by `AllocateEphemeralKeypairForCASE()`
     247              :      */
     248              :     virtual void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) = 0;
     249              : };
     250              : 
     251              : } // namespace Crypto
     252              : } // namespace chip
        

Generated by: LCOV version 2.0-1