Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2022 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 : /**
20 : * @file
21 : * This file implements the CHIP SPAKE2P Session object that provides
22 : * APIs for constructing spake2p messages and establishing encryption
23 : * keys.
24 : *
25 : * The protocol for handling pA, pB, cB and cA is defined in SPAKE2
26 : * Plus specifications.
27 : * (https://www.ietf.org/id/draft-bar-cfrg-spake2plus-01.html)
28 : *
29 : */
30 : #include <protocols/secure_channel/PASESession.h>
31 :
32 : #include <inttypes.h>
33 : #include <string.h>
34 :
35 : #include <lib/core/CHIPEncoding.h>
36 : #include <lib/core/CHIPSafeCasts.h>
37 : #include <lib/support/BufferWriter.h>
38 : #include <lib/support/CHIPMem.h>
39 : #include <lib/support/CodeUtils.h>
40 : #include <lib/support/SafeInt.h>
41 : #include <lib/support/TypeTraits.h>
42 : #include <messaging/SessionParameters.h>
43 : #include <protocols/Protocols.h>
44 : #include <protocols/secure_channel/Constants.h>
45 : #include <protocols/secure_channel/StatusReport.h>
46 : #include <setup_payload/SetupPayload.h>
47 : #include <system/TLVPacketBufferBackingStore.h>
48 : #include <tracing/macros.h>
49 : #include <transport/SessionManager.h>
50 :
51 : namespace chip {
52 :
53 : using namespace Crypto;
54 : using namespace Messaging;
55 : using namespace Protocols::SecureChannel;
56 :
57 : const char kSpake2pContext[] = "CHIP PAKE V1 Commissioning";
58 :
59 : // Amounts of time to allow for server-side processing of messages.
60 : //
61 : // These timeout values only allow for the server-side processing and assume that any transport-specific
62 : // latency will be added to them.
63 : //
64 : // The session establishment fails if the response is not received within the resulting timeout window,
65 : // which accounts for both transport latency and the server-side latency.
66 : static constexpr ExchangeContext::Timeout kExpectedLowProcessingTime = System::Clock::Seconds16(2);
67 : static constexpr ExchangeContext::Timeout kExpectedHighProcessingTime = System::Clock::Seconds16(30);
68 :
69 16 : PASESession::~PASESession()
70 : {
71 : // Let's clear out any security state stored in the object, before destroying it.
72 16 : Clear();
73 16 : }
74 :
75 10 : void PASESession::OnSessionReleased()
76 : {
77 : // Call into our super-class before we clear our state.
78 10 : PairingSession::OnSessionReleased();
79 10 : Clear();
80 10 : }
81 :
82 10 : void PASESession::Finish()
83 : {
84 10 : mPairingComplete = true;
85 10 : PairingSession::Finish();
86 10 : }
87 :
88 61 : void PASESession::Clear()
89 : {
90 : MATTER_TRACE_SCOPE("Clear", "PASESession");
91 : // This function zeroes out and resets the memory used by the object.
92 : // It's done so that no security related information will be leaked.
93 61 : memset(&mPASEVerifier, 0, sizeof(mPASEVerifier));
94 61 : mNextExpectedMsg.ClearValue();
95 :
96 61 : mSpake2p.Clear();
97 61 : mCommissioningHash.Clear();
98 :
99 61 : mIterationCount = 0;
100 61 : mSaltLength = 0;
101 61 : if (mSalt != nullptr)
102 : {
103 13 : chip::Platform::MemoryFree(mSalt);
104 13 : mSalt = nullptr;
105 : }
106 61 : mPairingComplete = false;
107 61 : PairingSession::Clear();
108 61 : }
109 :
110 21 : CHIP_ERROR PASESession::Init(SessionManager & sessionManager, uint32_t setupCode, SessionEstablishmentDelegate * delegate)
111 : {
112 : MATTER_TRACE_SCOPE("Init", "PASESession");
113 21 : VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
114 21 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
115 :
116 : // Reset any state maintained by PASESession object (in case it's being reused for pairing)
117 21 : Clear();
118 :
119 21 : ReturnErrorOnFailure(mCommissioningHash.Begin());
120 21 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ Uint8::from_const_char(kSpake2pContext), strlen(kSpake2pContext) }));
121 :
122 21 : mDelegate = delegate;
123 21 : ReturnErrorOnFailure(AllocateSecureSession(sessionManager));
124 21 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
125 21 : ChipLogDetail(SecureChannel, "Assigned local session key ID %u", GetLocalSessionId().Value());
126 :
127 21 : VerifyOrReturnError(setupCode < (1 << kSetupPINCodeFieldLengthInBits), CHIP_ERROR_INVALID_ARGUMENT);
128 21 : mSetupPINCode = setupCode;
129 :
130 21 : return CHIP_NO_ERROR;
131 : }
132 :
133 3 : CHIP_ERROR PASESession::GeneratePASEVerifier(Spake2pVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt,
134 : bool useRandomPIN, uint32_t & setupPINCode)
135 : {
136 : MATTER_TRACE_SCOPE("GeneratePASEVerifier", "PASESession");
137 :
138 3 : if (useRandomPIN)
139 : {
140 1 : ReturnErrorOnFailure(SetupPayload::generateRandomSetupPin(setupPINCode));
141 : }
142 :
143 3 : return verifier.Generate(pbkdf2IterCount, salt, setupPINCode);
144 : }
145 :
146 12 : CHIP_ERROR PASESession::SetupSpake2p()
147 : {
148 : MATTER_TRACE_SCOPE("SetupSpake2p", "PASESession");
149 12 : uint8_t context[kSHA256_Hash_Length] = { 0 };
150 12 : MutableByteSpan contextSpan{ context };
151 :
152 12 : ReturnErrorOnFailure(mCommissioningHash.Finish(contextSpan));
153 12 : ReturnErrorOnFailure(mSpake2p.Init(contextSpan.data(), contextSpan.size()));
154 :
155 12 : return CHIP_NO_ERROR;
156 : }
157 :
158 16 : CHIP_ERROR PASESession::WaitForPairing(SessionManager & sessionManager, const Spake2pVerifier & verifier, uint32_t pbkdf2IterCount,
159 : const ByteSpan & salt, Optional<ReliableMessageProtocolConfig> mrpLocalConfig,
160 : SessionEstablishmentDelegate * delegate)
161 : {
162 : // Return early on error here, as we have not initialized any state yet
163 16 : VerifyOrReturnError(!salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
164 15 : VerifyOrReturnError(salt.data() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
165 15 : VerifyOrReturnError(salt.size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
166 : CHIP_ERROR_INVALID_ARGUMENT);
167 :
168 13 : CHIP_ERROR err = Init(sessionManager, kSetupPINCodeUndefinedValue, delegate);
169 : // From here onwards, let's go to exit on error, as some state might have already
170 : // been initialized
171 13 : SuccessOrExit(err);
172 :
173 13 : mRole = CryptoContext::SessionRole::kResponder;
174 :
175 13 : VerifyOrExit(CanCastTo<uint16_t>(salt.size()), err = CHIP_ERROR_INVALID_ARGUMENT);
176 13 : mSaltLength = static_cast<uint16_t>(salt.size());
177 :
178 13 : if (mSalt != nullptr)
179 : {
180 0 : chip::Platform::MemoryFree(mSalt);
181 0 : mSalt = nullptr;
182 : }
183 :
184 13 : mSalt = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(mSaltLength));
185 13 : VerifyOrExit(mSalt != nullptr, err = CHIP_ERROR_NO_MEMORY);
186 :
187 13 : memmove(mSalt, salt.data(), mSaltLength);
188 13 : memmove(&mPASEVerifier, &verifier, sizeof(verifier));
189 :
190 13 : mIterationCount = pbkdf2IterCount;
191 13 : mNextExpectedMsg.SetValue(MsgType::PBKDFParamRequest);
192 13 : mPairingComplete = false;
193 13 : mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
194 :
195 13 : ChipLogDetail(SecureChannel, "Waiting for PBKDF param request");
196 :
197 0 : exit:
198 13 : if (err != CHIP_NO_ERROR)
199 : {
200 0 : Clear();
201 : }
202 13 : return err;
203 : }
204 :
205 9 : CHIP_ERROR PASESession::Pair(SessionManager & sessionManager, uint32_t peerSetUpPINCode,
206 : Optional<ReliableMessageProtocolConfig> mrpLocalConfig, Messaging::ExchangeContext * exchangeCtxt,
207 : SessionEstablishmentDelegate * delegate)
208 : {
209 : MATTER_TRACE_SCOPE("Pair", "PASESession");
210 9 : VerifyOrReturnError(exchangeCtxt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
211 8 : CHIP_ERROR err = Init(sessionManager, peerSetUpPINCode, delegate);
212 8 : SuccessOrExit(err);
213 :
214 8 : mRole = CryptoContext::SessionRole::kInitiator;
215 :
216 8 : mExchangeCtxt.Emplace(*exchangeCtxt);
217 :
218 : // When commissioning starts, the peer is assumed to be active.
219 8 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->MarkActiveRx();
220 :
221 8 : mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedLowProcessingTime);
222 :
223 8 : mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
224 :
225 8 : err = SendPBKDFParamRequest();
226 8 : SuccessOrExit(err);
227 :
228 7 : mDelegate->OnSessionEstablishmentStarted();
229 :
230 8 : exit:
231 8 : if (err != CHIP_NO_ERROR)
232 : {
233 : // If a failure happens before we have placed the incoming exchange into `mExchangeCtxt`, we need to make
234 : // sure to close the exchange to fulfill our API contract.
235 1 : if (!mExchangeCtxt.HasValue())
236 : {
237 0 : exchangeCtxt->Close();
238 : }
239 1 : Clear();
240 1 : ChipLogError(SecureChannel, "Failed during PASE session pairing request: %" CHIP_ERROR_FORMAT, err.Format());
241 : MATTER_TRACE_COUNTER("PASEFail");
242 : }
243 8 : return err;
244 : }
245 :
246 0 : void PASESession::OnResponseTimeout(ExchangeContext * ec)
247 : {
248 : MATTER_TRACE_SCOPE("OnResponseTimeout", "PASESession");
249 0 : VerifyOrReturn(ec != nullptr, ChipLogError(SecureChannel, "PASESession::OnResponseTimeout was called by null exchange"));
250 0 : VerifyOrReturn(!mExchangeCtxt.HasValue() || &mExchangeCtxt.Value().Get() == ec,
251 : ChipLogError(SecureChannel, "PASESession::OnResponseTimeout exchange doesn't match"));
252 : // If we were waiting for something, mNextExpectedMsg had better have a value.
253 0 : ChipLogError(SecureChannel, "PASESession timed out while waiting for a response from the peer. Expected message type was %u",
254 : to_underlying(mNextExpectedMsg.Value()));
255 : MATTER_TRACE_COUNTER("PASETimeout");
256 : // Discard the exchange so that Clear() doesn't try closing it. The
257 : // exchange will handle that.
258 0 : DiscardExchange();
259 0 : Clear();
260 : // Do this last in case the delegate frees us.
261 0 : NotifySessionEstablishmentError(CHIP_ERROR_TIMEOUT);
262 : }
263 :
264 10 : CHIP_ERROR PASESession::DeriveSecureSession(CryptoContext & session)
265 : {
266 10 : VerifyOrReturnError(mPairingComplete, CHIP_ERROR_INCORRECT_STATE);
267 :
268 10 : SessionKeystore & keystore = *mSessionManager->GetSessionKeystore();
269 10 : AutoReleaseSymmetricKey<HkdfKeyHandle> hkdfKey(keystore);
270 :
271 10 : ReturnErrorOnFailure(mSpake2p.GetKeys(keystore, hkdfKey.KeyHandle()));
272 10 : ReturnErrorOnFailure(session.InitFromSecret(keystore, hkdfKey.KeyHandle(), ByteSpan{} /* salt */,
273 : CryptoContext::SessionInfoType::kSessionEstablishment, mRole));
274 :
275 10 : return CHIP_NO_ERROR;
276 10 : }
277 :
278 8 : CHIP_ERROR PASESession::SendPBKDFParamRequest()
279 : {
280 : MATTER_TRACE_SCOPE("SendPBKDFParamRequest", "PASESession");
281 :
282 8 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
283 :
284 8 : ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
285 :
286 8 : const size_t max_msg_len = TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize, // initiatorRandom,
287 : sizeof(uint16_t), // initiatorSessionId
288 : sizeof(PasscodeId), // passcodeId,
289 : sizeof(uint8_t), // hasPBKDFParameters
290 : SessionParameters::kEstimatedTLVSize // Session Parameters
291 : );
292 :
293 8 : System::PacketBufferHandle req = System::PacketBufferHandle::New(max_msg_len);
294 8 : VerifyOrReturnError(!req.IsNull(), CHIP_ERROR_NO_MEMORY);
295 :
296 8 : System::PacketBufferTLVWriter tlvWriter;
297 8 : tlvWriter.Init(std::move(req));
298 :
299 8 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
300 8 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
301 8 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(1), mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
302 8 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), GetLocalSessionId().Value()));
303 8 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), kDefaultCommissioningPasscodeId));
304 8 : ReturnErrorOnFailure(tlvWriter.PutBoolean(TLV::ContextTag(4), mHavePBKDFParameters));
305 :
306 8 : VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
307 8 : ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter));
308 :
309 8 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
310 8 : ReturnErrorOnFailure(tlvWriter.Finalize(&req));
311 :
312 : // Update commissioning hash with the pbkdf2 param request that's being sent.
313 8 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ req->Start(), req->DataLength() }));
314 :
315 8 : ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(MsgType::PBKDFParamRequest, std::move(req),
316 : SendFlags(SendMessageFlags::kExpectResponse)));
317 :
318 7 : mNextExpectedMsg.SetValue(MsgType::PBKDFParamResponse);
319 :
320 : #if CHIP_PROGRESS_LOGGING
321 7 : const auto localMRPConfig = mLocalMRPConfig.Value();
322 : #endif // CHIP_PROGRESS_LOGGING
323 7 : ChipLogProgress(SecureChannel, "Sent PBKDF param request [II:%" PRIu32 "ms AI:%" PRIu32 "ms AT:%ums)",
324 : localMRPConfig.mIdleRetransTimeout.count(), localMRPConfig.mActiveRetransTimeout.count(),
325 : localMRPConfig.mActiveThresholdTime.count());
326 :
327 7 : return CHIP_NO_ERROR;
328 8 : }
329 :
330 6 : CHIP_ERROR PASESession::HandlePBKDFParamRequest(System::PacketBufferHandle && msg)
331 : {
332 : MATTER_TRACE_SCOPE("HandlePBKDFParamRequest", "PASESession");
333 6 : CHIP_ERROR err = CHIP_NO_ERROR;
334 :
335 6 : System::PacketBufferTLVReader tlvReader;
336 6 : TLV::TLVType containerType = TLV::kTLVType_Structure;
337 :
338 : uint16_t initiatorSessionId;
339 : uint8_t initiatorRandom[kPBKDFParamRandomNumberSize];
340 :
341 6 : uint32_t decodeTagIdSeq = 0;
342 6 : PasscodeId passcodeId = kDefaultCommissioningPasscodeId;
343 6 : bool hasPBKDFParameters = false;
344 :
345 6 : ChipLogDetail(SecureChannel, "Received PBKDF param request");
346 :
347 6 : SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
348 :
349 6 : tlvReader.Init(std::move(msg));
350 6 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
351 6 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
352 :
353 6 : SuccessOrExit(err = tlvReader.Next());
354 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
355 6 : SuccessOrExit(err = tlvReader.GetBytes(initiatorRandom, sizeof(initiatorRandom)));
356 :
357 6 : SuccessOrExit(err = tlvReader.Next());
358 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
359 6 : SuccessOrExit(err = tlvReader.Get(initiatorSessionId));
360 :
361 6 : ChipLogDetail(SecureChannel, "Peer assigned session ID %d", initiatorSessionId);
362 6 : SetPeerSessionId(initiatorSessionId);
363 :
364 6 : SuccessOrExit(err = tlvReader.Next());
365 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
366 6 : SuccessOrExit(err = tlvReader.Get(passcodeId));
367 6 : VerifyOrExit(passcodeId == kDefaultCommissioningPasscodeId, err = CHIP_ERROR_INVALID_PASE_PARAMETER);
368 :
369 6 : SuccessOrExit(err = tlvReader.Next());
370 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
371 6 : SuccessOrExit(err = tlvReader.Get(hasPBKDFParameters));
372 :
373 6 : if (tlvReader.Next() != CHIP_END_OF_TLV)
374 : {
375 6 : SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader));
376 6 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
377 : GetRemoteSessionParameters());
378 : }
379 :
380 6 : err = SendPBKDFParamResponse(ByteSpan(initiatorRandom), hasPBKDFParameters);
381 6 : SuccessOrExit(err);
382 :
383 6 : mDelegate->OnSessionEstablishmentStarted();
384 :
385 6 : exit:
386 :
387 6 : if (err != CHIP_NO_ERROR)
388 : {
389 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
390 : }
391 6 : return err;
392 6 : }
393 :
394 6 : CHIP_ERROR PASESession::SendPBKDFParamResponse(ByteSpan initiatorRandom, bool initiatorHasPBKDFParams)
395 : {
396 : MATTER_TRACE_SCOPE("SendPBKDFParamResponse", "PASESession");
397 :
398 6 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
399 :
400 6 : ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
401 :
402 : const size_t max_msg_len =
403 6 : TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize, // initiatorRandom
404 : kPBKDFParamRandomNumberSize, // responderRandom
405 : sizeof(uint16_t), // responderSessionId
406 6 : TLV::EstimateStructOverhead(sizeof(uint32_t), mSaltLength), // pbkdf_parameters
407 : SessionParameters::kEstimatedTLVSize // Session Parameters
408 : );
409 :
410 6 : System::PacketBufferHandle resp = System::PacketBufferHandle::New(max_msg_len);
411 6 : VerifyOrReturnError(!resp.IsNull(), CHIP_ERROR_NO_MEMORY);
412 :
413 6 : System::PacketBufferTLVWriter tlvWriter;
414 6 : tlvWriter.Init(std::move(resp));
415 :
416 6 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
417 6 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
418 : // The initiator random value is being sent back in the response as required by the specifications
419 6 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), initiatorRandom));
420 6 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(2), mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
421 6 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), GetLocalSessionId().Value()));
422 :
423 6 : if (!initiatorHasPBKDFParams)
424 : {
425 : TLV::TLVType pbkdfParamContainer;
426 6 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(4), TLV::kTLVType_Structure, pbkdfParamContainer));
427 6 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), mIterationCount));
428 6 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(2), mSalt, mSaltLength));
429 6 : ReturnErrorOnFailure(tlvWriter.EndContainer(pbkdfParamContainer));
430 : }
431 :
432 6 : VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
433 6 : ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter));
434 :
435 6 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
436 6 : ReturnErrorOnFailure(tlvWriter.Finalize(&resp));
437 :
438 : // Update commissioning hash with the pbkdf2 param response that's being sent.
439 6 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ resp->Start(), resp->DataLength() }));
440 6 : ReturnErrorOnFailure(SetupSpake2p());
441 :
442 6 : ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(MsgType::PBKDFParamResponse, std::move(resp),
443 : SendFlags(SendMessageFlags::kExpectResponse)));
444 6 : ChipLogDetail(SecureChannel, "Sent PBKDF param response");
445 :
446 6 : mNextExpectedMsg.SetValue(MsgType::PASE_Pake1);
447 :
448 6 : return CHIP_NO_ERROR;
449 6 : }
450 :
451 6 : CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && msg)
452 : {
453 : MATTER_TRACE_SCOPE("HandlePBKDFParamResponse", "PASESession");
454 6 : CHIP_ERROR err = CHIP_NO_ERROR;
455 :
456 6 : System::PacketBufferTLVReader tlvReader;
457 6 : TLV::TLVType containerType = TLV::kTLVType_Structure;
458 :
459 : uint16_t responderSessionId;
460 : uint8_t random[kPBKDFParamRandomNumberSize];
461 :
462 6 : uint32_t decodeTagIdSeq = 0;
463 6 : ByteSpan salt;
464 6 : uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
465 :
466 6 : ChipLogDetail(SecureChannel, "Received PBKDF param response");
467 :
468 6 : SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
469 :
470 6 : tlvReader.Init(std::move(msg));
471 6 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
472 6 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
473 :
474 6 : SuccessOrExit(err = tlvReader.Next());
475 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
476 : // Initiator's random value
477 6 : SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
478 6 : VerifyOrExit(ByteSpan(random).data_equal(ByteSpan(mPBKDFLocalRandomData)), err = CHIP_ERROR_INVALID_PASE_PARAMETER);
479 :
480 6 : SuccessOrExit(err = tlvReader.Next());
481 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
482 : // Responder's random value
483 6 : SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
484 :
485 6 : SuccessOrExit(err = tlvReader.Next());
486 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
487 6 : SuccessOrExit(err = tlvReader.Get(responderSessionId));
488 :
489 6 : ChipLogDetail(SecureChannel, "Peer assigned session ID %d", responderSessionId);
490 6 : SetPeerSessionId(responderSessionId);
491 :
492 6 : if (mHavePBKDFParameters)
493 : {
494 0 : if (tlvReader.Next() != CHIP_END_OF_TLV)
495 : {
496 0 : SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader));
497 0 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
498 : GetRemoteSessionParameters());
499 : }
500 :
501 : // TODO - Add a unit test that exercises mHavePBKDFParameters path
502 0 : salt = ByteSpan(mSalt, mSaltLength);
503 : }
504 : else
505 : {
506 6 : SuccessOrExit(err = tlvReader.Next());
507 6 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
508 6 : decodeTagIdSeq = 0;
509 :
510 6 : SuccessOrExit(err = tlvReader.Next());
511 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
512 6 : SuccessOrExit(err = tlvReader.Get(mIterationCount));
513 :
514 6 : SuccessOrExit(err = tlvReader.Next());
515 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
516 6 : SuccessOrExit(err = tlvReader.Get(salt));
517 :
518 6 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
519 :
520 6 : if (tlvReader.Next() != CHIP_END_OF_TLV)
521 : {
522 6 : SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader));
523 6 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
524 : GetRemoteSessionParameters());
525 : }
526 : }
527 :
528 6 : err = SetupSpake2p();
529 6 : SuccessOrExit(err);
530 :
531 6 : err = Spake2pVerifier::ComputeWS(mIterationCount, salt, mSetupPINCode, serializedWS, sizeof(serializedWS));
532 6 : SuccessOrExit(err);
533 :
534 6 : err = mSpake2p.BeginProver(nullptr, 0, nullptr, 0, &serializedWS[0], kSpake2p_WS_Length, &serializedWS[kSpake2p_WS_Length],
535 : kSpake2p_WS_Length);
536 6 : SuccessOrExit(err);
537 :
538 6 : err = SendMsg1();
539 6 : SuccessOrExit(err);
540 :
541 6 : exit:
542 6 : if (err != CHIP_NO_ERROR)
543 : {
544 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
545 : }
546 6 : return err;
547 6 : }
548 :
549 6 : CHIP_ERROR PASESession::SendMsg1()
550 : {
551 : MATTER_TRACE_SCOPE("SendMsg1", "PASESession");
552 6 : const size_t max_msg_len = TLV::EstimateStructOverhead(kMAX_Point_Length);
553 6 : System::PacketBufferHandle msg = System::PacketBufferHandle::New(max_msg_len);
554 6 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY);
555 :
556 6 : System::PacketBufferTLVWriter tlvWriter;
557 6 : tlvWriter.Init(std::move(msg));
558 :
559 6 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
560 6 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
561 :
562 : uint8_t X[kMAX_Point_Length];
563 6 : size_t X_len = sizeof(X);
564 :
565 6 : constexpr uint8_t kPake1_pA = 1;
566 :
567 6 : ReturnErrorOnFailure(mSpake2p.ComputeRoundOne(nullptr, 0, X, &X_len));
568 6 : VerifyOrReturnError(X_len == sizeof(X), CHIP_ERROR_INTERNAL);
569 6 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kPake1_pA), ByteSpan(X)));
570 6 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
571 6 : ReturnErrorOnFailure(tlvWriter.Finalize(&msg));
572 :
573 6 : ReturnErrorOnFailure(
574 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake1, std::move(msg), SendFlags(SendMessageFlags::kExpectResponse)));
575 6 : ChipLogDetail(SecureChannel, "Sent spake2p msg1");
576 :
577 6 : mNextExpectedMsg.SetValue(MsgType::PASE_Pake2);
578 :
579 6 : return CHIP_NO_ERROR;
580 6 : }
581 :
582 6 : CHIP_ERROR PASESession::HandleMsg1_and_SendMsg2(System::PacketBufferHandle && msg1)
583 : {
584 : MATTER_TRACE_SCOPE("HandleMsg1_and_SendMsg2", "PASESession");
585 6 : CHIP_ERROR err = CHIP_NO_ERROR;
586 :
587 : uint8_t Y[kMAX_Point_Length];
588 6 : size_t Y_len = sizeof(Y);
589 :
590 : uint8_t verifier[kMAX_Hash_Length];
591 6 : size_t verifier_len = kMAX_Hash_Length;
592 :
593 6 : ChipLogDetail(SecureChannel, "Received spake2p msg1");
594 : MATTER_TRACE_SCOPE("Pake1", "PASESession");
595 :
596 6 : System::PacketBufferTLVReader tlvReader;
597 6 : TLV::TLVType containerType = TLV::kTLVType_Structure;
598 :
599 : const uint8_t * X;
600 6 : size_t X_len = 0;
601 :
602 6 : tlvReader.Init(std::move(msg1));
603 6 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
604 6 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
605 :
606 6 : SuccessOrExit(err = tlvReader.Next());
607 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == 1, err = CHIP_ERROR_INVALID_TLV_TAG);
608 6 : X_len = tlvReader.GetLength();
609 6 : SuccessOrExit(err = tlvReader.GetDataPtr(X));
610 6 : SuccessOrExit(err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kP256_FE_Length, mPASEVerifier.mL,
611 : kP256_Point_Length));
612 :
613 6 : SuccessOrExit(err = mSpake2p.ComputeRoundOne(X, X_len, Y, &Y_len));
614 6 : VerifyOrReturnError(Y_len == sizeof(Y), CHIP_ERROR_INTERNAL);
615 6 : SuccessOrExit(err = mSpake2p.ComputeRoundTwo(X, X_len, verifier, &verifier_len));
616 6 : msg1 = nullptr;
617 :
618 : {
619 6 : const size_t max_msg_len = TLV::EstimateStructOverhead(Y_len, verifier_len);
620 6 : constexpr uint8_t kPake2_pB = 1;
621 6 : constexpr uint8_t kPake2_cB = 2;
622 :
623 6 : System::PacketBufferHandle msg2 = System::PacketBufferHandle::New(max_msg_len);
624 6 : VerifyOrExit(!msg2.IsNull(), err = CHIP_ERROR_NO_MEMORY);
625 :
626 6 : System::PacketBufferTLVWriter tlvWriter;
627 6 : tlvWriter.Init(std::move(msg2));
628 :
629 6 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
630 6 : SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
631 6 : SuccessOrExit(err = tlvWriter.Put(TLV::ContextTag(kPake2_pB), ByteSpan(Y)));
632 6 : SuccessOrExit(err = tlvWriter.Put(TLV::ContextTag(kPake2_cB), ByteSpan(verifier, verifier_len)));
633 6 : SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
634 6 : SuccessOrExit(err = tlvWriter.Finalize(&msg2));
635 :
636 6 : err =
637 6 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake2, std::move(msg2), SendFlags(SendMessageFlags::kExpectResponse));
638 6 : SuccessOrExit(err);
639 :
640 6 : mNextExpectedMsg.SetValue(MsgType::PASE_Pake3);
641 6 : }
642 :
643 6 : ChipLogDetail(SecureChannel, "Sent spake2p msg2");
644 : MATTER_TRACE_COUNTER("Pake2");
645 :
646 0 : exit:
647 :
648 6 : if (err != CHIP_NO_ERROR)
649 : {
650 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
651 : }
652 6 : return err;
653 6 : }
654 :
655 6 : CHIP_ERROR PASESession::HandleMsg2_and_SendMsg3(System::PacketBufferHandle && msg2)
656 : {
657 : MATTER_TRACE_SCOPE("HandleMsg2_and_SendMsg3", "PASESession");
658 6 : CHIP_ERROR err = CHIP_NO_ERROR;
659 :
660 : uint8_t verifier[kMAX_Hash_Length];
661 6 : size_t verifier_len = kMAX_Hash_Length;
662 :
663 6 : System::PacketBufferHandle resp;
664 :
665 6 : ChipLogDetail(SecureChannel, "Received spake2p msg2");
666 :
667 6 : System::PacketBufferTLVReader tlvReader;
668 6 : TLV::TLVType containerType = TLV::kTLVType_Structure;
669 :
670 : const uint8_t * Y;
671 6 : size_t Y_len = 0;
672 :
673 : const uint8_t * peer_verifier;
674 6 : size_t peer_verifier_len = 0;
675 :
676 6 : uint32_t decodeTagIdSeq = 0;
677 :
678 6 : tlvReader.Init(std::move(msg2));
679 6 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
680 6 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
681 :
682 6 : SuccessOrExit(err = tlvReader.Next());
683 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
684 6 : Y_len = tlvReader.GetLength();
685 6 : SuccessOrExit(err = tlvReader.GetDataPtr(Y));
686 :
687 6 : SuccessOrExit(err = tlvReader.Next());
688 6 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
689 6 : peer_verifier_len = tlvReader.GetLength();
690 6 : SuccessOrExit(err = tlvReader.GetDataPtr(peer_verifier));
691 :
692 6 : SuccessOrExit(err = mSpake2p.ComputeRoundTwo(Y, Y_len, verifier, &verifier_len));
693 :
694 6 : SuccessOrExit(err = mSpake2p.KeyConfirm(peer_verifier, peer_verifier_len));
695 5 : msg2 = nullptr;
696 :
697 : {
698 5 : const size_t max_msg_len = TLV::EstimateStructOverhead(verifier_len);
699 5 : constexpr uint8_t kPake3_cB = 1;
700 :
701 5 : System::PacketBufferHandle msg3 = System::PacketBufferHandle::New(max_msg_len);
702 5 : VerifyOrExit(!msg3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
703 :
704 5 : System::PacketBufferTLVWriter tlvWriter;
705 5 : tlvWriter.Init(std::move(msg3));
706 :
707 5 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
708 5 : SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
709 5 : SuccessOrExit(err = tlvWriter.Put(TLV::ContextTag(kPake3_cB), ByteSpan(verifier, verifier_len)));
710 5 : SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
711 5 : SuccessOrExit(err = tlvWriter.Finalize(&msg3));
712 :
713 5 : err =
714 5 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake3, std::move(msg3), SendFlags(SendMessageFlags::kExpectResponse));
715 5 : SuccessOrExit(err);
716 :
717 5 : mNextExpectedMsg.SetValue(MsgType::StatusReport);
718 5 : }
719 5 : ChipLogDetail(SecureChannel, "Sent spake2p msg3");
720 :
721 0 : exit:
722 :
723 6 : if (err != CHIP_NO_ERROR)
724 : {
725 1 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
726 : }
727 6 : return err;
728 6 : }
729 :
730 5 : CHIP_ERROR PASESession::HandleMsg3(System::PacketBufferHandle && msg)
731 : {
732 : MATTER_TRACE_SCOPE("HandleMsg3", "PASESession");
733 5 : CHIP_ERROR err = CHIP_NO_ERROR;
734 :
735 5 : ChipLogDetail(SecureChannel, "Received spake2p msg3");
736 : MATTER_TRACE_COUNTER("Pake3");
737 :
738 5 : mNextExpectedMsg.ClearValue();
739 :
740 5 : System::PacketBufferTLVReader tlvReader;
741 5 : TLV::TLVType containerType = TLV::kTLVType_Structure;
742 :
743 : const uint8_t * peer_verifier;
744 5 : size_t peer_verifier_len = 0;
745 :
746 5 : tlvReader.Init(std::move(msg));
747 5 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
748 5 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
749 :
750 5 : SuccessOrExit(err = tlvReader.Next());
751 5 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == 1, err = CHIP_ERROR_INVALID_TLV_TAG);
752 5 : peer_verifier_len = tlvReader.GetLength();
753 5 : SuccessOrExit(err = tlvReader.GetDataPtr(peer_verifier));
754 :
755 5 : VerifyOrExit(peer_verifier_len == kMAX_Hash_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
756 :
757 5 : SuccessOrExit(err = mSpake2p.KeyConfirm(peer_verifier, peer_verifier_len));
758 :
759 : // Send confirmation to peer that we succeeded so they can start using the session.
760 5 : SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
761 :
762 5 : Finish();
763 5 : exit:
764 :
765 5 : if (err != CHIP_NO_ERROR)
766 : {
767 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
768 : }
769 5 : return err;
770 5 : }
771 :
772 5 : void PASESession::OnSuccessStatusReport()
773 : {
774 5 : Finish();
775 5 : }
776 :
777 1 : CHIP_ERROR PASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
778 : Optional<uintptr_t> protocolData)
779 : {
780 1 : CHIP_ERROR err = CHIP_NO_ERROR;
781 1 : switch (protocolCode)
782 : {
783 1 : case kProtocolCodeInvalidParam:
784 1 : err = CHIP_ERROR_INVALID_PASE_PARAMETER;
785 1 : break;
786 :
787 0 : default:
788 0 : err = CHIP_ERROR_INTERNAL;
789 0 : break;
790 : };
791 1 : ChipLogError(SecureChannel, "Received error (protocol code %d) during PASE process: %" CHIP_ERROR_FORMAT, protocolCode,
792 : err.Format());
793 1 : return err;
794 : }
795 :
796 35 : CHIP_ERROR PASESession::ValidateReceivedMessage(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
797 : const System::PacketBufferHandle & msg)
798 : {
799 35 : VerifyOrReturnError(exchange != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
800 :
801 : // mExchangeCtxt can be nullptr if this is the first message (PBKDFParamRequest) received by PASESession
802 : // via UnsolicitedMessageHandler. The exchange context is allocated by exchange manager and provided
803 : // to the handler (PASESession object).
804 35 : if (mExchangeCtxt.HasValue())
805 : {
806 29 : if (&mExchangeCtxt.Value().Get() != exchange)
807 : {
808 0 : ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
809 : }
810 : }
811 : else
812 : {
813 6 : mExchangeCtxt.Emplace(*exchange);
814 : }
815 :
816 35 : if (!mExchangeCtxt.Value()->GetSessionHandle()->IsUnauthenticatedSession())
817 : {
818 0 : ChipLogError(SecureChannel, "PASESession received PBKDFParamRequest over encrypted session. Ignoring.");
819 0 : return CHIP_ERROR_INCORRECT_STATE;
820 : }
821 :
822 35 : mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedHighProcessingTime);
823 :
824 35 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
825 35 : VerifyOrReturnError((mNextExpectedMsg.HasValue() && payloadHeader.HasMessageType(mNextExpectedMsg.Value())) ||
826 : payloadHeader.HasMessageType(MsgType::StatusReport),
827 : CHIP_ERROR_INVALID_MESSAGE_TYPE);
828 :
829 35 : return CHIP_NO_ERROR;
830 : }
831 :
832 6 : CHIP_ERROR PASESession::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate)
833 : {
834 : // Handle messages by myself
835 6 : newDelegate = this;
836 6 : return CHIP_NO_ERROR;
837 : }
838 :
839 35 : CHIP_ERROR PASESession::OnMessageReceived(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
840 : System::PacketBufferHandle && msg)
841 : {
842 : MATTER_TRACE_SCOPE("OnMessageReceived", "PASESession");
843 35 : CHIP_ERROR err = ValidateReceivedMessage(exchange, payloadHeader, msg);
844 35 : MsgType msgType = static_cast<MsgType>(payloadHeader.GetMessageType());
845 35 : SuccessOrExit(err);
846 :
847 : #if CHIP_CONFIG_SLOW_CRYPTO
848 : if (msgType == MsgType::PBKDFParamRequest || msgType == MsgType::PBKDFParamResponse || msgType == MsgType::PASE_Pake1 ||
849 : msgType == MsgType::PASE_Pake2 || msgType == MsgType::PASE_Pake3)
850 : {
851 : SuccessOrExit(err = mExchangeCtxt.Value()->FlushAcks());
852 : }
853 : #endif // CHIP_CONFIG_SLOW_CRYPTO
854 :
855 35 : switch (msgType)
856 : {
857 6 : case MsgType::PBKDFParamRequest:
858 6 : err = HandlePBKDFParamRequest(std::move(msg));
859 6 : break;
860 :
861 6 : case MsgType::PBKDFParamResponse:
862 6 : err = HandlePBKDFParamResponse(std::move(msg));
863 6 : break;
864 :
865 6 : case MsgType::PASE_Pake1:
866 6 : err = HandleMsg1_and_SendMsg2(std::move(msg));
867 6 : break;
868 :
869 6 : case MsgType::PASE_Pake2:
870 6 : err = HandleMsg2_and_SendMsg3(std::move(msg));
871 6 : break;
872 :
873 5 : case MsgType::PASE_Pake3:
874 5 : err = HandleMsg3(std::move(msg));
875 5 : break;
876 :
877 6 : case MsgType::StatusReport:
878 6 : err =
879 6 : HandleStatusReport(std::move(msg), mNextExpectedMsg.HasValue() && (mNextExpectedMsg.Value() == MsgType::StatusReport));
880 6 : break;
881 :
882 0 : default:
883 0 : err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
884 0 : break;
885 : };
886 :
887 35 : exit:
888 :
889 : // Call delegate to indicate pairing failure
890 35 : if (err != CHIP_NO_ERROR)
891 : {
892 : // Discard the exchange so that Clear() doesn't try closing it. The
893 : // exchange will handle that.
894 2 : DiscardExchange();
895 2 : Clear();
896 2 : ChipLogError(SecureChannel, "Failed during PASE session setup: %" CHIP_ERROR_FORMAT, err.Format());
897 : MATTER_TRACE_COUNTER("PASEFail");
898 : // Do this last in case the delegate frees us.
899 2 : NotifySessionEstablishmentError(err);
900 : }
901 35 : return err;
902 : }
903 :
904 : } // namespace chip
|