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

Generated by: LCOV version 2.0-1