Matter SDK Coverage Report
Current view: top level - transport - SecureSession.h (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 89.0 % 91 81
Test Date: 2025-03-30 07:08:27 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         1522 :     SecureSession(SecureSessionTable & table, Type secureSessionType, uint16_t localSessionId, NodeId localNodeId,
      72              :                   NodeId peerNodeId, CATValues peerCATs, uint16_t peerSessionId, FabricIndex fabric,
      73         1522 :                   const ReliableMessageProtocolConfig & config) :
      74         1522 :         mTable(table),
      75         1522 :         mState(State::kEstablishing), mSecureSessionType(secureSessionType), mLocalNodeId(localNodeId), mPeerNodeId(peerNodeId),
      76         1522 :         mPeerCATs(peerCATs), mLocalSessionId(localSessionId), mPeerSessionId(peerSessionId), mRemoteSessionParams(config)
      77              :     {
      78         1522 :         MoveToState(State::kActive);
      79         1522 :         Retain(); // Put the test session in Active state. This ref is released inside MarkForEviction
      80         1522 :         SetFabricIndex(fabric);
      81         1522 :         ChipLogDetail(Inet, "SecureSession[%p]: Allocated for Test Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
      82              :                       mLocalSessionId);
      83         1522 :     }
      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       135272 :     ~SecureSession() override
     108       135272 :     {
     109       135272 :         ChipLogDetail(Inet, "SecureSession[%p]: Released - Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
     110              :                       mLocalSessionId);
     111       135272 :     }
     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        22521 :     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        10106 :     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       582708 :     Session::SessionType GetSessionType() const override { return Session::SessionType::kSecure; }
     152              : 
     153        22863 :     ScopedNodeId GetPeer() const override { return ScopedNodeId(mPeerNodeId, GetFabricIndex()); }
     154              : 
     155        10080 :     ScopedNodeId GetLocalScopedNodeId() const override { return ScopedNodeId(mLocalNodeId, GetFabricIndex()); }
     156              : 
     157              :     Access::SubjectDescriptor GetSubjectDescriptor() const override;
     158              : 
     159              :     bool IsCommissioningSession() const override;
     160              : 
     161        41833 :     bool AllowsMRP() const override
     162              :     {
     163        42044 :         return ((GetPeerAddress().GetTransportType() == Transport::Type::kUdp) ||
     164        42044 :                 (GetPeerAddress().GetTransportType() == Transport::Type::kWiFiPAF));
     165              :     }
     166              : 
     167        12086 :     bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
     168              : 
     169         6640 :     System::Clock::Milliseconds32 GetAckTimeout(bool isFirstMessageOnExchange) const override
     170              :     {
     171         6640 :         switch (mPeerAddress.GetTransportType())
     172              :         {
     173         6593 :         case Transport::Type::kUdp: {
     174         6593 :             const ReliableMessageProtocolConfig & remoteMRPConfig = mRemoteSessionParams.GetMRPConfig();
     175         6593 :             return GetRetransmissionTimeout(remoteMRPConfig.mActiveRetransTimeout, remoteMRPConfig.mIdleRetransTimeout,
     176        13186 :                                             GetLastPeerActivityTime(), remoteMRPConfig.mActiveThresholdTime,
     177         6593 :                                             isFirstMessageOnExchange);
     178              :         }
     179            0 :         case Transport::Type::kTcp:
     180            0 :             return System::Clock::Seconds16(30);
     181            0 :         case Transport::Type::kBle:
     182            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     183           47 :         default:
     184           47 :             break;
     185              :         }
     186           47 :         return System::Clock::Timeout();
     187              :     }
     188              : 
     189         7020 :     System::Clock::Milliseconds32 GetMessageReceiptTimeout(System::Clock::Timestamp ourLastActivity,
     190              :                                                            bool isFirstMessageOnExchange) const override
     191              :     {
     192         7020 :         switch (mPeerAddress.GetTransportType())
     193              :         {
     194         6973 :         case Transport::Type::kUdp: {
     195         6973 :             const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
     196         6973 :             const auto & defaultMRRPConfig   = GetDefaultMRPConfig();
     197         6973 :             const auto & localMRPConfig      = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
     198        13946 :             return GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
     199        13946 :                                             ourLastActivity, localMRPConfig.mActiveThresholdTime, isFirstMessageOnExchange);
     200              :         }
     201            0 :         case Transport::Type::kTcp:
     202            0 :             return System::Clock::Seconds16(30);
     203            0 :         case Transport::Type::kBle:
     204            0 :             return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
     205           47 :         default:
     206           47 :             break;
     207              :         }
     208           47 :         return System::Clock::Timeout();
     209              :     }
     210              : 
     211        84319 :     const PeerAddress & GetPeerAddress() const { return mPeerAddress; }
     212         1514 :     void SetPeerAddress(const PeerAddress & address) { mPeerAddress = address; }
     213              : 
     214        27783 :     Type GetSecureSessionType() const { return mSecureSessionType; }
     215        10029 :     bool IsCASESession() const { return GetSecureSessionType() == Type::kCASE; }
     216         7568 :     bool IsPASESession() const { return GetSecureSessionType() == Type::kPASE; }
     217        19003 :     NodeId GetPeerNodeId() const { return mPeerNodeId; }
     218         9968 :     NodeId GetLocalNodeId() const { return mLocalNodeId; }
     219              : 
     220          106 :     const CATValues & GetPeerCATs() const { return mPeerCATs; }
     221              : 
     222              :     void SetRemoteSessionParameters(const SessionParameters & sessionParams) { mRemoteSessionParams = sessionParams; }
     223              : 
     224        27232 :     const SessionParameters & GetRemoteSessionParameters() const override { return mRemoteSessionParams; }
     225              : 
     226        44767 :     uint16_t GetLocalSessionId() const { return mLocalSessionId; }
     227        10078 :     uint16_t GetPeerSessionId() const { return mPeerSessionId; }
     228              : 
     229              :     // Called when AddNOC has gone through sufficient success that we need to switch the
     230              :     // session to reflect a new fabric if it was a PASE session
     231              :     CHIP_ERROR AdoptFabricIndex(FabricIndex fabricIndex)
     232              :     {
     233              :         // It's not legal to augment session type for non-PASE
     234              :         if (mSecureSessionType != Type::kPASE)
     235              :         {
     236              :             return CHIP_ERROR_INVALID_ARGUMENT;
     237              :         }
     238              :         SetFabricIndex(fabricIndex);
     239              :         return CHIP_NO_ERROR;
     240              :     }
     241              : 
     242          282 :     System::Clock::Timestamp GetLastActivityTime() const { return mLastActivityTime; }
     243        16735 :     System::Clock::Timestamp GetLastPeerActivityTime() const { return mLastPeerActivityTime; }
     244        20191 :     void MarkActive() { mLastActivityTime = System::SystemClock().GetMonotonicTimestamp(); }
     245        10080 :     void MarkActiveRx()
     246              :     {
     247        10080 :         mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
     248        10080 :         MarkActive();
     249              : 
     250        10080 :         if (mState == State::kDefunct)
     251              :         {
     252            0 :             MoveToState(State::kActive);
     253              :         }
     254        10080 :     }
     255              : 
     256           10 :     void SetCaseCommissioningSessionStatus(bool isCaseCommissioningSession)
     257              :     {
     258           10 :         VerifyOrDie(GetSecureSessionType() == Type::kCASE);
     259           10 :         mIsCaseCommissioningSession = isCaseCommissioningSession;
     260           10 :     }
     261              : 
     262        10134 :     bool IsPeerActive() const
     263              :     {
     264        20268 :         return ((System::SystemClock().GetMonotonicTimestamp() - GetLastPeerActivityTime()) <
     265        20268 :                 GetRemoteMRPConfig().mActiveThresholdTime);
     266              :     }
     267              : 
     268         1775 :     System::Clock::Timestamp GetMRPBaseTimeout() const override
     269              :     {
     270         1775 :         return IsPeerActive() ? GetRemoteMRPConfig().mActiveRetransTimeout : GetRemoteMRPConfig().mIdleRetransTimeout;
     271              :     }
     272              : 
     273        21559 :     CryptoContext & GetCryptoContext() { return mCryptoContext; }
     274              : 
     275            0 :     const CryptoContext & GetCryptoContext() const { return mCryptoContext; }
     276              : 
     277        31445 :     SessionMessageCounter & GetSessionMessageCounter() { return mSessionMessageCounter; }
     278              : 
     279              :     // This should be a private API, only meant to be called by SecureSessionTable
     280              :     // Session holders to this session may shift to the target session regarding SessionDelegate::GetNewSessionHandlingPolicy.
     281              :     // It requires that the target sessoin is also a CASE session, having the same peer and CATs as this session.
     282              :     void NewerSessionAvailable(const SessionHandle & session);
     283              : 
     284              : private:
     285              :     enum class State : uint8_t
     286              :     {
     287              :         //
     288              :         // Denotes a secure session object that is internally
     289              :         // reserved by the stack before and during session establishment.
     290              :         //
     291              :         // Although the stack can tolerate eviction of these (releasing one
     292              :         // out from under the holder would exhibit as CHIP_ERROR_INCORRECT_STATE
     293              :         // during CASE or PASE), intent is that we should not and would leave
     294              :         // these untouched until CASE or PASE complete.
     295              :         //
     296              :         // In this state, the reference count is held by the PairingSession.
     297              :         //
     298              :         kEstablishing = 1,
     299              : 
     300              :         //
     301              :         // The session is active, ready for use. When transitioning to this state via Activate, the
     302              :         // reference count is incremented by 1, and will subsequently be decremented
     303              :         // by 1 when MarkForEviction is called. This ensures the session remains resident
     304              :         // and active for future use even if there currently are no references to it.
     305              :         //
     306              :         kActive = 2,
     307              : 
     308              :         //
     309              :         // The session is temporarily disabled due to suspicion of a loss of synchronization
     310              :         // with the session state on the peer (e.g transport failure).
     311              :         // In this state, no new outbound exchanges can be created. However, if we receive valid messages
     312              :         // again on this session, we CAN mark this session as being active again.
     313              :         //
     314              :         // Transitioning to this state does not detach any existing SessionHolders.
     315              :         //
     316              :         // In addition to any existing SessionHolders holding a reference to this session, the SessionManager
     317              :         // maintains a reference as well to the session that will only be relinquished when MarkForEviction is called.
     318              :         //
     319              :         kDefunct = 3,
     320              : 
     321              :         //
     322              :         // The session has been marked for eviction and is pending deallocation. All SessionHolders would have already
     323              :         // been detached in a previous call to MarkForEviction. Future SessionHolders will not be able to attach to
     324              :         // this session.
     325              :         //
     326              :         // When all SessionHandles go out of scope, the session will be released automatically.
     327              :         //
     328              :         kPendingEviction = 4,
     329              :     };
     330              : 
     331              :     const char * StateToString(State state) const;
     332              :     void MoveToState(State targetState);
     333              : 
     334              :     friend class SecureSessionDeleter;
     335              :     friend class TestSecureSessionTable;
     336              : 
     337              :     SecureSessionTable & mTable;
     338              :     State mState;
     339              :     const Type mSecureSessionType;
     340              :     bool mIsCaseCommissioningSession = false;
     341              :     NodeId mLocalNodeId              = kUndefinedNodeId;
     342              :     NodeId mPeerNodeId               = kUndefinedNodeId;
     343              :     CATValues mPeerCATs              = CATValues{};
     344              :     const uint16_t mLocalSessionId;
     345              :     uint16_t mPeerSessionId = 0;
     346              : 
     347              :     PeerAddress mPeerAddress;
     348              : 
     349              :     /// Timestamp of last tx or rx. @see SessionTimestamp in the spec
     350              :     System::Clock::Timestamp mLastActivityTime = System::SystemClock().GetMonotonicTimestamp();
     351              : 
     352              :     /// Timestamp of last rx. @see ActiveTimestamp in the spec
     353              :     System::Clock::Timestamp mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
     354              : 
     355              :     SessionParameters mRemoteSessionParams;
     356              :     CryptoContext mCryptoContext;
     357              :     SessionMessageCounter mSessionMessageCounter;
     358              : };
     359              : 
     360              : } // namespace Transport
     361              : } // namespace chip
        

Generated by: LCOV version 2.0-1