Matter SDK Coverage Report
Current view: top level - app/icd/server - ICDMonitoringTable.h (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 100.0 % 13 13
Test Date: 2025-02-22 08:08:07 Functions: 100.0 % 2 2

            Line data    Source code
       1              : /**
       2              :  *
       3              :  *    Copyright (c) 2023 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              : #pragma once
      18              : 
      19              : #include <crypto/CHIPCryptoPAL.h>
      20              : #include <crypto/SessionKeystore.h>
      21              : #include <lib/core/CHIPConfig.h>
      22              : #include <lib/core/CHIPPersistentStorageDelegate.h>
      23              : #include <lib/core/ClusterEnums.h>
      24              : #include <lib/core/DataModelTypes.h>
      25              : #include <lib/support/CodeUtils.h>
      26              : #include <lib/support/PersistentData.h>
      27              : #include <stddef.h>
      28              : 
      29              : namespace chip {
      30              : namespace Crypto {
      31              : using SymmetricKeystore = SessionKeystore;
      32              : }
      33              : } // namespace chip
      34              : 
      35              : namespace chip {
      36              : 
      37              : static constexpr size_t MaxICDMonitoringEntrySize()
      38              : {
      39              :     // All the fields added together
      40              :     return TLV::EstimateStructOverhead(sizeof(NodeId) /*checkInNodeID*/, sizeof(uint64_t) /*monitoredSubject*/,
      41              :                                        sizeof(Crypto::Symmetric128BitsKeyByteArray) /*aes_key_handle*/,
      42              :                                        sizeof(Crypto::Symmetric128BitsKeyByteArray) /*hmac_key_handle*/,
      43              :                                        sizeof(uint8_t) /*client_type*/) *
      44              :         // Provide 50% extra space to make a firmware upgrade that starts storing
      45              :         // more data followed by a downgrade work easily and reliably.
      46              :         // The 50% number is chosen fairly randomly; storage increases larger than that are
      47              :         // possible but need to be staged carefully.
      48              :         3 / 2;
      49              : }
      50              : 
      51              : inline constexpr size_t kICDMonitoringBufferSize = MaxICDMonitoringEntrySize();
      52              : 
      53              : struct ICDMonitoringEntry : public PersistentData<kICDMonitoringBufferSize>
      54              : {
      55           13 :     ICDMonitoringEntry(FabricIndex fabric = kUndefinedFabricIndex, NodeId nodeId = kUndefinedNodeId)
      56           13 :     {
      57           13 :         this->fabricIndex      = fabric;
      58           13 :         this->checkInNodeID    = nodeId;
      59           13 :         this->monitoredSubject = nodeId;
      60           13 :     }
      61              : 
      62           44 :     ICDMonitoringEntry(Crypto::SymmetricKeystore * keyStore, FabricIndex fabric = kUndefinedFabricIndex,
      63              :                        NodeId nodeId = kUndefinedNodeId)
      64           44 :     {
      65           44 :         this->fabricIndex       = fabric;
      66           44 :         this->checkInNodeID     = nodeId;
      67           44 :         this->monitoredSubject  = nodeId;
      68           44 :         this->symmetricKeystore = keyStore;
      69           44 :     }
      70              : 
      71              :     CHIP_ERROR UpdateKey(StorageKeyName & key) override;
      72              :     CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override;
      73              :     CHIP_ERROR Deserialize(TLV::TLVReader & reader) override;
      74              :     void Clear() override;
      75              :     /**
      76              :      * @brief Set the Key object
      77              :      *        This method will create a new keyHandle. The key handle might contain either
      78              :      *        the raw key or a keyID depending on which Crypto implementation is used.
      79              :      *        To avoid leaking keys, API consumers must either call the DeleteKey method
      80              :      *        or save the entry within the ICDMonitoring Table before this object goes out of scope.
      81              :      *
      82              :      *        A new entry object should be used for each key when adding entries to the ICDMonitoring
      83              :      *        table.
      84              :      *
      85              :      * @param keyData A byte span containing the raw key
      86              :      * @return CHIP_ERROR CHIP_NO_ERROR     success
      87              :      *         CHIP_ERROR_INVALID_ARGUMENT  wrong size of the raw key
      88              :      *         CHIP_ERROR_INTERNAL          No KeyStore for the entry or Key Handle already present
      89              :      *         CHIP_ERROR_XXX               Crypto API related failure
      90              :      */
      91              :     CHIP_ERROR SetKey(ByteSpan keyData);
      92              :     CHIP_ERROR DeleteKey(void);
      93              :     inline bool IsValid()
      94              :     {
      95              :         return (symmetricKeystore != nullptr && keyHandleValid && fabricIndex != kUndefinedFabricIndex &&
      96              :                 checkInNodeID != kUndefinedNodeId);
      97              :     }
      98              : 
      99              :     ICDMonitoringEntry & operator=(const ICDMonitoringEntry & icdMonitoringEntry);
     100              : 
     101              :     /**
     102              :      * @brief Implement the key verification needed by the ICDManagement Server.
     103              :      *        Since for some key implementations we cannot retrieve the key from the AES128KeyHandle
     104              :      *        we must implement a way to deduce whether the verification key
     105              :      *        received is the same or at least works as the same way as the one stored.
     106              :      *
     107              :      *        This method will produce a random number and then encrypt it with the keyData.
     108              :      *        It will then decrypt it with the key stored in the entry. If the resulting decrypted
     109              :      *        challenge matches the randomly generated number, then we can safely assume that both key are interchangeable.
     110              :      *        This method cannot guarantee a perfect match since the probability of two keys generating the same output in AES128 is
     111              :      *        not 0 but 1/2^128 which is small enough for our purposes.
     112              :      *
     113              :      * @param keyData
     114              :      * @return bool True if the key is equivalent to the one stored, otherwise false
     115              :      */
     116              :     bool IsKeyEquivalent(ByteSpan keyData);
     117              : 
     118              :     chip::FabricIndex fabricIndex                           = kUndefinedFabricIndex;
     119              :     chip::NodeId checkInNodeID                              = kUndefinedNodeId;
     120              :     uint64_t monitoredSubject                               = static_cast<uint64_t>(0);
     121              :     app::Clusters::IcdManagement::ClientTypeEnum clientType = app::Clusters::IcdManagement::ClientTypeEnum::kPermanent;
     122              :     Crypto::Aes128KeyHandle aesKeyHandle                    = Crypto::Aes128KeyHandle();
     123              :     Crypto::Hmac128KeyHandle hmacKeyHandle                  = Crypto::Hmac128KeyHandle();
     124              :     bool keyHandleValid                                     = false;
     125              :     uint16_t index                                          = 0;
     126              :     Crypto::SymmetricKeystore * symmetricKeystore           = nullptr;
     127              : };
     128              : 
     129              : /**
     130              :  * @brief ICDMonitoringTable exists to manage the persistence of entries in the IcdManagement Cluster.
     131              :  *        To access persisted data with the ICDMonitoringTable class, instantiate an instance of this class
     132              :  *        and call the LoadFromStorage function.
     133              :  *
     134              :  *        This class can only manage one fabric at a time. The flow is load a fabric, execute necessary operations,
     135              :  *        save it if there are any changes and load another fabric.
     136              :  *
     137              :  *        Issue to refactor the class to use one entry for the entire table
     138              :  *        https://github.com/project-chip/connectedhomeip/issues/24288
     139              :  */
     140              : 
     141              : struct ICDMonitoringTable
     142              : {
     143              :     ICDMonitoringTable(PersistentStorageDelegate & storage, FabricIndex fabric, uint16_t limit,
     144              :                        Crypto::SymmetricKeystore * symmetricKeystore) :
     145              :         mStorage(&storage),
     146              :         mFabric(fabric), mLimit(limit), mSymmetricKeystore(symmetricKeystore)
     147              :     {}
     148              : 
     149              :     /**
     150              :      * @brief Returns the MonitoringRegistrationStruct entry at the given position.
     151              :      * @param index Zero-based position within the RegisteredClients table.
     152              :      * @param entry On success, contains the MonitoringRegistrationStruct matching the given index.
     153              :      * @return CHIP_NO_ERROR on success,
     154              :      *         CHIP_ERROR_NOT_FOUND if index is greater than the index of the last entry on the table.
     155              :      */
     156              :     CHIP_ERROR Get(uint16_t index, ICDMonitoringEntry & entry) const;
     157              : 
     158              :     /**
     159              :      * @brief Stores the MonitoringRegistrationStruct entry at the given position,
     160              :      *        overwriting any existing entry.
     161              :      * @param index Zero-based position within the RegisteredClients table.
     162              :      * @param entry On success, contains the MonitoringRegistrationStruct matching the given index.
     163              :      * @return CHIP_NO_ERROR on success
     164              :      */
     165              :     CHIP_ERROR Set(uint16_t index, const ICDMonitoringEntry & entry);
     166              : 
     167              :     /**
     168              :      * @brief Search the registered clients for an entry on the fabric whose checkInNodeID matches the given id.
     169              :      * @param id    NodeId to match.
     170              :      * @param entry On success, contains the MonitoringRegistrationStruct matching the given node ID.
     171              :      *  If found, entry.index contains the position of the entry in the table.
     172              :      *  If CHIP_ERROR_NOT_FOUND is returned, entry.index contains the total number of entries in the table.
     173              :      * @return CHIP_NO_ERROR if found, CHIP_ERROR_NOT_FOUND if no checkInNodeID matches the provided id.
     174              :      */
     175              :     CHIP_ERROR Find(NodeId id, ICDMonitoringEntry & entry);
     176              : 
     177              :     /**
     178              :      * @brief Removes the MonitoringRegistrationStruct entry at the given position,
     179              :      *        shifting down the upper entries.
     180              :      * @param index Zero-based position within the RegisteredClients table.
     181              :      * @return CHIP_NO_ERROR on success
     182              :      */
     183              :     CHIP_ERROR Remove(uint16_t index);
     184              : 
     185              :     /**
     186              :      * @brief Removes all the entries for the current fabricIndex.
     187              :      * @return CHIP_NO_ERROR on success
     188              :      */
     189              :     CHIP_ERROR RemoveAll();
     190              : 
     191              :     /**
     192              :      * @brief Check if the table is empty
     193              :      * @return True when there is no entry in the table. False if there is at least one
     194              :      */
     195              :     bool IsEmpty();
     196              : 
     197              :     /**
     198              :      * @return Maximum number of entries allowed in the RegisteredClients table.
     199              :      */
     200              :     uint16_t Limit() const;
     201              : 
     202              : private:
     203              :     PersistentStorageDelegate * mStorage;
     204              :     FabricIndex mFabric;
     205              :     uint16_t mLimit                                = 0;
     206              :     Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
     207              : };
     208              : 
     209              : } // namespace chip
        

Generated by: LCOV version 2.0-1