Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - MessageCounterManager.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 9.4 % 117 11
Test Date: 2026-01-31 08:14:20 Functions: 15.4 % 13 2

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 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              : /**
      19              :  *    @file
      20              :  *      This file implements the CHIP message counter messages in secure channel protocol.
      21              :  *
      22              :  */
      23              : 
      24              : #include <protocols/secure_channel/MessageCounterManager.h>
      25              : 
      26              : #include <lib/core/CHIPCore.h>
      27              : #include <lib/core/CHIPEncoding.h>
      28              : #include <lib/core/CHIPKeyIds.h>
      29              : #include <lib/support/BufferWriter.h>
      30              : #include <lib/support/CodeUtils.h>
      31              : #include <lib/support/logging/CHIPLogging.h>
      32              : #include <messaging/ExchangeContext.h>
      33              : #include <messaging/ExchangeMgr.h>
      34              : #include <messaging/Flags.h>
      35              : #include <protocols/Protocols.h>
      36              : #include <protocols/secure_channel/Constants.h>
      37              : 
      38              : namespace chip {
      39              : namespace secure_channel {
      40              : 
      41              : constexpr System::Clock::Timeout MessageCounterManager::kSyncTimeout;
      42              : 
      43          427 : CHIP_ERROR MessageCounterManager::Init(Messaging::ExchangeManager * exchangeMgr)
      44              : {
      45          427 :     VerifyOrReturnError(exchangeMgr != nullptr, CHIP_ERROR_INCORRECT_STATE);
      46          427 :     mExchangeMgr = exchangeMgr;
      47              : 
      48          427 :     ReturnErrorOnFailure(
      49              :         mExchangeMgr->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq, this));
      50              : 
      51          427 :     return CHIP_NO_ERROR;
      52              : }
      53              : 
      54          427 : void MessageCounterManager::Shutdown()
      55              : {
      56          427 :     if (mExchangeMgr != nullptr)
      57              :     {
      58          427 :         TEMPORARY_RETURN_IGNORED mExchangeMgr->UnregisterUnsolicitedMessageHandlerForType(
      59              :             Protocols::SecureChannel::MsgType::MsgCounterSyncReq);
      60          427 :         mExchangeMgr->CloseAllContextsForDelegate(this);
      61          427 :         mExchangeMgr = nullptr;
      62              :     }
      63          427 : }
      64              : 
      65            0 : CHIP_ERROR MessageCounterManager::StartSync(const SessionHandle & session, Transport::SecureSession * state)
      66              : {
      67              :     // Initiate message counter synchronization if no message counter synchronization is in progress.
      68            0 :     Transport::PeerMessageCounter & counter = state->GetSessionMessageCounter().GetPeerMessageCounter();
      69            0 :     if (!counter.IsSynchronizing() && !counter.IsSynchronized())
      70              :     {
      71            0 :         ReturnErrorOnFailure(SendMsgCounterSyncReq(session, state));
      72              :     }
      73              : 
      74            0 :     return CHIP_NO_ERROR;
      75              : }
      76              : 
      77            0 : CHIP_ERROR MessageCounterManager::QueueReceivedMessageAndStartSync(const PacketHeader & packetHeader, const SessionHandle & session,
      78              :                                                                    Transport::SecureSession * state,
      79              :                                                                    const Transport::PeerAddress & peerAddress,
      80              :                                                                    System::PacketBufferHandle && msgBuf)
      81              : {
      82              :     // Queue the message to be reprocessed when sync completes.
      83            0 :     ReturnErrorOnFailure(AddToReceiveTable(packetHeader, peerAddress, std::move(msgBuf)));
      84            0 :     ReturnErrorOnFailure(StartSync(session, state));
      85              : 
      86              :     // After the message that triggers message counter synchronization is stored, and a message counter
      87              :     // synchronization exchange is initiated, we need to return immediately and re-process the original message
      88              :     // when the synchronization is completed.
      89              : 
      90            0 :     return CHIP_NO_ERROR;
      91              : }
      92              : 
      93            0 : CHIP_ERROR MessageCounterManager::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate)
      94              : {
      95              :     // MessageCounterManager do not use an extra context to handle messages
      96            0 :     newDelegate = this;
      97            0 :     return CHIP_NO_ERROR;
      98              : }
      99              : 
     100            0 : CHIP_ERROR MessageCounterManager::OnMessageReceived(Messaging::ExchangeContext * exchangeContext,
     101              :                                                     const PayloadHeader & payloadHeader, System::PacketBufferHandle && msgBuf)
     102              : {
     103            0 :     if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq))
     104              :     {
     105            0 :         return HandleMsgCounterSyncReq(exchangeContext, std::move(msgBuf));
     106              :     }
     107            0 :     if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp))
     108              :     {
     109            0 :         return HandleMsgCounterSyncResp(exchangeContext, std::move(msgBuf));
     110              :     }
     111            0 :     return CHIP_NO_ERROR;
     112              : }
     113              : 
     114            0 : void MessageCounterManager::OnResponseTimeout(Messaging::ExchangeContext * exchangeContext)
     115              : {
     116            0 :     if (exchangeContext->HasSessionHandle())
     117              :     {
     118            0 :         exchangeContext->GetSessionHandle()->AsSecureSession()->GetSessionMessageCounter().GetPeerMessageCounter().SyncFailed();
     119              :     }
     120              :     else
     121              :     {
     122            0 :         ChipLogError(SecureChannel, "MCSP Timeout! On a already released session.");
     123              :     }
     124            0 : }
     125              : 
     126            0 : CHIP_ERROR MessageCounterManager::AddToReceiveTable(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
     127              :                                                     System::PacketBufferHandle && msgBuf)
     128              : {
     129            0 :     ReturnErrorOnFailure(packetHeader.EncodeBeforeData(msgBuf));
     130              : 
     131            0 :     for (ReceiveTableEntry & entry : mReceiveTable)
     132              :     {
     133            0 :         if (entry.msgBuf.IsNull())
     134              :         {
     135            0 :             entry.peerAddress = peerAddress;
     136            0 :             entry.msgBuf      = std::move(msgBuf);
     137              : 
     138            0 :             return CHIP_NO_ERROR;
     139              :         }
     140              :     }
     141              : 
     142            0 :     ChipLogError(SecureChannel, "MCSP ReceiveTable Already Full");
     143            0 :     return CHIP_ERROR_NO_MEMORY;
     144              : }
     145              : 
     146              : /**
     147              :  *  Reprocess all pending messages that were encrypted with application
     148              :  *  group key and were addressed to the specified node id.
     149              :  *
     150              :  *  @param[in] peerNodeId    Node ID of the destination node.
     151              :  *
     152              :  */
     153            0 : void MessageCounterManager::ProcessPendingMessages(NodeId peerNodeId)
     154              : {
     155            0 :     auto * sessionManager = mExchangeMgr->GetSessionManager();
     156              : 
     157              :     // Find all receive entries matching peerNodeId.  Note that everything in
     158              :     // this table was using an application group key; that's why it was added.
     159            0 :     for (ReceiveTableEntry & entry : mReceiveTable)
     160              :     {
     161            0 :         if (!entry.msgBuf.IsNull())
     162              :         {
     163            0 :             PacketHeader packetHeader;
     164            0 :             uint16_t headerSize = 0;
     165              : 
     166            0 :             if (packetHeader.Decode((entry.msgBuf)->Start(), (entry.msgBuf)->DataLength(), &headerSize) != CHIP_NO_ERROR)
     167              :             {
     168            0 :                 ChipLogError(SecureChannel, "MessageCounterManager::ProcessPendingMessages: Failed to decode PacketHeader");
     169            0 :                 entry.msgBuf = nullptr;
     170            0 :                 continue;
     171              :             }
     172              : 
     173            0 :             if (packetHeader.GetSourceNodeId().HasValue() && packetHeader.GetSourceNodeId().Value() == peerNodeId)
     174              :             {
     175              :                 // Reprocess message.
     176            0 :                 sessionManager->OnMessageReceived(entry.peerAddress, std::move(entry.msgBuf));
     177              : 
     178              :                 // Explicitly free any buffer owned by this handle.
     179            0 :                 entry.msgBuf = nullptr;
     180              :             }
     181              :         }
     182              :     }
     183            0 : }
     184              : 
     185            0 : CHIP_ERROR MessageCounterManager::SendMsgCounterSyncReq(const SessionHandle & session, Transport::SecureSession * state)
     186              : {
     187            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     188              : 
     189            0 :     Messaging::ExchangeContext * exchangeContext = nullptr;
     190            0 :     System::PacketBufferHandle msgBuf;
     191            0 :     Messaging::SendFlags sendFlags;
     192              : 
     193            0 :     exchangeContext = mExchangeMgr->NewContext(session, this);
     194            0 :     VerifyOrExit(exchangeContext != nullptr, err = CHIP_ERROR_NO_MEMORY);
     195              : 
     196            0 :     msgBuf = MessagePacketBuffer::New(kChallengeSize);
     197            0 :     VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
     198              : 
     199              :     // Generate a 64-bit random number to uniquely identify the request.
     200            0 :     SuccessOrExit(err = Crypto::DRBG_get_bytes(msgBuf->Start(), kChallengeSize));
     201              : 
     202            0 :     msgBuf->SetDataLength(kChallengeSize);
     203              : 
     204              :     // Store generated Challenge value to message counter context to resolve synchronization response.
     205            0 :     state->GetSessionMessageCounter().GetPeerMessageCounter().SyncStarting(FixedByteSpan<kChallengeSize>(msgBuf->Start()));
     206              : 
     207            0 :     sendFlags.Set(Messaging::SendMessageFlags::kNoAutoRequestAck).Set(Messaging::SendMessageFlags::kExpectResponse);
     208              : 
     209              :     // Arm a timer to enforce that a MsgCounterSyncRsp is received before kSyncTimeout.
     210            0 :     exchangeContext->SetResponseTimeout(kSyncTimeout);
     211              : 
     212              :     // Send the message counter synchronization request in a Secure Channel Protocol::MsgCounterSyncReq message.
     213            0 :     SuccessOrExit(
     214              :         err = exchangeContext->SendMessage(Protocols::SecureChannel::MsgType::MsgCounterSyncReq, std::move(msgBuf), sendFlags));
     215              : 
     216            0 : exit:
     217            0 :     if (err != CHIP_NO_ERROR)
     218              :     {
     219            0 :         if (exchangeContext != nullptr)
     220              :         {
     221            0 :             exchangeContext->Close();
     222              :         }
     223            0 :         state->GetSessionMessageCounter().GetPeerMessageCounter().SyncFailed();
     224            0 :         ChipLogError(SecureChannel, "Failed to send message counter synchronization request with error:%" CHIP_ERROR_FORMAT,
     225              :                      err.Format());
     226              :     }
     227              : 
     228            0 :     return err;
     229            0 : }
     230              : 
     231            0 : CHIP_ERROR MessageCounterManager::SendMsgCounterSyncResp(Messaging::ExchangeContext * exchangeContext,
     232              :                                                          FixedByteSpan<kChallengeSize> challenge)
     233              : {
     234            0 :     System::PacketBufferHandle msgBuf;
     235            0 :     VerifyOrDie(exchangeContext->HasSessionHandle());
     236              : 
     237            0 :     VerifyOrReturnError(exchangeContext->GetSessionHandle()->IsGroupSession(), CHIP_ERROR_INVALID_ARGUMENT);
     238              : 
     239              :     // NOTE: not currently implemented. When implementing, the following should be done:
     240              :     //    - allocate a new buffer: MessagePacketBuffer::New
     241              :     //    - setup payload and place the local message counter + challange in it
     242              :     //    - exchangeContext->SendMessage(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp, ...)
     243              :     //
     244              :     // You can view the history of this file for a partial implementation that got
     245              :     // removed due to it using non-group sessions.
     246              : 
     247            0 :     return CHIP_ERROR_NOT_IMPLEMENTED;
     248            0 : }
     249              : 
     250            0 : CHIP_ERROR MessageCounterManager::HandleMsgCounterSyncReq(Messaging::ExchangeContext * exchangeContext,
     251              :                                                           System::PacketBufferHandle && msgBuf)
     252              : {
     253            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     254              : 
     255            0 :     uint8_t * req = msgBuf->Start();
     256            0 :     size_t reqlen = msgBuf->DataLength();
     257              : 
     258            0 :     ChipLogDetail(SecureChannel, "Received MsgCounterSyncReq request");
     259              : 
     260            0 :     VerifyOrExit(req != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
     261            0 :     VerifyOrExit(reqlen == kChallengeSize, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     262              : 
     263              :     // Respond with MsgCounterSyncResp
     264            0 :     err = SendMsgCounterSyncResp(exchangeContext, FixedByteSpan<kChallengeSize>(req));
     265              : 
     266            0 : exit:
     267            0 :     if (err != CHIP_NO_ERROR)
     268              :     {
     269            0 :         ChipLogError(SecureChannel, "Failed to handle MsgCounterSyncReq message with error:%" CHIP_ERROR_FORMAT, err.Format());
     270              :     }
     271              : 
     272            0 :     return err;
     273              : }
     274              : 
     275            0 : CHIP_ERROR MessageCounterManager::HandleMsgCounterSyncResp(Messaging::ExchangeContext * exchangeContext,
     276              :                                                            System::PacketBufferHandle && msgBuf)
     277              : {
     278            0 :     CHIP_ERROR err = CHIP_NO_ERROR;
     279              : 
     280            0 :     uint32_t syncCounter = 0;
     281              : 
     282            0 :     const uint8_t * resp = msgBuf->Start();
     283            0 :     size_t resplen       = msgBuf->DataLength();
     284              : 
     285            0 :     ChipLogDetail(SecureChannel, "Received MsgCounterSyncResp response");
     286              : 
     287            0 :     VerifyOrDie(exchangeContext->HasSessionHandle());
     288              : 
     289            0 :     VerifyOrExit(msgBuf->DataLength() == kSyncRespMsgSize, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     290              : 
     291            0 :     VerifyOrExit(resp != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
     292            0 :     VerifyOrExit(resplen == kSyncRespMsgSize, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     293              : 
     294            0 :     syncCounter = chip::Encoding::LittleEndian::Read32(resp);
     295            0 :     VerifyOrExit(syncCounter != 0, err = CHIP_ERROR_READ_FAILED);
     296              : 
     297              :     // Verify that the response field matches the expected Challenge field for the exchange.
     298              :     err =
     299            0 :         exchangeContext->GetSessionHandle()->AsSecureSession()->GetSessionMessageCounter().GetPeerMessageCounter().VerifyChallenge(
     300              :             syncCounter, FixedByteSpan<kChallengeSize>(resp));
     301            0 :     SuccessOrExit(err);
     302              : 
     303              :     // Process all queued incoming messages after message counter synchronization is completed.
     304            0 :     ProcessPendingMessages(exchangeContext->GetSessionHandle()->AsSecureSession()->GetPeerNodeId());
     305              : 
     306            0 : exit:
     307            0 :     if (err != CHIP_NO_ERROR)
     308              :     {
     309            0 :         ChipLogError(SecureChannel, "Failed to handle MsgCounterSyncResp message with error:%" CHIP_ERROR_FORMAT, err.Format());
     310              :     }
     311              : 
     312            0 :     return err;
     313              : }
     314              : 
     315              : } // namespace secure_channel
     316              : } // namespace chip
        

Generated by: LCOV version 2.0-1