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 175 : PASESession::~PASESession()
119 : {
120 : // Let's clear out any security state stored in the object, before destroying it.
121 175 : Clear();
122 175 : }
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 239 : 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 239 : ClearSecretData(reinterpret_cast<uint8_t *>(&mPASEVerifier), sizeof(mPASEVerifier));
144 239 : mNextExpectedMsg.ClearValue();
145 :
146 239 : mSpake2p.Clear();
147 239 : mCommissioningHash.Clear();
148 :
149 239 : mIterationCount = 0;
150 239 : if (mSalt != nullptr)
151 : {
152 17 : ClearSecretData(mSalt, mSaltLength);
153 17 : chip::Platform::MemoryFree(mSalt);
154 17 : mSalt = nullptr;
155 : }
156 239 : mSaltLength = 0;
157 239 : mPairingComplete = false;
158 239 : PairingSession::Clear();
159 239 : }
160 :
161 27 : CHIP_ERROR PASESession::Init(SessionManager & sessionManager, uint32_t setupCode, SessionEstablishmentDelegate * delegate)
162 : {
163 : MATTER_TRACE_SCOPE("Init", "PASESession");
164 27 : VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
165 27 : 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 27 : Clear();
169 :
170 27 : ReturnErrorOnFailure(mCommissioningHash.Begin());
171 27 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ Uint8::from_const_char(kSpake2pContext), strlen(kSpake2pContext) }));
172 :
173 27 : mDelegate = delegate;
174 27 : ReturnErrorOnFailure(AllocateSecureSession(sessionManager));
175 27 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
176 27 : ChipLogDetail(SecureChannel, "Assigned local session key ID %u", GetLocalSessionId().Value());
177 :
178 27 : VerifyOrReturnError(setupCode < (1 << kSetupPINCodeFieldLengthInBits), CHIP_ERROR_INVALID_ARGUMENT);
179 27 : mSetupPINCode = setupCode;
180 :
181 27 : 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 20 : 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 20 : VerifyOrReturnError(!salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
215 19 : VerifyOrReturnError(salt.data() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
216 19 : VerifyOrReturnError(salt.size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
217 : CHIP_ERROR_INVALID_ARGUMENT);
218 :
219 17 : 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 17 : SuccessOrExit(err);
223 :
224 17 : mRole = CryptoContext::SessionRole::kResponder;
225 :
226 17 : VerifyOrExit(CanCastTo<uint16_t>(salt.size()), err = CHIP_ERROR_INVALID_ARGUMENT);
227 17 : mSaltLength = static_cast<uint16_t>(salt.size());
228 :
229 17 : if (mSalt != nullptr)
230 : {
231 0 : chip::Platform::MemoryFree(mSalt);
232 0 : mSalt = nullptr;
233 : }
234 :
235 17 : mSalt = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(mSaltLength));
236 17 : VerifyOrExit(mSalt != nullptr, err = CHIP_ERROR_NO_MEMORY);
237 :
238 17 : memmove(mSalt, salt.data(), mSaltLength);
239 17 : memmove(&mPASEVerifier, &verifier, sizeof(verifier));
240 :
241 17 : mIterationCount = pbkdf2IterCount;
242 17 : mNextExpectedMsg.SetValue(MsgType::PBKDFParamRequest);
243 17 : mPairingComplete = false;
244 17 : mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
245 :
246 17 : ChipLogDetail(SecureChannel, "Waiting for PBKDF param request");
247 :
248 17 : exit:
249 34 : if (err != CHIP_NO_ERROR)
250 : {
251 0 : Clear();
252 : }
253 17 : 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 : SuccessOrExit(err = 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 : VerifyOrExit(tlvReader.GetLength() == kPBKDFParamRandomNumberSize, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
551 8 : SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
552 8 : VerifyOrExit(ByteSpan(random).data_equal(ByteSpan(mPBKDFLocalRandomData)), err = CHIP_ERROR_INVALID_PASE_PARAMETER);
553 :
554 : // Responder's random value
555 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kResponderRandom)));
556 8 : VerifyOrExit(tlvReader.GetLength() == kPBKDFParamRandomNumberSize, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
557 8 : SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
558 :
559 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionId)));
560 8 : SuccessOrExit(err = tlvReader.Get(responderSessionId));
561 :
562 8 : ChipLogDetail(SecureChannel, "Peer assigned session ID %d", responderSessionId);
563 8 : SetPeerSessionId(responderSessionId);
564 :
565 8 : if (mHavePBKDFParameters)
566 : {
567 0 : err = ReadSessionParamsIfPresent(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionParams), tlvReader);
568 :
569 : // Future-proofing: CHIP_NO_ERROR will be returned by Next() within ReadSessionParamsIfPresent() if we have additional
570 : // non-parsed TLV Elements, which could happen in the future if additional elements are added to the specification.
571 0 : VerifyOrExit(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, /* No Action */);
572 :
573 : // TODO - Add a unit test that exercises mHavePBKDFParameters path
574 0 : salt = ByteSpan(mSalt, mSaltLength);
575 : }
576 : else
577 : {
578 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kPbkdfParameters)));
579 8 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
580 :
581 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParameterSetTags::kIterations)));
582 8 : SuccessOrExit(err = tlvReader.Get(mIterationCount));
583 :
584 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParameterSetTags::kSalt)));
585 8 : VerifyOrExit(tlvReader.GetLength() >= kSpake2p_Min_PBKDF_Salt_Length &&
586 : tlvReader.GetLength() <= kSpake2p_Max_PBKDF_Salt_Length,
587 : err = CHIP_ERROR_INVALID_TLV_ELEMENT);
588 8 : SuccessOrExit(err = tlvReader.Get(salt));
589 :
590 8 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
591 :
592 8 : err = ReadSessionParamsIfPresent(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionParams), tlvReader);
593 :
594 : // Future-proofing: CHIP_NO_ERROR will be returned by Next() within ReadSessionParamsIfPresent() if we have additional
595 : // non-parsed TLV Elements, which could happen in the future if additional elements are added to the specification.
596 16 : VerifyOrExit(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, /* No Action */);
597 : }
598 :
599 : // ExitContainer() acts as a safeguard to ensure that the received encoded message is properly terminated with an EndOfContainer
600 : // TLV element. It is called as an extra validation step to enforce input data structure integrity. Without it, the message may
601 : // still parse correctly, but malformed or incomplete data might go undetected.
602 : // ExitContainer() will return CHIP_END_OF_TLV if the EndOfContainer TLV element terminator is missing.
603 8 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
604 :
605 8 : err = SetupSpake2p();
606 8 : SuccessOrExit(err);
607 :
608 8 : err = Spake2pVerifier::ComputeWS(mIterationCount, salt, mSetupPINCode, serializedWS.Bytes(), serializedWS.Capacity());
609 8 : SuccessOrExit(err);
610 :
611 8 : err = mSpake2p.BeginProver(nullptr, 0, nullptr, 0, serializedWS.Bytes(), kSpake2p_WS_Length,
612 8 : serializedWS.Bytes() + kSpake2p_WS_Length, kSpake2p_WS_Length);
613 8 : SuccessOrExit(err);
614 :
615 8 : err = SendMsg1();
616 8 : SuccessOrExit(err);
617 :
618 8 : exit:
619 16 : if (err != CHIP_NO_ERROR)
620 : {
621 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
622 : }
623 16 : return err;
624 8 : }
625 :
626 8 : CHIP_ERROR PASESession::SendMsg1()
627 : {
628 : MATTER_TRACE_SCOPE("SendMsg1", "PASESession");
629 8 : const size_t max_msg_len = TLV::EstimateStructOverhead(kMAX_Point_Length);
630 8 : System::PacketBufferHandle msg = System::PacketBufferHandle::New(max_msg_len);
631 8 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY);
632 :
633 8 : System::PacketBufferTLVWriter tlvWriter;
634 8 : tlvWriter.Init(std::move(msg));
635 :
636 8 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
637 8 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
638 :
639 : uint8_t X[kMAX_Point_Length];
640 8 : size_t X_len = sizeof(X);
641 :
642 8 : ReturnErrorOnFailure(mSpake2p.ComputeRoundOne(nullptr, 0, X, &X_len));
643 8 : VerifyOrReturnError(X_len == sizeof(X), CHIP_ERROR_INTERNAL);
644 8 : ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Pake1Tags::kPa), ByteSpan(X)));
645 8 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
646 8 : ReturnErrorOnFailure(tlvWriter.Finalize(&msg));
647 :
648 8 : ReturnErrorOnFailure(
649 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake1, std::move(msg), SendFlags(SendMessageFlags::kExpectResponse)));
650 8 : ChipLogDetail(SecureChannel, "Sent spake2p msg1");
651 :
652 8 : mNextExpectedMsg.SetValue(MsgType::PASE_Pake2);
653 :
654 8 : return CHIP_NO_ERROR;
655 8 : }
656 :
657 8 : CHIP_ERROR PASESession::HandleMsg1_and_SendMsg2(System::PacketBufferHandle && msg1)
658 : {
659 : MATTER_TRACE_SCOPE("HandleMsg1_and_SendMsg2", "PASESession");
660 8 : CHIP_ERROR err = CHIP_NO_ERROR;
661 :
662 : uint8_t Y[kMAX_Point_Length];
663 8 : size_t Y_len = sizeof(Y);
664 :
665 : SensitiveDataFixedBuffer<kMAX_Hash_Length> verifier;
666 8 : size_t verifier_len = kMAX_Hash_Length;
667 :
668 8 : ChipLogDetail(SecureChannel, "Received spake2p msg1");
669 : MATTER_TRACE_SCOPE("Pake1", "PASESession");
670 :
671 8 : System::PacketBufferTLVReader tlvReader;
672 8 : TLV::TLVType containerType = TLV::kTLVType_Structure;
673 :
674 : const uint8_t * X;
675 8 : size_t X_len = 0;
676 :
677 8 : tlvReader.Init(std::move(msg1));
678 8 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
679 8 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
680 :
681 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake1Tags::kPa)));
682 8 : X_len = tlvReader.GetLength();
683 8 : VerifyOrExit(X_len == kMAX_Point_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
684 8 : SuccessOrExit(err = tlvReader.GetDataPtr(X));
685 :
686 8 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
687 :
688 8 : SuccessOrExit(err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kP256_FE_Length, mPASEVerifier.mL,
689 : kP256_Point_Length));
690 :
691 8 : SuccessOrExit(err = mSpake2p.ComputeRoundOne(X, X_len, Y, &Y_len));
692 8 : VerifyOrReturnError(Y_len == sizeof(Y), CHIP_ERROR_INTERNAL);
693 8 : SuccessOrExit(err = mSpake2p.ComputeRoundTwo(X, X_len, verifier.Bytes(), &verifier_len));
694 8 : msg1 = nullptr;
695 :
696 : {
697 8 : const size_t max_msg_len = TLV::EstimateStructOverhead(Y_len, verifier_len);
698 :
699 8 : System::PacketBufferHandle msg2 = System::PacketBufferHandle::New(max_msg_len);
700 8 : VerifyOrExit(!msg2.IsNull(), err = CHIP_ERROR_NO_MEMORY);
701 :
702 8 : System::PacketBufferTLVWriter tlvWriter;
703 8 : tlvWriter.Init(std::move(msg2));
704 :
705 8 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
706 8 : SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
707 8 : SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake2Tags::kPb), ByteSpan(Y)));
708 8 : SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake2Tags::kCb), ByteSpan(verifier.Bytes(), verifier_len)));
709 8 : SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
710 8 : SuccessOrExit(err = tlvWriter.Finalize(&msg2));
711 :
712 : err =
713 8 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake2, std::move(msg2), SendFlags(SendMessageFlags::kExpectResponse));
714 8 : SuccessOrExit(err);
715 :
716 8 : mNextExpectedMsg.SetValue(MsgType::PASE_Pake3);
717 8 : }
718 :
719 8 : ChipLogDetail(SecureChannel, "Sent spake2p msg2");
720 : MATTER_TRACE_COUNTER("Pake2");
721 :
722 8 : exit:
723 :
724 16 : if (err != CHIP_NO_ERROR)
725 : {
726 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
727 : }
728 8 : return err;
729 8 : }
730 :
731 8 : CHIP_ERROR PASESession::HandleMsg2_and_SendMsg3(System::PacketBufferHandle && msg2)
732 : {
733 : MATTER_TRACE_SCOPE("HandleMsg2_and_SendMsg3", "PASESession");
734 8 : CHIP_ERROR err = CHIP_NO_ERROR;
735 :
736 : SensitiveDataFixedBuffer<kMAX_Hash_Length> verifier;
737 8 : size_t verifier_len = kMAX_Hash_Length;
738 :
739 8 : System::PacketBufferHandle resp;
740 :
741 8 : ChipLogDetail(SecureChannel, "Received spake2p msg2");
742 :
743 8 : System::PacketBufferTLVReader tlvReader;
744 8 : TLV::TLVType containerType = TLV::kTLVType_Structure;
745 :
746 : const uint8_t * Y;
747 8 : size_t Y_len = 0;
748 :
749 : const uint8_t * peer_verifier;
750 8 : size_t peer_verifier_len = 0;
751 :
752 8 : tlvReader.Init(std::move(msg2));
753 8 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
754 8 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
755 :
756 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake2Tags::kPb)));
757 8 : Y_len = tlvReader.GetLength();
758 8 : VerifyOrExit(Y_len == kMAX_Point_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
759 8 : SuccessOrExit(err = tlvReader.GetDataPtr(Y));
760 :
761 8 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake2Tags::kCb)));
762 8 : peer_verifier_len = tlvReader.GetLength();
763 8 : VerifyOrExit(peer_verifier_len == kMAX_Hash_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
764 8 : SuccessOrExit(err = tlvReader.GetDataPtr(peer_verifier));
765 :
766 : // ExitContainer() acts as a safeguard to ensure that the received encoded message is properly terminated with an EndOfContainer
767 : // TLV element. It is called as an extra validation step to enforce input data structure integrity. Without it, the message may
768 : // still parse correctly, but malformed or incomplete data might go undetected.
769 : // ExitContainer() will return CHIP_END_OF_TLV if the EndOfContainer TLV element terminator is missing.
770 8 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
771 :
772 8 : SuccessOrExit(err = mSpake2p.ComputeRoundTwo(Y, Y_len, verifier.Bytes(), &verifier_len));
773 :
774 8 : SuccessOrExit(err = mSpake2p.KeyConfirm(peer_verifier, peer_verifier_len));
775 7 : msg2 = nullptr;
776 :
777 : {
778 7 : const size_t max_msg_len = TLV::EstimateStructOverhead(verifier_len);
779 :
780 7 : System::PacketBufferHandle msg3 = System::PacketBufferHandle::New(max_msg_len);
781 7 : VerifyOrExit(!msg3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
782 :
783 7 : System::PacketBufferTLVWriter tlvWriter;
784 7 : tlvWriter.Init(std::move(msg3));
785 :
786 7 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
787 7 : SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
788 7 : SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake3Tags::kCa), ByteSpan(verifier.Bytes(), verifier_len)));
789 7 : SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
790 7 : SuccessOrExit(err = tlvWriter.Finalize(&msg3));
791 :
792 : err =
793 7 : mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake3, std::move(msg3), SendFlags(SendMessageFlags::kExpectResponse));
794 7 : SuccessOrExit(err);
795 :
796 7 : mNextExpectedMsg.SetValue(MsgType::StatusReport);
797 7 : }
798 7 : ChipLogDetail(SecureChannel, "Sent spake2p msg3");
799 :
800 7 : exit:
801 16 : if (err != CHIP_NO_ERROR)
802 : {
803 1 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
804 : }
805 16 : return err;
806 8 : }
807 :
808 7 : CHIP_ERROR PASESession::HandleMsg3(System::PacketBufferHandle && msg)
809 : {
810 : MATTER_TRACE_SCOPE("HandleMsg3", "PASESession");
811 7 : CHIP_ERROR err = CHIP_NO_ERROR;
812 :
813 7 : ChipLogDetail(SecureChannel, "Received spake2p msg3");
814 : MATTER_TRACE_COUNTER("Pake3");
815 :
816 7 : mNextExpectedMsg.ClearValue();
817 :
818 7 : System::PacketBufferTLVReader tlvReader;
819 7 : TLV::TLVType containerType = TLV::kTLVType_Structure;
820 :
821 : const uint8_t * peer_verifier;
822 7 : size_t peer_verifier_len = 0;
823 :
824 7 : tlvReader.Init(std::move(msg));
825 7 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
826 7 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
827 :
828 7 : SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake3Tags::kCa)));
829 7 : peer_verifier_len = tlvReader.GetLength();
830 7 : VerifyOrExit(peer_verifier_len == kMAX_Hash_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
831 7 : SuccessOrExit(err = tlvReader.GetDataPtr(peer_verifier));
832 :
833 : // ExitContainer() acts as a safeguard to ensure that the received encoded message is properly terminated with an EndOfContainer
834 : // TLV element. It is called as an extra validation step to enforce input data structure integrity. Without it, the message may
835 : // still parse correctly, but malformed or incomplete data might go undetected.
836 : // ExitContainer() will return CHIP_END_OF_TLV if the EndOfContainer TLV element terminator is missing.
837 7 : SuccessOrExit(err = tlvReader.ExitContainer(containerType));
838 :
839 7 : SuccessOrExit(err = mSpake2p.KeyConfirm(peer_verifier, peer_verifier_len));
840 :
841 : // Send confirmation to peer that we succeeded so they can start using the session.
842 7 : SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
843 :
844 7 : Finish();
845 7 : exit:
846 :
847 14 : if (err != CHIP_NO_ERROR)
848 : {
849 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
850 : }
851 14 : return err;
852 7 : }
853 :
854 7 : void PASESession::OnSuccessStatusReport()
855 : {
856 7 : Finish();
857 7 : }
858 :
859 1 : CHIP_ERROR PASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
860 : Optional<uintptr_t> protocolData)
861 : {
862 1 : CHIP_ERROR err = CHIP_NO_ERROR;
863 1 : switch (protocolCode)
864 : {
865 1 : case kProtocolCodeInvalidParam:
866 1 : err = CHIP_ERROR_INVALID_PASE_PARAMETER;
867 1 : break;
868 :
869 0 : case kProtocolCodeNoSharedRoot:
870 : // kProtocolCodeNoSharedRoot only has a defined meaning in CASE (where it indicates
871 : // the responder lacks a trusted root for the initiator's fabric). PASE has no
872 : // shared-root semantics, so a peer sending this status during PASE is misconfigured.
873 : // Mapping it to CHIP_ERROR_NO_SHARED_TRUSTED_ROOT is more useful for diagnostics
874 : // than collapsing to CHIP_ERROR_INTERNAL.
875 0 : err = CHIP_ERROR_NO_SHARED_TRUSTED_ROOT;
876 0 : break;
877 :
878 0 : case kProtocolCodeBusy:
879 : // Spec doesn't explicitly forbid a peer returning kProtocolCodeBusy during PASE,
880 : // even though it's not commonly seen. Distinguishing "device temporarily busy" from
881 : // generic INTERNAL helps callers decide whether to retry.
882 0 : err = CHIP_ERROR_BUSY;
883 0 : break;
884 :
885 0 : default:
886 0 : err = CHIP_ERROR_INTERNAL;
887 0 : break;
888 : };
889 1 : ChipLogError(SecureChannel, "Received error (protocol code %d) during PASE process: %" CHIP_ERROR_FORMAT, protocolCode,
890 : err.Format());
891 1 : return err;
892 : }
893 :
894 47 : CHIP_ERROR PASESession::ValidateReceivedMessage(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
895 : const System::PacketBufferHandle & msg)
896 : {
897 47 : VerifyOrReturnError(exchange != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
898 :
899 : // mExchangeCtxt can be nullptr if this is the first message (PBKDFParamRequest) received by PASESession
900 : // via UnsolicitedMessageHandler. The exchange context is allocated by exchange manager and provided
901 : // to the handler (PASESession object).
902 47 : if (mExchangeCtxt.HasValue())
903 : {
904 39 : if (&mExchangeCtxt.Value().Get() != exchange)
905 : {
906 0 : ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
907 : }
908 : }
909 : else
910 : {
911 8 : mExchangeCtxt.Emplace(*exchange);
912 : }
913 :
914 47 : if (!mExchangeCtxt.Value()->GetSessionHandle()->IsUnauthenticatedSession())
915 : {
916 0 : ChipLogError(SecureChannel, "PASESession received PBKDFParamRequest over encrypted session. Ignoring.");
917 0 : return CHIP_ERROR_INCORRECT_STATE;
918 : }
919 :
920 47 : ReturnErrorOnFailure(mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedHighProcessingTime));
921 :
922 47 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
923 47 : VerifyOrReturnError((mNextExpectedMsg.HasValue() && payloadHeader.HasMessageType(mNextExpectedMsg.Value())) ||
924 : payloadHeader.HasMessageType(MsgType::StatusReport),
925 : CHIP_ERROR_INVALID_MESSAGE_TYPE);
926 :
927 47 : return CHIP_NO_ERROR;
928 : }
929 :
930 6 : CHIP_ERROR PASESession::OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate)
931 : {
932 : // Handle messages by myself
933 6 : newDelegate = this;
934 6 : return CHIP_NO_ERROR;
935 : }
936 :
937 47 : CHIP_ERROR PASESession::OnMessageReceived(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
938 : System::PacketBufferHandle && msg)
939 : {
940 : MATTER_TRACE_SCOPE("OnMessageReceived", "PASESession");
941 47 : CHIP_ERROR err = ValidateReceivedMessage(exchange, payloadHeader, msg);
942 47 : MsgType msgType = static_cast<MsgType>(payloadHeader.GetMessageType());
943 47 : SuccessOrExit(err);
944 :
945 : #if CHIP_CONFIG_SLOW_CRYPTO
946 : if (msgType == MsgType::PBKDFParamRequest || msgType == MsgType::PBKDFParamResponse || msgType == MsgType::PASE_Pake1 ||
947 : msgType == MsgType::PASE_Pake2 || msgType == MsgType::PASE_Pake3)
948 : {
949 : SuccessOrExit(err = mExchangeCtxt.Value()->FlushAcks());
950 : }
951 : #endif // CHIP_CONFIG_SLOW_CRYPTO
952 :
953 47 : switch (msgType)
954 : {
955 8 : case MsgType::PBKDFParamRequest:
956 8 : err = HandlePBKDFParamRequest(std::move(msg));
957 8 : break;
958 :
959 8 : case MsgType::PBKDFParamResponse:
960 8 : err = HandlePBKDFParamResponse(std::move(msg));
961 8 : break;
962 :
963 8 : case MsgType::PASE_Pake1:
964 8 : err = HandleMsg1_and_SendMsg2(std::move(msg));
965 8 : break;
966 :
967 8 : case MsgType::PASE_Pake2:
968 8 : err = HandleMsg2_and_SendMsg3(std::move(msg));
969 8 : break;
970 :
971 7 : case MsgType::PASE_Pake3:
972 7 : err = HandleMsg3(std::move(msg));
973 7 : break;
974 :
975 8 : case MsgType::StatusReport:
976 : err =
977 8 : HandleStatusReport(std::move(msg), mNextExpectedMsg.HasValue() && (mNextExpectedMsg.Value() == MsgType::StatusReport));
978 8 : break;
979 :
980 0 : default:
981 0 : err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
982 0 : break;
983 : };
984 :
985 47 : exit:
986 :
987 : // Call delegate to indicate pairing failure
988 94 : if (err != CHIP_NO_ERROR)
989 : {
990 : // Discard the exchange so that Clear() doesn't try closing it. The
991 : // exchange will handle that.
992 2 : DiscardExchange();
993 2 : Clear();
994 2 : ChipLogError(SecureChannel, "Failed during PASE session setup: %" CHIP_ERROR_FORMAT, err.Format());
995 : MATTER_TRACE_COUNTER("PASEFail");
996 : // Do this last in case the delegate frees us.
997 2 : NotifySessionEstablishmentError(err);
998 : }
999 47 : return err;
1000 : }
1001 :
1002 : } // namespace chip
|