LCOV - code coverage report
Current view: top level - transport - SessionManager.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 369 457 80.7 %
Date: 2024-02-15 08:20:41 Functions: 21 36 58.3 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4             :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5             :  *    All rights reserved.
       6             :  *
       7             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8             :  *    you may not use this file except in compliance with the License.
       9             :  *    You may obtain a copy of the License at
      10             :  *
      11             :  *        http://www.apache.org/licenses/LICENSE-2.0
      12             :  *
      13             :  *    Unless required by applicable law or agreed to in writing, software
      14             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16             :  *    See the License for the specific language governing permissions and
      17             :  *    limitations under the License.
      18             :  */
      19             : 
      20             : /**
      21             :  *    @file
      22             :  *      This file implements the CHIP Connection object that maintains a UDP connection.
      23             :  *      TODO This class should be extended to support TCP as well...
      24             :  *
      25             :  */
      26             : 
      27             : #include "SessionManager.h"
      28             : 
      29             : #include <inttypes.h>
      30             : #include <string.h>
      31             : 
      32             : #include "transport/TraceMessage.h"
      33             : #include <app/util/basic-types.h>
      34             : #include <credentials/GroupDataProvider.h>
      35             : #include <inttypes.h>
      36             : #include <lib/core/CHIPKeyIds.h>
      37             : #include <lib/core/Global.h>
      38             : #include <lib/support/CodeUtils.h>
      39             : #include <lib/support/SafeInt.h>
      40             : #include <lib/support/logging/CHIPLogging.h>
      41             : #include <platform/CHIPDeviceLayer.h>
      42             : #include <protocols/Protocols.h>
      43             : #include <protocols/secure_channel/Constants.h>
      44             : #include <tracing/macros.h>
      45             : #include <transport/GroupPeerMessageCounter.h>
      46             : #include <transport/GroupSession.h>
      47             : #include <transport/SecureMessageCodec.h>
      48             : #include <transport/TracingStructs.h>
      49             : #include <transport/TransportMgr.h>
      50             : 
      51             : namespace chip {
      52             : 
      53             : using System::PacketBufferHandle;
      54             : using Transport::GroupPeerTable;
      55             : using Transport::PeerAddress;
      56             : using Transport::SecureSession;
      57             : 
      58             : namespace {
      59             : Global<GroupPeerTable> gGroupPeerTable;
      60             : } // namespace
      61             : 
      62        7876 : uint32_t EncryptedPacketBufferHandle::GetMessageCounter() const
      63             : {
      64        7876 :     PacketHeader header;
      65        7876 :     uint16_t headerSize = 0;
      66        7876 :     CHIP_ERROR err      = header.Decode((*this)->Start(), (*this)->DataLength(), &headerSize);
      67             : 
      68        7876 :     if (err == CHIP_NO_ERROR)
      69             :     {
      70        7876 :         return header.GetMessageCounter();
      71             :     }
      72             : 
      73           0 :     ChipLogError(Inet, "Failed to decode EncryptedPacketBufferHandle header with error: %" CHIP_ERROR_FORMAT, err.Format());
      74             : 
      75           0 :     return 0;
      76        7876 : }
      77             : 
      78         101 : SessionManager::SessionManager() : mState(State::kNotReady) {}
      79             : 
      80         101 : SessionManager::~SessionManager()
      81             : {
      82         101 :     this->Shutdown();
      83         101 : }
      84             : 
      85         334 : CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * transportMgr,
      86             :                                 Transport::MessageCounterManagerInterface * messageCounterManager,
      87             :                                 chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable,
      88             :                                 Crypto::SessionKeystore & sessionKeystore)
      89             : {
      90         334 :     VerifyOrReturnError(mState == State::kNotReady, CHIP_ERROR_INCORRECT_STATE);
      91         334 :     VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      92         334 :     VerifyOrReturnError(storageDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      93         334 :     VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      94         334 :     ReturnErrorOnFailure(fabricTable->AddFabricDelegate(this));
      95             : 
      96         334 :     mState                 = State::kInitialized;
      97         334 :     mSystemLayer           = systemLayer;
      98         334 :     mTransportMgr          = transportMgr;
      99         334 :     mMessageCounterManager = messageCounterManager;
     100         334 :     mFabricTable           = fabricTable;
     101         334 :     mSessionKeystore       = &sessionKeystore;
     102             : 
     103         334 :     mSecureSessions.Init();
     104             : 
     105         334 :     mGlobalUnencryptedMessageCounter.Init();
     106             : 
     107         334 :     ReturnErrorOnFailure(mGroupClientCounter.Init(storageDelegate));
     108             : 
     109         334 :     mTransportMgr->SetSessionManager(this);
     110             : 
     111         334 :     return CHIP_NO_ERROR;
     112             : }
     113             : 
     114         434 : void SessionManager::Shutdown()
     115             : {
     116         434 :     if (mFabricTable != nullptr)
     117             :     {
     118         334 :         mFabricTable->RemoveFabricDelegate(this);
     119         334 :         mFabricTable = nullptr;
     120             :     }
     121             : 
     122             :     // Ensure that we don't create new sessions as we iterate our session table.
     123         434 :     mState = State::kNotReady;
     124             : 
     125         434 :     mSecureSessions.ForEachSession([&](auto session) {
     126        1204 :         session->MarkForEviction();
     127        1204 :         return Loop::Continue;
     128             :     });
     129             : 
     130         434 :     mMessageCounterManager = nullptr;
     131             : 
     132         434 :     mSystemLayer  = nullptr;
     133         434 :     mTransportMgr = nullptr;
     134         434 :     mCB           = nullptr;
     135         434 : }
     136             : 
     137             : /**
     138             :  * @brief Notification that a fabric was removed.
     139             :  *        This function doesn't call ExpireAllSessionsForFabric
     140             :  *        since the CASE session might still be open to send a response
     141             :  *        on the removed fabric.
     142             :  */
     143           5 : void SessionManager::FabricRemoved(FabricIndex fabricIndex)
     144             : {
     145           5 :     gGroupPeerTable->FabricRemoved(fabricIndex);
     146           5 : }
     147             : 
     148        9587 : CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, PayloadHeader & payloadHeader,
     149             :                                           System::PacketBufferHandle && message, EncryptedPacketBufferHandle & preparedMessage)
     150             : {
     151             :     MATTER_TRACE_SCOPE("PrepareMessage", "SessionManager");
     152             : 
     153        9587 :     PacketHeader packetHeader;
     154        9587 :     bool isControlMsg = IsControlMessage(payloadHeader);
     155        9587 :     if (isControlMsg)
     156             :     {
     157           0 :         packetHeader.SetSecureSessionControlMsg(true);
     158             :     }
     159             : 
     160             : #if CHIP_PROGRESS_LOGGING
     161             :     NodeId destination;
     162             :     FabricIndex fabricIndex;
     163             : #endif // CHIP_PROGRESS_LOGGING
     164             : 
     165        9587 :     PeerAddress destination_address;
     166             : 
     167        9587 :     switch (sessionHandle->GetSessionType())
     168             :     {
     169           1 :     case Transport::Session::SessionType::kGroupOutgoing: {
     170           1 :         auto groupSession = sessionHandle->AsOutgoingGroupSession();
     171           1 :         auto * groups     = Credentials::GetGroupDataProvider();
     172           1 :         VerifyOrReturnError(nullptr != groups, CHIP_ERROR_INTERNAL);
     173             : 
     174           1 :         const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
     175           1 :         VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     176             : 
     177           1 :         packetHeader.SetDestinationGroupId(groupSession->GetGroupId());
     178           1 :         packetHeader.SetMessageCounter(mGroupClientCounter.GetCounter(isControlMsg));
     179           1 :         mGroupClientCounter.IncrementCounter(isControlMsg);
     180           1 :         packetHeader.SetSessionType(Header::SessionType::kGroupSession);
     181           1 :         NodeId sourceNodeId = fabric->GetNodeId();
     182           1 :         packetHeader.SetSourceNodeId(sourceNodeId);
     183             : 
     184           1 :         if (!packetHeader.IsValidGroupMsg())
     185             :         {
     186           0 :             return CHIP_ERROR_INTERNAL;
     187             :         }
     188             : 
     189           1 :         destination_address = Transport::PeerAddress::Multicast(fabric->GetFabricId(), groupSession->GetGroupId());
     190             : 
     191             :         // Trace before any encryption
     192             :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kGroupMessage, &payloadHeader, &packetHeader,
     193             :                                 chip::ByteSpan(message->Start(), message->TotalLength()));
     194             : 
     195           1 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     196             : 
     197             :         Crypto::SymmetricKeyContext * keyContext =
     198           1 :             groups->GetKeyContext(groupSession->GetFabricIndex(), groupSession->GetGroupId());
     199           1 :         VerifyOrReturnError(nullptr != keyContext, CHIP_ERROR_INTERNAL);
     200             : 
     201           1 :         packetHeader.SetSessionId(keyContext->GetKeyHash());
     202             :         CryptoContext::NonceStorage nonce;
     203           1 :         CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(), sourceNodeId);
     204           1 :         CHIP_ERROR err = SecureMessageCodec::Encrypt(CryptoContext(keyContext), nonce, payloadHeader, packetHeader, message);
     205           1 :         keyContext->Release();
     206           1 :         ReturnErrorOnFailure(err);
     207             : 
     208             : #if CHIP_PROGRESS_LOGGING
     209           1 :         destination = NodeIdFromGroupId(groupSession->GetGroupId());
     210           1 :         fabricIndex = groupSession->GetFabricIndex();
     211             : #endif // CHIP_PROGRESS_LOGGING
     212             :     }
     213           1 :     break;
     214        9488 :     case Transport::Session::SessionType::kSecure: {
     215        9488 :         SecureSession * session = sessionHandle->AsSecureSession();
     216        9488 :         if (session == nullptr)
     217             :         {
     218           2 :             return CHIP_ERROR_NOT_CONNECTED;
     219             :         }
     220             : 
     221        9488 :         MessageCounter & counter = session->GetSessionMessageCounter().GetLocalMessageCounter();
     222             :         uint32_t messageCounter;
     223        9488 :         ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
     224             :         packetHeader
     225        9487 :             .SetMessageCounter(messageCounter)         //
     226        9487 :             .SetSessionId(session->GetPeerSessionId()) //
     227        9487 :             .SetSessionType(Header::SessionType::kUnicastSession);
     228             : 
     229        9487 :         destination_address = session->GetPeerAddress();
     230             : 
     231             :         // Trace before any encryption
     232             :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kSecureSession, &payloadHeader, &packetHeader,
     233             :                                 chip::ByteSpan(message->Start(), message->TotalLength()));
     234        9487 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     235             : 
     236             :         CryptoContext::NonceStorage nonce;
     237        9487 :         NodeId sourceNodeId = session->GetLocalScopedNodeId().GetNodeId();
     238        9487 :         CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), messageCounter, sourceNodeId);
     239             : 
     240        9487 :         ReturnErrorOnFailure(SecureMessageCodec::Encrypt(session->GetCryptoContext(), nonce, payloadHeader, packetHeader, message));
     241             : 
     242             : #if CHIP_PROGRESS_LOGGING
     243        9486 :         destination = session->GetPeerNodeId();
     244        9486 :         fabricIndex = session->GetFabricIndex();
     245             : #endif // CHIP_PROGRESS_LOGGING
     246             :     }
     247        9486 :     break;
     248          98 :     case Transport::Session::SessionType::kUnauthenticated: {
     249          98 :         MessageCounter & counter = mGlobalUnencryptedMessageCounter;
     250             :         uint32_t messageCounter;
     251          98 :         ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
     252          98 :         packetHeader.SetMessageCounter(messageCounter);
     253          98 :         Transport::UnauthenticatedSession * session = sessionHandle->AsUnauthenticatedSession();
     254          98 :         switch (session->GetSessionRole())
     255             :         {
     256          58 :         case Transport::UnauthenticatedSession::SessionRole::kInitiator:
     257          58 :             packetHeader.SetSourceNodeId(session->GetEphemeralInitiatorNodeID());
     258          58 :             break;
     259          40 :         case Transport::UnauthenticatedSession::SessionRole::kResponder:
     260          40 :             packetHeader.SetDestinationNodeId(session->GetEphemeralInitiatorNodeID());
     261          40 :             break;
     262             :         }
     263             : 
     264          98 :         auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
     265          98 :         destination_address  = unauthenticated->GetPeerAddress();
     266             : 
     267             :         // Trace after all headers are settled.
     268             :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
     269             :                                 chip::ByteSpan(message->Start(), message->TotalLength()));
     270          98 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     271             : 
     272          98 :         ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(message));
     273             : 
     274             : #if CHIP_PROGRESS_LOGGING
     275          98 :         destination = kUndefinedNodeId;
     276          98 :         fabricIndex = kUndefinedFabricIndex;
     277             : #endif // CHIP_PROGRESS_LOGGING
     278             :     }
     279          98 :     break;
     280           0 :     default:
     281           0 :         return CHIP_ERROR_INTERNAL;
     282             :     }
     283             : 
     284             : #if CHIP_PROGRESS_LOGGING
     285        9585 :     CompressedFabricId compressedFabricId = kUndefinedCompressedFabricId;
     286             : 
     287        9585 :     if (fabricIndex != kUndefinedFabricIndex && mFabricTable != nullptr)
     288             :     {
     289        9440 :         auto fabricInfo = mFabricTable->FindFabricWithIndex(fabricIndex);
     290        9440 :         if (fabricInfo)
     291             :         {
     292        9440 :             compressedFabricId = fabricInfo->GetCompressedFabricId();
     293             :         }
     294             :     }
     295             : 
     296        9585 :     auto * protocolName = Protocols::GetProtocolName(payloadHeader.GetProtocolID());
     297        9585 :     auto * msgTypeName  = Protocols::GetMessageTypeName(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType());
     298             : 
     299             :     //
     300             :     // 32-bit value maximum = 10 chars + text preamble (6) + trailer (1) + null (1) + 2 buffer = 20
     301             :     //
     302             :     char ackBuf[20];
     303        9585 :     ackBuf[0] = '\0';
     304        9585 :     if (payloadHeader.GetAckMessageCounter().HasValue())
     305             :     {
     306        7877 :         snprintf(ackBuf, sizeof(ackBuf), " (Ack:" ChipLogFormatMessageCounter ")", payloadHeader.GetAckMessageCounter().Value());
     307             :     }
     308             : 
     309        9585 :     char addressStr[Transport::PeerAddress::kMaxToStringSize] = { 0 };
     310        9585 :     destination_address.ToString(addressStr);
     311             : 
     312             :     // Work around pigweed not allowing more than 14 format args in a log
     313             :     // message when using tokenized logs.
     314             :     char typeStr[4 + 1 + 2 + 1];
     315        9585 :     snprintf(typeStr, sizeof(typeStr), "%04X:%02X", payloadHeader.GetProtocolID().GetProtocolId(), payloadHeader.GetMessageType());
     316             : 
     317             :     //
     318             :     // Legend that can be used to decode this log line can be found in messaging/README.md
     319             :     //
     320        9585 :     ChipLogProgress(ExchangeManager,
     321             :                     "<<< [E:" ChipLogFormatExchangeId " S:%u M:" ChipLogFormatMessageCounter
     322             :                     "%s] (%s) Msg TX to %u:" ChipLogFormatX64 " [%04X] [%s] --- Type %s (%s:%s)",
     323             :                     ChipLogValueExchangeIdFromSentHeader(payloadHeader), sessionHandle->SessionIdForLogging(),
     324             :                     packetHeader.GetMessageCounter(), ackBuf, Transport::GetSessionTypeString(sessionHandle), fabricIndex,
     325             :                     ChipLogValueX64(destination), static_cast<uint16_t>(compressedFabricId), addressStr, typeStr, protocolName,
     326             :                     msgTypeName);
     327             : #endif
     328             : 
     329        9585 :     ReturnErrorOnFailure(packetHeader.EncodeBeforeData(message));
     330        9585 :     preparedMessage = EncryptedPacketBufferHandle::MarkEncrypted(std::move(message));
     331             : 
     332        9585 :     return CHIP_NO_ERROR;
     333        9587 : }
     334             : 
     335        9619 : CHIP_ERROR SessionManager::SendPreparedMessage(const SessionHandle & sessionHandle,
     336             :                                                const EncryptedPacketBufferHandle & preparedMessage)
     337             : {
     338        9619 :     VerifyOrReturnError(mState == State::kInitialized, CHIP_ERROR_INCORRECT_STATE);
     339        9619 :     VerifyOrReturnError(!preparedMessage.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     340             : 
     341        9619 :     Transport::PeerAddress multicastAddress; // Only used for the group case
     342             :     const Transport::PeerAddress * destination;
     343             : 
     344        9619 :     switch (sessionHandle->GetSessionType())
     345             :     {
     346           1 :     case Transport::Session::SessionType::kGroupOutgoing: {
     347           1 :         auto groupSession = sessionHandle->AsOutgoingGroupSession();
     348             : 
     349           1 :         const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
     350           1 :         VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     351             : 
     352           1 :         multicastAddress = Transport::PeerAddress::Multicast(fabric->GetFabricId(), groupSession->GetGroupId());
     353           1 :         destination      = &multicastAddress;
     354             :     }
     355           1 :     break;
     356        9517 :     case Transport::Session::SessionType::kSecure: {
     357             :         // Find an active connection to the specified peer node
     358        9517 :         SecureSession * secure = sessionHandle->AsSecureSession();
     359             : 
     360             :         // This marks any connection where we send data to as 'active'
     361        9517 :         secure->MarkActive();
     362             : 
     363        9517 :         destination = &secure->GetPeerAddress();
     364             :     }
     365        9517 :     break;
     366         101 :     case Transport::Session::SessionType::kUnauthenticated: {
     367         101 :         auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
     368         101 :         unauthenticated->MarkActive();
     369         101 :         destination = &unauthenticated->GetPeerAddress();
     370             :     }
     371         101 :     break;
     372           0 :     default:
     373           0 :         return CHIP_ERROR_INTERNAL;
     374             :     }
     375             : 
     376       19238 :     PacketBufferHandle msgBuf = preparedMessage.CastToWritable();
     377        9619 :     VerifyOrReturnError(!msgBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     378        9619 :     VerifyOrReturnError(!msgBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     379             : 
     380             : #if CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
     381        9619 :     if (sessionHandle->GetSessionType() == Transport::Session::SessionType::kGroupOutgoing)
     382             :     {
     383           1 :         chip::Inet::InterfaceIterator interfaceIt;
     384           1 :         chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
     385             :         chip::Inet::IPAddress addr;
     386           1 :         bool interfaceFound = false;
     387             : 
     388           3 :         while (interfaceIt.Next())
     389             :         {
     390             :             char name[chip::Inet::InterfaceId::kMaxIfNameLength];
     391           2 :             interfaceIt.GetInterfaceName(name, chip::Inet::InterfaceId::kMaxIfNameLength);
     392           2 :             if (interfaceIt.SupportsMulticast() && interfaceIt.IsUp())
     393             :             {
     394           1 :                 interfaceId = interfaceIt.GetInterfaceId();
     395           1 :                 if (CHIP_NO_ERROR == interfaceId.GetLinkLocalAddr(&addr))
     396             :                 {
     397           1 :                     ChipLogDetail(Inet, "Interface %s has a link local address", name);
     398             : 
     399           1 :                     interfaceFound             = true;
     400           1 :                     PacketBufferHandle tempBuf = msgBuf.CloneData();
     401           1 :                     VerifyOrReturnError(!tempBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     402           1 :                     VerifyOrReturnError(!tempBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     403             : 
     404           1 :                     destination = &(multicastAddress.SetInterface(interfaceId));
     405           1 :                     if (mTransportMgr != nullptr)
     406             :                     {
     407           1 :                         if (CHIP_NO_ERROR != mTransportMgr->SendMessage(*destination, std::move(tempBuf)))
     408             :                         {
     409           0 :                             ChipLogError(Inet, "Failed to send Multicast message on interface %s", name);
     410             :                         }
     411             :                         else
     412             :                         {
     413           1 :                             ChipLogDetail(Inet, "Successfully send Multicast message on interface %s", name);
     414             :                         }
     415             :                     }
     416           1 :                 }
     417             :             }
     418             :         }
     419             : 
     420           1 :         if (!interfaceFound)
     421             :         {
     422           0 :             ChipLogError(Inet, "No valid Interface found.. Sending to the default one.. ");
     423             :         }
     424             :         else
     425             :         {
     426             :             // Always return No error, because we expect some interface to fails and others to always succeed (e.g. lo interface)
     427           1 :             return CHIP_NO_ERROR;
     428             :         }
     429           1 :     }
     430             : 
     431             : #endif // CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
     432             : 
     433        9618 :     if (mTransportMgr != nullptr)
     434             :     {
     435        9618 :         return mTransportMgr->SendMessage(*destination, std::move(msgBuf));
     436             :     }
     437             : 
     438           0 :     ChipLogError(Inet, "The transport manager is not initialized. Unable to send the message");
     439           0 :     return CHIP_ERROR_INCORRECT_STATE;
     440             : }
     441             : 
     442           0 : void SessionManager::ExpireAllSessions(const ScopedNodeId & node)
     443             : {
     444           0 :     ChipLogDetail(Inet, "Expiring all sessions for node " ChipLogFormatScopedNodeId "!!", ChipLogValueScopedNodeId(node));
     445             : 
     446           0 :     ForEachMatchingSession(node, [](auto * session) { session->MarkForEviction(); });
     447           0 : }
     448             : 
     449           2 : void SessionManager::ExpireAllSessionsForFabric(FabricIndex fabricIndex)
     450             : {
     451           2 :     ChipLogDetail(Inet, "Expiring all sessions for fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
     452             : 
     453           8 :     ForEachMatchingSession(fabricIndex, [](auto * session) { session->MarkForEviction(); });
     454           2 : }
     455             : 
     456           0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(const ScopedNodeId & node)
     457             : {
     458           0 :     ChipLogDetail(Inet, "Expiring all sessions to peer " ChipLogFormatScopedNodeId " that are on the same logical fabric!!",
     459             :                   ChipLogValueScopedNodeId(node));
     460             : 
     461           0 :     return ForEachMatchingSessionOnLogicalFabric(node, [](auto * session) { session->MarkForEviction(); });
     462             : }
     463             : 
     464           0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(FabricIndex fabricIndex)
     465             : {
     466           0 :     ChipLogDetail(Inet, "Expiring all sessions on the same logical fabric as fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
     467             : 
     468           0 :     return ForEachMatchingSessionOnLogicalFabric(fabricIndex, [](auto * session) { session->MarkForEviction(); });
     469             : }
     470             : 
     471           0 : void SessionManager::ExpireAllPASESessions()
     472             : {
     473           0 :     ChipLogDetail(Inet, "Expiring all PASE sessions");
     474           0 :     mSecureSessions.ForEachSession([&](auto session) {
     475           0 :         if (session->GetSecureSessionType() == Transport::SecureSession::Type::kPASE)
     476             :         {
     477           0 :             session->MarkForEviction();
     478             :         }
     479           0 :         return Loop::Continue;
     480             :     });
     481           0 : }
     482             : 
     483           0 : void SessionManager::MarkSessionsAsDefunct(const ScopedNodeId & node, const Optional<Transport::SecureSession::Type> & type)
     484             : {
     485           0 :     mSecureSessions.ForEachSession([&node, &type](auto session) {
     486           0 :         if (session->IsActiveSession() && session->GetPeer() == node &&
     487           0 :             (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
     488             :         {
     489           0 :             session->MarkAsDefunct();
     490             :         }
     491           0 :         return Loop::Continue;
     492             :     });
     493           0 : }
     494             : 
     495           0 : void SessionManager::UpdateAllSessionsPeerAddress(const ScopedNodeId & node, const Transport::PeerAddress & addr)
     496             : {
     497           0 :     mSecureSessions.ForEachSession([&node, &addr](auto session) {
     498             :         // Arguably we should only be updating active and defunct sessions, but there is no harm
     499             :         // in updating evicted sessions.
     500           0 :         if (session->GetPeer() == node && Transport::SecureSession::Type::kCASE == session->GetSecureSessionType())
     501             :         {
     502           0 :             session->SetPeerAddress(addr);
     503             :         }
     504           0 :         return Loop::Continue;
     505             :     });
     506           0 : }
     507             : 
     508      133656 : Optional<SessionHandle> SessionManager::AllocateSession(SecureSession::Type secureSessionType,
     509             :                                                         const ScopedNodeId & sessionEvictionHint)
     510             : {
     511      133656 :     VerifyOrReturnValue(mState == State::kInitialized, NullOptional);
     512      133656 :     return mSecureSessions.CreateNewSecureSession(secureSessionType, sessionEvictionHint);
     513             : }
     514             : 
     515        1269 : CHIP_ERROR SessionManager::InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId,
     516             :                                                         uint16_t peerSessionId, FabricIndex fabric,
     517             :                                                         const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role)
     518             : {
     519        1269 :     NodeId localNodeId              = kUndefinedNodeId;
     520             :     Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
     521             :         chip::Transport::SecureSession::Type::kPASE, localSessionId, localNodeId, peerNodeId, CATValues{}, peerSessionId, fabric,
     522        1269 :         GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
     523        1269 :     VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
     524        1269 :     SecureSession * secureSession = session.Value()->AsSecureSession();
     525        1269 :     secureSession->SetPeerAddress(peerAddress);
     526             : 
     527        1269 :     size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
     528        1269 :     ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
     529        1269 :     ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
     530             :         *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
     531        1269 :     secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
     532        1269 :     sessionHolder.Grab(session.Value());
     533        1269 :     return CHIP_NO_ERROR;
     534        1269 : }
     535             : 
     536          17 : CHIP_ERROR SessionManager::InjectCaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId,
     537             :                                                         uint16_t peerSessionId, NodeId localNodeId, NodeId peerNodeId,
     538             :                                                         FabricIndex fabric, const Transport::PeerAddress & peerAddress,
     539             :                                                         CryptoContext::SessionRole role, const CATValues & cats)
     540             : {
     541             :     Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
     542             :         chip::Transport::SecureSession::Type::kCASE, localSessionId, localNodeId, peerNodeId, cats, peerSessionId, fabric,
     543          17 :         GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
     544          17 :     VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
     545          17 :     SecureSession * secureSession = session.Value()->AsSecureSession();
     546          17 :     secureSession->SetPeerAddress(peerAddress);
     547             : 
     548          17 :     size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
     549          17 :     ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
     550          17 :     ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
     551             :         *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
     552          17 :     secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
     553          17 :     sessionHolder.Grab(session.Value());
     554          17 :     return CHIP_NO_ERROR;
     555          17 : }
     556             : 
     557        9507 : void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System::PacketBufferHandle && msg)
     558             : {
     559        9507 :     PacketHeader partialPacketHeader;
     560             : 
     561        9507 :     CHIP_ERROR err = partialPacketHeader.DecodeFixed(msg);
     562        9507 :     if (err != CHIP_NO_ERROR)
     563             :     {
     564           0 :         ChipLogError(Inet, "Failed to decode packet header: %" CHIP_ERROR_FORMAT, err.Format());
     565           0 :         return;
     566             :     }
     567             : 
     568        9507 :     if (partialPacketHeader.IsEncrypted())
     569             :     {
     570        9411 :         if (partialPacketHeader.IsGroupSession())
     571             :         {
     572           6 :             SecureGroupMessageDispatch(partialPacketHeader, peerAddress, std::move(msg));
     573             :         }
     574             :         else
     575             :         {
     576        9405 :             SecureUnicastMessageDispatch(partialPacketHeader, peerAddress, std::move(msg));
     577             :         }
     578             :     }
     579             :     else
     580             :     {
     581          96 :         UnauthenticatedMessageDispatch(partialPacketHeader, peerAddress, std::move(msg));
     582             :     }
     583        9507 : }
     584             : 
     585          96 : void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader,
     586             :                                                     const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg)
     587             : {
     588             :     MATTER_TRACE_SCOPE("Unauthenticated Message Dispatch", "SessionManager");
     589             : 
     590             :     // Drop unsecured messages with privacy enabled.
     591          96 :     if (partialPacketHeader.HasPrivacyFlag())
     592             :     {
     593           0 :         ChipLogError(Inet, "Dropping unauthenticated message with privacy flag set");
     594           0 :         return;
     595             :     }
     596             : 
     597          96 :     PacketHeader packetHeader;
     598          96 :     ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
     599             : 
     600          96 :     Optional<NodeId> source      = packetHeader.GetSourceNodeId();
     601          96 :     Optional<NodeId> destination = packetHeader.GetDestinationNodeId();
     602             : 
     603          96 :     if ((source.HasValue() && destination.HasValue()) || (!source.HasValue() && !destination.HasValue()))
     604             :     {
     605           0 :         ChipLogProgress(Inet,
     606             :                         "Received malformed unsecure packet with source 0x" ChipLogFormatX64 " destination 0x" ChipLogFormatX64,
     607             :                         ChipLogValueX64(source.ValueOr(kUndefinedNodeId)), ChipLogValueX64(destination.ValueOr(kUndefinedNodeId)));
     608           0 :         return; // ephemeral node id is only assigned to the initiator, there should be one and only one node id exists.
     609             :     }
     610             : 
     611          96 :     Optional<SessionHandle> optionalSession;
     612          96 :     if (source.HasValue())
     613             :     {
     614             :         // Assume peer is the initiator, we are the responder.
     615          56 :         optionalSession = mUnauthenticatedSessions.FindOrAllocateResponder(source.Value(), GetDefaultMRPConfig());
     616          56 :         if (!optionalSession.HasValue())
     617             :         {
     618           0 :             ChipLogError(Inet, "UnauthenticatedSession exhausted");
     619           0 :             return;
     620             :         }
     621             :     }
     622             :     else
     623             :     {
     624             :         // Assume peer is the responder, we are the initiator.
     625          40 :         optionalSession = mUnauthenticatedSessions.FindInitiator(destination.Value());
     626          40 :         if (!optionalSession.HasValue())
     627             :         {
     628           0 :             ChipLogProgress(Inet, "Received unknown unsecure packet for initiator 0x" ChipLogFormatX64,
     629             :                             ChipLogValueX64(destination.Value()));
     630           0 :             return;
     631             :         }
     632             :     }
     633             : 
     634          96 :     const SessionHandle & session                        = optionalSession.Value();
     635          96 :     Transport::UnauthenticatedSession * unsecuredSession = session->AsUnauthenticatedSession();
     636          96 :     unsecuredSession->SetPeerAddress(peerAddress);
     637          96 :     SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
     638             : 
     639          96 :     unsecuredSession->MarkActiveRx();
     640             : 
     641          96 :     PayloadHeader payloadHeader;
     642          96 :     ReturnOnFailure(payloadHeader.DecodeAndConsume(msg));
     643             : 
     644             :     // Verify message counter
     645          96 :     CHIP_ERROR err = unsecuredSession->GetPeerMessageCounter().VerifyUnencrypted(packetHeader.GetMessageCounter());
     646          96 :     if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
     647             :     {
     648           0 :         ChipLogDetail(Inet,
     649             :                       "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
     650             :                       " on exchange " ChipLogFormatExchangeId,
     651             :                       packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
     652           0 :         isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
     653           0 :         err         = CHIP_NO_ERROR;
     654             :     }
     655             :     else
     656             :     {
     657             :         // VerifyUnencrypted always returns one of CHIP_NO_ERROR or
     658             :         // CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED.
     659          96 :         unsecuredSession->GetPeerMessageCounter().CommitUnencrypted(packetHeader.GetMessageCounter());
     660             :     }
     661          96 :     if (mCB != nullptr)
     662             :     {
     663             :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
     664             :                                     unsecuredSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
     665             : 
     666          96 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, unsecuredSession, peerAddress, msg->Start(), msg->TotalLength());
     667          96 :         mCB->OnMessageReceived(packetHeader, payloadHeader, session, isDuplicate, std::move(msg));
     668             :     }
     669             :     else
     670             :     {
     671           0 :         ChipLogError(Inet, "Received UNSECURED message was not processed.");
     672             :     }
     673          96 : }
     674             : 
     675        9405 : void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader,
     676             :                                                   const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg)
     677             : {
     678             :     MATTER_TRACE_SCOPE("Secure Unicast Message Dispatch", "SessionManager");
     679             : 
     680        9405 :     CHIP_ERROR err = CHIP_NO_ERROR;
     681             : 
     682        9405 :     Optional<SessionHandle> session = mSecureSessions.FindSecureSessionByLocalKey(partialPacketHeader.GetSessionId());
     683             : 
     684        9405 :     PayloadHeader payloadHeader;
     685             : 
     686             :     // Drop secure unicast messages with privacy enabled.
     687        9405 :     if (partialPacketHeader.HasPrivacyFlag())
     688             :     {
     689           1 :         ChipLogError(Inet, "Dropping secure unicast message with privacy flag set");
     690           1 :         return;
     691             :     }
     692             : 
     693        9404 :     PacketHeader packetHeader;
     694        9404 :     ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
     695             : 
     696        9404 :     SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
     697             : 
     698        9404 :     if (msg.IsNull())
     699             :     {
     700           0 :         ChipLogError(Inet, "Secure transport received Unicast NULL packet, discarding");
     701           0 :         return;
     702             :     }
     703             : 
     704        9404 :     if (!session.HasValue())
     705             :     {
     706          10 :         ChipLogError(Inet, "Data received on an unknown session (LSID=%d). Dropping it!", packetHeader.GetSessionId());
     707          10 :         return;
     708             :     }
     709             : 
     710        9394 :     Transport::SecureSession * secureSession = session.Value()->AsSecureSession();
     711             : 
     712             :     // We need to allow through messages even on sessions that are pending
     713             :     // evictions, because for some cases (UpdateNOC, RemoveFabric, etc) there
     714             :     // can be a single exchange alive on the session waiting for a MRP ack, and
     715             :     // we need to make sure to send the ack through.  The exchange manager is
     716             :     // responsible for ensuring that such messages do not lead to new exchange
     717             :     // creation.
     718        9394 :     if (!secureSession->IsDefunct() && !secureSession->IsActiveSession() && !secureSession->IsPendingEviction())
     719             :     {
     720           0 :         ChipLogError(Inet, "Secure transport received message on a session in an invalid state (state = '%s')",
     721             :                      secureSession->GetStateStr());
     722           0 :         return;
     723             :     }
     724             : 
     725             :     // Decrypt and verify the message before message counter verification or any further processing.
     726             :     CryptoContext::NonceStorage nonce;
     727             :     // PASE Sessions use the undefined node ID of all zeroes, since there is no node ID to use
     728             :     // and the key is short-lived and always different for each PASE session.
     729        9402 :     CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(),
     730        9402 :                               secureSession->GetSecureSessionType() == SecureSession::Type::kCASE ? secureSession->GetPeerNodeId()
     731             :                                                                                                   : kUndefinedNodeId);
     732        9394 :     if (SecureMessageCodec::Decrypt(secureSession->GetCryptoContext(), nonce, payloadHeader, packetHeader, msg) != CHIP_NO_ERROR)
     733             :     {
     734           3 :         ChipLogError(Inet, "Secure transport received message, but failed to decode/authenticate it, discarding");
     735           3 :         return;
     736             :     }
     737             : 
     738        9391 :     err =
     739        9391 :         secureSession->GetSessionMessageCounter().GetPeerMessageCounter().VerifyEncryptedUnicast(packetHeader.GetMessageCounter());
     740        9391 :     if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
     741             :     {
     742           8 :         ChipLogDetail(Inet,
     743             :                       "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
     744             :                       " on exchange " ChipLogFormatExchangeId,
     745             :                       packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
     746           8 :         isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
     747           8 :         err         = CHIP_NO_ERROR;
     748             :     }
     749        9391 :     if (err != CHIP_NO_ERROR)
     750             :     {
     751           0 :         ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
     752           0 :         return;
     753             :     }
     754             : 
     755        9391 :     secureSession->MarkActiveRx();
     756             : 
     757        9391 :     if (isDuplicate == SessionMessageDelegate::DuplicateMessage::Yes && !payloadHeader.NeedsAck())
     758             :     {
     759             :         // If it's a duplicate message, but doesn't require an ack, let's drop it right here to save CPU
     760             :         // cycles on further message processing.
     761           2 :         return;
     762             :     }
     763             : 
     764        9389 :     if (isDuplicate == SessionMessageDelegate::DuplicateMessage::No)
     765             :     {
     766        9383 :         secureSession->GetSessionMessageCounter().GetPeerMessageCounter().CommitEncryptedUnicast(packetHeader.GetMessageCounter());
     767             :     }
     768             : 
     769             :     // TODO: once mDNS address resolution is available reconsider if this is required
     770             :     // This updates the peer address once a packet is received from a new address
     771             :     // and serves as a way to auto-detect peer changing IPs.
     772        9389 :     if (secureSession->GetPeerAddress() != peerAddress)
     773             :     {
     774         225 :         secureSession->SetPeerAddress(peerAddress);
     775             :     }
     776             : 
     777        9389 :     if (mCB != nullptr)
     778             :     {
     779             :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kSecureUnicast, &payloadHeader, &packetHeader,
     780             :                                     secureSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
     781        9389 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, secureSession, peerAddress, msg->Start(), msg->TotalLength());
     782        9389 :         mCB->OnMessageReceived(packetHeader, payloadHeader, session.Value(), isDuplicate, std::move(msg));
     783             :     }
     784             :     else
     785             :     {
     786           0 :         ChipLogError(Inet, "Received SECURED message was not processed.");
     787             :     }
     788        9436 : }
     789             : 
     790             : /**
     791             :  * Helper function to implement a single attempt to decrypt a groupcast message
     792             :  * using the given group key and privacy setting.
     793             :  *
     794             :  * @param[in] partialPacketHeader The partial packet header with non-obfuscated message fields (result of calling DecodeFixed).
     795             :  * @param[out] packetHeaderCopy A copy of the packet header, to be filled with privacy decrypted fields
     796             :  * @param[out] payloadHeader The payload header of the decrypted message
     797             :  * @param[in] applyPrivacy Whether to apply privacy deobfuscation
     798             :  * @param[out] msgCopy A copy of the message, to be filled with the decrypted message
     799             :  * @param[in] mac The MAC of the message
     800             :  * @param[in] groupContext The group context to use for decryption key material
     801             :  *
     802             :  * @return true if the message was decrypted successfully
     803             :  * @return false if the message could not be decrypted
     804             :  */
     805           8 : static bool GroupKeyDecryptAttempt(const PacketHeader & partialPacketHeader, PacketHeader & packetHeaderCopy,
     806             :                                    PayloadHeader & payloadHeader, bool applyPrivacy, System::PacketBufferHandle & msgCopy,
     807             :                                    const MessageAuthenticationCode & mac,
     808             :                                    const Credentials::GroupDataProvider::GroupSession & groupContext)
     809             : {
     810           8 :     bool decrypted = false;
     811           8 :     CryptoContext context(groupContext.keyContext);
     812             : 
     813           8 :     if (applyPrivacy)
     814             :     {
     815             :         // Perform privacy deobfuscation, if applicable.
     816           3 :         uint8_t * privacyHeader = partialPacketHeader.PrivacyHeader(msgCopy->Start());
     817           3 :         size_t privacyLength    = partialPacketHeader.PrivacyHeaderLength();
     818           3 :         if (CHIP_NO_ERROR != context.PrivacyDecrypt(privacyHeader, privacyLength, privacyHeader, partialPacketHeader, mac))
     819             :         {
     820           0 :             return false;
     821             :         }
     822             :     }
     823             : 
     824           8 :     if (packetHeaderCopy.DecodeAndConsume(msgCopy) != CHIP_NO_ERROR)
     825             :     {
     826           0 :         ChipLogError(Inet, "Failed to decode Groupcast packet header. Discarding.");
     827           0 :         return false;
     828             :     }
     829             : 
     830             :     // Optimization to reduce number of decryption attempts
     831           8 :     GroupId groupId = packetHeaderCopy.GetDestinationGroupId().Value();
     832           8 :     if (groupId != groupContext.group_id)
     833             :     {
     834           3 :         return false;
     835             :     }
     836             : 
     837             :     CryptoContext::NonceStorage nonce;
     838           5 :     CryptoContext::BuildNonce(nonce, packetHeaderCopy.GetSecurityFlags(), packetHeaderCopy.GetMessageCounter(),
     839           5 :                               packetHeaderCopy.GetSourceNodeId().Value());
     840           5 :     decrypted = (CHIP_NO_ERROR == SecureMessageCodec::Decrypt(context, nonce, payloadHeader, packetHeaderCopy, msgCopy));
     841             : 
     842           5 :     return decrypted;
     843           8 : }
     844             : 
     845           6 : void SessionManager::SecureGroupMessageDispatch(const PacketHeader & partialPacketHeader,
     846             :                                                 const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg)
     847             : {
     848             :     MATTER_TRACE_SCOPE("Group Message Dispatch", "SessionManager");
     849             : 
     850           6 :     PayloadHeader payloadHeader;
     851           6 :     PacketHeader packetHeaderCopy; /// Packet header decoded per group key, with privacy decrypted fields
     852           6 :     System::PacketBufferHandle msgCopy;
     853           6 :     Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider();
     854           6 :     VerifyOrReturn(nullptr != groups);
     855           6 :     CHIP_ERROR err = CHIP_NO_ERROR;
     856             : 
     857           6 :     if (!partialPacketHeader.HasDestinationGroupId())
     858             :     {
     859           0 :         return; // malformed packet
     860             :     }
     861             : 
     862             :     // Check if Message Header is valid first
     863           6 :     if (!(partialPacketHeader.IsValidMCSPMsg() || partialPacketHeader.IsValidGroupMsg()))
     864             :     {
     865           0 :         ChipLogError(Inet, "Invalid condition found in packet header");
     866           0 :         return;
     867             :     }
     868             : 
     869             :     // Trial decryption with GroupDataProvider
     870           6 :     Credentials::GroupDataProvider::GroupSession groupContext;
     871           6 :     auto iter = groups->IterateGroupSessions(partialPacketHeader.GetSessionId());
     872           6 :     if (iter == nullptr)
     873             :     {
     874           0 :         ChipLogError(Inet, "Failed to retrieve Groups iterator. Discarding everything");
     875           0 :         return;
     876             :     }
     877             : 
     878             :     // Extract MIC from the end of the message.
     879           6 :     uint8_t * data     = msg->Start();
     880           6 :     uint16_t len       = msg->DataLength();
     881           6 :     uint16_t footerLen = partialPacketHeader.MICTagLength();
     882           6 :     VerifyOrReturn(footerLen <= len);
     883             : 
     884           6 :     uint16_t taglen = 0;
     885             :     MessageAuthenticationCode mac;
     886           6 :     ReturnOnFailure(mac.Decode(partialPacketHeader, &data[len - footerLen], footerLen, &taglen));
     887           6 :     VerifyOrReturn(taglen == footerLen);
     888             : 
     889           6 :     bool decrypted = false;
     890          12 :     while (!decrypted && iter->Next(groupContext))
     891             :     {
     892           6 :         CryptoContext context(groupContext.keyContext);
     893           6 :         msgCopy = msg.CloneData();
     894           6 :         if (msgCopy.IsNull())
     895             :         {
     896           0 :             ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
     897           0 :             return;
     898             :         }
     899             : 
     900           6 :         bool privacy = partialPacketHeader.HasPrivacyFlag();
     901             :         decrypted =
     902           6 :             GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, privacy, msgCopy, mac, groupContext);
     903             : 
     904             : #if CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
     905           6 :         if (privacy && !decrypted)
     906             :         {
     907             :             // Try processing the P=1 message again without privacy as a work-around for invalid early-SVE2 nodes.
     908           2 :             msgCopy = msg.CloneData();
     909           2 :             if (msgCopy.IsNull())
     910             :             {
     911           0 :                 ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
     912           0 :                 return;
     913             :             }
     914             :             decrypted =
     915           2 :                 GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, false, msgCopy, mac, groupContext);
     916             :         }
     917             : #endif // CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
     918           6 :     }
     919           6 :     iter->Release();
     920             : 
     921           6 :     if (!decrypted)
     922             :     {
     923           1 :         ChipLogError(Inet, "Failed to decrypt group message. Discarding everything");
     924           1 :         return;
     925             :     }
     926           5 :     msg = std::move(msgCopy);
     927             : 
     928             :     // MCSP check
     929           5 :     if (packetHeaderCopy.IsValidMCSPMsg())
     930             :     {
     931             :         // TODO: When MCSP Msg, create Secure Session instead of a Group session
     932             : 
     933             :         // TODO
     934             :         // if (packetHeaderCopy.GetDestinationNodeId().Value() == ThisDeviceNodeID)
     935             :         // {
     936             :         //     MCSP processing..
     937             :         // }
     938             : 
     939           0 :         return;
     940             :     }
     941             : 
     942             :     // Group Messages should never send an Ack
     943           5 :     if (payloadHeader.NeedsAck())
     944             :     {
     945           0 :         ChipLogError(Inet, "Unexpected ACK requested for group message");
     946           0 :         return;
     947             :     }
     948             : 
     949             :     // Handle Group message counter here spec 4.7.3
     950             :     // spec 4.5.1.2 for msg counter
     951           5 :     Transport::PeerMessageCounter * counter = nullptr;
     952             : 
     953           5 :     if (CHIP_NO_ERROR ==
     954          15 :         gGroupPeerTable->FindOrAddPeer(groupContext.fabric_index, packetHeaderCopy.GetSourceNodeId().Value(),
     955          10 :                                        packetHeaderCopy.IsSecureSessionControlMsg(), counter))
     956             :     {
     957             : 
     958           5 :         if (Credentials::GroupDataProvider::SecurityPolicy::kTrustFirst == groupContext.security_policy)
     959             :         {
     960           4 :             err = counter->VerifyOrTrustFirstGroup(packetHeaderCopy.GetMessageCounter());
     961             :         }
     962             :         else
     963             :         {
     964             : 
     965             :             // TODO support cache and sync with MCSP. Issue  #11689
     966           1 :             ChipLogError(Inet, "Received Group Msg with key policy Cache and Sync, but MCSP is not implemented");
     967           1 :             return;
     968             : 
     969             :             // cache and sync
     970             :             // err = counter->VerifyGroup(packetHeaderCopy.GetMessageCounter());
     971             :         }
     972             : 
     973           4 :         if (err != CHIP_NO_ERROR)
     974             :         {
     975             :             // Exit now, since Group Messages don't have acks or responses of any kind.
     976           1 :             ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
     977           1 :             return;
     978             :         }
     979             :     }
     980             :     else
     981             :     {
     982           0 :         ChipLogError(Inet,
     983             :                      "Group Counter Tables full or invalid NodeId/FabricIndex after decryption of message, dropping everything");
     984           0 :         return;
     985             :     }
     986             : 
     987           3 :     counter->CommitGroup(packetHeaderCopy.GetMessageCounter());
     988             : 
     989           3 :     if (mCB != nullptr)
     990             :     {
     991             :         // TODO : When MCSP is done, clean up session creation logic
     992           3 :         Transport::IncomingGroupSession groupSession(groupContext.group_id, groupContext.fabric_index,
     993           3 :                                                      packetHeaderCopy.GetSourceNodeId().Value());
     994             : 
     995             :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kGroupMessage, &payloadHeader, &packetHeaderCopy,
     996             :                                     &groupSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
     997             : 
     998           3 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeaderCopy, &groupSession, peerAddress, msg->Start(), msg->TotalLength());
     999           3 :         mCB->OnMessageReceived(packetHeaderCopy, payloadHeader, SessionHandle(groupSession),
    1000           3 :                                SessionMessageDelegate::DuplicateMessage::No, std::move(msg));
    1001           3 :     }
    1002             :     else
    1003             :     {
    1004           0 :         ChipLogError(Inet, "Received GROUP message was not processed.");
    1005             :     }
    1006          12 : }
    1007             : 
    1008           1 : Optional<SessionHandle> SessionManager::FindSecureSessionForNode(ScopedNodeId peerNodeId,
    1009             :                                                                  const Optional<Transport::SecureSession::Type> & type)
    1010             : {
    1011           1 :     SecureSession * found = nullptr;
    1012             : 
    1013           1 :     mSecureSessions.ForEachSession([&peerNodeId, &type, &found](auto session) {
    1014           4 :         if (session->IsActiveSession() && session->GetPeer() == peerNodeId &&
    1015           2 :             (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
    1016             :         {
    1017             :             //
    1018             :             // Select the active session with the most recent activity to return back to the caller.
    1019             :             //
    1020           2 :             if ((found == nullptr) || (found->GetLastActivityTime() < session->GetLastActivityTime()))
    1021             :             {
    1022           2 :                 found = session;
    1023             :             }
    1024             :         }
    1025             : 
    1026           2 :         return Loop::Continue;
    1027             :     });
    1028             : 
    1029           1 :     return found != nullptr ? MakeOptional<SessionHandle>(*found) : Optional<SessionHandle>::Missing();
    1030             : }
    1031             : 
    1032             : /**
    1033             :  * Provides a means to get diagnostic information such as number of sessions.
    1034             :  */
    1035           0 : [[maybe_unused]] CHIP_ERROR SessionManager::ForEachSessionHandle(void * context, SessionHandleCallback lambda)
    1036             : {
    1037           0 :     mSecureSessions.ForEachSession([&](auto session) {
    1038           0 :         SessionHandle handle(*session);
    1039           0 :         lambda(context, handle);
    1040           0 :         return Loop::Continue;
    1041           0 :     });
    1042           0 :     return CHIP_NO_ERROR;
    1043             : }
    1044             : 
    1045             : } // namespace chip

Generated by: LCOV version 1.14