Line data Source code
1 : /*
2 : * Copyright (c) 2021 Project CHIP Authors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 :
17 : #include <access/AuthMode.h>
18 : #include <transport/SecureSession.h>
19 : #include <transport/SecureSessionTable.h>
20 :
21 : namespace chip {
22 : namespace Transport {
23 :
24 135111 : void SecureSessionDeleter::Release(SecureSession * entry)
25 : {
26 135111 : entry->mTable.ReleaseSession(entry);
27 135111 : }
28 :
29 110 : void SecureSession::Activate(const ScopedNodeId & localNode, const ScopedNodeId & peerNode, CATValues peerCATs,
30 : uint16_t peerSessionId, const SessionParameters & sessionParameters)
31 : {
32 110 : VerifyOrDie(mState == State::kEstablishing);
33 110 : VerifyOrDie(peerNode.GetFabricIndex() == localNode.GetFabricIndex());
34 :
35 : // PASE sessions must always start unassociated with a Fabric!
36 110 : VerifyOrDie(!((mSecureSessionType == Type::kPASE) && (peerNode.GetFabricIndex() != kUndefinedFabricIndex)));
37 : // CASE sessions must always start "associated" a given Fabric!
38 110 : VerifyOrDie(!((mSecureSessionType == Type::kCASE) && (peerNode.GetFabricIndex() == kUndefinedFabricIndex)));
39 : // CASE sessions can only be activated against operational node IDs!
40 110 : VerifyOrDie(!((mSecureSessionType == Type::kCASE) &&
41 : (!IsOperationalNodeId(peerNode.GetNodeId()) || !IsOperationalNodeId(localNode.GetNodeId()))));
42 :
43 110 : mPeerNodeId = peerNode.GetNodeId();
44 110 : mLocalNodeId = localNode.GetNodeId();
45 110 : mPeerCATs = peerCATs;
46 110 : mPeerSessionId = peerSessionId;
47 110 : mRemoteSessionParams = sessionParameters;
48 110 : SetFabricIndex(peerNode.GetFabricIndex());
49 110 : MarkActiveRx(); // Initialize SessionTimestamp and ActiveTimestamp per spec.
50 :
51 110 : Retain(); // This ref is released inside MarkForEviction
52 110 : MoveToState(State::kActive);
53 :
54 110 : if (mSecureSessionType == Type::kCASE)
55 100 : mTable.NewerSessionAvailable(this);
56 :
57 110 : ChipLogDetail(Inet, "SecureSession[%p]: Activated - Type:%d LSID:%d", this, to_underlying(mSecureSessionType), mLocalSessionId);
58 110 : }
59 :
60 273404 : const char * SecureSession::StateToString(State state) const
61 : {
62 273404 : switch (state)
63 : {
64 135187 : case State::kEstablishing:
65 135187 : return "kEstablishing";
66 : break;
67 :
68 3138 : case State::kActive:
69 3138 : return "kActive";
70 : break;
71 :
72 17 : case State::kDefunct:
73 17 : return "kDefunct";
74 : break;
75 :
76 135062 : case State::kPendingEviction:
77 135062 : return "kPendingEviction";
78 : break;
79 :
80 0 : default:
81 0 : return "???";
82 : break;
83 : }
84 : }
85 :
86 136660 : void SecureSession::MoveToState(State targetState)
87 : {
88 136660 : if (mState != targetState)
89 : {
90 136660 : ChipLogProgress(SecureChannel, "SecureSession[%p, LSID:%d]: State change '%s' --> '%s'", this, mLocalSessionId,
91 : StateToString(mState), StateToString(targetState));
92 136660 : mState = targetState;
93 : }
94 136660 : }
95 :
96 5 : void SecureSession::MarkAsDefunct()
97 : {
98 5 : ChipLogDetail(Inet, "SecureSession[%p]: MarkAsDefunct Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
99 : mLocalSessionId);
100 5 : ReferenceCountedHandle<Transport::Session> ref(*this);
101 :
102 5 : switch (mState)
103 : {
104 0 : case State::kEstablishing:
105 : //
106 : // A session can only be marked as defunct from the state of Active.
107 : //
108 0 : VerifyOrDie(false);
109 : return;
110 :
111 4 : case State::kActive:
112 4 : MoveToState(State::kDefunct);
113 4 : return;
114 :
115 0 : case State::kDefunct:
116 : //
117 : // Do nothing
118 : //
119 0 : return;
120 :
121 1 : case State::kPendingEviction:
122 : //
123 : // Once a session is headed for eviction, we CANNOT bring it back to either being active or defunct. Let's just
124 : // do nothing and return.
125 : //
126 1 : return;
127 : }
128 5 : }
129 :
130 135062 : void SecureSession::MarkForEviction()
131 : {
132 135062 : ChipLogDetail(Inet, "SecureSession[%p]: MarkForEviction Type:%d LSID:%d", this, to_underlying(mSecureSessionType),
133 : mLocalSessionId);
134 135062 : ReferenceCountedHandle<Transport::Session> ref(*this);
135 :
136 135062 : switch (mState)
137 : {
138 133591 : case State::kEstablishing:
139 133591 : MoveToState(State::kPendingEviction);
140 : // Interrupt the pairing
141 133591 : NotifySessionReleased();
142 133591 : return;
143 :
144 1471 : case State::kDefunct:
145 : FALLTHROUGH;
146 : case State::kActive:
147 1471 : Release(); // Decrease the ref which is retained at Activate
148 1471 : MoveToState(State::kPendingEviction);
149 1471 : NotifySessionReleased();
150 1471 : return;
151 :
152 0 : case State::kPendingEviction:
153 : // Do nothing
154 0 : return;
155 : }
156 135062 : }
157 :
158 7484 : Access::SubjectDescriptor SecureSession::GetSubjectDescriptor() const
159 : {
160 7484 : Access::SubjectDescriptor subjectDescriptor;
161 7484 : if (IsOperationalNodeId(mPeerNodeId))
162 : {
163 7484 : subjectDescriptor.authMode = Access::AuthMode::kCase;
164 7484 : subjectDescriptor.subject = mPeerNodeId;
165 7484 : subjectDescriptor.cats = mPeerCATs;
166 7484 : subjectDescriptor.fabricIndex = GetFabricIndex();
167 7484 : subjectDescriptor.isCommissioning = IsCommissioningSession();
168 : }
169 0 : else if (IsPAKEKeyId(mPeerNodeId))
170 : {
171 : // Responder (aka commissionee) gets subject descriptor filled in.
172 : // Initiator (aka commissioner) leaves subject descriptor unfilled.
173 0 : if (GetCryptoContext().IsResponder())
174 : {
175 0 : subjectDescriptor.authMode = Access::AuthMode::kPase;
176 0 : subjectDescriptor.subject = mPeerNodeId;
177 0 : subjectDescriptor.fabricIndex = GetFabricIndex();
178 0 : subjectDescriptor.isCommissioning = IsCommissioningSession();
179 : }
180 : }
181 : else
182 : {
183 0 : VerifyOrDie(false);
184 : }
185 7484 : return subjectDescriptor;
186 : }
187 :
188 7484 : bool SecureSession::IsCommissioningSession() const
189 : {
190 : // PASE session is always a commissioning session.
191 7484 : if (IsPASESession())
192 : {
193 7477 : return true;
194 : }
195 :
196 : // CASE session is a commissioning session if it was marked as such.
197 : // The SessionManager is what keeps track.
198 7 : if (IsCASESession() && mIsCaseCommissioningSession)
199 : {
200 0 : return true;
201 : }
202 :
203 7 : return false;
204 : }
205 :
206 764336 : void SecureSession::Retain()
207 : {
208 : #if CHIP_CONFIG_SECURE_SESSION_REFCOUNT_LOGGING
209 : ChipLogProgress(SecureChannel, "SecureSession[%p]: ++ %d -> %d", this, GetReferenceCount(), GetReferenceCount() + 1);
210 : #endif
211 :
212 764336 : ReferenceCounted<SecureSession, SecureSessionDeleter, 0, uint16_t>::Retain();
213 764336 : }
214 :
215 764213 : void SecureSession::Release()
216 : {
217 : #if CHIP_CONFIG_SECURE_SESSION_REFCOUNT_LOGGING
218 : ChipLogProgress(SecureChannel, "SecureSession[%p]: -- %d -> %d", this, GetReferenceCount(), GetReferenceCount() - 1);
219 : #endif
220 :
221 764213 : ReferenceCounted<SecureSession, SecureSessionDeleter, 0, uint16_t>::Release();
222 764213 : }
223 :
224 54 : void SecureSession::NewerSessionAvailable(const SessionHandle & session)
225 : {
226 : // Shift to the new session, checks are performed by the the caller SecureSessionTable::NewerSessionAvailable.
227 54 : IntrusiveList<SessionHolder>::Iterator iter = mHolders.begin();
228 100 : while (iter != mHolders.end())
229 : {
230 : // The iterator can be invalid once the session holder is migrated to another session. So we store its next value before
231 : // notifying the holder.
232 46 : IntrusiveList<SessionHolder>::Iterator next = iter;
233 46 : ++next;
234 :
235 46 : iter->ShiftToSession(session);
236 :
237 46 : iter = next;
238 : }
239 54 : }
240 :
241 : } // namespace Transport
242 : } // namespace chip
|