Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - PASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 93.3 % 448 418
Test Date: 2025-02-22 08:08:07 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          200 : constexpr chip::TLV::Tag AsTlvContextTag(Enum e)
      95              : {
      96          200 :     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           16 : PASESession::~PASESession()
     119              : {
     120              :     // Let's clear out any security state stored in the object, before destroying it.
     121           16 :     Clear();
     122           16 : }
     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           10 : void PASESession::Finish()
     132              : {
     133           10 :     mPairingComplete = true;
     134           10 :     PairingSession::Finish();
     135           10 : }
     136              : 
     137           61 : 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           61 :     memset(&mPASEVerifier, 0, sizeof(mPASEVerifier));
     143           61 :     mNextExpectedMsg.ClearValue();
     144              : 
     145           61 :     mSpake2p.Clear();
     146           61 :     mCommissioningHash.Clear();
     147              : 
     148           61 :     mIterationCount = 0;
     149           61 :     mSaltLength     = 0;
     150           61 :     if (mSalt != nullptr)
     151              :     {
     152           13 :         chip::Platform::MemoryFree(mSalt);
     153           13 :         mSalt = nullptr;
     154              :     }
     155           61 :     mPairingComplete = false;
     156           61 :     PairingSession::Clear();
     157           61 : }
     158              : 
     159           21 : CHIP_ERROR PASESession::Init(SessionManager & sessionManager, uint32_t setupCode, SessionEstablishmentDelegate * delegate)
     160              : {
     161              :     MATTER_TRACE_SCOPE("Init", "PASESession");
     162           21 :     VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     163           21 :     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           21 :     Clear();
     167              : 
     168           21 :     ReturnErrorOnFailure(mCommissioningHash.Begin());
     169           21 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ Uint8::from_const_char(kSpake2pContext), strlen(kSpake2pContext) }));
     170              : 
     171           21 :     mDelegate = delegate;
     172           21 :     ReturnErrorOnFailure(AllocateSecureSession(sessionManager));
     173           21 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
     174           21 :     ChipLogDetail(SecureChannel, "Assigned local session key ID %u", GetLocalSessionId().Value());
     175              : 
     176           21 :     VerifyOrReturnError(setupCode < (1 << kSetupPINCodeFieldLengthInBits), CHIP_ERROR_INVALID_ARGUMENT);
     177           21 :     mSetupPINCode = setupCode;
     178              : 
     179           21 :     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           12 : CHIP_ERROR PASESession::SetupSpake2p()
     196              : {
     197              :     MATTER_TRACE_SCOPE("SetupSpake2p", "PASESession");
     198           12 :     uint8_t context[kSHA256_Hash_Length] = { 0 };
     199           12 :     MutableByteSpan contextSpan{ context };
     200              : 
     201           12 :     ReturnErrorOnFailure(mCommissioningHash.Finish(contextSpan));
     202           12 :     ReturnErrorOnFailure(mSpake2p.Init(contextSpan.data(), contextSpan.size()));
     203              : 
     204           12 :     return CHIP_NO_ERROR;
     205              : }
     206              : 
     207           16 : 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           16 :     VerifyOrReturnError(!salt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
     213           15 :     VerifyOrReturnError(salt.data() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     214           15 :     VerifyOrReturnError(salt.size() >= kSpake2p_Min_PBKDF_Salt_Length && salt.size() <= kSpake2p_Max_PBKDF_Salt_Length,
     215              :                         CHIP_ERROR_INVALID_ARGUMENT);
     216              : 
     217           13 :     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           13 :     SuccessOrExit(err);
     221              : 
     222           13 :     mRole = CryptoContext::SessionRole::kResponder;
     223              : 
     224           13 :     VerifyOrExit(CanCastTo<uint16_t>(salt.size()), err = CHIP_ERROR_INVALID_ARGUMENT);
     225           13 :     mSaltLength = static_cast<uint16_t>(salt.size());
     226              : 
     227           13 :     if (mSalt != nullptr)
     228              :     {
     229            0 :         chip::Platform::MemoryFree(mSalt);
     230            0 :         mSalt = nullptr;
     231              :     }
     232              : 
     233           13 :     mSalt = static_cast<uint8_t *>(chip::Platform::MemoryAlloc(mSaltLength));
     234           13 :     VerifyOrExit(mSalt != nullptr, err = CHIP_ERROR_NO_MEMORY);
     235              : 
     236           13 :     memmove(mSalt, salt.data(), mSaltLength);
     237           13 :     memmove(&mPASEVerifier, &verifier, sizeof(verifier));
     238              : 
     239           13 :     mIterationCount = pbkdf2IterCount;
     240           13 :     mNextExpectedMsg.SetValue(MsgType::PBKDFParamRequest);
     241           13 :     mPairingComplete = false;
     242           13 :     mLocalMRPConfig  = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
     243              : 
     244           13 :     ChipLogDetail(SecureChannel, "Waiting for PBKDF param request");
     245              : 
     246            0 : exit:
     247           13 :     if (err != CHIP_NO_ERROR)
     248              :     {
     249            0 :         Clear();
     250              :     }
     251           13 :     return err;
     252              : }
     253              : 
     254            9 : 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            9 :     VerifyOrReturnError(exchangeCtxt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     260            8 :     CHIP_ERROR err = Init(sessionManager, peerSetUpPINCode, delegate);
     261            8 :     SuccessOrExit(err);
     262              : 
     263            8 :     mRole = CryptoContext::SessionRole::kInitiator;
     264              : 
     265            8 :     mExchangeCtxt.Emplace(*exchangeCtxt);
     266              : 
     267              :     // When commissioning starts, the peer is assumed to be active.
     268            8 :     mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->MarkActiveRx();
     269              : 
     270            8 :     mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedLowProcessingTime);
     271              : 
     272            8 :     mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
     273              : 
     274            8 :     err = SendPBKDFParamRequest();
     275            8 :     SuccessOrExit(err);
     276              : 
     277            7 :     mDelegate->OnSessionEstablishmentStarted();
     278              : 
     279            8 : exit:
     280            8 :     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            8 :     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           10 : CHIP_ERROR PASESession::DeriveSecureSession(CryptoContext & session)
     314              : {
     315           10 :     VerifyOrReturnError(mPairingComplete, CHIP_ERROR_INCORRECT_STATE);
     316              : 
     317           10 :     SessionKeystore & keystore = *mSessionManager->GetSessionKeystore();
     318           10 :     AutoReleaseSymmetricKey<HkdfKeyHandle> hkdfKey(keystore);
     319              : 
     320           10 :     ReturnErrorOnFailure(mSpake2p.GetKeys(keystore, hkdfKey.KeyHandle()));
     321           10 :     ReturnErrorOnFailure(session.InitFromSecret(keystore, hkdfKey.KeyHandle(), ByteSpan{} /* salt */,
     322              :                                                 CryptoContext::SessionInfoType::kSessionEstablishment, mRole));
     323              : 
     324           10 :     return CHIP_NO_ERROR;
     325           10 : }
     326              : 
     327           12 : CHIP_ERROR PASESession::ReadSessionParamsIfPresent(const TLV::Tag & expectedSessionParamsTag,
     328              :                                                    System::PacketBufferTLVReader & tlvReader)
     329              : {
     330           12 :     CHIP_ERROR err = CHIP_NO_ERROR;
     331              : 
     332           12 :     err = tlvReader.Next();
     333           12 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == expectedSessionParamsTag)
     334              :     {
     335           12 :         ReturnErrorOnFailure(DecodeSessionParametersIfPresent(expectedSessionParamsTag, tlvReader, mRemoteSessionParams));
     336           12 :         mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
     337              :             GetRemoteSessionParameters());
     338              : 
     339           12 :         err = tlvReader.Next();
     340              :     }
     341           12 :     return err;
     342              : }
     343              : 
     344            8 : CHIP_ERROR PASESession::SendPBKDFParamRequest()
     345              : {
     346              :     MATTER_TRACE_SCOPE("SendPBKDFParamRequest", "PASESession");
     347              : 
     348            8 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
     349              : 
     350            8 :     ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
     351              : 
     352            8 :     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            8 :     System::PacketBufferHandle req = System::PacketBufferHandle::New(max_msg_len);
     360            8 :     VerifyOrReturnError(!req.IsNull(), CHIP_ERROR_NO_MEMORY);
     361              : 
     362            8 :     System::PacketBufferTLVWriter tlvWriter;
     363            8 :     tlvWriter.Init(std::move(req));
     364              : 
     365            8 :     TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     366            8 :     ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     367            8 :     ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(PBKDFParamRequestTags::kInitiatorRandom), mPBKDFLocalRandomData,
     368              :                                             sizeof(mPBKDFLocalRandomData)));
     369            8 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(PBKDFParamRequestTags::kInitiatorSessionId), GetLocalSessionId().Value()));
     370            8 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(PBKDFParamRequestTags::kPasscodeId), kDefaultCommissioningPasscodeId));
     371            8 :     ReturnErrorOnFailure(tlvWriter.PutBoolean(AsTlvContextTag(PBKDFParamRequestTags::kHasPBKDFParameters), mHavePBKDFParameters));
     372              : 
     373            8 :     VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
     374              : 
     375            8 :     ReturnErrorOnFailure(EncodeSessionParameters(AsTlvContextTag(PBKDFParamRequestTags::kInitiatorSessionParams),
     376              :                                                  mLocalMRPConfig.Value(), tlvWriter));
     377              : 
     378            8 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     379            8 :     ReturnErrorOnFailure(tlvWriter.Finalize(&req));
     380              : 
     381              :     // Update commissioning hash with the pbkdf2 param request that's being sent.
     382            8 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ req->Start(), req->DataLength() }));
     383              : 
     384            8 :     ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(MsgType::PBKDFParamRequest, std::move(req),
     385              :                                                             SendFlags(SendMessageFlags::kExpectResponse)));
     386              : 
     387            7 :     mNextExpectedMsg.SetValue(MsgType::PBKDFParamResponse);
     388              : 
     389              : #if CHIP_PROGRESS_LOGGING
     390            7 :     const auto localMRPConfig = mLocalMRPConfig.Value();
     391              : #endif // CHIP_PROGRESS_LOGGING
     392            7 :     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            7 :     return CHIP_NO_ERROR;
     397            8 : }
     398              : 
     399            6 : CHIP_ERROR PASESession::HandlePBKDFParamRequest(System::PacketBufferHandle && msg)
     400              : {
     401              :     MATTER_TRACE_SCOPE("HandlePBKDFParamRequest", "PASESession");
     402            6 :     CHIP_ERROR err = CHIP_NO_ERROR;
     403              : 
     404            6 :     System::PacketBufferTLVReader tlvReader;
     405            6 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     406              : 
     407              :     uint16_t initiatorSessionId;
     408              :     uint8_t initiatorRandom[kPBKDFParamRandomNumberSize];
     409              : 
     410            6 :     PasscodeId passcodeId   = kDefaultCommissioningPasscodeId;
     411            6 :     bool hasPBKDFParameters = false;
     412              : 
     413            6 :     ChipLogDetail(SecureChannel, "Received PBKDF param request");
     414              : 
     415            6 :     SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
     416              : 
     417            6 :     tlvReader.Init(std::move(msg));
     418            6 :     SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
     419            6 :     SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     420              : 
     421            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamRequestTags::kInitiatorRandom)));
     422            6 :     VerifyOrExit(tlvReader.GetLength() == kPBKDFParamRandomNumberSize, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     423            6 :     SuccessOrExit(err = tlvReader.GetBytes(initiatorRandom, sizeof(initiatorRandom)));
     424              : 
     425            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamRequestTags::kInitiatorSessionId)));
     426            6 :     SuccessOrExit(err = tlvReader.Get(initiatorSessionId));
     427              : 
     428            6 :     ChipLogDetail(SecureChannel, "Peer assigned session ID %d", initiatorSessionId);
     429            6 :     SetPeerSessionId(initiatorSessionId);
     430              : 
     431            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamRequestTags::kPasscodeId)));
     432            6 :     SuccessOrExit(err = tlvReader.Get(passcodeId));
     433            6 :     VerifyOrExit(passcodeId == kDefaultCommissioningPasscodeId, err = CHIP_ERROR_INVALID_PASE_PARAMETER);
     434              : 
     435            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamRequestTags::kHasPBKDFParameters)));
     436            6 :     SuccessOrExit(err = tlvReader.Get(hasPBKDFParameters));
     437              : 
     438            6 :     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            6 :     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            6 :     SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     449              : 
     450            6 :     err = SendPBKDFParamResponse(ByteSpan(initiatorRandom), hasPBKDFParameters);
     451            6 :     SuccessOrExit(err);
     452              : 
     453            6 :     mDelegate->OnSessionEstablishmentStarted();
     454              : 
     455            6 : exit:
     456              : 
     457            6 :     if (err != CHIP_NO_ERROR)
     458              :     {
     459            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     460              :     }
     461            6 :     return err;
     462            6 : }
     463              : 
     464            6 : CHIP_ERROR PASESession::SendPBKDFParamResponse(ByteSpan initiatorRandom, bool initiatorHasPBKDFParams)
     465              : {
     466              :     MATTER_TRACE_SCOPE("SendPBKDFParamResponse", "PASESession");
     467              : 
     468            6 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
     469              : 
     470            6 :     ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData)));
     471              : 
     472              :     const size_t max_msg_len =
     473            6 :         TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize,                                // initiatorRandom
     474              :                                     kPBKDFParamRandomNumberSize,                                // responderRandom
     475              :                                     sizeof(uint16_t),                                           // responderSessionId
     476            6 :                                     TLV::EstimateStructOverhead(sizeof(uint32_t), mSaltLength), // pbkdf_parameters
     477              :                                     SessionParameters::kEstimatedTLVSize                        // Session Parameters
     478              :         );
     479              : 
     480            6 :     System::PacketBufferHandle resp = System::PacketBufferHandle::New(max_msg_len);
     481            6 :     VerifyOrReturnError(!resp.IsNull(), CHIP_ERROR_NO_MEMORY);
     482              : 
     483            6 :     System::PacketBufferTLVWriter tlvWriter;
     484            6 :     tlvWriter.Init(std::move(resp));
     485              : 
     486            6 :     TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     487            6 :     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            6 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(PBKDFParamResponseTags::kInitiatorRandom), initiatorRandom));
     490            6 :     ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(PBKDFParamResponseTags::kResponderRandom), mPBKDFLocalRandomData,
     491              :                                             sizeof(mPBKDFLocalRandomData)));
     492            6 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionId), GetLocalSessionId().Value()));
     493              : 
     494            6 :     if (!initiatorHasPBKDFParams)
     495              :     {
     496              :         TLV::TLVType pbkdfParamContainer;
     497            6 :         ReturnErrorOnFailure(tlvWriter.StartContainer(AsTlvContextTag(PBKDFParamResponseTags::kPbkdfParameters),
     498              :                                                       TLV::kTLVType_Structure, pbkdfParamContainer));
     499            6 :         ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(PBKDFParameterSetTags::kIterations), mIterationCount));
     500            6 :         ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(PBKDFParameterSetTags::kSalt), mSalt, mSaltLength));
     501            6 :         ReturnErrorOnFailure(tlvWriter.EndContainer(pbkdfParamContainer));
     502              :     }
     503              : 
     504            6 :     VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
     505            6 :     ReturnErrorOnFailure(EncodeSessionParameters(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionParams),
     506              :                                                  mLocalMRPConfig.Value(), tlvWriter));
     507              : 
     508            6 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     509            6 :     ReturnErrorOnFailure(tlvWriter.Finalize(&resp));
     510              : 
     511              :     // Update commissioning hash with the pbkdf2 param response that's being sent.
     512            6 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ resp->Start(), resp->DataLength() }));
     513            6 :     ReturnErrorOnFailure(SetupSpake2p());
     514              : 
     515            6 :     ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(MsgType::PBKDFParamResponse, std::move(resp),
     516              :                                                             SendFlags(SendMessageFlags::kExpectResponse)));
     517            6 :     ChipLogDetail(SecureChannel, "Sent PBKDF param response");
     518              : 
     519            6 :     mNextExpectedMsg.SetValue(MsgType::PASE_Pake1);
     520              : 
     521            6 :     return CHIP_NO_ERROR;
     522            6 : }
     523              : 
     524            6 : CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && msg)
     525              : {
     526              :     MATTER_TRACE_SCOPE("HandlePBKDFParamResponse", "PASESession");
     527            6 :     CHIP_ERROR err = CHIP_NO_ERROR;
     528              : 
     529            6 :     System::PacketBufferTLVReader tlvReader;
     530            6 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     531              : 
     532              :     uint16_t responderSessionId;
     533              :     uint8_t random[kPBKDFParamRandomNumberSize];
     534              : 
     535            6 :     ByteSpan salt;
     536            6 :     uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 };
     537              : 
     538            6 :     ChipLogDetail(SecureChannel, "Received PBKDF param response");
     539              : 
     540            6 :     SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
     541              : 
     542            6 :     tlvReader.Init(std::move(msg));
     543            6 :     SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
     544            6 :     SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     545              : 
     546              :     // Initiator's random value
     547            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kInitiatorRandom)));
     548            6 :     SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
     549            6 :     VerifyOrExit(ByteSpan(random).data_equal(ByteSpan(mPBKDFLocalRandomData)), err = CHIP_ERROR_INVALID_PASE_PARAMETER);
     550              : 
     551              :     // Responder's random value
     552            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kResponderRandom)));
     553            6 :     VerifyOrExit(tlvReader.GetLength() == kPBKDFParamRandomNumberSize, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     554            6 :     SuccessOrExit(err = tlvReader.GetBytes(random, sizeof(random)));
     555              : 
     556            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kResponderSessionId)));
     557            6 :     SuccessOrExit(err = tlvReader.Get(responderSessionId));
     558              : 
     559            6 :     ChipLogDetail(SecureChannel, "Peer assigned session ID %d", responderSessionId);
     560            6 :     SetPeerSessionId(responderSessionId);
     561              : 
     562            6 :     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            6 :         SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParamResponseTags::kPbkdfParameters)));
     576            6 :         SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     577              : 
     578            6 :         SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParameterSetTags::kIterations)));
     579            6 :         SuccessOrExit(err = tlvReader.Get(mIterationCount));
     580              : 
     581            6 :         SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(PBKDFParameterSetTags::kSalt)));
     582            6 :         VerifyOrExit(tlvReader.GetLength() >= kSpake2p_Min_PBKDF_Salt_Length &&
     583              :                          tlvReader.GetLength() <= kSpake2p_Max_PBKDF_Salt_Length,
     584              :                      err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     585            6 :         SuccessOrExit(err = tlvReader.Get(salt));
     586              : 
     587            6 :         SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     588              : 
     589            6 :         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            6 :         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            6 :     SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     601              : 
     602            6 :     err = SetupSpake2p();
     603            6 :     SuccessOrExit(err);
     604              : 
     605            6 :     err = Spake2pVerifier::ComputeWS(mIterationCount, salt, mSetupPINCode, serializedWS, sizeof(serializedWS));
     606            6 :     SuccessOrExit(err);
     607              : 
     608            6 :     err = mSpake2p.BeginProver(nullptr, 0, nullptr, 0, &serializedWS[0], kSpake2p_WS_Length, &serializedWS[kSpake2p_WS_Length],
     609              :                                kSpake2p_WS_Length);
     610            6 :     SuccessOrExit(err);
     611              : 
     612            6 :     err = SendMsg1();
     613            6 :     SuccessOrExit(err);
     614              : 
     615            6 : exit:
     616            6 :     if (err != CHIP_NO_ERROR)
     617              :     {
     618            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     619              :     }
     620            6 :     return err;
     621            6 : }
     622              : 
     623            6 : CHIP_ERROR PASESession::SendMsg1()
     624              : {
     625              :     MATTER_TRACE_SCOPE("SendMsg1", "PASESession");
     626            6 :     const size_t max_msg_len       = TLV::EstimateStructOverhead(kMAX_Point_Length);
     627            6 :     System::PacketBufferHandle msg = System::PacketBufferHandle::New(max_msg_len);
     628            6 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY);
     629              : 
     630            6 :     System::PacketBufferTLVWriter tlvWriter;
     631            6 :     tlvWriter.Init(std::move(msg));
     632              : 
     633            6 :     TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     634            6 :     ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     635              : 
     636              :     uint8_t X[kMAX_Point_Length];
     637            6 :     size_t X_len = sizeof(X);
     638              : 
     639            6 :     ReturnErrorOnFailure(mSpake2p.ComputeRoundOne(nullptr, 0, X, &X_len));
     640            6 :     VerifyOrReturnError(X_len == sizeof(X), CHIP_ERROR_INTERNAL);
     641            6 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Pake1Tags::kPa), ByteSpan(X)));
     642            6 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     643            6 :     ReturnErrorOnFailure(tlvWriter.Finalize(&msg));
     644              : 
     645            6 :     ReturnErrorOnFailure(
     646              :         mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake1, std::move(msg), SendFlags(SendMessageFlags::kExpectResponse)));
     647            6 :     ChipLogDetail(SecureChannel, "Sent spake2p msg1");
     648              : 
     649            6 :     mNextExpectedMsg.SetValue(MsgType::PASE_Pake2);
     650              : 
     651            6 :     return CHIP_NO_ERROR;
     652            6 : }
     653              : 
     654            6 : CHIP_ERROR PASESession::HandleMsg1_and_SendMsg2(System::PacketBufferHandle && msg1)
     655              : {
     656              :     MATTER_TRACE_SCOPE("HandleMsg1_and_SendMsg2", "PASESession");
     657            6 :     CHIP_ERROR err = CHIP_NO_ERROR;
     658              : 
     659              :     uint8_t Y[kMAX_Point_Length];
     660            6 :     size_t Y_len = sizeof(Y);
     661              : 
     662              :     uint8_t verifier[kMAX_Hash_Length];
     663            6 :     size_t verifier_len = kMAX_Hash_Length;
     664              : 
     665            6 :     ChipLogDetail(SecureChannel, "Received spake2p msg1");
     666              :     MATTER_TRACE_SCOPE("Pake1", "PASESession");
     667              : 
     668            6 :     System::PacketBufferTLVReader tlvReader;
     669            6 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     670              : 
     671              :     const uint8_t * X;
     672            6 :     size_t X_len = 0;
     673              : 
     674            6 :     tlvReader.Init(std::move(msg1));
     675            6 :     SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
     676            6 :     SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     677              : 
     678            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake1Tags::kPa)));
     679            6 :     X_len = tlvReader.GetLength();
     680            6 :     VerifyOrExit(X_len == kMAX_Point_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     681            6 :     SuccessOrExit(err = tlvReader.GetDataPtr(X));
     682              : 
     683            6 :     SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     684              : 
     685            6 :     SuccessOrExit(err = mSpake2p.BeginVerifier(nullptr, 0, nullptr, 0, mPASEVerifier.mW0, kP256_FE_Length, mPASEVerifier.mL,
     686              :                                                kP256_Point_Length));
     687              : 
     688            6 :     SuccessOrExit(err = mSpake2p.ComputeRoundOne(X, X_len, Y, &Y_len));
     689            6 :     VerifyOrReturnError(Y_len == sizeof(Y), CHIP_ERROR_INTERNAL);
     690            6 :     SuccessOrExit(err = mSpake2p.ComputeRoundTwo(X, X_len, verifier, &verifier_len));
     691            6 :     msg1 = nullptr;
     692              : 
     693              :     {
     694            6 :         const size_t max_msg_len = TLV::EstimateStructOverhead(Y_len, verifier_len);
     695              : 
     696            6 :         System::PacketBufferHandle msg2 = System::PacketBufferHandle::New(max_msg_len);
     697            6 :         VerifyOrExit(!msg2.IsNull(), err = CHIP_ERROR_NO_MEMORY);
     698              : 
     699            6 :         System::PacketBufferTLVWriter tlvWriter;
     700            6 :         tlvWriter.Init(std::move(msg2));
     701              : 
     702            6 :         TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     703            6 :         SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     704            6 :         SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake2Tags::kPb), ByteSpan(Y)));
     705            6 :         SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake2Tags::kCb), ByteSpan(verifier, verifier_len)));
     706            6 :         SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
     707            6 :         SuccessOrExit(err = tlvWriter.Finalize(&msg2));
     708              : 
     709            6 :         err =
     710            6 :             mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake2, std::move(msg2), SendFlags(SendMessageFlags::kExpectResponse));
     711            6 :         SuccessOrExit(err);
     712              : 
     713            6 :         mNextExpectedMsg.SetValue(MsgType::PASE_Pake3);
     714            6 :     }
     715              : 
     716            6 :     ChipLogDetail(SecureChannel, "Sent spake2p msg2");
     717              :     MATTER_TRACE_COUNTER("Pake2");
     718              : 
     719            0 : exit:
     720              : 
     721            6 :     if (err != CHIP_NO_ERROR)
     722              :     {
     723            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     724              :     }
     725            6 :     return err;
     726            6 : }
     727              : 
     728            6 : CHIP_ERROR PASESession::HandleMsg2_and_SendMsg3(System::PacketBufferHandle && msg2)
     729              : {
     730              :     MATTER_TRACE_SCOPE("HandleMsg2_and_SendMsg3", "PASESession");
     731            6 :     CHIP_ERROR err = CHIP_NO_ERROR;
     732              : 
     733              :     uint8_t verifier[kMAX_Hash_Length];
     734            6 :     size_t verifier_len = kMAX_Hash_Length;
     735              : 
     736            6 :     System::PacketBufferHandle resp;
     737              : 
     738            6 :     ChipLogDetail(SecureChannel, "Received spake2p msg2");
     739              : 
     740            6 :     System::PacketBufferTLVReader tlvReader;
     741            6 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     742              : 
     743              :     const uint8_t * Y;
     744            6 :     size_t Y_len = 0;
     745              : 
     746              :     const uint8_t * peer_verifier;
     747            6 :     size_t peer_verifier_len = 0;
     748              : 
     749            6 :     tlvReader.Init(std::move(msg2));
     750            6 :     SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
     751            6 :     SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     752              : 
     753            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake2Tags::kPb)));
     754            6 :     Y_len = tlvReader.GetLength();
     755            6 :     VerifyOrExit(Y_len == kMAX_Point_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     756            6 :     SuccessOrExit(err = tlvReader.GetDataPtr(Y));
     757              : 
     758            6 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake2Tags::kCb)));
     759            6 :     peer_verifier_len = tlvReader.GetLength();
     760            6 :     VerifyOrExit(peer_verifier_len == kMAX_Hash_Length, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
     761            6 :     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            6 :     SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     768              : 
     769            6 :     SuccessOrExit(err = mSpake2p.ComputeRoundTwo(Y, Y_len, verifier, &verifier_len));
     770              : 
     771            6 :     SuccessOrExit(err = mSpake2p.KeyConfirm(peer_verifier, peer_verifier_len));
     772            5 :     msg2 = nullptr;
     773              : 
     774              :     {
     775            5 :         const size_t max_msg_len = TLV::EstimateStructOverhead(verifier_len);
     776              : 
     777            5 :         System::PacketBufferHandle msg3 = System::PacketBufferHandle::New(max_msg_len);
     778            5 :         VerifyOrExit(!msg3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
     779              : 
     780            5 :         System::PacketBufferTLVWriter tlvWriter;
     781            5 :         tlvWriter.Init(std::move(msg3));
     782              : 
     783            5 :         TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
     784            5 :         SuccessOrExit(err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
     785            5 :         SuccessOrExit(err = tlvWriter.Put(AsTlvContextTag(Pake3Tags::kCa), ByteSpan(verifier, verifier_len)));
     786            5 :         SuccessOrExit(err = tlvWriter.EndContainer(outerContainerType));
     787            5 :         SuccessOrExit(err = tlvWriter.Finalize(&msg3));
     788              : 
     789            5 :         err =
     790            5 :             mExchangeCtxt.Value()->SendMessage(MsgType::PASE_Pake3, std::move(msg3), SendFlags(SendMessageFlags::kExpectResponse));
     791            5 :         SuccessOrExit(err);
     792              : 
     793            5 :         mNextExpectedMsg.SetValue(MsgType::StatusReport);
     794            5 :     }
     795            5 :     ChipLogDetail(SecureChannel, "Sent spake2p msg3");
     796              : 
     797            0 : exit:
     798              : 
     799            6 :     if (err != CHIP_NO_ERROR)
     800              :     {
     801            1 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     802              :     }
     803            6 :     return err;
     804            6 : }
     805              : 
     806            5 : CHIP_ERROR PASESession::HandleMsg3(System::PacketBufferHandle && msg)
     807              : {
     808              :     MATTER_TRACE_SCOPE("HandleMsg3", "PASESession");
     809            5 :     CHIP_ERROR err = CHIP_NO_ERROR;
     810              : 
     811            5 :     ChipLogDetail(SecureChannel, "Received spake2p msg3");
     812              :     MATTER_TRACE_COUNTER("Pake3");
     813              : 
     814            5 :     mNextExpectedMsg.ClearValue();
     815              : 
     816            5 :     System::PacketBufferTLVReader tlvReader;
     817            5 :     TLV::TLVType containerType = TLV::kTLVType_Structure;
     818              : 
     819              :     const uint8_t * peer_verifier;
     820            5 :     size_t peer_verifier_len = 0;
     821              : 
     822            5 :     tlvReader.Init(std::move(msg));
     823            5 :     SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
     824            5 :     SuccessOrExit(err = tlvReader.EnterContainer(containerType));
     825              : 
     826            5 :     SuccessOrExit(err = tlvReader.Next(AsTlvContextTag(Pake3Tags::kCa)));
     827            5 :     peer_verifier_len = tlvReader.GetLength();
     828            5 :     VerifyOrExit(peer_verifier_len == kMAX_Hash_Length, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     829            5 :     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            5 :     SuccessOrExit(err = tlvReader.ExitContainer(containerType));
     836              : 
     837            5 :     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            5 :     SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
     841              : 
     842            5 :     Finish();
     843            5 : exit:
     844              : 
     845            5 :     if (err != CHIP_NO_ERROR)
     846              :     {
     847            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     848              :     }
     849            5 :     return err;
     850            5 : }
     851              : 
     852            5 : void PASESession::OnSuccessStatusReport()
     853              : {
     854            5 :     Finish();
     855            5 : }
     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           35 : CHIP_ERROR PASESession::ValidateReceivedMessage(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
     877              :                                                 const System::PacketBufferHandle & msg)
     878              : {
     879           35 :     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           35 :     if (mExchangeCtxt.HasValue())
     885              :     {
     886           29 :         if (&mExchangeCtxt.Value().Get() != exchange)
     887              :         {
     888            0 :             ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
     889              :         }
     890              :     }
     891              :     else
     892              :     {
     893            6 :         mExchangeCtxt.Emplace(*exchange);
     894              :     }
     895              : 
     896           35 :     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           35 :     mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedHighProcessingTime);
     903              : 
     904           35 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     905           35 :     VerifyOrReturnError((mNextExpectedMsg.HasValue() && payloadHeader.HasMessageType(mNextExpectedMsg.Value())) ||
     906              :                             payloadHeader.HasMessageType(MsgType::StatusReport),
     907              :                         CHIP_ERROR_INVALID_MESSAGE_TYPE);
     908              : 
     909           35 :     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           35 : CHIP_ERROR PASESession::OnMessageReceived(ExchangeContext * exchange, const PayloadHeader & payloadHeader,
     920              :                                           System::PacketBufferHandle && msg)
     921              : {
     922              :     MATTER_TRACE_SCOPE("OnMessageReceived", "PASESession");
     923           35 :     CHIP_ERROR err  = ValidateReceivedMessage(exchange, payloadHeader, msg);
     924           35 :     MsgType msgType = static_cast<MsgType>(payloadHeader.GetMessageType());
     925           35 :     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           35 :     switch (msgType)
     936              :     {
     937            6 :     case MsgType::PBKDFParamRequest:
     938            6 :         err = HandlePBKDFParamRequest(std::move(msg));
     939            6 :         break;
     940              : 
     941            6 :     case MsgType::PBKDFParamResponse:
     942            6 :         err = HandlePBKDFParamResponse(std::move(msg));
     943            6 :         break;
     944              : 
     945            6 :     case MsgType::PASE_Pake1:
     946            6 :         err = HandleMsg1_and_SendMsg2(std::move(msg));
     947            6 :         break;
     948              : 
     949            6 :     case MsgType::PASE_Pake2:
     950            6 :         err = HandleMsg2_and_SendMsg3(std::move(msg));
     951            6 :         break;
     952              : 
     953            5 :     case MsgType::PASE_Pake3:
     954            5 :         err = HandleMsg3(std::move(msg));
     955            5 :         break;
     956              : 
     957            6 :     case MsgType::StatusReport:
     958            6 :         err =
     959            6 :             HandleStatusReport(std::move(msg), mNextExpectedMsg.HasValue() && (mNextExpectedMsg.Value() == MsgType::StatusReport));
     960            6 :         break;
     961              : 
     962            0 :     default:
     963            0 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     964            0 :         break;
     965              :     };
     966              : 
     967           35 : exit:
     968              : 
     969              :     // Call delegate to indicate pairing failure
     970           35 :     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           35 :     return err;
     982              : }
     983              : 
     984              : } // namespace chip
        

Generated by: LCOV version 2.0-1