Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - PASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:704d97f9c619242ad76fcf75aeabc67802fa72d4 Lines: 93.9 % 446 419
Test Date: 2026-05-18 07:37:39 Functions: 93.8 % 32 30

            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
        

Generated by: LCOV version 2.0-1