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/BleConfig.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 1338 : SecureSession(SecureSessionTable & table, Type secureSessionType, uint16_t localSessionId, NodeId localNodeId,
72 : NodeId peerNodeId, CATValues peerCATs, uint16_t peerSessionId, FabricIndex fabric,
73 1338 : const ReliableMessageProtocolConfig & config) :
74 1338 : mTable(table),
75 1338 : mState(State::kEstablishing), mSecureSessionType(secureSessionType), mLocalNodeId(localNodeId), mPeerNodeId(peerNodeId),
76 1338 : mPeerCATs(peerCATs), mLocalSessionId(localSessionId), mPeerSessionId(peerSessionId), mRemoteSessionParams(config)
77 : {
78 1338 : MoveToState(State::kActive);
79 1338 : Retain(); // Put the test session in Active state. This ref is released inside MarkForEviction
80 1338 : SetFabricIndex(fabric);
81 1338 : ChipLogDetail(Inet, "SecureSession[%p]: Allocated for Test Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
82 : mLocalSessionId);
83 1338 : }
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 133753 : SecureSession(SecureSessionTable & table, Type secureSessionType, uint16_t localSessionId) :
92 133753 : mTable(table), mState(State::kEstablishing), mSecureSessionType(secureSessionType), mLocalSessionId(localSessionId)
93 : {
94 133753 : ChipLogDetail(Inet, "SecureSession[%p]: Allocated Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
95 : mLocalSessionId);
96 133753 : }
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 135091 : ~SecureSession() override
108 135091 : {
109 135091 : ChipLogDetail(Inet, "SecureSession[%p]: Released - Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
110 : mLocalSessionId);
111 135091 : }
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 20818 : bool IsActiveSession() const override { return mState == State::kActive; }
122 59 : bool IsEstablishing() const { return mState == State::kEstablishing; }
123 16 : bool IsPendingEviction() const { return mState == State::kPendingEviction; }
124 9621 : 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 492801 : Session::SessionType GetSessionType() const override { return Session::SessionType::kSecure; }
152 :
153 21637 : ScopedNodeId GetPeer() const override { return ScopedNodeId(mPeerNodeId, GetFabricIndex()); }
154 :
155 9489 : ScopedNodeId GetLocalScopedNodeId() const override { return ScopedNodeId(mLocalNodeId, GetFabricIndex()); }
156 :
157 : Access::SubjectDescriptor GetSubjectDescriptor() const override;
158 :
159 39304 : bool AllowsMRP() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kUdp; }
160 :
161 0 : bool AllowsLargePayload() const override { return GetPeerAddress().GetTransportType() == Transport::Type::kTcp; }
162 :
163 6275 : System::Clock::Milliseconds32 GetAckTimeout() const override
164 : {
165 6275 : switch (mPeerAddress.GetTransportType())
166 : {
167 6228 : case Transport::Type::kUdp: {
168 6228 : const ReliableMessageProtocolConfig & remoteMRPConfig = mRemoteSessionParams.GetMRPConfig();
169 6228 : return GetRetransmissionTimeout(remoteMRPConfig.mActiveRetransTimeout, remoteMRPConfig.mIdleRetransTimeout,
170 12456 : GetLastPeerActivityTime(), remoteMRPConfig.mActiveThresholdTime);
171 : }
172 0 : case Transport::Type::kTcp:
173 0 : return System::Clock::Seconds16(30);
174 0 : case Transport::Type::kBle:
175 0 : return System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS);
176 47 : default:
177 47 : break;
178 : }
179 47 : return System::Clock::Timeout();
180 : }
181 :
182 67697 : const PeerAddress & GetPeerAddress() const { return mPeerAddress; }
183 1537 : void SetPeerAddress(const PeerAddress & address) { mPeerAddress = address; }
184 :
185 9795 : Type GetSecureSessionType() const { return mSecureSessionType; }
186 21 : bool IsCASESession() const { return GetSecureSessionType() == Type::kCASE; }
187 0 : bool IsPASESession() const { return GetSecureSessionType() == Type::kPASE; }
188 10026 : NodeId GetPeerNodeId() const { return mPeerNodeId; }
189 : NodeId GetLocalNodeId() const { return mLocalNodeId; }
190 :
191 106 : const CATValues & GetPeerCATs() const { return mPeerCATs; }
192 :
193 : void SetRemoteSessionParameters(const SessionParameters & sessionParams) { mRemoteSessionParams = sessionParams; }
194 :
195 9519 : const SessionParameters & GetRemoteSessionParameters() const override { return mRemoteSessionParams; }
196 :
197 34211 : uint16_t GetLocalSessionId() const { return mLocalSessionId; }
198 9487 : uint16_t GetPeerSessionId() const { return mPeerSessionId; }
199 :
200 : // Called when AddNOC has gone through sufficient success that we need to switch the
201 : // session to reflect a new fabric if it was a PASE session
202 : CHIP_ERROR AdoptFabricIndex(FabricIndex fabricIndex)
203 : {
204 : // It's not legal to augment session type for non-PASE
205 : if (mSecureSessionType != Type::kPASE)
206 : {
207 : return CHIP_ERROR_INVALID_ARGUMENT;
208 : }
209 : SetFabricIndex(fabricIndex);
210 : return CHIP_NO_ERROR;
211 : }
212 :
213 374 : System::Clock::Timestamp GetLastActivityTime() const { return mLastActivityTime; }
214 7851 : System::Clock::Timestamp GetLastPeerActivityTime() const { return mLastPeerActivityTime; }
215 18992 : void MarkActive() { mLastActivityTime = System::SystemClock().GetMonotonicTimestamp(); }
216 9501 : void MarkActiveRx()
217 : {
218 9501 : mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
219 9501 : MarkActive();
220 :
221 9501 : if (mState == State::kDefunct)
222 : {
223 0 : MoveToState(State::kActive);
224 : }
225 9501 : }
226 :
227 1616 : bool IsPeerActive() const
228 : {
229 3232 : return ((System::SystemClock().GetMonotonicTimestamp() - GetLastPeerActivityTime()) <
230 3232 : GetRemoteMRPConfig().mActiveThresholdTime);
231 : }
232 :
233 1616 : System::Clock::Timestamp GetMRPBaseTimeout() const override
234 : {
235 1616 : return IsPeerActive() ? GetRemoteMRPConfig().mActiveRetransTimeout : GetRemoteMRPConfig().mIdleRetransTimeout;
236 : }
237 :
238 20193 : CryptoContext & GetCryptoContext() { return mCryptoContext; }
239 :
240 0 : const CryptoContext & GetCryptoContext() const { return mCryptoContext; }
241 :
242 29487 : SessionMessageCounter & GetSessionMessageCounter() { return mSessionMessageCounter; }
243 :
244 : // This should be a private API, only meant to be called by SecureSessionTable
245 : // Session holders to this session may shift to the target session regarding SessionDelegate::GetNewSessionHandlingPolicy.
246 : // It requires that the target sessoin is also a CASE session, having the same peer and CATs as this session.
247 : void NewerSessionAvailable(const SessionHandle & session);
248 :
249 : private:
250 : enum class State : uint8_t
251 : {
252 : //
253 : // Denotes a secure session object that is internally
254 : // reserved by the stack before and during session establishment.
255 : //
256 : // Although the stack can tolerate eviction of these (releasing one
257 : // out from under the holder would exhibit as CHIP_ERROR_INCORRECT_STATE
258 : // during CASE or PASE), intent is that we should not and would leave
259 : // these untouched until CASE or PASE complete.
260 : //
261 : // In this state, the reference count is held by the PairingSession.
262 : //
263 : kEstablishing = 1,
264 :
265 : //
266 : // The session is active, ready for use. When transitioning to this state via Activate, the
267 : // reference count is incremented by 1, and will subsequently be decremented
268 : // by 1 when MarkForEviction is called. This ensures the session remains resident
269 : // and active for future use even if there currently are no references to it.
270 : //
271 : kActive = 2,
272 :
273 : //
274 : // The session is temporarily disabled due to suspicion of a loss of synchronization
275 : // with the session state on the peer (e.g transport failure).
276 : // In this state, no new outbound exchanges can be created. However, if we receive valid messages
277 : // again on this session, we CAN mark this session as being active again.
278 : //
279 : // Transitioning to this state does not detach any existing SessionHolders.
280 : //
281 : // In addition to any existing SessionHolders holding a reference to this session, the SessionManager
282 : // maintains a reference as well to the session that will only be relinquished when MarkForEviction is called.
283 : //
284 : kDefunct = 3,
285 :
286 : //
287 : // The session has been marked for eviction and is pending deallocation. All SessionHolders would have already
288 : // been detached in a previous call to MarkForEviction. Future SessionHolders will not be able to attach to
289 : // this session.
290 : //
291 : // When all SessionHandles go out of scope, the session will be released automatically.
292 : //
293 : kPendingEviction = 4,
294 : };
295 :
296 : const char * StateToString(State state) const;
297 : void MoveToState(State targetState);
298 :
299 : friend class SecureSessionDeleter;
300 : friend class TestSecureSessionTable;
301 :
302 : SecureSessionTable & mTable;
303 : State mState;
304 : const Type mSecureSessionType;
305 : NodeId mLocalNodeId = kUndefinedNodeId;
306 : NodeId mPeerNodeId = kUndefinedNodeId;
307 : CATValues mPeerCATs = CATValues{};
308 : const uint16_t mLocalSessionId;
309 : uint16_t mPeerSessionId = 0;
310 :
311 : PeerAddress mPeerAddress;
312 :
313 : /// Timestamp of last tx or rx. @see SessionTimestamp in the spec
314 : System::Clock::Timestamp mLastActivityTime = System::SystemClock().GetMonotonicTimestamp();
315 :
316 : /// Timestamp of last rx. @see ActiveTimestamp in the spec
317 : System::Clock::Timestamp mLastPeerActivityTime = System::SystemClock().GetMonotonicTimestamp();
318 :
319 : SessionParameters mRemoteSessionParams;
320 : CryptoContext mCryptoContext;
321 : SessionMessageCounter mSessionMessageCounter;
322 : };
323 :
324 : } // namespace Transport
325 : } // namespace chip
|