Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - PairingSession.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 93.8 % 129 121
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : #include <protocols/secure_channel/PairingSession.h>
      20              : 
      21              : #include <app/SpecificationDefinedRevisions.h>
      22              : #include <lib/core/CHIPConfig.h>
      23              : #include <lib/core/TLVTypes.h>
      24              : #include <lib/support/SafeInt.h>
      25              : #include <lib/support/TypeTraits.h>
      26              : #include <platform/CHIPDeviceEvent.h>
      27              : #include <platform/PlatformManager.h>
      28              : #include <transport/SessionManager.h>
      29              : 
      30              : namespace chip {
      31              : 
      32           51 : CHIP_ERROR PairingSession::AllocateSecureSession(SessionManager & sessionManager, const ScopedNodeId & sessionEvictionHint)
      33              : {
      34           51 :     auto handle = sessionManager.AllocateSession(GetSecureSessionType(), sessionEvictionHint);
      35           51 :     VerifyOrReturnError(handle.HasValue(), CHIP_ERROR_NO_MEMORY);
      36           51 :     VerifyOrReturnError(mSecureSessionHolder.GrabPairingSession(handle.Value()), CHIP_ERROR_INTERNAL);
      37           51 :     mSessionManager = &sessionManager;
      38           51 :     return CHIP_NO_ERROR;
      39           51 : }
      40              : 
      41           26 : CHIP_ERROR PairingSession::ActivateSecureSession(const Transport::PeerAddress & peerAddress)
      42              : {
      43              :     // Prepare SecureSession fields, including key derivation, first, before activation
      44           26 :     Transport::SecureSession * secureSession = mSecureSessionHolder->AsSecureSession();
      45           26 :     ReturnErrorOnFailure(DeriveSecureSession(secureSession->GetCryptoContext()));
      46              : 
      47           26 :     uint16_t peerSessionId = GetPeerSessionId();
      48           26 :     secureSession->SetPeerAddress(peerAddress);
      49           26 :     secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
      50              : 
      51              :     // Call Activate last, otherwise errors on anything after would lead to
      52              :     // a partially valid session.
      53           26 :     secureSession->Activate(GetLocalScopedNodeId(), GetPeer(), GetPeerCATs(), peerSessionId, GetRemoteSessionParameters());
      54              : 
      55           26 :     ChipLogDetail(Inet, "New secure session activated for device " ChipLogFormatScopedNodeId ", LSID:%d PSID:%d!",
      56              :                   ChipLogValueScopedNodeId(GetPeer()), secureSession->GetLocalSessionId(), peerSessionId);
      57              : 
      58           26 :     return CHIP_NO_ERROR;
      59              : }
      60              : 
      61           26 : void PairingSession::Finish()
      62              : {
      63           26 :     Transport::PeerAddress address = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress();
      64              : 
      65              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
      66           26 :     if (address.GetTransportType() == Transport::Type::kTcp)
      67              :     {
      68              :         // Fetch the connection for the unauthenticated session used to set up
      69              :         // the secure session.
      70              :         Transport::ActiveTCPConnectionState * conn =
      71            0 :             mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetTCPConnection();
      72              : 
      73              :         // Associate the connection with the secure session being activated.
      74            0 :         mSecureSessionHolder->AsSecureSession()->SetTCPConnection(conn);
      75              :     }
      76              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
      77              :     // Discard the exchange so that Clear() doesn't try closing it. The exchange will handle that.
      78           26 :     DiscardExchange();
      79              : 
      80           26 :     CHIP_ERROR err = ActivateSecureSession(address);
      81           26 :     if (err == CHIP_NO_ERROR)
      82              :     {
      83           26 :         VerifyOrDie(mSecureSessionHolder);
      84           26 :         DeviceLayer::ChipDeviceEvent event{ .Type = DeviceLayer::DeviceEventType::kSecureSessionEstablished };
      85           26 :         event.SecureSessionEstablished.TransportType = to_underlying(address.GetTransportType());
      86           26 :         event.SecureSessionEstablished.SecureSessionType =
      87           26 :             to_underlying(mSecureSessionHolder->AsSecureSession()->GetSecureSessionType());
      88           26 :         event.SecureSessionEstablished.LocalSessionId = mSecureSessionHolder->AsSecureSession()->GetLocalSessionId();
      89           26 :         event.SecureSessionEstablished.PeerNodeId     = mSecureSessionHolder->GetPeer().GetNodeId();
      90           26 :         event.SecureSessionEstablished.FabricIndex    = mSecureSessionHolder->GetPeer().GetFabricIndex();
      91           26 :         if (DeviceLayer::PlatformMgr().PostEvent(&event) != CHIP_NO_ERROR)
      92              :         {
      93            0 :             ChipLogError(SecureChannel, "Failed to post Secure Session established event");
      94              :         }
      95              :         // Make sure to null out mDelegate so we don't send it any other
      96              :         // notifications.
      97           26 :         auto * delegate = mDelegate;
      98           26 :         mDelegate       = nullptr;
      99           26 :         delegate->OnSessionEstablished(mSecureSessionHolder.Get().Value());
     100              :     }
     101              :     else
     102              :     {
     103            0 :         NotifySessionEstablishmentError(err);
     104              :     }
     105           26 : }
     106              : 
     107           30 : void PairingSession::DiscardExchange()
     108              : {
     109           30 :     if (mExchangeCtxt.HasValue())
     110              :     {
     111              :         // Make sure the exchange doesn't try to notify us when it closes,
     112              :         // since we might be dead by then.
     113           30 :         mExchangeCtxt.Value()->SetDelegate(nullptr);
     114              : 
     115              :         // Null out mExchangeCtxt so that Clear() doesn't try closing it.  The
     116              :         // exchange will handle that.
     117           30 :         mExchangeCtxt.ClearValue();
     118              :     }
     119           30 : }
     120              : 
     121           36 : CHIP_ERROR PairingSession::EncodeSessionParameters(TLV::Tag tag, const ReliableMessageProtocolConfig & mrpLocalConfig,
     122              :                                                    TLV::TLVWriter & tlvWriter)
     123              : {
     124              :     TLV::TLVType mrpParamsContainer;
     125           36 :     ReturnErrorOnFailure(tlvWriter.StartContainer(tag, TLV::kTLVType_Structure, mrpParamsContainer));
     126           36 :     ReturnErrorOnFailure(
     127              :         tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionIdleInterval), mrpLocalConfig.mIdleRetransTimeout.count()));
     128           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveInterval),
     129              :                                        mrpLocalConfig.mActiveRetransTimeout.count()));
     130           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveThreshold),
     131              :                                        mrpLocalConfig.mActiveThresholdTime.count()));
     132              : 
     133           36 :     uint16_t dataModel = Revision::kDataModelRevision;
     134           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kDataModelRevision), dataModel));
     135              : 
     136           36 :     uint16_t interactionModel = Revision::kInteractionModelRevision;
     137           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kInteractionModelRevision), interactionModel));
     138              : 
     139           36 :     uint32_t specVersion = Revision::kSpecificationVersion;
     140           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSpecificationVersion), specVersion));
     141              : 
     142           36 :     uint16_t maxPathsPerInvoke = CHIP_CONFIG_MAX_PATHS_PER_INVOKE;
     143           36 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxPathsPerInvoke), maxPathsPerInvoke));
     144           36 :     return tlvWriter.EndContainer(mrpParamsContainer);
     145              : }
     146              : 
     147           31 : CHIP_ERROR PairingSession::DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TLV::ContiguousBufferTLVReader & tlvReader)
     148              : {
     149           31 :     CHIP_ERROR err = CHIP_NO_ERROR;
     150              : 
     151              :     // The MRP parameters are optional.
     152           31 :     if (tlvReader.GetTag() != expectedTag)
     153              :     {
     154            1 :         return CHIP_NO_ERROR;
     155              :     }
     156              : 
     157           30 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     158           30 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
     159              : 
     160           30 :     ReturnErrorOnFailure(tlvReader.Next());
     161              : 
     162           30 :     ChipLogDetail(SecureChannel, "Found MRP parameters in the message");
     163              : 
     164              :     // All TLV elements in the structure are optional. If the first element is present, process it and move
     165              :     // the TLV reader to the next element.
     166           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionIdleInterval)
     167              :     {
     168              :         uint32_t idleRetransTimeout;
     169           30 :         ReturnErrorOnFailure(tlvReader.Get(idleRetransTimeout));
     170           30 :         mRemoteSessionParams.SetMRPIdleRetransTimeout(System::Clock::Milliseconds32(idleRetransTimeout));
     171              : 
     172              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     173           30 :         SuccessOrExit(err = tlvReader.Next());
     174              :     }
     175              : 
     176           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveInterval)
     177              :     {
     178              :         uint32_t activeRetransTimeout;
     179           30 :         ReturnErrorOnFailure(tlvReader.Get(activeRetransTimeout));
     180           30 :         mRemoteSessionParams.SetMRPActiveRetransTimeout(System::Clock::Milliseconds32(activeRetransTimeout));
     181              : 
     182              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     183           30 :         SuccessOrExit(err = tlvReader.Next());
     184              :     }
     185              : 
     186           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveThreshold)
     187              :     {
     188              :         uint16_t activeThresholdTime;
     189           30 :         ReturnErrorOnFailure(tlvReader.Get(activeThresholdTime));
     190           30 :         mRemoteSessionParams.SetMRPActiveThresholdTime(System::Clock::Milliseconds16(activeThresholdTime));
     191              : 
     192              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     193           30 :         SuccessOrExit(err = tlvReader.Next());
     194              :     }
     195              : 
     196           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kDataModelRevision)
     197              :     {
     198              :         uint16_t dataModelRevision;
     199           30 :         ReturnErrorOnFailure(tlvReader.Get(dataModelRevision));
     200           30 :         mRemoteSessionParams.SetDataModelRevision(dataModelRevision);
     201              : 
     202              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     203           30 :         SuccessOrExit(err = tlvReader.Next());
     204              :     }
     205              : 
     206           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kInteractionModelRevision)
     207              :     {
     208              :         uint16_t interactionModelRevision;
     209           30 :         ReturnErrorOnFailure(tlvReader.Get(interactionModelRevision));
     210           30 :         mRemoteSessionParams.SetInteractionModelRevision(interactionModelRevision);
     211              : 
     212              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     213           30 :         SuccessOrExit(err = tlvReader.Next());
     214              :     }
     215              : 
     216           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSpecificationVersion)
     217              :     {
     218              :         uint32_t specificationVersion;
     219           30 :         ReturnErrorOnFailure(tlvReader.Get(specificationVersion));
     220           30 :         mRemoteSessionParams.SetSpecificationVersion(specificationVersion);
     221              : 
     222              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     223           30 :         SuccessOrExit(err = tlvReader.Next());
     224              :     }
     225              : 
     226           30 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kMaxPathsPerInvoke)
     227              :     {
     228              :         uint16_t maxPathsPerInvoke;
     229           30 :         ReturnErrorOnFailure(tlvReader.Get(maxPathsPerInvoke));
     230           30 :         mRemoteSessionParams.SetMaxPathsPerInvoke(maxPathsPerInvoke);
     231              : 
     232              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     233           30 :         SuccessOrExit(err = tlvReader.Next());
     234              :     }
     235              : 
     236              :     // Future proofing - Don't error out if there are other tags
     237            0 : exit:
     238           30 :     if (err == CHIP_END_OF_TLV)
     239              :     {
     240           30 :         return tlvReader.ExitContainer(containerType);
     241              :     }
     242            0 :     return err;
     243              : }
     244              : 
     245            4 : bool PairingSession::IsSessionEstablishmentInProgress()
     246              : {
     247            4 :     if (!mSecureSessionHolder)
     248              :     {
     249            0 :         return false;
     250              :     }
     251              : 
     252            4 :     Transport::SecureSession * secureSession = mSecureSessionHolder->AsSecureSession();
     253            4 :     return secureSession->IsEstablishing();
     254              : }
     255              : 
     256          208 : void PairingSession::Clear()
     257              : {
     258              :     // Clear acts like the destructor of PairingSession. If it is called during
     259              :     // the middle of pairing, that means we should terminate the exchange. For the
     260              :     // normal path, the exchange should already be discarded before calling Clear.
     261          208 :     if (mExchangeCtxt.HasValue())
     262              :     {
     263              :         // The only time we reach this is when we are getting destroyed in the
     264              :         // middle of our handshake. In that case, there is no point in trying to
     265              :         // do MRP resends of the last message we sent. So, abort the exchange
     266              :         // instead of just closing it.
     267            6 :         mExchangeCtxt.Value()->Abort();
     268            6 :         mExchangeCtxt.ClearValue();
     269              :     }
     270          208 :     mSecureSessionHolder.Release();
     271          208 :     mPeerSessionId.ClearValue();
     272          208 :     mSessionManager = nullptr;
     273          208 : }
     274              : 
     275           16 : void PairingSession::NotifySessionEstablishmentError(CHIP_ERROR error, SessionEstablishmentStage stage)
     276              : {
     277           16 :     if (mDelegate == nullptr)
     278              :     {
     279              :         // Already notified success or error.
     280           10 :         return;
     281              :     }
     282              : 
     283            6 :     auto * delegate = mDelegate;
     284            6 :     mDelegate       = nullptr;
     285            6 :     delegate->OnSessionEstablishmentError(error, stage);
     286              : }
     287              : 
     288           10 : void PairingSession::OnSessionReleased()
     289              : {
     290           10 :     if (mRole == CryptoContext::SessionRole::kInitiator)
     291              :     {
     292            5 :         NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
     293            5 :         return;
     294              :     }
     295              : 
     296              :     // Send the error notification async, because our delegate is likely to want
     297              :     // to create a new session to listen for new connection attempts, and doing
     298              :     // that under an OnSessionReleased notification is not safe.
     299            5 :     if (!mSessionManager)
     300              :     {
     301            0 :         return;
     302              :     }
     303              : 
     304            5 :     mSessionManager->SystemLayer()->ScheduleWork(
     305            5 :         [](auto * systemLayer, auto * appState) -> void {
     306            5 :             ChipLogError(Inet, "ASYNC CASE Session establishment failed");
     307            5 :             auto * _this = static_cast<PairingSession *>(appState);
     308            5 :             _this->NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
     309            5 :         },
     310              :         this);
     311              : }
     312              : 
     313              : } // namespace chip
        

Generated by: LCOV version 2.0-1