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