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

Generated by: LCOV version 2.0-1