Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - PairingSession.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 93.8 % 129 121
Test Date: 2025-02-22 08:08:07 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           48 : CHIP_ERROR PairingSession::EncodeSessionParameters(TLV::Tag tag, const ReliableMessageProtocolConfig & mrpLocalConfig,
     122              :                                                    TLV::TLVWriter & tlvWriter)
     123              : {
     124              :     TLV::TLVType mrpParamsContainer;
     125           48 :     ReturnErrorOnFailure(tlvWriter.StartContainer(tag, TLV::kTLVType_Structure, mrpParamsContainer));
     126           48 :     ReturnErrorOnFailure(
     127              :         tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionIdleInterval), mrpLocalConfig.mIdleRetransTimeout.count()));
     128           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveInterval),
     129              :                                        mrpLocalConfig.mActiveRetransTimeout.count()));
     130           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveThreshold),
     131              :                                        mrpLocalConfig.mActiveThresholdTime.count()));
     132              : 
     133           48 :     uint16_t dataModel = Revision::kDataModelRevision;
     134           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kDataModelRevision), dataModel));
     135              : 
     136           48 :     uint16_t interactionModel = Revision::kInteractionModelRevision;
     137           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kInteractionModelRevision), interactionModel));
     138              : 
     139           48 :     uint32_t specVersion = Revision::kSpecificationVersion;
     140           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSpecificationVersion), specVersion));
     141              : 
     142           48 :     uint16_t maxPathsPerInvoke = CHIP_CONFIG_MAX_PATHS_PER_INVOKE;
     143           48 :     ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxPathsPerInvoke), maxPathsPerInvoke));
     144           48 :     return tlvWriter.EndContainer(mrpParamsContainer);
     145              : }
     146              : 
     147           43 : CHIP_ERROR PairingSession::DecodeSessionParametersIfPresent(TLV::Tag expectedTag, TLV::ContiguousBufferTLVReader & tlvReader,
     148              :                                                             SessionParameters & outSessionParameters)
     149              : {
     150           43 :     CHIP_ERROR err = CHIP_NO_ERROR;
     151              : 
     152              :     // The MRP parameters are optional.
     153           43 :     if (tlvReader.GetTag() != expectedTag)
     154              :     {
     155            1 :         return CHIP_NO_ERROR;
     156              :     }
     157              : 
     158           42 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     159           42 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
     160              : 
     161           42 :     ReturnErrorOnFailure(tlvReader.Next());
     162              : 
     163           42 :     ChipLogDetail(SecureChannel, "Found MRP parameters in the message");
     164              : 
     165              :     // All TLV elements in the structure are optional. If the first element is present, process it and move
     166              :     // the TLV reader to the next element.
     167           42 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionIdleInterval)
     168              :     {
     169              :         uint32_t idleRetransTimeout;
     170           42 :         ReturnErrorOnFailure(tlvReader.Get(idleRetransTimeout));
     171           42 :         outSessionParameters.SetMRPIdleRetransTimeout(System::Clock::Milliseconds32(idleRetransTimeout));
     172              : 
     173              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     174           42 :         SuccessOrExit(err = tlvReader.Next());
     175              :     }
     176              : 
     177           42 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveInterval)
     178              :     {
     179              :         uint32_t activeRetransTimeout;
     180           42 :         ReturnErrorOnFailure(tlvReader.Get(activeRetransTimeout));
     181           42 :         outSessionParameters.SetMRPActiveRetransTimeout(System::Clock::Milliseconds32(activeRetransTimeout));
     182              : 
     183              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     184           42 :         SuccessOrExit(err = tlvReader.Next());
     185              :     }
     186              : 
     187           42 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveThreshold)
     188              :     {
     189              :         uint16_t activeThresholdTime;
     190           42 :         ReturnErrorOnFailure(tlvReader.Get(activeThresholdTime));
     191           42 :         outSessionParameters.SetMRPActiveThresholdTime(System::Clock::Milliseconds16(activeThresholdTime));
     192              : 
     193              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     194           42 :         SuccessOrExit(err = tlvReader.Next());
     195              :     }
     196              : 
     197           39 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kDataModelRevision)
     198              :     {
     199              :         uint16_t dataModelRevision;
     200           39 :         ReturnErrorOnFailure(tlvReader.Get(dataModelRevision));
     201           39 :         outSessionParameters.SetDataModelRevision(dataModelRevision);
     202              : 
     203              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     204           39 :         SuccessOrExit(err = tlvReader.Next());
     205              :     }
     206              : 
     207           39 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kInteractionModelRevision)
     208              :     {
     209              :         uint16_t interactionModelRevision;
     210           39 :         ReturnErrorOnFailure(tlvReader.Get(interactionModelRevision));
     211           39 :         outSessionParameters.SetInteractionModelRevision(interactionModelRevision);
     212              : 
     213              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     214           39 :         SuccessOrExit(err = tlvReader.Next());
     215              :     }
     216              : 
     217           39 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSpecificationVersion)
     218              :     {
     219              :         uint32_t specificationVersion;
     220           39 :         ReturnErrorOnFailure(tlvReader.Get(specificationVersion));
     221           39 :         outSessionParameters.SetSpecificationVersion(specificationVersion);
     222              : 
     223              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     224           39 :         SuccessOrExit(err = tlvReader.Next());
     225              :     }
     226              : 
     227           39 :     if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kMaxPathsPerInvoke)
     228              :     {
     229              :         uint16_t maxPathsPerInvoke;
     230           39 :         ReturnErrorOnFailure(tlvReader.Get(maxPathsPerInvoke));
     231           39 :         outSessionParameters.SetMaxPathsPerInvoke(maxPathsPerInvoke);
     232              : 
     233              :         // The next element is optional. If it's not present, return CHIP_NO_ERROR.
     234           39 :         SuccessOrExit(err = tlvReader.Next());
     235              :     }
     236              : 
     237              :     // Future proofing - Don't error out if there are other tags
     238            0 : exit:
     239           42 :     if (err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR)
     240              :     {
     241           42 :         return tlvReader.ExitContainer(containerType);
     242              :     }
     243            0 :     return err;
     244              : }
     245              : 
     246            4 : bool PairingSession::IsSessionEstablishmentInProgress()
     247              : {
     248            4 :     if (!mSecureSessionHolder)
     249              :     {
     250            0 :         return false;
     251              :     }
     252              : 
     253            4 :     Transport::SecureSession * secureSession = mSecureSessionHolder->AsSecureSession();
     254            4 :     return secureSession->IsEstablishing();
     255              : }
     256              : 
     257          177 : void PairingSession::Clear()
     258              : {
     259              :     // Clear acts like the destructor of PairingSession. If it is called during
     260              :     // the middle of pairing, that means we should terminate the exchange. For the
     261              :     // normal path, the exchange should already be discarded before calling Clear.
     262          177 :     if (mExchangeCtxt.HasValue())
     263              :     {
     264              :         // The only time we reach this is when we are getting destroyed in the
     265              :         // middle of our handshake. In that case, there is no point in trying to
     266              :         // do MRP resends of the last message we sent. So, abort the exchange
     267              :         // instead of just closing it.
     268            6 :         mExchangeCtxt.Value()->Abort();
     269            6 :         mExchangeCtxt.ClearValue();
     270              :     }
     271          177 :     mSecureSessionHolder.Release();
     272          177 :     mPeerSessionId.ClearValue();
     273          177 :     mSessionManager = nullptr;
     274          177 : }
     275              : 
     276           16 : void PairingSession::NotifySessionEstablishmentError(CHIP_ERROR error, SessionEstablishmentStage stage)
     277              : {
     278           16 :     if (mDelegate == nullptr)
     279              :     {
     280              :         // Already notified success or error.
     281           10 :         return;
     282              :     }
     283              : 
     284            6 :     auto * delegate = mDelegate;
     285            6 :     mDelegate       = nullptr;
     286            6 :     delegate->OnSessionEstablishmentError(error, stage);
     287              : }
     288              : 
     289           10 : void PairingSession::OnSessionReleased()
     290              : {
     291           10 :     if (mRole == CryptoContext::SessionRole::kInitiator)
     292              :     {
     293            5 :         NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
     294            5 :         return;
     295              :     }
     296              : 
     297              :     // Send the error notification async, because our delegate is likely to want
     298              :     // to create a new session to listen for new connection attempts, and doing
     299              :     // that under an OnSessionReleased notification is not safe.
     300            5 :     if (!mSessionManager)
     301              :     {
     302            0 :         return;
     303              :     }
     304              : 
     305            5 :     mSessionManager->SystemLayer()->ScheduleWork(
     306            5 :         [](auto * systemLayer, auto * appState) -> void {
     307            5 :             ChipLogError(Inet, "ASYNC CASE Session establishment failed");
     308            5 :             auto * _this = static_cast<PairingSession *>(appState);
     309            5 :             _this->NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
     310            5 :         },
     311              :         this);
     312              : }
     313              : 
     314              : } // namespace chip
        

Generated by: LCOV version 2.0-1