LCOV - code coverage report
Current view: top level - protocols/secure_channel - DefaultSessionResumptionStorage.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 94 109 86.2 %
Date: 2024-02-15 08:20:41 Functions: 6 6 100.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             : #include <protocols/secure_channel/DefaultSessionResumptionStorage.h>
      19             : 
      20             : #include <lib/support/Base64.h>
      21             : #include <lib/support/SafeInt.h>
      22             : 
      23             : namespace chip {
      24             : 
      25         312 : CHIP_ERROR DefaultSessionResumptionStorage::FindByScopedNodeId(const ScopedNodeId & node, ResumptionIdStorage & resumptionId,
      26             :                                                                Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
      27             : {
      28         312 :     ReturnErrorOnFailure(LoadState(node, resumptionId, sharedSecret, peerCATs));
      29         158 :     return CHIP_NO_ERROR;
      30             : }
      31             : 
      32         161 : CHIP_ERROR DefaultSessionResumptionStorage::FindByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node,
      33             :                                                                Crypto::P256ECDHDerivedSecret & sharedSecret, CATValues & peerCATs)
      34             : {
      35         161 :     ReturnErrorOnFailure(FindNodeByResumptionId(resumptionId, node));
      36             :     ResumptionIdStorage tmpResumptionId;
      37          55 :     ReturnErrorOnFailure(FindByScopedNodeId(node, tmpResumptionId, sharedSecret, peerCATs));
      38          55 :     VerifyOrReturnError(std::equal(tmpResumptionId.begin(), tmpResumptionId.end(), resumptionId.begin(), resumptionId.end()),
      39             :                         CHIP_ERROR_KEY_NOT_FOUND);
      40          55 :     return CHIP_NO_ERROR;
      41             : }
      42             : 
      43         161 : CHIP_ERROR DefaultSessionResumptionStorage::FindNodeByResumptionId(ConstResumptionIdView resumptionId, ScopedNodeId & node)
      44             : {
      45         161 :     ReturnErrorOnFailure(LoadLink(resumptionId, node));
      46          55 :     return CHIP_NO_ERROR;
      47             : }
      48             : 
      49         206 : CHIP_ERROR DefaultSessionResumptionStorage::Save(const ScopedNodeId & node, ConstResumptionIdView resumptionId,
      50             :                                                  const Crypto::P256ECDHDerivedSecret & sharedSecret, const CATValues & peerCATs)
      51             : {
      52         206 :     SessionIndex index;
      53         206 :     ReturnErrorOnFailure(LoadIndex(index));
      54             : 
      55        3698 :     for (size_t i = 0; i < index.mSize; ++i)
      56             :     {
      57        3550 :         if (index.mNodes[i] == node)
      58             :         {
      59             :             // Node already exists in the index.  Save in place.
      60          58 :             CHIP_ERROR err = CHIP_NO_ERROR;
      61             :             ResumptionIdStorage oldResumptionId;
      62          58 :             Crypto::P256ECDHDerivedSecret oldSharedSecret;
      63          58 :             CATValues oldPeerCATs;
      64             :             // This follows the approach in Delete.  Removal of the old
      65             :             // resumption-id-keyed link is best effort.  If we cannot load
      66             :             // state to lookup the resumption ID for the key, the entry in
      67             :             // the link table will be leaked.
      68          58 :             err = LoadState(node, oldResumptionId, oldSharedSecret, oldPeerCATs);
      69          58 :             if (err != CHIP_NO_ERROR)
      70             :             {
      71           0 :                 ChipLogError(SecureChannel,
      72             :                              "LoadState failed; unable to fully delete session resumption record for node " ChipLogFormatX64
      73             :                              ": %" CHIP_ERROR_FORMAT,
      74             :                              ChipLogValueX64(node.GetNodeId()), err.Format());
      75             :             }
      76             :             else
      77             :             {
      78          58 :                 err = DeleteLink(oldResumptionId);
      79          58 :                 if (err != CHIP_NO_ERROR)
      80             :                 {
      81           0 :                     ChipLogError(SecureChannel,
      82             :                                  "DeleteLink failed; unable to fully delete session resumption record for node " ChipLogFormatX64
      83             :                                  ": %" CHIP_ERROR_FORMAT,
      84             :                                  ChipLogValueX64(node.GetNodeId()), err.Format());
      85             :                 }
      86             :             }
      87          58 :             ReturnErrorOnFailure(SaveState(node, resumptionId, sharedSecret, peerCATs));
      88          58 :             ReturnErrorOnFailure(SaveLink(resumptionId, node));
      89          58 :             return CHIP_NO_ERROR;
      90          58 :         }
      91             :     }
      92             : 
      93         148 :     if (index.mSize == CHIP_CONFIG_CASE_SESSION_RESUME_CACHE_SIZE)
      94             :     {
      95             :         // TODO: implement LRU for resumption
      96           1 :         ReturnErrorOnFailure(Delete(index.mNodes[0]));
      97           1 :         ReturnErrorOnFailure(LoadIndex(index));
      98             :     }
      99             : 
     100         148 :     ReturnErrorOnFailure(SaveState(node, resumptionId, sharedSecret, peerCATs));
     101         148 :     ReturnErrorOnFailure(SaveLink(resumptionId, node));
     102             : 
     103         148 :     index.mNodes[index.mSize++] = node;
     104         148 :     ReturnErrorOnFailure(SaveIndex(index));
     105             : 
     106         148 :     return CHIP_NO_ERROR;
     107             : }
     108             : 
     109          49 : CHIP_ERROR DefaultSessionResumptionStorage::Delete(const ScopedNodeId & node)
     110             : {
     111          49 :     SessionIndex index;
     112          49 :     ReturnErrorOnFailure(LoadIndex(index));
     113             : 
     114             :     ResumptionIdStorage resumptionId;
     115          49 :     Crypto::P256ECDHDerivedSecret sharedSecret;
     116          49 :     CATValues peerCATs;
     117          49 :     CHIP_ERROR err = LoadState(node, resumptionId, sharedSecret, peerCATs);
     118          49 :     if (err == CHIP_NO_ERROR)
     119             :     {
     120          49 :         err = DeleteLink(resumptionId);
     121          49 :         if (err != CHIP_NO_ERROR && err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     122             :         {
     123           0 :             ChipLogError(SecureChannel,
     124             :                          "Unable to delete session resumption link for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
     125             :                          ChipLogValueX64(node.GetNodeId()), err.Format());
     126             :         }
     127             :     }
     128           0 :     else if (err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     129             :     {
     130           0 :         ChipLogError(SecureChannel,
     131             :                      "Unable to load session resumption state during session deletion for node " ChipLogFormatX64
     132             :                      ": %" CHIP_ERROR_FORMAT,
     133             :                      ChipLogValueX64(node.GetNodeId()), err.Format());
     134             :     }
     135             : 
     136          49 :     err = DeleteState(node);
     137          49 :     if (err != CHIP_NO_ERROR && err != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)
     138             :     {
     139           0 :         ChipLogError(SecureChannel, "Unable to delete session resumption state for node " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
     140             :                      ChipLogValueX64(node.GetNodeId()), err.Format());
     141             :     }
     142             : 
     143          49 :     bool found = false;
     144        1225 :     for (size_t i = 0; i < index.mSize; ++i)
     145             :     {
     146        1176 :         if (found)
     147             :         {
     148             :             // index.mSize was decreased by 1 when found was set to true.
     149             :             // So the (i+1)th element isn't out of bounds.
     150        1127 :             index.mNodes[i] = index.mNodes[i + 1];
     151             :         }
     152             :         else
     153             :         {
     154          49 :             if (index.mNodes[i] == node)
     155             :             {
     156          49 :                 found = true;
     157          49 :                 if (i + 1 < index.mSize)
     158             :                 {
     159          48 :                     index.mNodes[i] = index.mNodes[i + 1];
     160             :                 }
     161          49 :                 index.mSize -= 1;
     162             :             }
     163             :         }
     164             :     }
     165             : 
     166          49 :     if (found)
     167             :     {
     168          49 :         err = SaveIndex(index);
     169          49 :         if (err != CHIP_NO_ERROR)
     170             :         {
     171           0 :             ChipLogError(SecureChannel, "Unable to save session resumption index: %" CHIP_ERROR_FORMAT, err.Format());
     172             :         }
     173             :     }
     174             :     else
     175             :     {
     176           0 :         ChipLogError(SecureChannel,
     177             :                      "Unable to find session resumption state for node in index" ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT,
     178             :                      ChipLogValueX64(node.GetNodeId()), err.Format());
     179             :     }
     180             : 
     181          49 :     return CHIP_NO_ERROR;
     182          49 : }
     183             : 
     184          19 : CHIP_ERROR DefaultSessionResumptionStorage::DeleteAll(FabricIndex fabricIndex)
     185             : {
     186          19 :     CHIP_ERROR stickyErr = CHIP_NO_ERROR;
     187          19 :     size_t found         = 0;
     188          19 :     SessionIndex index;
     189          19 :     ReturnErrorOnFailure(LoadIndex(index));
     190          19 :     size_t initialSize = index.mSize;
     191         433 :     for (size_t i = 0; i < initialSize; ++i)
     192             :     {
     193         414 :         CHIP_ERROR err = CHIP_NO_ERROR;
     194         414 :         size_t cur     = i - found;
     195         414 :         size_t remain  = initialSize - i;
     196             :         ResumptionIdStorage resumptionId;
     197         414 :         Crypto::P256ECDHDerivedSecret sharedSecret;
     198         414 :         CATValues peerCATs;
     199         414 :         if (index.mNodes[cur].GetFabricIndex() != fabricIndex)
     200             :         {
     201         363 :             continue;
     202             :         }
     203          51 :         err       = LoadState(index.mNodes[cur], resumptionId, sharedSecret, peerCATs);
     204          51 :         stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
     205          51 :         if (err != CHIP_NO_ERROR)
     206             :         {
     207           0 :             ChipLogError(SecureChannel,
     208             :                          "Session resumption cache deletion partially failed for fabric index %u, "
     209             :                          "unable to load node state: %" CHIP_ERROR_FORMAT,
     210             :                          fabricIndex, err.Format());
     211           0 :             continue;
     212             :         }
     213          51 :         err       = DeleteLink(resumptionId);
     214          51 :         stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
     215          51 :         if (err != CHIP_NO_ERROR)
     216             :         {
     217           0 :             ChipLogError(SecureChannel,
     218             :                          "Session resumption cache deletion partially failed for fabric index %u, "
     219             :                          "unable to delete node link: %" CHIP_ERROR_FORMAT,
     220             :                          fabricIndex, err.Format());
     221           0 :             continue;
     222             :         }
     223          51 :         err       = DeleteState(index.mNodes[cur]);
     224          51 :         stickyErr = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
     225          51 :         if (err != CHIP_NO_ERROR)
     226             :         {
     227           0 :             ChipLogError(SecureChannel,
     228             :                          "Session resumption cache is in an inconsistent state!  "
     229             :                          "Unable to delete node state during attempted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
     230             :                          fabricIndex, err.Format());
     231           0 :             continue;
     232             :         }
     233          51 :         ++found;
     234          51 :         --remain;
     235          51 :         if (remain)
     236             :         {
     237          49 :             memmove(&index.mNodes[cur], &index.mNodes[cur + 1], remain * sizeof(index.mNodes[0]));
     238             :         }
     239         414 :     }
     240          19 :     if (found)
     241             :     {
     242          19 :         index.mSize -= found;
     243          19 :         CHIP_ERROR err = SaveIndex(index);
     244          19 :         stickyErr      = stickyErr == CHIP_NO_ERROR ? err : stickyErr;
     245          19 :         if (err != CHIP_NO_ERROR)
     246             :         {
     247           0 :             ChipLogError(
     248             :                 SecureChannel,
     249             :                 "Session resumption cache is in an inconsistent state!  "
     250             :                 "Unable to save session resumption index during attempted deletion of fabric index %u: %" CHIP_ERROR_FORMAT,
     251             :                 fabricIndex, err.Format());
     252             :         }
     253             :     }
     254          19 :     return stickyErr;
     255             : }
     256             : 
     257             : } // namespace chip

Generated by: LCOV version 1.14