Matter SDK Coverage Report
Current view: top level - transport - SecureSession.h (source / functions) Coverage Total Hit
Test: SHA:4cbce7f768f16e614f5a8ccb8cd93c92cbeae70d Lines: 88.8 % 89 79
Test Date: 2025-04-26 07:09:35 Functions: 94.6 % 37 35

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : /**
      19              :  * @brief Defines state relevant for an active connection to a peer.
      20              :  */
      21              : 
      22              : #pragma once
      23              : 
      24              : #include <app/util/basic-types.h>
      25              : #include <ble/Ble.h>
      26              : #include <lib/core/ReferenceCounted.h>
      27              : #include <messaging/ReliableMessageProtocolConfig.h>
      28              : #include <transport/CryptoContext.h>
      29              : #include <transport/Session.h>
      30              : #include <transport/SessionMessageCounter.h>
      31              : #include <transport/raw/PeerAddress.h>
      32              : 
      33              : namespace chip {
      34              : namespace Transport {
      35              : 
      36              : class SecureSessionTable;
      37              : class SecureSessionDeleter
      38              : {
      39              : public:
      40              :     static void Release(SecureSession * entry);
      41              : };
      42              : 
      43              : /**
      44              :  * Defines state of a peer connection at a transport layer.
      45              :  *
      46              :  * Information contained within the state:
      47              :  *   - SecureSessionType represents CASE or PASE session
      48              :  *   - PeerAddress represents how to talk to the peer
      49              :  *   - PeerNodeId is the unique ID of the peer
      50              :  *   - PeerCATs represents CASE Authenticated Tags
      51              :  *   - SendMessageIndex is an ever increasing index for sending messages
      52              :  *   - LastActivityTime is a monotonic timestamp of when this connection was
      53              :  *     last used. Inactive connections can expire.
      54              :  *   - CryptoContext contains the encryption context of a connection
      55              :  */
      56              : class SecureSession : public Session, public ReferenceCounted<SecureSession, SecureSessionDeleter, 0, uint16_t>
      57              : {
      58              : public:
      59              :     /**
      60              :      *  @brief
      61              :      *    Defines SecureSession Type. Currently supported types are PASE and CASE.
      62              :      */
      63              :     enum class Type : uint8_t
      64              :     {
      65              :         kPASE = 1,
      66              :         kCASE = 2,
      67              :     };
      68              : 
      69              :     // Test-only: inject a session in Active state.
      70              :     // TODO: Tests should allocate a pending session and then call Activate(), just like non-test code does.
      71         1550 :     SecureSession(SecureSessionTable & table, Type secureSessionType, uint16_t localSessionId, NodeId localNodeId,
      72              :                   NodeId peerNodeId, CATValues peerCATs, uint16_t peerSessionId, FabricIndex fabric,
      73         1550 :                   const ReliableMessageProtocolConfig & config) :
      74         1550 :         mTable(table),
      75         1550 :         mState(State::kEstablishing), mSecureSessionType(secureSessionType), mLocalNodeId(localNodeId), mPeerNodeId(peerNodeId),
      76         1550 :         mPeerCATs(peerCATs), mLocalSessionId(localSessionId), mPeerSessionId(peerSessionId), mRemoteSessionParams(config)
      77              :     {
      78         1550 :         MoveToState(State::kActive);
      79         1550 :         Retain(); // Put the test session in Active state. This ref is released inside MarkForEviction
      80         1550 :         SetFabricIndex(fabric);
      81         1550 :         ChipLogDetail(Inet, "SecureSession[%p]: Allocated for Test Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
      82              :                       mLocalSessionId);
      83         1550 :     }
      84              : 
      85              :     /**
      86              :      * @brief
      87              :      *   Construct a secure session object to associate with a pending secure
      88              :      *   session establishment attempt.  The object for the pending session
      89              :      *   receives a local session ID, but no other state.
      90              :      */
      91       133750 :     SecureSession(SecureSessionTable & table, Type secureSessionType, uint16_t localSessionId) :
      92       133750 :         mTable(table), mState(State::kEstablishing), mSecureSessionType(secureSessionType), mLocalSessionId(localSessionId)
      93              :     {
      94       133750 :         ChipLogDetail(Inet, "SecureSession[%p]: Allocated Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
      95              :                       mLocalSessionId);
      96       133750 :     }
      97              : 
      98              :     /**
      99              :      * @brief
     100              :      *   Activate a pending Secure Session that had been reserved during CASE or
     101              :      *   PASE, setting internal state according to the parameters used and
     102              :      *   discovered during session establishment.
     103              :      */
     104              :     void Activate(const ScopedNodeId & localNode, const ScopedNodeId & peerNode, CATValues peerCATs, uint16_t peerSessionId,
     105              :                   const SessionParameters & sessionParameters);
     106              : 
     107       135300 :     ~SecureSession() override
     108       135300 :     {
     109       135300 :         ChipLogDetail(Inet, "SecureSession[%p]: Released - Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
     110              :                       mLocalSessionId);
     111       135300 :     }
     112              : 
     113              :     SecureSession(SecureSession &&)                  = delete;
     114              :     SecureSession(const SecureSession &)             = delete;
     115              :     SecureSession & operator=(const SecureSession &) = delete;
     116              :     SecureSession & operator=(SecureSession &&)      = delete;
     117              : 
     118              :     void Retain() override;
     119              :     void Release() override;
     120              : 
     121        27773 :     bool IsActiveSession() const override { return mState == State::kActive; }
     122           56 :     bool IsEstablishing() const { return mState == State::kEstablishing; }
     123           16 :     bool IsPendingEviction() const { return mState == State::kPendingEviction; }
     124        13873 :     bool IsDefunct() const { return mState == State::kDefunct; }
     125           84 :     const char * GetStateStr() const { return StateToString(mState); }
     126              : 
     127              :     /*
     128              :      * This marks the session for eviction. It will first detach all SessionHolders attached to this
     129              :      * session by calling 'OnSessionReleased' on each of them. This will force them to release their reference
     130              :      * to the session. If there are no more references left, the session will then be de-allocated.
     131              :      *
     132              :      * Once marked for eviction, the session SHALL NOT ever become active again.
     133              :      *
     134              :      */
     135              :     void MarkForEviction();
     136              : 
     137              :     /*
     138              :      * This marks a previously active session as defunct to temporarily prevent it from being used with
     139              :      * new exchanges to send or receive messages on this session. This should be called when there is suspicion of
     140              :      * a loss-of-sync with the session state on the associated peer. This could arise if there is evidence
     141              :      * of transport failure.
     142              :      *
     143              :      * If messages are received thereafter on this session, the session SHALL be put back into the Active state.
     144              :      *
     145              :      * This SHALL only be callable on an active session.
     146              :      * This SHALL NOT detach any existing SessionHolders.
     147              :      *
     148              :      */
     149              :     void MarkAsDefunct();
     150              : 
     151       702291 :     Session::SessionType GetSessionType() const override { return Session::SessionType::kSecure; }
     152              : 
     153        30402 :     ScopedNodeId GetPeer() const override { return ScopedNodeId(mPeerNodeId, GetFabricIndex()); }
     154              : 
     155        13847 :     ScopedNodeId GetLocalScopedNodeId() const override { return ScopedNodeId(mLocalNodeId, GetFabricIndex()); }
     156              : 
     157              :     Access::SubjectDescriptor GetSubjectDescriptor() const override;
     158              : 
     159              :     bool IsCommissioningSession() const override;
     160              : 
     161        57266 :     bool AllowsMRP() const override { return (GetPeerAddress().GetTransportType() == Transport::Type::kUdp); }
     162              : 
     163        15856 :     bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
     164              : 
     165         8723 :     System::Clock::Milliseconds32 GetAckTimeout(bool isFirstMessageOnExchange) const override
     166              :     {
     167         8723 :         switch (mPeerAddress.GetTransportType())
     168              :         {
     169         8676 :         case Transport::Type::kUdp: {
     170         8676 :             const ReliableMessageProtocolConfig & remoteMRPConfig = mRemoteSessionParams.GetMRPConfig();
     171         8676 :             return GetRetransmissionTimeout(remoteMRPConfig.mActiveRetransTimeout, remoteMRPConfig.mIdleRetransTimeout,
     172        17352 :                                             GetLastPeerActivityTime(), remoteMRPConfig.mActiveThresholdTime,
     173         8676 :                                             isFirstMessageOnExchange);
     174              :         }
     175            0 :         case Transport::Type::kTcp:
     176            0 :             return System::Clock::Seconds16(30);
     177            0 :         case Transport::Type::kBle:
     178            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     179           47 :         default:
     180           47 :             break;
     181              :         }
     182           47 :         return System::Clock::Timeout();
     183              :     }
     184              : 
     185         9106 :     System::Clock::Milliseconds32 GetMessageReceiptTimeout(System::Clock::Timestamp ourLastActivity,
     186              :                                                            bool isFirstMessageOnExchange) const override
     187              :     {
     188         9106 :         switch (mPeerAddress.GetTransportType())
     189              :         {
     190         9059 :         case Transport::Type::kUdp: {
     191         9059 :             const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
     192         9059 :             const auto & defaultMRRPConfig   = GetDefaultMRPConfig();
     193         9059 :             const auto & localMRPConfig      = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
     194        18118 :             return GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
     195        18118 :                                             ourLastActivity, localMRPConfig.mActiveThresholdTime, isFirstMessageOnExchange);
     196              :         }
     197            0 :         case Transport::Type::kTcp:
     198            0 :             return System::Clock::Seconds16(30);
     199            0 :         case Transport::Type::kBle:
     200            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     201           47 :         default:
     202           47 :             break;
     203              :         }
     204           47 :         return System::Clock::Timeout();
     205              :     }
     206              : 
     207       114612 :     const PeerAddress & GetPeerAddress() const { return mPeerAddress; }
     208         1542 :     void SetPeerAddress(const PeerAddress & address) { mPeerAddress = address; }
     209              : 
     210        37019 :     Type GetSecureSessionType() const { return mSecureSessionType; }
     211        13795 :     bool IsCASESession() const { return GetSecureSessionType() == Type::kCASE; }
     212         9271 :     bool IsPASESession() const { return GetSecureSessionType() == Type::kPASE; }
     213        26188 :     NodeId GetPeerNodeId() const { return mPeerNodeId; }
     214        13735 :     NodeId GetLocalNodeId() const { return mLocalNodeId; }
     215              : 
     216          106 :     const CATValues & GetPeerCATs() const { return mPeerCATs; }
     217              : 
     218              :     void SetRemoteSessionParameters(const SessionParameters & sessionParams) { mRemoteSessionParams = sessionParams; }
     219              : 
     220        37814 :     const SessionParameters & GetRemoteSessionParameters() const override { return mRemoteSessionParams; }
     221              : 
     222        61538 :     uint16_t GetLocalSessionId() const { return mLocalSessionId; }
     223        13845 :     uint16_t GetPeerSessionId() const { return mPeerSessionId; }
     224              : 
     225              :     // Called when AddNOC has gone through sufficient success that we need to switch the
     226              :     // session to reflect a new fabric if it was a PASE session
     227              :     CHIP_ERROR AdoptFabricIndex(FabricIndex fabricIndex)
     228              :     {
     229              :         // It's not legal to augment session type for non-PASE
     230              :         if (mSecureSessionType != Type::kPASE)
     231              :         {
     232              :             return CHIP_ERROR_INVALID_ARGUMENT;
     233              :         }
     234              :         SetFabricIndex(fabricIndex);
     235              :         return CHIP_NO_ERROR;
     236              :     }
     237              : 
     238          282 :     System::Clock::Timestamp GetLastActivityTime() const { return mLastActivityTime; }
     239        22585 :     System::Clock::Timestamp GetLastPeerActivityTime() const { return mLastPeerActivityTime; }
     240        27725 :     void MarkActive() { mLastActivityTime = System::SystemClock().GetMonotonicTimestamp(); }
     241        13847 :     void MarkActiveRx()
     242              :     {
     243        13847 :         mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
     244        13847 :         MarkActive();
     245              : 
     246        13847 :         if (mState == State::kDefunct)
     247              :         {
     248            0 :             MoveToState(State::kActive);
     249              :         }
     250        13847 :     }
     251              : 
     252           10 :     void SetCaseCommissioningSessionStatus(bool isCaseCommissioningSession)
     253              :     {
     254           10 :         VerifyOrDie(GetSecureSessionType() == Type::kCASE);
     255           10 :         mIsCaseCommissioningSession = isCaseCommissioningSession;
     256           10 :     }
     257              : 
     258        13901 :     bool IsPeerActive() const
     259              :     {
     260        27802 :         return ((System::SystemClock().GetMonotonicTimestamp() - GetLastPeerActivityTime()) <
     261        27802 :                 GetRemoteMRPConfig().mActiveThresholdTime);
     262              :     }
     263              : 
     264         2136 :     System::Clock::Timestamp GetMRPBaseTimeout() const override
     265              :     {
     266         2136 :         return IsPeerActive() ? GetRemoteMRPConfig().mActiveRetransTimeout : GetRemoteMRPConfig().mIdleRetransTimeout;
     267              :     }
     268              : 
     269        29121 :     CryptoContext & GetCryptoContext() { return mCryptoContext; }
     270              : 
     271            0 :     const CryptoContext & GetCryptoContext() const { return mCryptoContext; }
     272              : 
     273        42774 :     SessionMessageCounter & GetSessionMessageCounter() { return mSessionMessageCounter; }
     274              : 
     275              :     // This should be a private API, only meant to be called by SecureSessionTable
     276              :     // Session holders to this session may shift to the target session regarding SessionDelegate::GetNewSessionHandlingPolicy.
     277              :     // It requires that the target sessoin is also a CASE session, having the same peer and CATs as this session.
     278              :     void NewerSessionAvailable(const SessionHandle & session);
     279              : 
     280              : private:
     281              :     enum class State : uint8_t
     282              :     {
     283              :         //
     284              :         // Denotes a secure session object that is internally
     285              :         // reserved by the stack before and during session establishment.
     286              :         //
     287              :         // Although the stack can tolerate eviction of these (releasing one
     288              :         // out from under the holder would exhibit as CHIP_ERROR_INCORRECT_STATE
     289              :         // during CASE or PASE), intent is that we should not and would leave
     290              :         // these untouched until CASE or PASE complete.
     291              :         //
     292              :         // In this state, the reference count is held by the PairingSession.
     293              :         //
     294              :         kEstablishing = 1,
     295              : 
     296              :         //
     297              :         // The session is active, ready for use. When transitioning to this state via Activate, the
     298              :         // reference count is incremented by 1, and will subsequently be decremented
     299              :         // by 1 when MarkForEviction is called. This ensures the session remains resident
     300              :         // and active for future use even if there currently are no references to it.
     301              :         //
     302              :         kActive = 2,
     303              : 
     304              :         //
     305              :         // The session is temporarily disabled due to suspicion of a loss of synchronization
     306              :         // with the session state on the peer (e.g transport failure).
     307              :         // In this state, no new outbound exchanges can be created. However, if we receive valid messages
     308              :         // again on this session, we CAN mark this session as being active again.
     309              :         //
     310              :         // Transitioning to this state does not detach any existing SessionHolders.
     311              :         //
     312              :         // In addition to any existing SessionHolders holding a reference to this session, the SessionManager
     313              :         // maintains a reference as well to the session that will only be relinquished when MarkForEviction is called.
     314              :         //
     315              :         kDefunct = 3,
     316              : 
     317              :         //
     318              :         // The session has been marked for eviction and is pending deallocation. All SessionHolders would have already
     319              :         // been detached in a previous call to MarkForEviction. Future SessionHolders will not be able to attach to
     320              :         // this session.
     321              :         //
     322              :         // When all SessionHandles go out of scope, the session will be released automatically.
     323              :         //
     324              :         kPendingEviction = 4,
     325              :     };
     326              : 
     327              :     const char * StateToString(State state) const;
     328              :     void MoveToState(State targetState);
     329              : 
     330              :     friend class SecureSessionDeleter;
     331              :     friend class TestSecureSessionTable;
     332              : 
     333              :     SecureSessionTable & mTable;
     334              :     State mState;
     335              :     const Type mSecureSessionType;
     336              :     bool mIsCaseCommissioningSession = false;
     337              :     NodeId mLocalNodeId              = kUndefinedNodeId;
     338              :     NodeId mPeerNodeId               = kUndefinedNodeId;
     339              :     CATValues mPeerCATs              = CATValues{};
     340              :     const uint16_t mLocalSessionId;
     341              :     uint16_t mPeerSessionId = 0;
     342              : 
     343              :     PeerAddress mPeerAddress;
     344              : 
     345              :     /// Timestamp of last tx or rx. @see SessionTimestamp in the spec
     346              :     System::Clock::Timestamp mLastActivityTime = System::SystemClock().GetMonotonicTimestamp();
     347              : 
     348              :     /// Timestamp of last rx. @see ActiveTimestamp in the spec
     349              :     System::Clock::Timestamp mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
     350              : 
     351              :     SessionParameters mRemoteSessionParams;
     352              :     CryptoContext mCryptoContext;
     353              :     SessionMessageCounter mSessionMessageCounter;
     354              : };
     355              : 
     356              : } // namespace Transport
     357              : } // namespace chip
        

Generated by: LCOV version 2.0-1