Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : #include <protocols/secure_channel/PairingSession.h>
20 :
21 : #include <app/SpecificationDefinedRevisions.h>
22 : #include <lib/core/CHIPConfig.h>
23 : #include <lib/core/TLVTypes.h>
24 : #include <lib/support/SafeInt.h>
25 : #include <lib/support/TypeTraits.h>
26 : #include <platform/CHIPDeviceEvent.h>
27 : #include <platform/PlatformManager.h>
28 : #include <transport/SessionManager.h>
29 :
30 : namespace chip {
31 :
32 51 : CHIP_ERROR PairingSession::AllocateSecureSession(SessionManager & sessionManager, const ScopedNodeId & sessionEvictionHint)
33 : {
34 51 : auto handle = sessionManager.AllocateSession(GetSecureSessionType(), sessionEvictionHint);
35 51 : VerifyOrReturnError(handle.HasValue(), CHIP_ERROR_NO_MEMORY);
36 51 : VerifyOrReturnError(mSecureSessionHolder.GrabPairingSession(handle.Value()), CHIP_ERROR_INTERNAL);
37 51 : mSessionManager = &sessionManager;
38 51 : return CHIP_NO_ERROR;
39 51 : }
40 :
41 26 : CHIP_ERROR PairingSession::ActivateSecureSession(const Transport::PeerAddress & peerAddress)
42 : {
43 : // Prepare SecureSession fields, including key derivation, first, before activation
44 26 : Transport::SecureSession * secureSession = mSecureSessionHolder->AsSecureSession();
45 26 : ReturnErrorOnFailure(DeriveSecureSession(secureSession->GetCryptoContext()));
46 :
47 26 : uint16_t peerSessionId = GetPeerSessionId();
48 26 : secureSession->SetPeerAddress(peerAddress);
49 26 : secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
50 :
51 : // Call Activate last, otherwise errors on anything after would lead to
52 : // a partially valid session.
53 26 : secureSession->Activate(GetLocalScopedNodeId(), GetPeer(), GetPeerCATs(), peerSessionId, GetRemoteSessionParameters());
54 :
55 26 : ChipLogDetail(Inet, "New secure session activated for device " ChipLogFormatScopedNodeId ", LSID:%d PSID:%d!",
56 : ChipLogValueScopedNodeId(GetPeer()), secureSession->GetLocalSessionId(), peerSessionId);
57 :
58 26 : return CHIP_NO_ERROR;
59 : }
60 :
61 26 : void PairingSession::Finish()
62 : {
63 26 : Transport::PeerAddress address = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress();
64 :
65 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
66 26 : if (address.GetTransportType() == Transport::Type::kTcp)
67 : {
68 : // Fetch the connection for the unauthenticated session used to set up
69 : // the secure session.
70 : Transport::ActiveTCPConnectionState * conn =
71 0 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetTCPConnection();
72 :
73 : // Associate the connection with the secure session being activated.
74 0 : mSecureSessionHolder->AsSecureSession()->SetTCPConnection(conn);
75 : }
76 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
77 : // Discard the exchange so that Clear() doesn't try closing it. The exchange will handle that.
78 26 : DiscardExchange();
79 :
80 26 : CHIP_ERROR err = ActivateSecureSession(address);
81 26 : if (err == CHIP_NO_ERROR)
82 : {
83 26 : VerifyOrDie(mSecureSessionHolder);
84 26 : DeviceLayer::ChipDeviceEvent event{ .Type = DeviceLayer::DeviceEventType::kSecureSessionEstablished };
85 26 : event.SecureSessionEstablished.TransportType = to_underlying(address.GetTransportType());
86 26 : event.SecureSessionEstablished.SecureSessionType =
87 26 : to_underlying(mSecureSessionHolder->AsSecureSession()->GetSecureSessionType());
88 26 : event.SecureSessionEstablished.LocalSessionId = mSecureSessionHolder->AsSecureSession()->GetLocalSessionId();
89 26 : event.SecureSessionEstablished.PeerNodeId = mSecureSessionHolder->GetPeer().GetNodeId();
90 26 : event.SecureSessionEstablished.FabricIndex = mSecureSessionHolder->GetPeer().GetFabricIndex();
91 26 : if (DeviceLayer::PlatformMgr().PostEvent(&event) != CHIP_NO_ERROR)
92 : {
93 0 : ChipLogError(SecureChannel, "Failed to post Secure Session established event");
94 : }
95 : // Make sure to null out mDelegate so we don't send it any other
96 : // notifications.
97 26 : auto * delegate = mDelegate;
98 26 : mDelegate = nullptr;
99 26 : delegate->OnSessionEstablished(mSecureSessionHolder.Get().Value());
100 : }
101 : else
102 : {
103 0 : NotifySessionEstablishmentError(err);
104 : }
105 26 : }
106 :
107 30 : void PairingSession::DiscardExchange()
108 : {
109 30 : if (mExchangeCtxt.HasValue())
110 : {
111 : // Make sure the exchange doesn't try to notify us when it closes,
112 : // since we might be dead by then.
113 30 : mExchangeCtxt.Value()->SetDelegate(nullptr);
114 :
115 : // Null out mExchangeCtxt so that Clear() doesn't try closing it. The
116 : // exchange will handle that.
117 30 : mExchangeCtxt.ClearValue();
118 : }
119 30 : }
120 :
121 36 : CHIP_ERROR PairingSession::EncodeSessionParameters(TLV::Tag tag, const ReliableMessageProtocolConfig & mrpLocalConfig,
122 : TLV::TLVWriter & tlvWriter)
123 : {
124 : TLV::TLVType mrpParamsContainer;
125 36 : ReturnErrorOnFailure(tlvWriter.StartContainer(tag, TLV::kTLVType_Structure, mrpParamsContainer));
126 36 : ReturnErrorOnFailure(
127 : tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionIdleInterval), mrpLocalConfig.mIdleRetransTimeout.count()));
128 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveInterval),
129 : mrpLocalConfig.mActiveRetransTimeout.count()));
130 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveThreshold),
131 : mrpLocalConfig.mActiveThresholdTime.count()));
132 :
133 36 : uint16_t dataModel = Revision::kDataModelRevision;
134 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kDataModelRevision), dataModel));
135 :
136 36 : uint16_t interactionModel = Revision::kInteractionModelRevision;
137 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kInteractionModelRevision), interactionModel));
138 :
139 36 : uint32_t specVersion = Revision::kSpecificationVersion;
140 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSpecificationVersion), specVersion));
141 :
142 36 : uint16_t maxPathsPerInvoke = CHIP_CONFIG_MAX_PATHS_PER_INVOKE;
143 36 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxPathsPerInvoke), maxPathsPerInvoke));
144 36 : return tlvWriter.EndContainer(mrpParamsContainer);
145 : }
146 :
147 31 : CHIP_ERROR PairingSession::DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TLV::ContiguousBufferTLVReader & tlvReader)
148 : {
149 31 : CHIP_ERROR err = CHIP_NO_ERROR;
150 :
151 : // The MRP parameters are optional.
152 31 : if (tlvReader.GetTag() != expectedTag)
153 : {
154 1 : return CHIP_NO_ERROR;
155 : }
156 :
157 30 : TLV::TLVType containerType = TLV::kTLVType_Structure;
158 30 : ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
159 :
160 30 : ReturnErrorOnFailure(tlvReader.Next());
161 :
162 30 : ChipLogDetail(SecureChannel, "Found MRP parameters in the message");
163 :
164 : // All TLV elements in the structure are optional. If the first element is present, process it and move
165 : // the TLV reader to the next element.
166 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionIdleInterval)
167 : {
168 : uint32_t idleRetransTimeout;
169 30 : ReturnErrorOnFailure(tlvReader.Get(idleRetransTimeout));
170 30 : mRemoteSessionParams.SetMRPIdleRetransTimeout(System::Clock::Milliseconds32(idleRetransTimeout));
171 :
172 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
173 30 : SuccessOrExit(err = tlvReader.Next());
174 : }
175 :
176 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveInterval)
177 : {
178 : uint32_t activeRetransTimeout;
179 30 : ReturnErrorOnFailure(tlvReader.Get(activeRetransTimeout));
180 30 : mRemoteSessionParams.SetMRPActiveRetransTimeout(System::Clock::Milliseconds32(activeRetransTimeout));
181 :
182 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
183 30 : SuccessOrExit(err = tlvReader.Next());
184 : }
185 :
186 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveThreshold)
187 : {
188 : uint16_t activeThresholdTime;
189 30 : ReturnErrorOnFailure(tlvReader.Get(activeThresholdTime));
190 30 : mRemoteSessionParams.SetMRPActiveThresholdTime(System::Clock::Milliseconds16(activeThresholdTime));
191 :
192 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
193 30 : SuccessOrExit(err = tlvReader.Next());
194 : }
195 :
196 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kDataModelRevision)
197 : {
198 : uint16_t dataModelRevision;
199 30 : ReturnErrorOnFailure(tlvReader.Get(dataModelRevision));
200 30 : mRemoteSessionParams.SetDataModelRevision(dataModelRevision);
201 :
202 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
203 30 : SuccessOrExit(err = tlvReader.Next());
204 : }
205 :
206 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kInteractionModelRevision)
207 : {
208 : uint16_t interactionModelRevision;
209 30 : ReturnErrorOnFailure(tlvReader.Get(interactionModelRevision));
210 30 : mRemoteSessionParams.SetInteractionModelRevision(interactionModelRevision);
211 :
212 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
213 30 : SuccessOrExit(err = tlvReader.Next());
214 : }
215 :
216 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSpecificationVersion)
217 : {
218 : uint32_t specificationVersion;
219 30 : ReturnErrorOnFailure(tlvReader.Get(specificationVersion));
220 30 : mRemoteSessionParams.SetSpecificationVersion(specificationVersion);
221 :
222 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
223 30 : SuccessOrExit(err = tlvReader.Next());
224 : }
225 :
226 30 : if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kMaxPathsPerInvoke)
227 : {
228 : uint16_t maxPathsPerInvoke;
229 30 : ReturnErrorOnFailure(tlvReader.Get(maxPathsPerInvoke));
230 30 : mRemoteSessionParams.SetMaxPathsPerInvoke(maxPathsPerInvoke);
231 :
232 : // The next element is optional. If it's not present, return CHIP_NO_ERROR.
233 30 : SuccessOrExit(err = tlvReader.Next());
234 : }
235 :
236 : // Future proofing - Don't error out if there are other tags
237 0 : exit:
238 30 : if (err == CHIP_END_OF_TLV)
239 : {
240 30 : return tlvReader.ExitContainer(containerType);
241 : }
242 0 : return err;
243 : }
244 :
245 4 : bool PairingSession::IsSessionEstablishmentInProgress()
246 : {
247 4 : if (!mSecureSessionHolder)
248 : {
249 0 : return false;
250 : }
251 :
252 4 : Transport::SecureSession * secureSession = mSecureSessionHolder->AsSecureSession();
253 4 : return secureSession->IsEstablishing();
254 : }
255 :
256 208 : void PairingSession::Clear()
257 : {
258 : // Clear acts like the destructor of PairingSession. If it is called during
259 : // the middle of pairing, that means we should terminate the exchange. For the
260 : // normal path, the exchange should already be discarded before calling Clear.
261 208 : if (mExchangeCtxt.HasValue())
262 : {
263 : // The only time we reach this is when we are getting destroyed in the
264 : // middle of our handshake. In that case, there is no point in trying to
265 : // do MRP resends of the last message we sent. So, abort the exchange
266 : // instead of just closing it.
267 6 : mExchangeCtxt.Value()->Abort();
268 6 : mExchangeCtxt.ClearValue();
269 : }
270 208 : mSecureSessionHolder.Release();
271 208 : mPeerSessionId.ClearValue();
272 208 : mSessionManager = nullptr;
273 208 : }
274 :
275 16 : void PairingSession::NotifySessionEstablishmentError(CHIP_ERROR error, SessionEstablishmentStage stage)
276 : {
277 16 : if (mDelegate == nullptr)
278 : {
279 : // Already notified success or error.
280 10 : return;
281 : }
282 :
283 6 : auto * delegate = mDelegate;
284 6 : mDelegate = nullptr;
285 6 : delegate->OnSessionEstablishmentError(error, stage);
286 : }
287 :
288 10 : void PairingSession::OnSessionReleased()
289 : {
290 10 : if (mRole == CryptoContext::SessionRole::kInitiator)
291 : {
292 5 : NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
293 5 : return;
294 : }
295 :
296 : // Send the error notification async, because our delegate is likely to want
297 : // to create a new session to listen for new connection attempts, and doing
298 : // that under an OnSessionReleased notification is not safe.
299 5 : if (!mSessionManager)
300 : {
301 0 : return;
302 : }
303 :
304 5 : mSessionManager->SystemLayer()->ScheduleWork(
305 5 : [](auto * systemLayer, auto * appState) -> void {
306 5 : ChipLogError(Inet, "ASYNC CASE Session establishment failed");
307 5 : auto * _this = static_cast<PairingSession *>(appState);
308 5 : _this->NotifySessionEstablishmentError(CHIP_ERROR_CONNECTION_ABORTED);
309 5 : },
310 : this);
311 : }
312 :
313 : } // namespace chip
|