LCOV - code coverage report
Current view: top level - crypto - OperationalKeystore.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 1 6 16.7 %
Date: 2024-02-15 08:20:41 Functions: 1 5 20.0 %

          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 1.14