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