LCOV - code coverage report
Current view: top level - protocols/secure_channel - MessageCounterManager.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 11 119 9.2 %
Date: 2024-02-15 08:20:41 Functions: 2 13 15.4 %

          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         309 : CHIP_ERROR MessageCounterManager::Init(Messaging::ExchangeManager * exchangeMgr)
      44             : {
      45         309 :     VerifyOrReturnError(exchangeMgr != nullptr, CHIP_ERROR_INCORRECT_STATE);
      46         309 :     mExchangeMgr = exchangeMgr;
      47             : 
      48         309 :     ReturnErrorOnFailure(
      49             :         mExchangeMgr->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq, this));
      50             : 
      51         309 :     return CHIP_NO_ERROR;
      52             : }
      53             : 
      54         309 : void MessageCounterManager::Shutdown()
      55             : {
      56         309 :     if (mExchangeMgr != nullptr)
      57             :     {
      58         309 :         mExchangeMgr->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq);
      59         309 :         mExchangeMgr->CloseAllContextsForDelegate(this);
      60         309 :         mExchangeMgr = nullptr;
      61             :     }
      62         309 : }
      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 1.14