Matter SDK Coverage Report
Current view: top level - app/icd/server - ICDMonitoringTable.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 87.1 % 178 155
Test Date: 2025-02-22 08:08:07 Functions: 86.7 % 15 13

            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              : 
      18              : #include "ICDMonitoringTable.h"
      19              : 
      20              : #include <crypto/RandUtils.h>
      21              : 
      22              : namespace chip {
      23              : 
      24              : enum class Fields : uint8_t
      25              : {
      26              :     kCheckInNodeID    = 1,
      27              :     kMonitoredSubject = 2,
      28              :     kAesKeyHandle     = 3,
      29              :     kHmacKeyHandle    = 4,
      30              :     kClientType       = 5,
      31              : };
      32              : 
      33           44 : CHIP_ERROR ICDMonitoringEntry::UpdateKey(StorageKeyName & skey)
      34              : {
      35           44 :     VerifyOrReturnError(kUndefinedFabricIndex != this->fabricIndex, CHIP_ERROR_INVALID_FABRIC_INDEX);
      36           44 :     skey = DefaultStorageKeyAllocator::ICDManagementTableEntry(this->fabricIndex, index);
      37           44 :     return CHIP_NO_ERROR;
      38              : }
      39              : 
      40           12 : CHIP_ERROR ICDMonitoringEntry::Serialize(TLV::TLVWriter & writer) const
      41              : {
      42              :     TLV::TLVType outer;
      43           12 :     ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer));
      44           12 :     ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kCheckInNodeID), checkInNodeID));
      45           12 :     ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kMonitoredSubject), monitoredSubject));
      46              : 
      47           12 :     ByteSpan aesKeybuf(aesKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>());
      48           12 :     ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kAesKeyHandle), aesKeybuf));
      49              : 
      50           12 :     ByteSpan hmacKeybuf(hmacKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>());
      51           12 :     ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kHmacKeyHandle), hmacKeybuf));
      52              : 
      53           12 :     ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kClientType), clientType));
      54              : 
      55           12 :     ReturnErrorOnFailure(writer.EndContainer(outer));
      56           12 :     ReturnErrorOnFailure(writer.Finalize());
      57           12 :     return CHIP_NO_ERROR;
      58              : }
      59              : 
      60           18 : CHIP_ERROR ICDMonitoringEntry::Deserialize(TLV::TLVReader & reader)
      61              : {
      62              : 
      63           18 :     CHIP_ERROR err = CHIP_NO_ERROR;
      64              :     TLV::TLVType outer;
      65              : 
      66           18 :     ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag()));
      67           18 :     VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE);
      68           18 :     ReturnErrorOnFailure(reader.EnterContainer(outer));
      69          108 :     while ((err = reader.Next()) == CHIP_NO_ERROR)
      70              :     {
      71           90 :         if (TLV::IsContextTag(reader.GetTag()))
      72              :         {
      73           90 :             switch (TLV::TagNumFromTag(reader.GetTag()))
      74              :             {
      75           18 :             case to_underlying(Fields::kCheckInNodeID):
      76           18 :                 ReturnErrorOnFailure(reader.Get(checkInNodeID));
      77           18 :                 break;
      78           18 :             case to_underlying(Fields::kMonitoredSubject):
      79           18 :                 ReturnErrorOnFailure(reader.Get(monitoredSubject));
      80           18 :                 break;
      81           18 :             case to_underlying(Fields::kAesKeyHandle): {
      82           18 :                 ByteSpan buf;
      83           18 :                 ReturnErrorOnFailure(reader.Get(buf));
      84              :                 // Since we are storing either the raw key or a key ID, we must
      85              :                 // simply copy the data as is in the keyHandle.
      86              :                 // Calling SetKey here would create another keyHandle in storage and will cause
      87              :                 // key leaks in some implementations.
      88           18 :                 memcpy(aesKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(), buf.data(),
      89              :                        sizeof(Crypto::Symmetric128BitsKeyByteArray));
      90           18 :                 keyHandleValid = true;
      91              :             }
      92           18 :             break;
      93           18 :             case to_underlying(Fields::kHmacKeyHandle): {
      94           18 :                 ByteSpan buf;
      95           18 :                 CHIP_ERROR error = reader.Get(buf);
      96              : 
      97           18 :                 if (error != CHIP_NO_ERROR)
      98              :                 {
      99              :                     // If retreiving the hmac key handle failed, we need to set an invalid key handle
     100              :                     // even if the AesKeyHandle is valid.
     101            0 :                     keyHandleValid = false;
     102            0 :                     return error;
     103              :                 }
     104              : 
     105              :                 // Since we are storing either the raw key or a key ID, we must
     106              :                 // simply copy the data as is in the keyHandle.
     107              :                 // Calling SetKey here would create another keyHandle in storage and will cause
     108              :                 // key leaks in some implementations.
     109           18 :                 memcpy(hmacKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(), buf.data(),
     110              :                        sizeof(Crypto::Symmetric128BitsKeyByteArray));
     111              :             }
     112           18 :             break;
     113           18 :             case to_underlying(Fields::kClientType):
     114           18 :                 ReturnErrorOnFailure(reader.Get(clientType));
     115           18 :                 break;
     116            0 :             default:
     117            0 :                 break;
     118              :             }
     119              :         }
     120              :     }
     121              : 
     122           18 :     VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     123           18 :     ReturnErrorOnFailure(reader.ExitContainer(outer));
     124           18 :     return CHIP_NO_ERROR;
     125              : }
     126              : 
     127           27 : void ICDMonitoringEntry::Clear()
     128              : {
     129           27 :     this->checkInNodeID    = kUndefinedNodeId;
     130           27 :     this->monitoredSubject = kUndefinedNodeId;
     131           27 :     this->keyHandleValid   = false;
     132           27 :     this->clientType       = app::Clusters::IcdManagement::ClientTypeEnum::kPermanent;
     133           27 : }
     134              : 
     135           36 : CHIP_ERROR ICDMonitoringEntry::SetKey(ByteSpan keyData)
     136              : {
     137           36 :     VerifyOrReturnError(keyData.size() == sizeof(Crypto::Symmetric128BitsKeyByteArray), CHIP_ERROR_INVALID_ARGUMENT);
     138           33 :     VerifyOrReturnError(symmetricKeystore != nullptr, CHIP_ERROR_INTERNAL);
     139           33 :     VerifyOrReturnError(!keyHandleValid, CHIP_ERROR_INTERNAL);
     140              : 
     141              :     Crypto::Symmetric128BitsKeyByteArray keyMaterial;
     142           32 :     memcpy(keyMaterial, keyData.data(), sizeof(Crypto::Symmetric128BitsKeyByteArray));
     143              : 
     144           32 :     ReturnErrorOnFailure(symmetricKeystore->CreateKey(keyMaterial, aesKeyHandle));
     145           32 :     CHIP_ERROR error = symmetricKeystore->CreateKey(keyMaterial, hmacKeyHandle);
     146              : 
     147           32 :     if (error == CHIP_NO_ERROR)
     148              :     {
     149              :         // If the creation of the HmacKeyHandle succeeds, both key handles are valid
     150           32 :         keyHandleValid = true;
     151              :     }
     152              :     else
     153              :     {
     154              :         // Creation of the HmacKeyHandle failed, we need to delete the AesKeyHandle to avoid a key leak
     155            0 :         symmetricKeystore->DestroyKey(this->aesKeyHandle);
     156              :     }
     157              : 
     158           32 :     return error;
     159              : }
     160              : 
     161           22 : CHIP_ERROR ICDMonitoringEntry::DeleteKey()
     162              : {
     163           22 :     VerifyOrReturnError(symmetricKeystore != nullptr, CHIP_ERROR_INTERNAL);
     164           22 :     symmetricKeystore->DestroyKey(this->aesKeyHandle);
     165           22 :     symmetricKeystore->DestroyKey(this->hmacKeyHandle);
     166           22 :     keyHandleValid = false;
     167           22 :     return CHIP_NO_ERROR;
     168              : }
     169              : 
     170           15 : bool ICDMonitoringEntry::IsKeyEquivalent(ByteSpan keyData)
     171              : {
     172           15 :     VerifyOrReturnValue(keyData.size() == Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES, false);
     173           15 :     VerifyOrReturnValue(symmetricKeystore != nullptr, false);
     174           15 :     VerifyOrReturnValue(keyHandleValid, false);
     175              : 
     176           15 :     ICDMonitoringEntry tempEntry(symmetricKeystore);
     177              : 
     178           15 :     VerifyOrReturnValue(tempEntry.SetKey(keyData) == CHIP_NO_ERROR, false);
     179              : 
     180              :     // Challenge
     181           15 :     uint8_t mic[Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES]  = { 0 };
     182           15 :     uint8_t aead[Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES] = { 0 };
     183              : 
     184              :     CHIP_ERROR err;
     185              : 
     186           15 :     uint64_t data = Crypto::GetRandU64(), validation, encrypted;
     187           15 :     validation    = data;
     188              : 
     189           15 :     err = Crypto::AES_CCM_encrypt(reinterpret_cast<uint8_t *>(&data), sizeof(data), nullptr, 0, tempEntry.aesKeyHandle, aead,
     190              :                                   Crypto::CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, reinterpret_cast<uint8_t *>(&encrypted), mic,
     191              :                                   Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
     192              : 
     193           15 :     data = 0;
     194           15 :     if (err == CHIP_NO_ERROR)
     195              :     {
     196           15 :         err = Crypto::AES_CCM_decrypt(reinterpret_cast<uint8_t *>(&encrypted), sizeof(encrypted), nullptr, 0, mic,
     197           15 :                                       Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, aesKeyHandle, aead,
     198              :                                       Crypto::CHIP_CRYPTO_AEAD_NONCE_LENGTH_BYTES, reinterpret_cast<uint8_t *>(&data));
     199              :     }
     200           15 :     tempEntry.DeleteKey();
     201              : 
     202           15 :     if (err != CHIP_NO_ERROR)
     203              :     {
     204            1 :         return false;
     205              :     }
     206              : 
     207           14 :     return (data == validation) ? true : false;
     208           15 : }
     209              : 
     210            1 : ICDMonitoringEntry & ICDMonitoringEntry::operator=(const ICDMonitoringEntry & icdMonitoringEntry)
     211              : {
     212            1 :     if (this == &icdMonitoringEntry)
     213              :     {
     214            0 :         return *this;
     215              :     }
     216              : 
     217            1 :     fabricIndex       = icdMonitoringEntry.fabricIndex;
     218            1 :     checkInNodeID     = icdMonitoringEntry.checkInNodeID;
     219            1 :     monitoredSubject  = icdMonitoringEntry.monitoredSubject;
     220            1 :     clientType        = icdMonitoringEntry.clientType;
     221            1 :     index             = icdMonitoringEntry.index;
     222            1 :     keyHandleValid    = icdMonitoringEntry.keyHandleValid;
     223            1 :     symmetricKeystore = icdMonitoringEntry.symmetricKeystore;
     224            1 :     memcpy(aesKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(),
     225            1 :            icdMonitoringEntry.aesKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>(),
     226              :            sizeof(Crypto::Symmetric128BitsKeyByteArray));
     227            1 :     memcpy(hmacKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(),
     228            1 :            icdMonitoringEntry.hmacKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>(),
     229              :            sizeof(Crypto::Symmetric128BitsKeyByteArray));
     230              : 
     231            1 :     return *this;
     232              : }
     233              : 
     234           27 : CHIP_ERROR ICDMonitoringTable::Get(uint16_t index, ICDMonitoringEntry & entry) const
     235              : {
     236           27 :     entry.fabricIndex = this->mFabric;
     237           27 :     entry.index       = index;
     238           27 :     ReturnErrorOnFailure(entry.Load(this->mStorage));
     239           18 :     entry.fabricIndex = this->mFabric;
     240           18 :     return CHIP_NO_ERROR;
     241              : }
     242              : 
     243            0 : CHIP_ERROR ICDMonitoringTable::Find(NodeId id, ICDMonitoringEntry & entry)
     244              : {
     245              :     uint16_t index;
     246            0 :     ICDMonitoringEntry tempEntry(mSymmetricKeystore);
     247              : 
     248            0 :     for (index = 0; index < this->Limit(); index++)
     249              :     {
     250            0 :         if (this->Get(index, tempEntry) != CHIP_NO_ERROR)
     251              :         {
     252            0 :             break;
     253              :         }
     254            0 :         if (id == tempEntry.checkInNodeID)
     255              :         {
     256            0 :             entry = tempEntry;
     257            0 :             return CHIP_NO_ERROR;
     258              :         }
     259              :     }
     260              : 
     261            0 :     entry.index = index;
     262            0 :     return CHIP_ERROR_NOT_FOUND;
     263            0 : }
     264              : 
     265           19 : CHIP_ERROR ICDMonitoringTable::Set(uint16_t index, const ICDMonitoringEntry & entry)
     266              : {
     267           19 :     VerifyOrReturnError(index < this->Limit(), CHIP_ERROR_INVALID_ARGUMENT);
     268           17 :     VerifyOrReturnError(kUndefinedNodeId != entry.checkInNodeID, CHIP_ERROR_INVALID_ARGUMENT);
     269           16 :     VerifyOrReturnError(kUndefinedNodeId != entry.monitoredSubject, CHIP_ERROR_INVALID_ARGUMENT);
     270           15 :     VerifyOrReturnError(entry.keyHandleValid, CHIP_ERROR_INVALID_ARGUMENT);
     271              : 
     272           12 :     ICDMonitoringEntry e(this->mFabric, index);
     273           12 :     e.checkInNodeID     = entry.checkInNodeID;
     274           12 :     e.monitoredSubject  = entry.monitoredSubject;
     275           12 :     e.clientType        = entry.clientType;
     276           12 :     e.index             = index;
     277           12 :     e.symmetricKeystore = entry.symmetricKeystore;
     278              : 
     279           12 :     memcpy(e.aesKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(),
     280           12 :            entry.aesKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>(), sizeof(Crypto::Symmetric128BitsKeyByteArray));
     281           12 :     memcpy(e.hmacKeyHandle.AsMutable<Crypto::Symmetric128BitsKeyByteArray>(),
     282           12 :            entry.hmacKeyHandle.As<Crypto::Symmetric128BitsKeyByteArray>(), sizeof(Crypto::Symmetric128BitsKeyByteArray));
     283              : 
     284           12 :     ReturnErrorOnFailure(e.symmetricKeystore->PersistICDKey(e.aesKeyHandle));
     285           12 :     CHIP_ERROR error = e.symmetricKeystore->PersistICDKey(e.hmacKeyHandle);
     286           12 :     if (error != CHIP_NO_ERROR)
     287              :     {
     288              :         // If setting the persistence of the HmacKeyHandle failed, we need to delete the AesKeyHandle to avoid a key leak
     289            0 :         e.symmetricKeystore->DestroyKey(e.aesKeyHandle);
     290            0 :         return error;
     291              :     }
     292              : 
     293           12 :     return e.Save(this->mStorage);
     294           12 : }
     295              : 
     296            3 : CHIP_ERROR ICDMonitoringTable::Remove(uint16_t index)
     297              : {
     298            3 :     ICDMonitoringEntry entry(mSymmetricKeystore, this->mFabric);
     299              : 
     300              :     // Retrieve entry and delete the keyHandle first as to not
     301              :     // cause any key leaks.
     302            3 :     this->Get(index, entry);
     303            3 :     ReturnErrorOnFailure(entry.DeleteKey());
     304              : 
     305              :     // Shift remaining entries down one position
     306            5 :     while (CHIP_NO_ERROR == this->Get(static_cast<uint16_t>(index + 1), entry))
     307              :     {
     308            2 :         ReturnErrorOnFailure(this->Set(index++, entry));
     309              :     }
     310              : 
     311              :     // Remove last entry
     312            3 :     entry.fabricIndex = this->mFabric;
     313            3 :     entry.index       = index;
     314              : 
     315              :     // entry.Delete() doesn't delete the key from the AES128KeyHandle
     316            3 :     return entry.Delete(this->mStorage);
     317            3 : }
     318              : 
     319            2 : CHIP_ERROR ICDMonitoringTable::RemoveAll()
     320              : {
     321            2 :     ICDMonitoringEntry entry(mSymmetricKeystore, this->mFabric);
     322            2 :     uint16_t index = 0;
     323            4 :     while (index < this->Limit())
     324              :     {
     325            3 :         CHIP_ERROR err = this->Get(index++, entry);
     326            3 :         if (CHIP_ERROR_NOT_FOUND == err)
     327              :         {
     328            1 :             break;
     329              :         }
     330            2 :         ReturnErrorOnFailure(err);
     331            2 :         entry.fabricIndex = this->mFabric;
     332            2 :         ReturnErrorOnFailure(entry.DeleteKey());
     333            2 :         ReturnErrorOnFailure(entry.Delete(this->mStorage));
     334              :     }
     335            2 :     return CHIP_NO_ERROR;
     336            2 : }
     337              : 
     338            0 : bool ICDMonitoringTable::IsEmpty()
     339              : {
     340            0 :     ICDMonitoringEntry entry(mSymmetricKeystore, this->mFabric);
     341            0 :     return (this->Get(0, entry) == CHIP_ERROR_NOT_FOUND);
     342            0 : }
     343              : 
     344           24 : uint16_t ICDMonitoringTable::Limit() const
     345              : {
     346           24 :     return mLimit;
     347              : }
     348              : 
     349              : } // namespace chip
        

Generated by: LCOV version 2.0-1