Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:3640a4f95bebd68003e5aea27c711ffe4cd39423 Lines: 89.9 % 1174 1056
Test Date: 2025-09-14 07:12:24 Functions: 81.4 % 86 70

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021-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 the CHIP CASE Session object that provides
      22              :  *      APIs for constructing a secure session using a certificate from the device's
      23              :  *      operational credentials.
      24              :  *
      25              :  */
      26              : #include <protocols/secure_channel/CASESession.h>
      27              : 
      28              : #include <atomic>
      29              : #include <inttypes.h>
      30              : #include <memory>
      31              : #include <string.h>
      32              : 
      33              : #include <lib/core/CHIPEncoding.h>
      34              : #include <lib/core/CHIPSafeCasts.h>
      35              : #include <lib/support/CHIPFaultInjection.h>
      36              : #include <lib/support/CHIPMem.h>
      37              : #include <lib/support/CodeUtils.h>
      38              : #include <lib/support/SafeInt.h>
      39              : #include <lib/support/ScopedBuffer.h>
      40              : #include <lib/support/TypeTraits.h>
      41              : #include <messaging/SessionParameters.h>
      42              : #include <platform/PlatformManager.h>
      43              : #include <protocols/Protocols.h>
      44              : #include <protocols/secure_channel/CASEDestinationId.h>
      45              : #include <protocols/secure_channel/PairingSession.h>
      46              : #include <protocols/secure_channel/SessionResumptionStorage.h>
      47              : #include <protocols/secure_channel/StatusReport.h>
      48              : #include <system/SystemClock.h>
      49              : #include <tracing/macros.h>
      50              : #include <tracing/metric_event.h>
      51              : #include <transport/SessionManager.h>
      52              : 
      53              : namespace {
      54              : // TBEDataTags works for both sigma-2-tbedata and sigma-3-tbedata as they have the same tag numbers for the elements common between
      55              : // them.
      56              : enum class TBEDataTags : uint8_t
      57              : {
      58              :     kSenderNOC    = 1,
      59              :     kSenderICAC   = 2,
      60              :     kSignature    = 3,
      61              :     kResumptionID = 4,
      62              : };
      63              : 
      64              : // TBSDataTags works for both sigma-2-tbsdata and sigma-3-tbsdata as they have the same tag numbers for the elements common between
      65              : // them.
      66              : enum class TBSDataTags : uint8_t
      67              : {
      68              :     kSenderNOC      = 1,
      69              :     kSenderICAC     = 2,
      70              :     kSenderPubKey   = 3,
      71              :     kReceiverPubKey = 4,
      72              : };
      73              : 
      74              : enum class Sigma1Tags : uint8_t
      75              : {
      76              :     kInitiatorRandom        = 1,
      77              :     kInitiatorSessionId     = 2,
      78              :     kDestinationId          = 3,
      79              :     kInitiatorEphPubKey     = 4,
      80              :     kInitiatorSessionParams = 5,
      81              :     kResumptionID           = 6,
      82              :     kResume1MIC             = 7,
      83              : };
      84              : 
      85              : enum class Sigma2Tags : uint8_t
      86              : {
      87              :     kResponderRandom        = 1,
      88              :     kResponderSessionId     = 2,
      89              :     kResponderEphPubKey     = 3,
      90              :     kEncrypted2             = 4,
      91              :     kResponderSessionParams = 5,
      92              : };
      93              : 
      94              : enum class Sigma2ResumeTags : uint8_t
      95              : {
      96              :     kResumptionID           = 1,
      97              :     kSigma2ResumeMIC        = 2,
      98              :     kResponderSessionID     = 3,
      99              :     kResponderSessionParams = 4,
     100              : };
     101              : 
     102              : enum class Sigma3Tags : uint8_t
     103              : {
     104              :     kEncrypted3 = 1,
     105              : };
     106              : 
     107              : // Utility to extract the underlying value of TLV Tag enum classes, used in TLV encoding and parsing.
     108              : template <typename Enum>
     109          861 : constexpr chip::TLV::Tag AsTlvContextTag(Enum e)
     110              : {
     111          861 :     return chip::TLV::ContextTag(chip::to_underlying(e));
     112              : }
     113              : 
     114              : constexpr size_t kCaseOverheadForFutureTBEData = 128;
     115              : 
     116              : } // namespace
     117              : 
     118              : namespace chip {
     119              : 
     120              : using namespace Crypto;
     121              : using namespace Credentials;
     122              : using namespace Messaging;
     123              : using namespace Encoding;
     124              : using namespace Protocols::SecureChannel;
     125              : using namespace Tracing;
     126              : using namespace TLV;
     127              : 
     128              : constexpr uint8_t kKDFSR2Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32 };
     129              : constexpr uint8_t kKDFSR3Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33 };
     130              : 
     131              : constexpr uint8_t kKDFS1RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x31, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 };
     132              : constexpr uint8_t kKDFS2RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 };
     133              : 
     134              : constexpr uint8_t kResume1MIC_Nonce[] =
     135              :     /* "NCASE_SigmaS1" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x53, 0x31 };
     136              : constexpr uint8_t kResume2MIC_Nonce[] =
     137              :     /* "NCASE_SigmaS2" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x53, 0x32 };
     138              : constexpr uint8_t kTBEData2_Nonce[] =
     139              :     /* "NCASE_Sigma2N" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32, 0x4e };
     140              : constexpr uint8_t kTBEData3_Nonce[] =
     141              :     /* "NCASE_Sigma3N" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33, 0x4e };
     142              : constexpr size_t kTBEDataNonceLength = sizeof(kTBEData2_Nonce);
     143              : static_assert(sizeof(kTBEData2_Nonce) == sizeof(kTBEData3_Nonce), "TBEData2_Nonce and TBEData3_Nonce must be same size");
     144              : 
     145              : // Amounts of time to allow for server-side processing of messages.
     146              : //
     147              : // These timeout values only allow for the server-side processing and assume that any transport-specific
     148              : // latency will be added to them.
     149              : //
     150              : // The session establishment fails if the response is not received within the resulting timeout window,
     151              : // which accounts for both transport latency and the server-side latency.
     152              : static constexpr ExchangeContext::Timeout kExpectedLowProcessingTime    = System::Clock::Seconds16(2);
     153              : static constexpr ExchangeContext::Timeout kExpectedSigma1ProcessingTime = kExpectedLowProcessingTime;
     154              : static constexpr ExchangeContext::Timeout kExpectedHighProcessingTime   = System::Clock::Seconds16(30);
     155              : 
     156              : // Helper for managing a session's outstanding work.
     157              : // Holds work data which is provided to a scheduled work callback (standalone),
     158              : // then (if not canceled) to a scheduled after work callback (on the session).
     159              : template <class DATA>
     160              : class CASESession::WorkHelper
     161              : {
     162              : public:
     163              :     // Work callback, processed in the background via `PlatformManager::ScheduleBackgroundWork`.
     164              :     // This is a non-member function which does not use the associated session.
     165              :     // The return value is passed to the after work callback (called afterward).
     166              :     // Set `cancel` to true if calling the after work callback is not necessary.
     167              :     typedef CHIP_ERROR (*WorkCallback)(DATA & data, bool & cancel);
     168              : 
     169              :     // After work callback, processed in the main Matter task via `PlatformManager::ScheduleWork`.
     170              :     // This is a member function to be called on the associated session after the work callback.
     171              :     // The `status` value is the result of the work callback (called beforehand), or the status of
     172              :     // queueing the after work callback back to the Matter thread, if the work callback succeeds
     173              :     // but queueing fails.
     174              :     //
     175              :     // When this callback is called asynchronously (i.e. via ScheduleWork), the helper guarantees
     176              :     // that it will keep itself (and hence `data`) alive until the callback completes.
     177              :     typedef CHIP_ERROR (CASESession::*AfterWorkCallback)(DATA & data, CHIP_ERROR status);
     178              : 
     179              : public:
     180              :     // Create a work helper using the specified session, work callback, after work callback, and data (template arg).
     181              :     // Lifetime is managed by sharing between the caller (typically the session) and the helper itself (while work is scheduled).
     182           16 :     static Platform::SharedPtr<WorkHelper> Create(CASESession & session, WorkCallback workCallback,
     183              :                                                   AfterWorkCallback afterWorkCallback)
     184              :     {
     185              :         struct EnableShared : public WorkHelper
     186              :         {
     187           16 :             EnableShared(CASESession & session, WorkCallback workCallback, AfterWorkCallback afterWorkCallback) :
     188           16 :                 WorkHelper(session, workCallback, afterWorkCallback)
     189           16 :             {}
     190              :         };
     191           16 :         auto ptr = Platform::MakeShared<EnableShared>(session, workCallback, afterWorkCallback);
     192           16 :         if (ptr)
     193              :         {
     194           16 :             ptr->mWeakPtr = ptr; // used by `ScheduleWork`
     195              :         }
     196           16 :         return ptr;
     197           16 :     }
     198              : 
     199              :     // Do the work immediately.
     200              :     // No scheduling, no outstanding work, no shared lifetime management.
     201              :     //
     202              :     // The caller must guarantee that it keeps the helper alive across this call, most likely by
     203              :     // holding a reference to it on the stack.
     204            8 :     CHIP_ERROR DoWork()
     205              :     {
     206              :         // Ensure that this function is being called from main Matter thread
     207            8 :         assertChipStackLockedByCurrentThread();
     208              : 
     209            8 :         VerifyOrReturnError(mSession && mWorkCallback && mAfterWorkCallback, CHIP_ERROR_INCORRECT_STATE);
     210            8 :         auto * helper   = this;
     211            8 :         bool cancel     = false;
     212            8 :         helper->mStatus = helper->mWorkCallback(helper->mData, cancel);
     213            8 :         if (!cancel)
     214              :         {
     215            8 :             helper->mStatus = (helper->mSession->*(helper->mAfterWorkCallback))(helper->mData, helper->mStatus);
     216              :         }
     217            8 :         return helper->mStatus;
     218              :     }
     219              : 
     220              :     // Schedule the work for later execution.
     221              :     // If lifetime is managed, the helper shares management while work is outstanding.
     222            8 :     CHIP_ERROR ScheduleWork()
     223              :     {
     224            8 :         VerifyOrReturnError(mSession && mWorkCallback && mAfterWorkCallback, CHIP_ERROR_INCORRECT_STATE);
     225              :         // Hold strong ptr while work is outstanding
     226            8 :         mStrongPtr  = mWeakPtr.lock(); // set in `Create`
     227            8 :         auto status = DeviceLayer::PlatformMgr().ScheduleBackgroundWork(WorkHandler, reinterpret_cast<intptr_t>(this));
     228            8 :         if (status != CHIP_NO_ERROR)
     229              :         {
     230              :             // Release strong ptr since scheduling failed.
     231            0 :             mStrongPtr.reset();
     232              :         }
     233            8 :         return status;
     234              :     }
     235              : 
     236              :     // Cancel the work, by clearing the associated session.
     237            6 :     void CancelWork() { mSession.store(nullptr); }
     238              : 
     239           16 :     bool IsCancelled() const { return mSession.load() == nullptr; }
     240              : 
     241              :     // This API returns true when background thread fails to schedule the AfterWorkCallback
     242            0 :     bool UnableToScheduleAfterWorkCallback() { return mScheduleAfterWorkFailed.load(); }
     243              : 
     244              :     // Do after work immediately.
     245              :     // No scheduling, no outstanding work, no shared lifetime management.
     246            0 :     void DoAfterWork()
     247              :     {
     248            0 :         VerifyOrDie(UnableToScheduleAfterWorkCallback());
     249            0 :         AfterWorkHandler(reinterpret_cast<intptr_t>(this));
     250            0 :     }
     251              : 
     252              : private:
     253              :     // Create a work helper using the specified session, work callback, after work callback, and data (template arg).
     254              :     // Lifetime is not managed, see `Create` for that option.
     255           16 :     WorkHelper(CASESession & session, WorkCallback workCallback, AfterWorkCallback afterWorkCallback) :
     256           16 :         mSession(&session), mWorkCallback(workCallback), mAfterWorkCallback(afterWorkCallback)
     257           16 :     {}
     258              : 
     259              :     // Handler for the work callback.
     260            8 :     static void WorkHandler(intptr_t arg)
     261              :     {
     262            8 :         auto * helper = reinterpret_cast<WorkHelper *>(arg);
     263              :         // Hold strong ptr while work is handled
     264            8 :         auto strongPtr(std::move(helper->mStrongPtr));
     265            8 :         VerifyOrReturn(!helper->IsCancelled());
     266            8 :         bool cancel = false;
     267              :         // Execute callback in background thread; data must be OK with this
     268            8 :         helper->mStatus = helper->mWorkCallback(helper->mData, cancel);
     269            8 :         VerifyOrReturn(!cancel && !helper->IsCancelled());
     270              :         // Hold strong ptr to ourselves while work is outstanding
     271            8 :         helper->mStrongPtr.swap(strongPtr);
     272            8 :         auto status = DeviceLayer::PlatformMgr().ScheduleWork(AfterWorkHandler, reinterpret_cast<intptr_t>(helper));
     273            8 :         if (status != CHIP_NO_ERROR)
     274              :         {
     275            0 :             ChipLogError(SecureChannel, "Failed to Schedule the AfterWorkCallback on foreground thread: %" CHIP_ERROR_FORMAT,
     276              :                          status.Format());
     277              : 
     278              :             // We failed to schedule after work callback, so setting mScheduleAfterWorkFailed flag to true
     279              :             // This can be checked from foreground thread and after work callback can be retried
     280            0 :             helper->mStatus = status;
     281              : 
     282              :             // Release strong ptr to self since scheduling failed, because nothing guarantees
     283              :             // that AfterWorkHandler will get called at this point to release the reference,
     284              :             // and we don't want to leak.  That said, we want to ensure that "helper" stays
     285              :             // alive through the end of this function (so we can set mScheduleAfterWorkFailed
     286              :             // on it), but also want to avoid racing on the single SharedPtr instance in
     287              :             // helper->mStrongPtr.  That means we need to not touch helper->mStrongPtr after
     288              :             // writing to mScheduleAfterWorkFailed.
     289              :             //
     290              :             // The simplest way to do this is to move the reference in helper->mStrongPtr to
     291              :             // our stack, where it outlives all our accesses to "helper".
     292            0 :             strongPtr.swap(helper->mStrongPtr);
     293              : 
     294              :             // helper and any of its state should not be touched after storing mScheduleAfterWorkFailed.
     295            0 :             helper->mScheduleAfterWorkFailed.store(true);
     296              :         }
     297            8 :     }
     298              : 
     299              :     // Handler for the after work callback.
     300            8 :     static void AfterWorkHandler(intptr_t arg)
     301              :     {
     302              :         // Ensure that this function is being called from main Matter thread
     303            8 :         assertChipStackLockedByCurrentThread();
     304              : 
     305            8 :         auto * helper = reinterpret_cast<WorkHelper *>(arg);
     306              :         // Hold strong ptr while work is handled, and ensure that helper->mStrongPtr does not keep
     307              :         // holding a reference.
     308            8 :         auto strongPtr(std::move(helper->mStrongPtr));
     309            8 :         if (!strongPtr)
     310              :         {
     311              :             // This can happen if scheduling AfterWorkHandler failed.  Just grab a strong ref
     312              :             // to handler directly, to fulfill our API contract of holding a strong reference
     313              :             // across the after-work callback.  At this point, we are guaranteed that the
     314              :             // background thread is not touching the helper anymore.
     315            0 :             strongPtr = helper->mWeakPtr.lock();
     316              :         }
     317            8 :         if (auto * session = helper->mSession.load())
     318              :         {
     319              :             // Execute callback in Matter thread; session should be OK with this
     320            8 :             (session->*(helper->mAfterWorkCallback))(helper->mData, helper->mStatus);
     321              :         }
     322            8 :     }
     323              : 
     324              : private:
     325              :     // Lifetime management: `ScheduleWork` sets `mStrongPtr` from `mWeakPtr`.
     326              :     Platform::WeakPtr<WorkHelper> mWeakPtr;
     327              : 
     328              :     // Lifetime management: `ScheduleWork` sets `mStrongPtr` from `mWeakPtr`.
     329              :     Platform::SharedPtr<WorkHelper> mStrongPtr;
     330              : 
     331              :     // Associated session, cleared by `CancelWork`.
     332              :     std::atomic<CASESession *> mSession;
     333              : 
     334              :     // Work callback, called by `WorkHandler`.
     335              :     WorkCallback mWorkCallback;
     336              : 
     337              :     // After work callback, called by `AfterWorkHandler`.
     338              :     AfterWorkCallback mAfterWorkCallback;
     339              : 
     340              :     // Return value of `mWorkCallback`, passed to `mAfterWorkCallback`.
     341              :     CHIP_ERROR mStatus;
     342              : 
     343              :     // If background thread fails to schedule AfterWorkCallback then this flag is set to true
     344              :     // and CASEServer then can check this one and run the AfterWorkCallback for us.
     345              :     //
     346              :     // When this happens, the write to this boolean _must_ be the last code that touches this
     347              :     // object on the background thread.  After that, the Matter thread owns the object.
     348              :     std::atomic<bool> mScheduleAfterWorkFailed{ false };
     349              : 
     350              : public:
     351              :     // Data passed to `mWorkCallback` and `mAfterWorkCallback`.
     352              :     DATA mData;
     353              : };
     354              : 
     355           32 : CASESession::~CASESession()
     356              : {
     357              :     // Let's clear out any security state stored in the object, before destroying it.
     358           32 :     Clear();
     359           32 : }
     360              : 
     361            0 : void CASESession::OnSessionReleased()
     362              : {
     363              :     // Call into our super-class before we clear our state.
     364            0 :     PairingSession::OnSessionReleased();
     365            0 :     Clear();
     366            0 : }
     367              : 
     368          111 : void CASESession::Clear()
     369              : {
     370              :     MATTER_TRACE_SCOPE("Clear", "CASESession");
     371              :     // Cancel any outstanding work.
     372          111 :     if (mSendSigma3Helper)
     373              :     {
     374            0 :         mSendSigma3Helper->CancelWork();
     375            0 :         mSendSigma3Helper.reset();
     376              :     }
     377          111 :     if (mHandleSigma3Helper)
     378              :     {
     379            6 :         mHandleSigma3Helper->CancelWork();
     380            6 :         mHandleSigma3Helper.reset();
     381              :     }
     382              : 
     383              :     // This function zeroes out and resets the memory used by the object.
     384              :     // It's done so that no security related information will be leaked.
     385          111 :     mCommissioningHash.Clear();
     386          111 :     PairingSession::Clear();
     387              : 
     388          111 :     mState = State::kInitialized;
     389          111 :     Crypto::ClearSecretData(mIPK);
     390              : 
     391          111 :     if (mFabricsTable != nullptr)
     392              :     {
     393           34 :         mFabricsTable->RemoveFabricDelegate(this);
     394              : 
     395           34 :         mFabricsTable->ReleaseEphemeralKeypair(mEphemeralKey);
     396           34 :         mEphemeralKey = nullptr;
     397              :     }
     398              : 
     399          111 :     mLocalNodeId  = kUndefinedNodeId;
     400          111 :     mPeerNodeId   = kUndefinedNodeId;
     401          111 :     mFabricsTable = nullptr;
     402          111 :     mFabricIndex  = kUndefinedFabricIndex;
     403              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     404          111 :     if (!mPeerConnState.IsNull())
     405              :     {
     406              :         // Set the app state callback object in the Connection state to null
     407              :         // to prevent any dangling pointer to memory(mTCPConnCbCtxt) owned
     408              :         // by the CASESession object, that is now getting cleared.
     409            0 :         mPeerConnState->mAppState = nullptr;
     410            0 :         mPeerConnState.Release();
     411              :     }
     412              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     413          111 : }
     414              : 
     415            5 : void CASESession::InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex)
     416              : {
     417            5 :     if (mFabricIndex != fabricIndex)
     418              :     {
     419            1 :         return;
     420              :     }
     421            4 :     if (!IsSessionEstablishmentInProgress())
     422              :     {
     423            2 :         return;
     424              :     }
     425            2 :     AbortPendingEstablish(CHIP_ERROR_CANCELLED);
     426              : }
     427              : 
     428           34 : CHIP_ERROR CASESession::Init(SessionManager & sessionManager, Credentials::CertificateValidityPolicy * policy,
     429              :                              SessionEstablishmentDelegate * delegate, const ScopedNodeId & sessionEvictionHint)
     430              : {
     431              :     MATTER_TRACE_SCOPE("Init", "CASESession");
     432           34 :     VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     433           34 :     VerifyOrReturnError(mGroupDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     434           34 :     VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     435              : 
     436           34 :     Clear();
     437              : 
     438           34 :     ReturnErrorOnFailure(mCommissioningHash.Begin());
     439              : 
     440           34 :     mDelegate       = delegate;
     441           34 :     mSessionManager = &sessionManager;
     442              : 
     443           34 :     ReturnErrorOnFailure(AllocateSecureSession(sessionManager, sessionEvictionHint));
     444              : 
     445           34 :     mValidContext.Reset();
     446           34 :     mValidContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature);
     447           34 :     mValidContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth);
     448           34 :     mValidContext.mValidityPolicy = policy;
     449              : 
     450           34 :     return CHIP_NO_ERROR;
     451              : }
     452              : 
     453              : CHIP_ERROR
     454           22 : CASESession::PrepareForSessionEstablishment(SessionManager & sessionManager, FabricTable * fabricTable,
     455              :                                             SessionResumptionStorage * sessionResumptionStorage,
     456              :                                             Credentials::CertificateValidityPolicy * policy,
     457              :                                             SessionEstablishmentDelegate * delegate, const ScopedNodeId & previouslyEstablishedPeer,
     458              :                                             Optional<ReliableMessageProtocolConfig> mrpLocalConfig)
     459              : {
     460              :     MATTER_TRACE_SCOPE("PrepareForSessionEstablishment", "CASESession");
     461              :     // Below VerifyOrReturnError is not SuccessOrExit since we only want to goto `exit:` after
     462              :     // Init has been successfully called.
     463           22 :     VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     464           20 :     ReturnErrorOnFailure(Init(sessionManager, policy, delegate, previouslyEstablishedPeer));
     465              : 
     466           20 :     CHIP_ERROR err = CHIP_NO_ERROR;
     467              : 
     468           20 :     SuccessOrExit(err = fabricTable->AddFabricDelegate(this));
     469              : 
     470           20 :     mFabricsTable             = fabricTable;
     471           20 :     mRole                     = CryptoContext::SessionRole::kResponder;
     472           20 :     mSessionResumptionStorage = sessionResumptionStorage;
     473           20 :     mLocalMRPConfig           = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
     474              : 
     475           20 :     ChipLogDetail(SecureChannel, "Allocated SecureSession (%p) - waiting for Sigma1 msg",
     476              :                   mSecureSessionHolder.Get().Value()->AsSecureSession());
     477              : 
     478            0 : exit:
     479           20 :     if (err != CHIP_NO_ERROR)
     480              :     {
     481            0 :         Clear();
     482              :     }
     483           20 :     return err;
     484              : }
     485              : 
     486           16 : CHIP_ERROR CASESession::EstablishSession(SessionManager & sessionManager, FabricTable * fabricTable, ScopedNodeId peerScopedNodeId,
     487              :                                          ExchangeContext * exchangeCtxt, SessionResumptionStorage * sessionResumptionStorage,
     488              :                                          Credentials::CertificateValidityPolicy * policy, SessionEstablishmentDelegate * delegate,
     489              :                                          Optional<ReliableMessageProtocolConfig> mrpLocalConfig)
     490              : {
     491              :     MATTER_TRACE_SCOPE("EstablishSession", "CASESession");
     492           16 :     CHIP_ERROR err = CHIP_NO_ERROR;
     493              : 
     494              :     // Return early on error here, as we have not initialized any state yet
     495           16 :     VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, exchangeCtxt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     496           14 :     VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     497              : 
     498              :     // Use FabricTable directly to avoid situation of dangling index from stale FabricInfo
     499              :     // until we factor-out any FabricInfo direct usage.
     500           14 :     VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, peerScopedNodeId.GetFabricIndex() != kUndefinedFabricIndex,
     501              :                                   CHIP_ERROR_INVALID_ARGUMENT);
     502           14 :     const auto * fabricInfo = fabricTable->FindFabricWithIndex(peerScopedNodeId.GetFabricIndex());
     503           14 :     VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, fabricInfo != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     504              : 
     505           14 :     err = Init(sessionManager, policy, delegate, peerScopedNodeId);
     506              : 
     507           14 :     mRole = CryptoContext::SessionRole::kInitiator;
     508              : 
     509              :     // We are setting the exchange context specifically before checking for error.
     510              :     // This is to make sure the exchange will get closed if Init() returned an error.
     511           14 :     mExchangeCtxt.Emplace(*exchangeCtxt);
     512              : 
     513           14 :     Transport::PeerAddress peerAddress = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress();
     514              : 
     515              :     // From here onwards, let's go to exit on error, as some state might have already
     516              :     // been initialized
     517           14 :     SuccessOrExitWithMetric(kMetricDeviceCASESession, err);
     518              : 
     519           14 :     SuccessOrExitWithMetric(kMetricDeviceCASESession, err = fabricTable->AddFabricDelegate(this));
     520              : 
     521              :     MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESession);
     522              : 
     523              :     // Set the PeerAddress in the secure session up front to indicate the
     524              :     // Transport Type of the session that is being set up.
     525           14 :     mSecureSessionHolder->AsSecureSession()->SetPeerAddress(peerAddress);
     526              : 
     527           14 :     mFabricsTable             = fabricTable;
     528           14 :     mFabricIndex              = fabricInfo->GetFabricIndex();
     529           14 :     mSessionResumptionStorage = sessionResumptionStorage;
     530           14 :     mLocalMRPConfig           = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
     531              : 
     532           14 :     mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedSigma1ProcessingTime);
     533           14 :     mPeerNodeId  = peerScopedNodeId.GetNodeId();
     534           14 :     mLocalNodeId = fabricInfo->GetNodeId();
     535              : 
     536           14 :     ChipLogProgress(SecureChannel, "Initiating session on local FabricIndex %u from 0x" ChipLogFormatX64 " -> 0x" ChipLogFormatX64,
     537              :                     static_cast<unsigned>(mFabricIndex), ChipLogValueX64(mLocalNodeId), ChipLogValueX64(mPeerNodeId));
     538              : 
     539           14 :     if (peerAddress.GetTransportType() == Transport::Type::kTcp)
     540              :     {
     541              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     542            0 :         err = sessionManager.TCPConnect(peerAddress, nullptr, mPeerConnState);
     543            0 :         SuccessOrExit(err);
     544              : #else
     545              :         err = CHIP_ERROR_NOT_IMPLEMENTED;
     546              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     547              :     }
     548              :     else
     549              :     {
     550              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma1);
     551           14 :         err = SendSigma1();
     552           14 :         SuccessOrExit(err);
     553              :     }
     554              : 
     555           14 : exit:
     556           14 :     if (err != CHIP_NO_ERROR)
     557              :     {
     558              :         MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
     559              :         MATTER_LOG_METRIC_END(kMetricDeviceCASESession, err);
     560            1 :         Clear();
     561              :     }
     562           14 :     return err;
     563              : }
     564              : 
     565            0 : void CASESession::OnResponseTimeout(ExchangeContext * ec)
     566              : {
     567              :     MATTER_TRACE_SCOPE("OnResponseTimeout", "CASESession");
     568            0 :     VerifyOrReturn(ec != nullptr, ChipLogError(SecureChannel, "CASESession::OnResponseTimeout was called by null exchange"));
     569            0 :     VerifyOrReturn(mExchangeCtxt.HasValue() && (&mExchangeCtxt.Value().Get() == ec),
     570              :                    ChipLogError(SecureChannel, "CASESession::OnResponseTimeout exchange doesn't match"));
     571            0 :     ChipLogError(SecureChannel,
     572              :                  "CASESession timed out while waiting for a response from peer " ChipLogFormatScopedNodeId ". Current state was %u",
     573              :                  ChipLogValueScopedNodeId(GetPeer()), to_underlying(mState));
     574              :     MATTER_TRACE_COUNTER("CASETimeout");
     575              :     // Discard the exchange so that Clear() doesn't try aborting it.  The
     576              :     // exchange will handle that.
     577            0 :     DiscardExchange();
     578            0 :     AbortPendingEstablish(CHIP_ERROR_TIMEOUT);
     579              : }
     580              : 
     581            8 : void CASESession::AbortPendingEstablish(CHIP_ERROR err)
     582              : {
     583              :     MATTER_LOG_METRIC_END(kMetricDeviceCASESession, err);
     584              :     MATTER_TRACE_SCOPE("AbortPendingEstablish", "CASESession");
     585              :     // This needs to come before Clear() which will reset mState.
     586            8 :     SessionEstablishmentStage state = MapCASEStateToSessionEstablishmentStage(mState);
     587            8 :     Clear();
     588              :     // Do this last in case the delegate frees us.
     589            8 :     NotifySessionEstablishmentError(err, state);
     590            8 : }
     591              : 
     592           16 : CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session)
     593              : {
     594           16 :     switch (mState)
     595              :     {
     596           14 :     case State::kFinished: {
     597              :         std::array<uint8_t, sizeof(mIPK) + kSHA256_Hash_Length> msg_salt;
     598              : 
     599              :         {
     600           14 :             Encoding::LittleEndian::BufferWriter bbuf(msg_salt);
     601           14 :             bbuf.Put(mIPK, sizeof(mIPK));
     602           14 :             bbuf.Put(mMessageDigest, sizeof(mMessageDigest));
     603              : 
     604           14 :             VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
     605              :         }
     606              : 
     607           14 :         ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(),
     608              :                                                     ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionEstablishment,
     609              :                                                     mRole));
     610              : 
     611           14 :         return CHIP_NO_ERROR;
     612              :     }
     613            2 :     case State::kFinishedViaResume: {
     614              :         std::array<uint8_t, sizeof(mInitiatorRandom) + decltype(mResumeResumptionId)().size()> msg_salt;
     615              : 
     616              :         {
     617            2 :             Encoding::LittleEndian::BufferWriter bbuf(msg_salt);
     618            2 :             bbuf.Put(mInitiatorRandom, sizeof(mInitiatorRandom));
     619            2 :             bbuf.Put(mResumeResumptionId.data(), mResumeResumptionId.size());
     620              : 
     621            2 :             VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
     622              :         }
     623              : 
     624            2 :         ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(),
     625              :                                                     ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionResumption, mRole));
     626              : 
     627            2 :         return CHIP_NO_ERROR;
     628              :     }
     629            0 :     default:
     630            0 :         return CHIP_ERROR_INCORRECT_STATE;
     631              :     }
     632              : }
     633              : 
     634           14 : CHIP_ERROR CASESession::RecoverInitiatorIpk()
     635              : {
     636           14 :     Credentials::GroupDataProvider::KeySet ipkKeySet;
     637              : 
     638           14 :     CHIP_ERROR err = mGroupDataProvider->GetIpkKeySet(mFabricIndex, ipkKeySet);
     639              : 
     640           14 :     if (err != CHIP_NO_ERROR)
     641              :     {
     642            0 :         ChipLogError(SecureChannel, "Failed to obtain IPK for initiating: %" CHIP_ERROR_FORMAT, err.Format());
     643            0 :         return err;
     644              :     }
     645           14 :     if ((ipkKeySet.num_keys_used == 0) || (ipkKeySet.num_keys_used > Credentials::GroupDataProvider::KeySet::kEpochKeysMax))
     646              :     {
     647            0 :         ChipLogError(SecureChannel, "Found invalid IPK keyset for initiator.");
     648            0 :         return CHIP_ERROR_INTERNAL;
     649              :     }
     650              : 
     651              :     // For the generation of the Destination Identifier,
     652              :     // the originator SHALL use the operational group key with the second oldest
     653              :     // EpochStartTime, if one exists, otherwise it SHALL use the single operational
     654              :     // group key available. The EpochStartTime are already ordered
     655           14 :     size_t ipkIndex = (ipkKeySet.num_keys_used > 1) ? ((ipkKeySet.num_keys_used - 1) - 1) : 0;
     656           14 :     memcpy(&mIPK[0], ipkKeySet.epoch_keys[ipkIndex].key, sizeof(mIPK));
     657              : 
     658              :     // Leaving this logging code for debug, but this cannot be enabled at runtime
     659              :     // since it leaks private security material.
     660              : #if 0
     661              :     ChipLogProgress(SecureChannel, "RecoverInitiatorIpk: GroupDataProvider %p, Got IPK for FabricIndex %u", mGroupDataProvider,
     662              :                     static_cast<unsigned>(mFabricIndex));
     663              :     ChipLogByteSpan(SecureChannel, ByteSpan(mIPK));
     664              : #endif
     665              : 
     666           14 :     return CHIP_NO_ERROR;
     667              : }
     668              : 
     669              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     670            0 : void CASESession::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionHolder & conn, CHIP_ERROR err)
     671              : {
     672            0 :     VerifyOrReturn(conn == mPeerConnState);
     673              : 
     674              :     char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
     675            0 :     conn->mPeerAddr.ToString(peerAddrBuf);
     676              : 
     677            0 :     auto ConnectionCleanup = [](CASESession * s) {
     678            0 :         s->mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->ReleaseTCPConnection();
     679            0 :         s->mSecureSessionHolder.Get().Value()->AsSecureSession()->ReleaseTCPConnection();
     680            0 :         s->Clear();
     681            0 :     };
     682            0 :     std::unique_ptr<CASESession, decltype(ConnectionCleanup)> connectionHolder(this, ConnectionCleanup);
     683              : 
     684              :     // Bail if connection setup encountered an error.
     685            0 :     LogAndReturnOnFailure(err, SecureChannel, "Connection establishment failed with peer at %s", peerAddrBuf);
     686              : 
     687            0 :     ChipLogDetail(SecureChannel, "TCP Connection established with %s before session establishment", peerAddrBuf);
     688              : 
     689              :     // Associate the connection with the current unauthenticated session for the
     690              :     // CASE exchange.
     691            0 :     mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetTCPConnection(conn);
     692              : 
     693              :     // Associate the connection with the current secure session that is being
     694              :     // set up.
     695            0 :     mSecureSessionHolder.Get().Value()->AsSecureSession()->SetTCPConnection(conn);
     696              : 
     697              :     // Send Sigma1 after connection is established for sessions over TCP
     698            0 :     LogAndReturnOnFailure(SendSigma1(), SecureChannel, "Sigma1 failed to peer %s", peerAddrBuf);
     699              : 
     700            0 :     connectionHolder.release();
     701            0 : }
     702              : 
     703            0 : void CASESession::HandleConnectionClosed(const Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr)
     704              : {
     705            0 :     VerifyOrReturn(conn == mPeerConnState);
     706              :     // Drop our pointer to the now-invalid connection state.
     707              :     //
     708              :     // Since the connection is closed, message sends over the ExchangeContext
     709              :     // will just fail and be handled like normal send errors.
     710              :     //
     711              :     // Additionally, SessionManager notifies (via ExchangeMgr) all ExchangeContexts on the
     712              :     // connection closures for the attached sessions and the ExchangeContexts
     713              :     // can close proactively if that's appropriate.
     714            0 :     mPeerConnState.Release();
     715            0 :     ChipLogDetail(SecureChannel, "TCP Connection for this session has closed");
     716              : }
     717              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     718              : 
     719           14 : CHIP_ERROR CASESession::SendSigma1()
     720              : {
     721              :     MATTER_TRACE_SCOPE("SendSigma1", "CASESession");
     722              : 
     723           14 :     uint8_t destinationIdentifier[kSHA256_Hash_Length] = { 0 };
     724              : 
     725              :     // Struct that will be used as input to EncodeSigma1() method
     726           14 :     EncodeSigma1Inputs encodeSigma1Inputs;
     727              : 
     728              :     // Lookup fabric info.
     729           14 :     const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
     730           14 :     VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
     731              : 
     732              :     // Validate that we have a session ID allocated.
     733           14 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
     734           14 :     encodeSigma1Inputs.initiatorSessionId = GetLocalSessionId().Value();
     735              : 
     736              :     // Generate an ephemeral keypair
     737           14 :     mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE();
     738           14 :     VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY);
     739           14 :     ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH));
     740           14 :     encodeSigma1Inputs.initiatorEphPubKey = &mEphemeralKey->Pubkey();
     741              : 
     742              :     // Fill in the random value
     743           14 :     ReturnErrorOnFailure(DRBG_get_bytes(mInitiatorRandom, sizeof(mInitiatorRandom)));
     744           14 :     encodeSigma1Inputs.initiatorRandom = ByteSpan(mInitiatorRandom);
     745              : 
     746              :     // Generate a Destination Identifier based on the node we are attempting to reach
     747              :     {
     748              :         // Obtain originator IPK matching the fabric where we are trying to open a session. mIPK
     749              :         // will be properly set thereafter.
     750           14 :         ReturnErrorOnFailure(RecoverInitiatorIpk());
     751              : 
     752           14 :         FabricId fabricId = fabricInfo->GetFabricId();
     753           14 :         Crypto::P256PublicKey rootPubKey;
     754           14 :         ReturnErrorOnFailure(mFabricsTable->FetchRootPubkey(mFabricIndex, rootPubKey));
     755           14 :         Credentials::P256PublicKeySpan rootPubKeySpan{ rootPubKey.ConstBytes() };
     756              : 
     757           14 :         MutableByteSpan destinationIdSpan(destinationIdentifier);
     758           14 :         ReturnErrorOnFailure(GenerateCaseDestinationId(ByteSpan(mIPK), encodeSigma1Inputs.initiatorRandom, rootPubKeySpan, fabricId,
     759              :                                                        mPeerNodeId, destinationIdSpan));
     760           14 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptDestinationID, destinationIdentifier[0] ^= 0xFF);
     761           14 :         encodeSigma1Inputs.destinationId = destinationIdSpan;
     762           14 :     }
     763              : 
     764           14 :     VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
     765           14 :     encodeSigma1Inputs.initiatorMrpConfig = &mLocalMRPConfig.Value();
     766              : 
     767              :     // Try to find persistent session, and resume it.
     768           14 :     if (mSessionResumptionStorage != nullptr)
     769              :     {
     770            4 :         CHIP_ERROR err = mSessionResumptionStorage->FindByScopedNodeId(fabricInfo->GetScopedNodeIdForNode(mPeerNodeId),
     771            4 :                                                                        mResumeResumptionId, mSharedSecret, mPeerCATs);
     772            4 :         if (err == CHIP_NO_ERROR)
     773              :         {
     774              :             // Found valid resumption state, try to resume the session.
     775            3 :             encodeSigma1Inputs.resumptionId = mResumeResumptionId;
     776            3 :             MutableByteSpan resumeMICSpan(encodeSigma1Inputs.initiatorResume1MICBuffer);
     777            3 :             ReturnErrorOnFailure(GenerateSigmaResumeMIC(encodeSigma1Inputs.initiatorRandom, encodeSigma1Inputs.resumptionId,
     778              :                                                         ByteSpan(kKDFS1RKeyInfo), ByteSpan(kResume1MIC_Nonce), resumeMICSpan));
     779              : 
     780            3 :             encodeSigma1Inputs.initiatorResumeMIC         = resumeMICSpan;
     781            3 :             encodeSigma1Inputs.sessionResumptionRequested = true;
     782              :         }
     783              :     }
     784              : 
     785           14 :     System::PacketBufferHandle msgR1;
     786              : 
     787              :     // Encode Sigma1 in CHIP TLV Format
     788           14 :     ReturnErrorOnFailure(EncodeSigma1(msgR1, encodeSigma1Inputs));
     789              : 
     790           14 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msgR1->Start(), msgR1->DataLength() }));
     791              : 
     792              :     // Call delegate to send the msg to peer
     793           14 :     ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma1, std::move(msgR1),
     794              :                                                             SendFlags(SendMessageFlags::kExpectResponse)));
     795              : 
     796           13 :     if (encodeSigma1Inputs.sessionResumptionRequested)
     797              :     {
     798            3 :         mState = State::kSentSigma1Resume;
     799              : 
     800              :         // Flags that Resume is being attempted
     801              :         MATTER_LOG_METRIC(kMetricDeviceCASESessionSigma1Resume);
     802              :     }
     803              :     else
     804              :     {
     805           10 :         mState = State::kSentSigma1;
     806              :     }
     807              : 
     808              : #if CHIP_PROGRESS_LOGGING
     809           13 :     const auto localMRPConfig = mLocalMRPConfig.Value();
     810              : #endif // CHIP_PROGRESS_LOGGING
     811           13 :     ChipLogProgress(SecureChannel, "Sent Sigma1 msg to " ChipLogFormatScopedNodeId " [II:%" PRIu32 "ms AI:%" PRIu32 "ms AT:%ums]",
     812              :                     ChipLogValueScopedNodeId(GetPeer()), localMRPConfig.mIdleRetransTimeout.count(),
     813              :                     localMRPConfig.mActiveRetransTimeout.count(), localMRPConfig.mActiveThresholdTime.count());
     814              : 
     815           13 :     mDelegate->OnSessionEstablishmentStarted();
     816              : 
     817           13 :     return CHIP_NO_ERROR;
     818           14 : }
     819              : 
     820           20 : CHIP_ERROR CASESession::EncodeSigma1(System::PacketBufferHandle & msg, EncodeSigma1Inputs & input)
     821              : {
     822              :     MATTER_TRACE_SCOPE("EncodeSigma1", "CASESession");
     823              : 
     824           20 :     VerifyOrReturnError(input.initiatorEphPubKey != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     825              : 
     826           19 :     size_t dataLen = EstimateStructOverhead(kSigmaParamRandomNumberSize,                 // initiatorRandom
     827              :                                             sizeof(uint16_t),                            // initiatorSessionId,
     828              :                                             kSHA256_Hash_Length,                         // destinationId
     829              :                                             kP256_PublicKey_Length,                      // InitiatorEphPubKey,
     830              :                                             SessionParameters::kEstimatedTLVSize,        // initiatorSessionParams
     831              :                                             SessionResumptionStorage::kResumptionIdSize, // resumptionId
     832              :                                             CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES            // initiatorResumeMIC
     833              :     );
     834              : 
     835           19 :     msg = System::PacketBufferHandle::New(dataLen);
     836           19 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY);
     837              : 
     838           19 :     System::PacketBufferTLVWriter tlvWriter;
     839           19 :     tlvWriter.Init(std::move(msg));
     840              : 
     841           19 :     TLVType outerContainerType = kTLVType_NotSpecified;
     842           19 :     ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
     843           19 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kInitiatorRandom), input.initiatorRandom));
     844           19 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kInitiatorSessionId), input.initiatorSessionId));
     845           19 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kDestinationId), input.destinationId));
     846              : 
     847           19 :     ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(Sigma1Tags::kInitiatorEphPubKey), *input.initiatorEphPubKey,
     848              :                                             static_cast<uint32_t>(input.initiatorEphPubKey->Length())));
     849              : 
     850           19 :     VerifyOrReturnError(input.initiatorMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     851           18 :     ReturnErrorOnFailure(
     852              :         EncodeSessionParameters(AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams), *input.initiatorMrpConfig, tlvWriter));
     853              : 
     854           18 :     if (input.sessionResumptionRequested)
     855              :     {
     856            4 :         bool testOnlySkipResumptionID       = false;
     857            4 :         bool testOnlySkipInitiatorResumeMIC = false;
     858            4 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASESkipResumptionID, testOnlySkipResumptionID = true);
     859            4 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASESkipInitiatorResumeMIC, testOnlySkipInitiatorResumeMIC = true);
     860            4 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptInitiatorResumeMIC, input.initiatorResume1MICBuffer[0] ^= 0xFF);
     861              : 
     862            4 :         if (!testOnlySkipResumptionID)
     863              :         {
     864            4 :             ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kResumptionID), input.resumptionId));
     865              :         }
     866              : 
     867            4 :         if (!testOnlySkipInitiatorResumeMIC)
     868              :         {
     869            4 :             ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kResume1MIC), input.initiatorResumeMIC));
     870              :         }
     871              :     }
     872              : 
     873           18 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
     874           18 :     ReturnErrorOnFailure(tlvWriter.Finalize(&msg));
     875              : 
     876           18 :     return CHIP_NO_ERROR;
     877           19 : }
     878              : 
     879           12 : CHIP_ERROR CASESession::HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg)
     880              : {
     881              :     MATTER_TRACE_SCOPE("HandleSigma1_and_SendSigma2", "CASESession");
     882              : 
     883           12 :     CHIP_ERROR err = CHIP_NO_ERROR;
     884              : 
     885              :     // Parse and Validate Received Sigma1, and decide next step
     886           12 :     NextStep nextStep = HandleSigma1(std::move(msg));
     887           12 :     VerifyOrExit(nextStep.Is<Step>(), err = nextStep.Get<CHIP_ERROR>());
     888              : 
     889           11 :     switch (nextStep.Get<Step>())
     890              :     {
     891           10 :     case Step::kSendSigma2: {
     892              : 
     893           10 :         System::PacketBufferHandle msgR2;
     894           10 :         EncodeSigma2Inputs encodeSigma2;
     895              : 
     896           10 :         SuccessOrExit(err = PrepareSigma2(encodeSigma2));
     897           10 :         SuccessOrExit(err = EncodeSigma2(msgR2, encodeSigma2));
     898              : 
     899              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2);
     900           10 :         SuccessOrExitAction(err = SendSigma2(std::move(msgR2)), MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err));
     901              : 
     902           10 :         mDelegate->OnSessionEstablishmentStarted();
     903           10 :         break;
     904           20 :     }
     905            1 :     case Step::kSendSigma2Resume: {
     906              : 
     907            1 :         System::PacketBufferHandle msgR2Resume;
     908            1 :         EncodeSigma2ResumeInputs encodeSigma2Resume;
     909              : 
     910            1 :         SuccessOrExit(err = PrepareSigma2Resume(encodeSigma2Resume));
     911            1 :         SuccessOrExit(err = EncodeSigma2Resume(msgR2Resume, encodeSigma2Resume));
     912              : 
     913              :         MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2Resume);
     914            1 :         SuccessOrExitAction(err = SendSigma2Resume(std::move(msgR2Resume)),
     915              :                             MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2Resume, err));
     916              : 
     917            1 :         mDelegate->OnSessionEstablishmentStarted();
     918            1 :         break;
     919            1 :     }
     920            0 :     default:
     921            0 :         break;
     922              :     }
     923              : 
     924           12 : exit:
     925           12 :     if (err == CHIP_ERROR_KEY_NOT_FOUND)
     926              :     {
     927            1 :         SendStatusReport(mExchangeCtxt, kProtocolCodeNoSharedRoot);
     928            1 :         mState = State::kInitialized;
     929              :     }
     930           11 :     else if (err != CHIP_NO_ERROR)
     931              :     {
     932            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
     933            0 :         mState = State::kInitialized;
     934              :     }
     935           24 :     return err;
     936           12 : }
     937              : 
     938           11 : CHIP_ERROR CASESession::FindLocalNodeFromDestinationId(const ByteSpan & destinationId, const ByteSpan & initiatorRandom)
     939              : {
     940              :     MATTER_TRACE_SCOPE("FindLocalNodeFromDestinationId", "CASESession");
     941           11 :     VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
     942              : 
     943           11 :     bool found = false;
     944           12 :     for (const FabricInfo & fabricInfo : *mFabricsTable)
     945              :     {
     946              :         // Basic data for candidate fabric, used to compute candidate destination identifiers
     947           11 :         FabricId fabricId = fabricInfo.GetFabricId();
     948           11 :         NodeId nodeId     = fabricInfo.GetNodeId();
     949           11 :         Crypto::P256PublicKey rootPubKey;
     950           11 :         ReturnErrorOnFailure(mFabricsTable->FetchRootPubkey(fabricInfo.GetFabricIndex(), rootPubKey));
     951           11 :         Credentials::P256PublicKeySpan rootPubKeySpan{ rootPubKey.ConstBytes() };
     952              : 
     953              :         // Get IPK operational group key set for current candidate fabric
     954           11 :         GroupDataProvider::KeySet ipkKeySet;
     955           11 :         CHIP_ERROR err = mGroupDataProvider->GetIpkKeySet(fabricInfo.GetFabricIndex(), ipkKeySet);
     956           22 :         if ((err != CHIP_NO_ERROR) ||
     957           11 :             ((ipkKeySet.num_keys_used == 0) || (ipkKeySet.num_keys_used > Credentials::GroupDataProvider::KeySet::kEpochKeysMax)))
     958              :         {
     959            0 :             continue;
     960              :         }
     961              : 
     962              :         // Try every IPK candidate we have for a match
     963           12 :         for (size_t keyIdx = 0; keyIdx < ipkKeySet.num_keys_used; ++keyIdx)
     964              :         {
     965              :             uint8_t candidateDestinationId[kSHA256_Hash_Length];
     966           11 :             MutableByteSpan candidateDestinationIdSpan(candidateDestinationId);
     967           11 :             ByteSpan candidateIpkSpan(ipkKeySet.epoch_keys[keyIdx].key);
     968              : 
     969           11 :             err = GenerateCaseDestinationId(candidateIpkSpan, initiatorRandom, rootPubKeySpan, fabricId, nodeId,
     970              :                                             candidateDestinationIdSpan);
     971           11 :             if ((err == CHIP_NO_ERROR) && (candidateDestinationIdSpan.data_equal(destinationId)))
     972              :             {
     973              :                 // Found a match, stop working, cache IPK, update local fabric context
     974           10 :                 found = true;
     975           10 :                 MutableByteSpan ipkSpan(mIPK);
     976           10 :                 CopySpanToMutableSpan(candidateIpkSpan, ipkSpan);
     977           10 :                 mFabricIndex = fabricInfo.GetFabricIndex();
     978           10 :                 mLocalNodeId = nodeId;
     979           10 :                 break;
     980              :             }
     981              :         }
     982              : 
     983           11 :         if (found)
     984              :         {
     985           10 :             break;
     986              :         }
     987           11 :     }
     988              : 
     989           11 :     return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
     990              : }
     991              : 
     992            3 : CHIP_ERROR CASESession::TryResumeSession(SessionResumptionStorage::ConstResumptionIdView resumptionId, ByteSpan resume1MIC,
     993              :                                          ByteSpan initiatorRandom)
     994              : {
     995              :     MATTER_TRACE_SCOPE("TryResumeSession", "CASESession");
     996            3 :     VerifyOrReturnError(mSessionResumptionStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
     997            3 :     VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
     998              : 
     999            3 :     SessionResumptionStorage::ConstResumptionIdView resumptionIdSpan(resumptionId);
    1000            3 :     ScopedNodeId node;
    1001            3 :     ReturnErrorOnFailure(mSessionResumptionStorage->FindByResumptionId(resumptionIdSpan, node, mSharedSecret, mPeerCATs));
    1002              : 
    1003              :     // Cross check resume1MIC with the shared secret
    1004            2 :     ReturnErrorOnFailure(
    1005              :         ValidateSigmaResumeMIC(resume1MIC, initiatorRandom, resumptionId, ByteSpan(kKDFS1RKeyInfo), ByteSpan(kResume1MIC_Nonce)));
    1006              : 
    1007            1 :     const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(node.GetFabricIndex());
    1008            1 :     VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1009              : 
    1010            1 :     mFabricIndex = node.GetFabricIndex();
    1011            1 :     mPeerNodeId  = node.GetNodeId();
    1012            1 :     mLocalNodeId = fabricInfo->GetNodeId();
    1013              : 
    1014            1 :     return CHIP_NO_ERROR;
    1015              : }
    1016           12 : CASESession::NextStep CASESession::HandleSigma1(System::PacketBufferHandle && msg)
    1017              : {
    1018              :     MATTER_TRACE_SCOPE("HandleSigma1", "CASESession");
    1019           12 :     ChipLogProgress(SecureChannel, "Received Sigma1 msg");
    1020              :     MATTER_TRACE_COUNTER("Sigma1");
    1021              : 
    1022           12 :     VerifyOrReturnError(mFabricsTable != nullptr, NextStep::Create<CHIP_ERROR>(CHIP_ERROR_INCORRECT_STATE));
    1023              : 
    1024           12 :     ReturnErrorVariantOnFailure(NextStep, mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
    1025              : 
    1026           12 :     System::PacketBufferTLVReader tlvReader;
    1027           12 :     tlvReader.Init(std::move(msg));
    1028              : 
    1029              :     // Struct that will serve as output in ParseSigma1
    1030           12 :     ParsedSigma1 parsedSigma1;
    1031              : 
    1032           12 :     ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1));
    1033              : 
    1034           12 :     ChipLogDetail(SecureChannel, "Peer (Initiator) assigned session ID %d", parsedSigma1.initiatorSessionId);
    1035           12 :     SetPeerSessionId(parsedSigma1.initiatorSessionId);
    1036              : 
    1037              :     // Set the Session parameters provided in the Sigma1 message
    1038           12 :     if (parsedSigma1.initiatorSessionParamStructPresent)
    1039              :     {
    1040           11 :         SetRemoteSessionParameters(parsedSigma1.initiatorSessionParams);
    1041           11 :         mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
    1042              :             GetRemoteSessionParameters());
    1043              :     }
    1044              : 
    1045            3 :     if (parsedSigma1.sessionResumptionRequested &&
    1046           15 :         parsedSigma1.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize &&
    1047            3 :         CHIP_NO_ERROR ==
    1048           15 :             TryResumeSession(SessionResumptionStorage::ConstResumptionIdView(parsedSigma1.resumptionId.data()),
    1049            3 :                              parsedSigma1.initiatorResumeMIC, parsedSigma1.initiatorRandom))
    1050              :     {
    1051            1 :         std::copy(parsedSigma1.initiatorRandom.begin(), parsedSigma1.initiatorRandom.end(), mInitiatorRandom);
    1052            1 :         std::copy(parsedSigma1.resumptionId.begin(), parsedSigma1.resumptionId.end(), mResumeResumptionId.begin());
    1053              : 
    1054              :         //  Early returning here, since the next Step is known to be Sigma2Resume, and no further processing is needed for the
    1055              :         //  Sigma1 message
    1056            1 :         return NextStep::Create<Step>(Step::kSendSigma2Resume);
    1057              :     }
    1058              : 
    1059              :     //  ParseSigma1 ensures that:
    1060              :     //  mRemotePubKey.Length() == initiatorPubKey.size() == kP256_PublicKey_Length.
    1061           11 :     memcpy(mRemotePubKey.Bytes(), parsedSigma1.initiatorEphPubKey.data(), mRemotePubKey.Length());
    1062              : 
    1063           11 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1064              : 
    1065              :     // Attempt to match the initiator's desired destination based on local fabric table.
    1066           11 :     err = FindLocalNodeFromDestinationId(parsedSigma1.destinationId, parsedSigma1.initiatorRandom);
    1067           11 :     if (err == CHIP_NO_ERROR)
    1068              :     {
    1069           10 :         ChipLogProgress(SecureChannel, "CASE matched destination ID: fabricIndex %u, NodeID 0x" ChipLogFormatX64,
    1070              :                         static_cast<unsigned>(mFabricIndex), ChipLogValueX64(mLocalNodeId));
    1071              : 
    1072              :         // Side-effect of FindLocalNodeFromDestinationId success was that mFabricIndex/mLocalNodeId are now
    1073              :         // set to the local fabric and associated NodeId that was targeted by the initiator.
    1074              : 
    1075           10 :         return NextStep::Create<Step>(Step::kSendSigma2);
    1076              :     }
    1077              : 
    1078            1 :     ChipLogError(SecureChannel, "CASE failed to match destination ID with local fabrics");
    1079            1 :     ChipLogByteSpan(SecureChannel, parsedSigma1.destinationId);
    1080              : 
    1081              :     // FindLocalNodeFromDestinationId returns CHIP_ERROR_KEY_NOT_FOUND if Sigma1's DestinationId does not match any
    1082              :     // candidateDestinationId, this will trigger a status Report with ProtocolCode = NoSharedTrustRoots.
    1083              : 
    1084              :     // Returning a CHIP_ERROR variant that will trigger a corresponding Status Report.
    1085            1 :     return NextStep::Create<CHIP_ERROR>(err);
    1086           12 : }
    1087              : 
    1088            1 : CHIP_ERROR CASESession::PrepareSigma2Resume(EncodeSigma2ResumeInputs & outSigma2ResData)
    1089              : {
    1090              :     MATTER_TRACE_SCOPE("PrepareSigma2Resume", "CASESession");
    1091              : 
    1092            1 :     VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
    1093              : 
    1094              :     // Validate that we have a session ID allocated.
    1095            1 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
    1096            1 :     outSigma2ResData.responderSessionId = GetLocalSessionId().Value();
    1097              : 
    1098              :     // Generate a new resumption ID
    1099            1 :     ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size()));
    1100            1 :     outSigma2ResData.resumptionId = mNewResumptionId;
    1101              : 
    1102            1 :     ReturnErrorOnFailure(GenerateSigmaResumeMIC(ByteSpan(mInitiatorRandom), mNewResumptionId, ByteSpan(kKDFS2RKeyInfo),
    1103              :                                                 ByteSpan(kResume2MIC_Nonce), outSigma2ResData.sigma2ResumeMIC));
    1104              : 
    1105            1 :     outSigma2ResData.responderMrpConfig = &mLocalMRPConfig.Value();
    1106              : 
    1107            1 :     return CHIP_NO_ERROR;
    1108              : }
    1109              : 
    1110            5 : CHIP_ERROR CASESession::EncodeSigma2Resume(System::PacketBufferHandle & msgR2Resume, EncodeSigma2ResumeInputs & input)
    1111              : {
    1112              :     MATTER_TRACE_SCOPE("EncodeSigma2Resume", "CASESession");
    1113              : 
    1114            5 :     VerifyOrReturnError(input.responderMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1115              : 
    1116            4 :     size_t maxDatalLen = EstimateStructOverhead(SessionResumptionStorage::kResumptionIdSize, // resumptionID
    1117              :                                                 CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,           // sigma2ResumeMIC
    1118              :                                                 sizeof(uint16_t),                            // responderSessionID
    1119              :                                                 SessionParameters::kEstimatedTLVSize         // responderSessionParams
    1120              :     );
    1121              : 
    1122            4 :     msgR2Resume = System::PacketBufferHandle::New(maxDatalLen);
    1123            4 :     VerifyOrReturnError(!msgR2Resume.IsNull(), CHIP_ERROR_NO_MEMORY);
    1124              : 
    1125            4 :     System::PacketBufferTLVWriter tlvWriter;
    1126            4 :     tlvWriter.Init(std::move(msgR2Resume));
    1127              : 
    1128            4 :     TLVType outerContainerType = kTLVType_NotSpecified;
    1129              : 
    1130            4 :     ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
    1131            4 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kResumptionID), input.resumptionId));
    1132            4 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kSigma2ResumeMIC), input.sigma2ResumeMIC));
    1133            4 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionID), input.responderSessionId));
    1134              : 
    1135            4 :     ReturnErrorOnFailure(
    1136              :         EncodeSessionParameters(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionParams), *input.responderMrpConfig, tlvWriter));
    1137              : 
    1138            4 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    1139            4 :     ReturnErrorOnFailure(tlvWriter.Finalize(&msgR2Resume));
    1140              : 
    1141            4 :     return CHIP_NO_ERROR;
    1142            4 : }
    1143              : 
    1144            1 : CHIP_ERROR CASESession::SendSigma2Resume(System::PacketBufferHandle && msgR2Resume)
    1145              : {
    1146              : 
    1147              :     // Call delegate to send the msg to peer
    1148            1 :     ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2Resume,
    1149              :                                                             std::move(msgR2Resume), SendFlags(SendMessageFlags::kExpectResponse)));
    1150              : 
    1151            1 :     mState = State::kSentSigma2Resume;
    1152              : 
    1153            1 :     ChipLogProgress(SecureChannel, "Sent Sigma2Resume msg");
    1154              : 
    1155            1 :     return CHIP_NO_ERROR;
    1156              : }
    1157              : 
    1158           10 : CHIP_ERROR CASESession::PrepareSigma2(EncodeSigma2Inputs & outSigma2Data)
    1159              : {
    1160              : 
    1161              :     MATTER_TRACE_SCOPE("PrepareSigma2", "CASESession");
    1162              : 
    1163           10 :     VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1164           10 :     VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
    1165           10 :     VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
    1166           10 :     outSigma2Data.responderSessionId = GetLocalSessionId().Value();
    1167              : 
    1168           10 :     chip::Platform::ScopedMemoryBuffer<uint8_t> icacBuf;
    1169           10 :     VerifyOrReturnError(icacBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
    1170              : 
    1171           10 :     chip::Platform::ScopedMemoryBuffer<uint8_t> nocBuf;
    1172           10 :     VerifyOrReturnError(nocBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
    1173              : 
    1174           10 :     MutableByteSpan icaCert{ icacBuf.Get(), kMaxCHIPCertLength };
    1175           10 :     ReturnErrorOnFailure(mFabricsTable->FetchICACert(mFabricIndex, icaCert));
    1176              : 
    1177           10 :     MutableByteSpan nocCert{ nocBuf.Get(), kMaxCHIPCertLength };
    1178           10 :     ReturnErrorOnFailure(mFabricsTable->FetchNOCCert(mFabricIndex, nocCert));
    1179              : 
    1180              :     // Fill in the random value
    1181           10 :     ReturnErrorOnFailure(DRBG_get_bytes(&outSigma2Data.responderRandom[0], sizeof(outSigma2Data.responderRandom)));
    1182              : 
    1183              :     // Generate an ephemeral keypair
    1184           10 :     mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE();
    1185           10 :     VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY);
    1186           10 :     ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH));
    1187           10 :     outSigma2Data.responderEphPubKey = &mEphemeralKey->Pubkey();
    1188              : 
    1189              :     // Generate a Shared Secret
    1190           10 :     ReturnErrorOnFailure(mEphemeralKey->ECDH_derive_secret(mRemotePubKey, mSharedSecret));
    1191              : 
    1192              :     uint8_t msgSalt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length];
    1193              : 
    1194           10 :     MutableByteSpan saltSpan(msgSalt);
    1195           10 :     ReturnErrorOnFailure(
    1196              :         ConstructSaltSigma2(ByteSpan(outSigma2Data.responderRandom), mEphemeralKey->Pubkey(), ByteSpan(mIPK), saltSpan));
    1197              : 
    1198           10 :     AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore());
    1199           10 :     ReturnErrorOnFailure(DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k));
    1200              : 
    1201              :     // Construct Sigma2 TBS Data
    1202           10 :     P256ECDSASignature tbsData2Signature;
    1203              :     {
    1204           10 :         size_t msgR2SignedLen = EstimateStructOverhead(kMaxCHIPCertLength,     // responderNoc
    1205              :                                                        kMaxCHIPCertLength,     // responderICAC
    1206              :                                                        kP256_PublicKey_Length, // responderEphPubKey
    1207              :                                                        kP256_PublicKey_Length  // InitiatorEphPubKey
    1208              :         );
    1209              : 
    1210           10 :         chip::Platform::ScopedMemoryBuffer<uint8_t> msgR2Signed;
    1211           10 :         VerifyOrReturnError(msgR2Signed.Alloc(msgR2SignedLen), CHIP_ERROR_NO_MEMORY);
    1212           10 :         MutableByteSpan msgR2SignedSpan{ msgR2Signed.Get(), msgR2SignedLen };
    1213              : 
    1214           10 :         ReturnErrorOnFailure(ConstructTBSData(nocCert, icaCert, ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
    1215              :                                               ByteSpan(mRemotePubKey, mRemotePubKey.Length()), msgR2SignedSpan));
    1216              : 
    1217              :         // Generate a Signature
    1218           10 :         ReturnErrorOnFailure(mFabricsTable->SignWithOpKeypair(mFabricIndex, msgR2SignedSpan, tbsData2Signature));
    1219           10 :     }
    1220              :     // Construct Sigma2 TBE Data
    1221           10 :     size_t msgR2SignedEncLen = EstimateStructOverhead(nocCert.size(),                             // responderNoc
    1222              :                                                       icaCert.size(),                             // responderICAC
    1223              :                                                       tbsData2Signature.Length(),                 // signature
    1224              :                                                       SessionResumptionStorage::kResumptionIdSize // resumptionID
    1225              :     );
    1226              : 
    1227           10 :     VerifyOrReturnError(outSigma2Data.msgR2Encrypted.Alloc(msgR2SignedEncLen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES),
    1228              :                         CHIP_ERROR_NO_MEMORY);
    1229              : 
    1230           10 :     TLVWriter tlvWriter;
    1231           10 :     tlvWriter.Init(outSigma2Data.msgR2Encrypted.Get(), msgR2SignedEncLen);
    1232              : 
    1233           10 :     TLVType outerContainerType = kTLVType_NotSpecified;
    1234              : 
    1235           10 :     ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
    1236              : 
    1237           10 :     CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma2NOC, *nocCert.data() ^= 0xFF);
    1238           10 :     CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma2ICAC, *icaCert.data() ^= 0xFF);
    1239              : 
    1240           10 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderNOC), nocCert));
    1241           10 :     if (!icaCert.empty())
    1242              :     {
    1243           10 :         ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderICAC), icaCert));
    1244              :     }
    1245              : 
    1246              :     // We are now done with ICAC and NOC certs so we can release the memory.
    1247              :     {
    1248           10 :         icacBuf.Free();
    1249           10 :         icaCert = MutableByteSpan{};
    1250              : 
    1251           10 :         nocBuf.Free();
    1252           10 :         nocCert = MutableByteSpan{};
    1253              :     }
    1254              : 
    1255           10 :     CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma2Signature, *tbsData2Signature.Bytes() ^= 0xFF);
    1256              : 
    1257           10 :     ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(TBEDataTags::kSignature), tbsData2Signature.ConstBytes(),
    1258              :                                             static_cast<uint32_t>(tbsData2Signature.Length())));
    1259              : 
    1260              :     // Generate a new resumption ID
    1261           10 :     ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size()));
    1262           10 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kResumptionID), mNewResumptionId));
    1263              : 
    1264           10 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    1265           10 :     ReturnErrorOnFailure(tlvWriter.Finalize());
    1266           10 :     msgR2SignedEncLen              = static_cast<size_t>(tlvWriter.GetLengthWritten());
    1267           10 :     outSigma2Data.encrypted2Length = msgR2SignedEncLen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES;
    1268              :     // Generate the encrypted data blob
    1269           10 :     ReturnErrorOnFailure(AES_CCM_encrypt(outSigma2Data.msgR2Encrypted.Get(), msgR2SignedEncLen, nullptr, 0, sr2k.KeyHandle(),
    1270              :                                          kTBEData2_Nonce, kTBEDataNonceLength, outSigma2Data.msgR2Encrypted.Get(),
    1271              :                                          outSigma2Data.msgR2Encrypted.Get() + msgR2SignedEncLen,
    1272              :                                          CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
    1273              : 
    1274           10 :     outSigma2Data.responderMrpConfig = &mLocalMRPConfig.Value();
    1275              : 
    1276           10 :     return CHIP_NO_ERROR;
    1277           10 : }
    1278              : 
    1279           19 : CHIP_ERROR CASESession::EncodeSigma2(System::PacketBufferHandle & msgR2, EncodeSigma2Inputs & input)
    1280              : {
    1281           19 :     VerifyOrReturnError(input.responderEphPubKey != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1282           18 :     VerifyOrReturnError(input.msgR2Encrypted, CHIP_ERROR_INCORRECT_STATE);
    1283              :     // Check if length of msgR2Encrypted is set and is at least larger than the MIC length
    1284           17 :     VerifyOrReturnError(input.encrypted2Length > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INCORRECT_STATE);
    1285           16 :     VerifyOrReturnError(input.responderMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    1286              : 
    1287           15 :     size_t dataLen = EstimateStructOverhead(kSigmaParamRandomNumberSize,         // responderRandom
    1288              :                                             sizeof(uint16_t),                    // responderSessionId
    1289              :                                             kP256_PublicKey_Length,              // responderEphPubKey
    1290              :                                             input.encrypted2Length,              // encrypted2
    1291              :                                             SessionParameters::kEstimatedTLVSize // responderSessionParams
    1292              :     );
    1293              : 
    1294           15 :     msgR2 = System::PacketBufferHandle::New(dataLen);
    1295           15 :     VerifyOrReturnError(!msgR2.IsNull(), CHIP_ERROR_NO_MEMORY);
    1296              : 
    1297           15 :     System::PacketBufferTLVWriter tlvWriterMsg2;
    1298           15 :     tlvWriterMsg2.Init(std::move(msgR2));
    1299              : 
    1300           15 :     TLVType outerContainerType = kTLVType_NotSpecified;
    1301              : 
    1302           15 :     ReturnErrorOnFailure(tlvWriterMsg2.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
    1303              : 
    1304           15 :     ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kResponderRandom), &input.responderRandom[0],
    1305              :                                                 sizeof(input.responderRandom)));
    1306           15 :     ReturnErrorOnFailure(tlvWriterMsg2.Put(AsTlvContextTag(Sigma2Tags::kResponderSessionId), input.responderSessionId));
    1307              : 
    1308           15 :     ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kResponderEphPubKey), *input.responderEphPubKey,
    1309              :                                                 static_cast<uint32_t>(input.responderEphPubKey->Length())));
    1310              : 
    1311           15 :     CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptTBEData2Encrypted, *input.msgR2Encrypted.Get() ^= 0xFF);
    1312              : 
    1313           15 :     ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kEncrypted2), input.msgR2Encrypted.Get(),
    1314              :                                                 static_cast<uint32_t>(input.encrypted2Length)));
    1315           15 :     input.msgR2Encrypted.Free();
    1316              : 
    1317           15 :     ReturnErrorOnFailure(
    1318              :         EncodeSessionParameters(AsTlvContextTag(Sigma2Tags::kResponderSessionParams), *input.responderMrpConfig, tlvWriterMsg2));
    1319              : 
    1320           15 :     ReturnErrorOnFailure(tlvWriterMsg2.EndContainer(outerContainerType));
    1321           15 :     ReturnErrorOnFailure(tlvWriterMsg2.Finalize(&msgR2));
    1322              : 
    1323           15 :     return CHIP_NO_ERROR;
    1324           15 : }
    1325              : 
    1326           10 : CHIP_ERROR CASESession::SendSigma2(System::PacketBufferHandle && msgR2)
    1327              : {
    1328              :     MATTER_TRACE_SCOPE("SendSigma2", "CASESession");
    1329              : 
    1330           10 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msgR2->Start(), msgR2->DataLength() }));
    1331              : 
    1332              :     // Call delegate to send the msg to peer
    1333           10 :     ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2, std::move(msgR2),
    1334              :                                                             SendFlags(SendMessageFlags::kExpectResponse)));
    1335              : 
    1336           10 :     mState = State::kSentSigma2;
    1337              : 
    1338           10 :     ChipLogProgress(SecureChannel, "Sent Sigma2 msg");
    1339              :     MATTER_TRACE_COUNTER("Sigma2");
    1340              : 
    1341           10 :     return CHIP_NO_ERROR;
    1342              : }
    1343              : 
    1344            1 : CHIP_ERROR CASESession::HandleSigma2Resume(System::PacketBufferHandle && msg)
    1345              : {
    1346              :     MATTER_TRACE_SCOPE("HandleSigma2Resume", "CASESession");
    1347            1 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1348              : 
    1349            1 :     ChipLogDetail(SecureChannel, "Received Sigma2Resume msg");
    1350              :     MATTER_TRACE_COUNTER("Sigma2Resume");
    1351              :     MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
    1352              : 
    1353            1 :     System::PacketBufferTLVReader tlvReader;
    1354            1 :     tlvReader.Init(std::move(msg));
    1355            1 :     ParsedSigma2Resume parsedSigma2Resume;
    1356            1 :     SuccessOrExit(err = ParseSigma2Resume(tlvReader, parsedSigma2Resume));
    1357              : 
    1358            1 :     SuccessOrExit(err = ValidateSigmaResumeMIC(parsedSigma2Resume.sigma2ResumeMIC, ByteSpan(mInitiatorRandom),
    1359              :                                                parsedSigma2Resume.resumptionId, ByteSpan(kKDFS2RKeyInfo),
    1360              :                                                ByteSpan(kResume2MIC_Nonce)));
    1361              : 
    1362            1 :     if (parsedSigma2Resume.responderSessionParamStructPresent)
    1363              :     {
    1364            1 :         SetRemoteSessionParameters(parsedSigma2Resume.responderSessionParams);
    1365            1 :         mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
    1366              :             GetRemoteSessionParameters());
    1367              :     }
    1368              : 
    1369            1 :     ChipLogDetail(SecureChannel, "Peer " ChipLogFormatScopedNodeId " assigned session ID %d", ChipLogValueScopedNodeId(GetPeer()),
    1370              :                   parsedSigma2Resume.responderSessionId);
    1371            1 :     SetPeerSessionId(parsedSigma2Resume.responderSessionId);
    1372              : 
    1373            1 :     if (mSessionResumptionStorage != nullptr)
    1374              :     {
    1375            2 :         CHIP_ERROR err2 = mSessionResumptionStorage->Save(
    1376            1 :             GetPeer(), SessionResumptionStorage::ConstResumptionIdView(parsedSigma2Resume.resumptionId.data()), mSharedSecret,
    1377            1 :             mPeerCATs);
    1378            1 :         if (err2 != CHIP_NO_ERROR)
    1379            0 :             ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
    1380              :     }
    1381              : 
    1382              :     MATTER_LOG_METRIC(kMetricDeviceCASESessionSigmaFinished);
    1383            1 :     SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
    1384              : 
    1385            1 :     mState = State::kFinishedViaResume;
    1386            1 :     Finish();
    1387              : 
    1388            1 : exit:
    1389            1 :     if (err != CHIP_NO_ERROR)
    1390              :     {
    1391            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
    1392              :     }
    1393            2 :     return err;
    1394            1 : }
    1395              : 
    1396           13 : CHIP_ERROR CASESession::ParseSigma2Resume(ContiguousBufferTLVReader & tlvReader, ParsedSigma2Resume & outParsedSigma2Resume)
    1397              : {
    1398           13 :     TLVType containerType = kTLVType_Structure;
    1399              : 
    1400           13 :     ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag()));
    1401           13 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
    1402              : 
    1403           13 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2ResumeTags::kResumptionID)));
    1404           12 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma2Resume.resumptionId));
    1405           12 :     VerifyOrReturnError(outParsedSigma2Resume.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize,
    1406              :                         CHIP_ERROR_INVALID_CASE_PARAMETER);
    1407              : 
    1408           10 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2ResumeTags::kSigma2ResumeMIC)));
    1409           10 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma2Resume.sigma2ResumeMIC));
    1410           10 :     VerifyOrReturnError(outParsedSigma2Resume.sigma2ResumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,
    1411              :                         CHIP_ERROR_INVALID_CASE_PARAMETER);
    1412              : 
    1413            8 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionID)));
    1414            8 :     ReturnErrorOnFailure(tlvReader.Get(outParsedSigma2Resume.responderSessionId));
    1415              : 
    1416            7 :     CHIP_ERROR err = tlvReader.Next();
    1417            7 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma2ResumeTags::kResponderSessionParams))
    1418              :     {
    1419            2 :         ReturnErrorOnFailure(DecodeSessionParametersIfPresent(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionParams), tlvReader,
    1420              :                                                               outParsedSigma2Resume.responderSessionParams));
    1421            2 :         outParsedSigma2Resume.responderSessionParamStructPresent = true;
    1422              : 
    1423            2 :         err = tlvReader.Next();
    1424              :     }
    1425              : 
    1426              :     // Future-proofing: CHIP_NO_ERROR will be returned by Next() if we have additional non-parsed TLV Elements, which could
    1427              :     // happen in the future if additional elements are added to the specification.
    1428            7 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, err);
    1429              :     // Exit Container will fail (return CHIP_END_OF_TLV) if the received encoded message is not properly terminated with an
    1430              :     // EndOfContainer TLV Element.
    1431            7 :     ReturnErrorOnFailure(tlvReader.ExitContainer(containerType));
    1432              : 
    1433            5 :     return CHIP_NO_ERROR;
    1434              : }
    1435              : 
    1436            9 : CHIP_ERROR CASESession::HandleSigma2_and_SendSigma3(System::PacketBufferHandle && msg)
    1437              : {
    1438              :     MATTER_TRACE_SCOPE("HandleSigma2_and_SendSigma3", "CASESession");
    1439            9 :     CHIP_ERROR err = HandleSigma2(std::move(msg));
    1440              :     MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
    1441            9 :     SuccessOrExit(err);
    1442              : 
    1443              :     MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma3);
    1444            8 :     err = SendSigma3a();
    1445            8 :     if (CHIP_NO_ERROR != err)
    1446              :     {
    1447              :         MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma3, err);
    1448              :     }
    1449              : 
    1450            8 : exit:
    1451            9 :     if (CHIP_NO_ERROR != err)
    1452              :     {
    1453            1 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
    1454            1 :         mState = State::kInitialized;
    1455              :     }
    1456            9 :     return err;
    1457              : }
    1458              : 
    1459            9 : CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)
    1460              : {
    1461              :     MATTER_TRACE_SCOPE("HandleSigma2", "CASESession");
    1462            9 :     ChipLogProgress(SecureChannel, "Received Sigma2 msg");
    1463              : 
    1464            9 :     VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_INTERNAL);
    1465              : 
    1466            9 :     const uint8_t * buf = msg->Start();
    1467            9 :     size_t buflen       = msg->DataLength();
    1468            9 :     VerifyOrReturnError(buf != nullptr, CHIP_ERROR_MESSAGE_INCOMPLETE);
    1469              : 
    1470            9 :     FabricId fabricId = kUndefinedFabricId;
    1471              :     {
    1472            9 :         VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1473            9 :         const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
    1474            9 :         VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1475            9 :         fabricId = fabricInfo->GetFabricId();
    1476              :     }
    1477              : 
    1478            9 :     System::PacketBufferTLVReader tlvReader;
    1479            9 :     tlvReader.Init(std::move(msg));
    1480            9 :     ParsedSigma2 parsedSigma2;
    1481            9 :     ReturnErrorOnFailure(ParseSigma2(tlvReader, parsedSigma2));
    1482              : 
    1483              :     //  ParseSigma2 ensures that:
    1484              :     //  mRemotePubKey.Length() == responderEphPubKey.size() == kP256_PublicKey_Length.
    1485            9 :     memcpy(mRemotePubKey.Bytes(), parsedSigma2.responderEphPubKey.data(), mRemotePubKey.Length());
    1486              : 
    1487              :     // Generate a Shared Secret
    1488            9 :     ReturnErrorOnFailure(mEphemeralKey->ECDH_derive_secret(mRemotePubKey, mSharedSecret));
    1489              : 
    1490              :     // Generate the S2K key
    1491            9 :     AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore());
    1492              :     {
    1493              :         uint8_t msg_salt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length];
    1494            9 :         MutableByteSpan saltSpan(msg_salt);
    1495            9 :         ReturnErrorOnFailure(ConstructSaltSigma2(parsedSigma2.responderRandom, mRemotePubKey, ByteSpan(mIPK), saltSpan));
    1496            9 :         ReturnErrorOnFailure(DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k));
    1497              :     }
    1498              :     // Msg2 should only be added to MessageDigest after we construct SaltSigma2 that is used to derive S2K,
    1499              :     // Because constructing SaltSigma2 uses the MessageDigest at a point when it should only include Msg1.
    1500            9 :     ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ buf, buflen }));
    1501              : 
    1502            9 :     ReturnErrorOnFailure(AES_CCM_decrypt(parsedSigma2.msgR2EncryptedPayload.data(), parsedSigma2.msgR2EncryptedPayload.size(),
    1503              :                                          nullptr, 0, parsedSigma2.msgR2MIC.data(), parsedSigma2.msgR2MIC.size(), sr2k.KeyHandle(),
    1504              :                                          kTBEData2_Nonce, kTBEDataNonceLength, parsedSigma2.msgR2EncryptedPayload.data()));
    1505              : 
    1506            9 :     parsedSigma2.msgR2Decrypted = std::move(parsedSigma2.msgR2Encrypted);
    1507            9 :     size_t msgR2DecryptedLength = parsedSigma2.msgR2EncryptedPayload.size();
    1508              : 
    1509            9 :     ContiguousBufferTLVReader decryptedDataTlvReader;
    1510            9 :     decryptedDataTlvReader.Init(parsedSigma2.msgR2Decrypted.Get(), msgR2DecryptedLength);
    1511            9 :     ParsedSigma2TBEData parsedSigma2TBEData;
    1512            9 :     ReturnErrorOnFailure(ParseSigma2TBEData(decryptedDataTlvReader, parsedSigma2TBEData));
    1513              : 
    1514              :     // Validate responder identity located in msgR2Decrypted
    1515              :     // Constructing responder identity
    1516            9 :     P256PublicKey responderPublicKey;
    1517              :     {
    1518              :         NodeId responderNodeId;
    1519              : 
    1520              :         CompressedFabricId unused;
    1521              :         FabricId responderFabricId;
    1522            9 :         ReturnErrorOnFailure(SetEffectiveTime());
    1523            9 :         ReturnErrorOnFailure(mFabricsTable->VerifyCredentials(mFabricIndex, parsedSigma2TBEData.responderNOC,
    1524              :                                                               parsedSigma2TBEData.responderICAC, mValidContext, unused,
    1525              :                                                               responderFabricId, responderNodeId, responderPublicKey));
    1526            9 :         VerifyOrReturnError(fabricId == responderFabricId, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1527              :         // Verify that responderNodeId (from responderNOC) matches one that was included
    1528              :         // in the computation of the Destination Identifier when generating Sigma1.
    1529            9 :         VerifyOrReturnError(mPeerNodeId == responderNodeId, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1530              :     }
    1531              : 
    1532              :     // Construct msgR2Signed and validate the signature in msgR2Decrypted.
    1533            9 :     size_t msgR2SignedLen = EstimateStructOverhead(parsedSigma2TBEData.responderNOC.size(),  // resonderNOC
    1534              :                                                    parsedSigma2TBEData.responderICAC.size(), // responderICAC
    1535              :                                                    kP256_PublicKey_Length,                   // responderEphPubKey
    1536              :                                                    kP256_PublicKey_Length                    // initiatorEphPubKey
    1537              :     );
    1538              : 
    1539            9 :     chip::Platform::ScopedMemoryBuffer<uint8_t> msgR2Signed;
    1540            9 :     VerifyOrReturnError(msgR2Signed.Alloc(msgR2SignedLen), CHIP_ERROR_NO_MEMORY);
    1541            9 :     MutableByteSpan msgR2SignedSpan{ msgR2Signed.Get(), msgR2SignedLen };
    1542              : 
    1543            9 :     ReturnErrorOnFailure(ConstructTBSData(parsedSigma2TBEData.responderNOC, parsedSigma2TBEData.responderICAC,
    1544              :                                           ByteSpan(mRemotePubKey, mRemotePubKey.Length()),
    1545              :                                           ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), msgR2SignedSpan));
    1546              : 
    1547              :     // Validate signature
    1548            9 :     ReturnErrorOnFailure(responderPublicKey.ECDSA_validate_msg_signature(msgR2SignedSpan.data(), msgR2SignedSpan.size(),
    1549              :                                                                          parsedSigma2TBEData.tbsData2Signature));
    1550              : 
    1551            8 :     ChipLogDetail(SecureChannel, "Peer " ChipLogFormatScopedNodeId " assigned session ID %d", ChipLogValueScopedNodeId(GetPeer()),
    1552              :                   parsedSigma2.responderSessionId);
    1553            8 :     SetPeerSessionId(parsedSigma2.responderSessionId);
    1554              : 
    1555            8 :     std::copy(parsedSigma2TBEData.resumptionId.begin(), parsedSigma2TBEData.resumptionId.end(), mNewResumptionId.begin());
    1556              : 
    1557              :     // Retrieve peer CASE Authenticated Tags (CATs) from peer's NOC.
    1558            8 :     ReturnErrorOnFailure(ExtractCATsFromOpCert(parsedSigma2TBEData.responderNOC, mPeerCATs));
    1559              : 
    1560            8 :     if (parsedSigma2.responderSessionParamStructPresent)
    1561              :     {
    1562            8 :         SetRemoteSessionParameters(parsedSigma2.responderSessionParams);
    1563            8 :         mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
    1564              :             GetRemoteSessionParameters());
    1565              :     }
    1566              : 
    1567            8 :     return CHIP_NO_ERROR;
    1568            9 : }
    1569              : 
    1570           23 : CHIP_ERROR CASESession::ParseSigma2(ContiguousBufferTLVReader & tlvReader, ParsedSigma2 & outParsedSigma2)
    1571              : {
    1572           23 :     TLVType containerType = kTLVType_Structure;
    1573              : 
    1574           23 :     ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag()));
    1575           23 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
    1576              : 
    1577              :     // Retrieve Responder's Random value
    1578           23 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2Tags::kResponderRandom)));
    1579           22 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma2.responderRandom));
    1580           22 :     VerifyOrReturnError(outParsedSigma2.responderRandom.size() == kSigmaParamRandomNumberSize, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1581              : 
    1582              :     // Assign Session ID
    1583           20 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2Tags::kResponderSessionId)));
    1584           20 :     ReturnErrorOnFailure(tlvReader.Get(outParsedSigma2.responderSessionId));
    1585              : 
    1586              :     // Retrieve Responder's Ephemeral Pubkey
    1587           19 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2Tags::kResponderEphPubKey)));
    1588           19 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma2.responderEphPubKey));
    1589           19 :     VerifyOrReturnError(outParsedSigma2.responderEphPubKey.size() == kP256_PublicKey_Length, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1590              : 
    1591              :     // Generate decrypted data
    1592           17 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2Tags::kEncrypted2)));
    1593              : 
    1594           17 :     size_t maxMsgR2SignedEncLen = EstimateStructOverhead(kMaxCHIPCertLength,                          // responderNOC
    1595              :                                                          kMaxCHIPCertLength,                          // responderICAC
    1596              :                                                          kMax_ECDSA_Signature_Length,                 // signature
    1597              :                                                          SessionResumptionStorage::kResumptionIdSize, // resumptionID
    1598              :                                                          kCaseOverheadForFutureTBEData // extra bytes for future-proofing
    1599              :     );
    1600              : 
    1601           17 :     size_t msgR2EncryptedLenWithTag = tlvReader.GetLength();
    1602              : 
    1603              :     // Validate we did not receive a buffer larger than legal
    1604           17 :     VerifyOrReturnError(msgR2EncryptedLenWithTag <= maxMsgR2SignedEncLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
    1605           16 :     VerifyOrReturnError(msgR2EncryptedLenWithTag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_TLV_ELEMENT);
    1606           15 :     VerifyOrReturnError(outParsedSigma2.msgR2Encrypted.Alloc(msgR2EncryptedLenWithTag), CHIP_ERROR_NO_MEMORY);
    1607           15 :     ReturnErrorOnFailure(tlvReader.GetBytes(outParsedSigma2.msgR2Encrypted.Get(), outParsedSigma2.msgR2Encrypted.AllocatedSize()));
    1608              : 
    1609           15 :     size_t msgR2EncryptedPayloadLen       = msgR2EncryptedLenWithTag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES;
    1610           15 :     outParsedSigma2.msgR2EncryptedPayload = MutableByteSpan(outParsedSigma2.msgR2Encrypted.Get(), msgR2EncryptedPayloadLen);
    1611           15 :     outParsedSigma2.msgR2MIC =
    1612           15 :         ByteSpan(outParsedSigma2.msgR2Encrypted.Get() + msgR2EncryptedPayloadLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
    1613              : 
    1614              :     // Retrieve responderSessionParams if present
    1615           15 :     CHIP_ERROR err = tlvReader.Next();
    1616           15 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma2Tags::kResponderSessionParams))
    1617              :     {
    1618           10 :         ReturnErrorOnFailure(DecodeSessionParametersIfPresent(AsTlvContextTag(Sigma2Tags::kResponderSessionParams), tlvReader,
    1619              :                                                               outParsedSigma2.responderSessionParams));
    1620           10 :         outParsedSigma2.responderSessionParamStructPresent = true;
    1621              : 
    1622           10 :         err = tlvReader.Next();
    1623              :     }
    1624              : 
    1625              :     // Future-proofing: CHIP_NO_ERROR will be returned by Next() if we have additional non-parsed TLV Elements, which could
    1626              :     // happen in the future if additional elements are added to the specification.
    1627           15 :     VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, err);
    1628              : 
    1629              :     // Exit Container will fail (return CHIP_END_OF_TLV) if the received encoded message is not properly terminated with an
    1630              :     // EndOfContainer TLV Element.
    1631           15 :     ReturnErrorOnFailure(tlvReader.ExitContainer(containerType));
    1632              : 
    1633           13 :     return CHIP_NO_ERROR;
    1634              : }
    1635              : 
    1636           20 : CHIP_ERROR CASESession::ParseSigma2TBEData(ContiguousBufferTLVReader & decryptedDataTlvReader,
    1637              :                                            ParsedSigma2TBEData & outParsedSigma2TBE)
    1638              : {
    1639           20 :     TLVType containerType = kTLVType_Structure;
    1640              : 
    1641           20 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next(containerType, AnonymousTag()));
    1642           20 :     ReturnErrorOnFailure(decryptedDataTlvReader.EnterContainer(containerType));
    1643              : 
    1644           20 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next(AsTlvContextTag(TBEDataTags::kSenderNOC)));
    1645           19 :     ReturnErrorOnFailure(decryptedDataTlvReader.GetByteView(outParsedSigma2TBE.responderNOC));
    1646           19 :     VerifyOrReturnError(outParsedSigma2TBE.responderNOC.size() <= kMaxCHIPCertLength, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1647              : 
    1648           18 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next());
    1649           18 :     if (decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSenderICAC))
    1650              :     {
    1651           18 :         ReturnErrorOnFailure(decryptedDataTlvReader.GetByteView(outParsedSigma2TBE.responderICAC));
    1652           18 :         VerifyOrReturnError(outParsedSigma2TBE.responderICAC.size() <= kMaxCHIPCertLength, CHIP_ERROR_INVALID_CASE_PARAMETER);
    1653              : 
    1654           17 :         ReturnErrorOnFailure(decryptedDataTlvReader.Next(kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSignature)));
    1655              :     }
    1656              : 
    1657           17 :     VerifyOrReturnError(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), CHIP_ERROR_INVALID_TLV_TAG);
    1658              :     // tbsData2Signature's length should equal kMax_ECDSA_Signature_Length as per the Specification
    1659           17 :     size_t signatureLen = decryptedDataTlvReader.GetLength();
    1660           17 :     VerifyOrReturnError(outParsedSigma2TBE.tbsData2Signature.Capacity() == signatureLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
    1661           15 :     outParsedSigma2TBE.tbsData2Signature.SetLength(signatureLen);
    1662           15 :     ReturnErrorOnFailure(decryptedDataTlvReader.GetBytes(outParsedSigma2TBE.tbsData2Signature.Bytes(),
    1663              :                                                          outParsedSigma2TBE.tbsData2Signature.Length()));
    1664              : 
    1665              :     // Retrieve session resumption ID
    1666           15 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next(AsTlvContextTag(TBEDataTags::kResumptionID)));
    1667           15 :     ReturnErrorOnFailure(decryptedDataTlvReader.GetByteView(outParsedSigma2TBE.resumptionId));
    1668           15 :     VerifyOrReturnError(outParsedSigma2TBE.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize,
    1669              :                         CHIP_ERROR_INVALID_CASE_PARAMETER);
    1670              : 
    1671              :     // Exit Container will fail (return CHIP_END_OF_TLV) if the received encoded message is not properly terminated with an
    1672              :     // EndOfContainer TLV Element.
    1673           13 :     ReturnErrorOnFailure(decryptedDataTlvReader.ExitContainer(containerType));
    1674              : 
    1675           11 :     return CHIP_NO_ERROR;
    1676              : }
    1677              : 
    1678            8 : CHIP_ERROR CASESession::SendSigma3a()
    1679              : {
    1680              :     MATTER_TRACE_SCOPE("SendSigma3", "CASESession");
    1681              : 
    1682            8 :     ChipLogDetail(SecureChannel, "Sending Sigma3");
    1683              : 
    1684            8 :     auto helper = WorkHelper<SendSigma3Data>::Create(*this, &SendSigma3b, &CASESession::SendSigma3c);
    1685            8 :     VerifyOrReturnError(helper, CHIP_ERROR_NO_MEMORY);
    1686              :     {
    1687            8 :         auto & data = helper->mData;
    1688              : 
    1689            8 :         VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1690            8 :         data.fabricIndex = mFabricIndex;
    1691            8 :         data.fabricTable = nullptr;
    1692            8 :         data.keystore    = nullptr;
    1693              : 
    1694              :         {
    1695            8 :             const FabricInfo * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
    1696            8 :             VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_KEY_NOT_FOUND);
    1697            8 :             auto * keystore = mFabricsTable->GetOperationalKeystore();
    1698            8 :             if (!fabricInfo->HasOperationalKey() && keystore != nullptr && keystore->SupportsSignWithOpKeypairInBackground())
    1699              :             {
    1700              :                 // NOTE: used to sign in background.
    1701            0 :                 data.keystore = keystore;
    1702              :             }
    1703              :             else
    1704              :             {
    1705              :                 // NOTE: used to sign in foreground.
    1706            8 :                 data.fabricTable = mFabricsTable;
    1707              :             }
    1708              :         }
    1709              : 
    1710            8 :         VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_INTERNAL);
    1711              : 
    1712            8 :         VerifyOrReturnError(data.icacBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
    1713            8 :         data.icaCert = MutableByteSpan{ data.icacBuf.Get(), kMaxCHIPCertLength };
    1714              : 
    1715            8 :         VerifyOrReturnError(data.nocBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
    1716            8 :         data.nocCert = MutableByteSpan{ data.nocBuf.Get(), kMaxCHIPCertLength };
    1717              : 
    1718            8 :         ReturnErrorOnFailure(mFabricsTable->FetchICACert(mFabricIndex, data.icaCert));
    1719            8 :         ReturnErrorOnFailure(mFabricsTable->FetchNOCCert(mFabricIndex, data.nocCert));
    1720              : 
    1721            8 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma3NOC, *data.nocCert.data() ^= 0xFF);
    1722            8 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma3ICAC, *data.icaCert.data() ^= 0xFF);
    1723              : 
    1724            8 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma3InitiatorEphPubKey,
    1725              :                           *(mEphemeralKey->TestOnlyMutablePubkey().Bytes()) ^= 0xFF);
    1726              : 
    1727            8 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma3ResponderEphPubKey, *mRemotePubKey ^= 0xFF);
    1728              : 
    1729              :         // Prepare Sigma3 TBS Data Blob
    1730            8 :         size_t msgR3SignedLen = EstimateStructOverhead(data.nocCert.size(),    // initiatorNOC
    1731              :                                                        data.icaCert.size(),    // initiatorICAC
    1732              :                                                        kP256_PublicKey_Length, // initiatorEphPubKey
    1733              :                                                        kP256_PublicKey_Length  // responderEphPubKey
    1734              :         );
    1735              : 
    1736            8 :         VerifyOrReturnError(data.msgR3Signed.Alloc(msgR3SignedLen), CHIP_ERROR_NO_MEMORY);
    1737            8 :         data.msgR3SignedSpan = MutableByteSpan{ data.msgR3Signed.Get(), msgR3SignedLen };
    1738              : 
    1739            8 :         ReturnErrorOnFailure(ConstructTBSData(data.nocCert, data.icaCert,
    1740              :                                               ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
    1741              :                                               ByteSpan(mRemotePubKey, mRemotePubKey.Length()), data.msgR3SignedSpan));
    1742              : 
    1743            8 :         if (data.keystore != nullptr)
    1744              :         {
    1745            0 :             ReturnErrorOnFailure(helper->ScheduleWork());
    1746            0 :             mSendSigma3Helper = helper;
    1747            0 :             mExchangeCtxt.Value()->WillSendMessage();
    1748            0 :             mState = State::kSendSigma3Pending;
    1749              :         }
    1750              :         else
    1751              :         {
    1752            8 :             ReturnErrorOnFailure(helper->DoWork());
    1753              :         }
    1754              :     }
    1755              : 
    1756            8 :     return CHIP_NO_ERROR;
    1757            8 : }
    1758              : 
    1759            8 : CHIP_ERROR CASESession::SendSigma3b(SendSigma3Data & data, bool & cancel)
    1760              : {
    1761              :     // Generate a signature
    1762            8 :     if (data.keystore != nullptr)
    1763              :     {
    1764              :         // Recommended case: delegate to operational keystore
    1765            0 :         ReturnErrorOnFailure(data.keystore->SignWithOpKeypair(data.fabricIndex, data.msgR3SignedSpan, data.tbsData3Signature));
    1766              :     }
    1767              :     else
    1768              :     {
    1769              :         // Legacy case: delegate to fabric table fabric info
    1770            8 :         ReturnErrorOnFailure(data.fabricTable->SignWithOpKeypair(data.fabricIndex, data.msgR3SignedSpan, data.tbsData3Signature));
    1771              :     }
    1772              : 
    1773            8 :     CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptSigma3Signature, *data.tbsData3Signature.Bytes() ^= 0xFF);
    1774              : 
    1775              :     // Prepare Sigma3 TBE Data Blob
    1776            8 :     data.msg_r3_encrypted_len =
    1777            8 :         TLV::EstimateStructOverhead(data.nocCert.size(), data.icaCert.size(), data.tbsData3Signature.Length());
    1778              : 
    1779            8 :     VerifyOrReturnError(data.msg_R3_Encrypted.Alloc(data.msg_r3_encrypted_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES),
    1780              :                         CHIP_ERROR_NO_MEMORY);
    1781              : 
    1782              :     {
    1783            8 :         TLVWriter tlvWriter;
    1784            8 :         TLVType outerContainerType = kTLVType_NotSpecified;
    1785              : 
    1786            8 :         tlvWriter.Init(data.msg_R3_Encrypted.Get(), data.msg_r3_encrypted_len);
    1787            8 :         ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
    1788            8 :         ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderNOC), data.nocCert));
    1789            8 :         if (!data.icaCert.empty())
    1790              :         {
    1791            0 :             ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderICAC), data.icaCert));
    1792              :         }
    1793              : 
    1794              :         // We are now done with ICAC and NOC certs so we can release the memory.
    1795              :         {
    1796            8 :             data.icacBuf.Free();
    1797            8 :             data.icaCert = MutableByteSpan{};
    1798              : 
    1799            8 :             data.nocBuf.Free();
    1800            8 :             data.nocCert = MutableByteSpan{};
    1801              :         }
    1802              : 
    1803            8 :         ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(TBEDataTags::kSignature), data.tbsData3Signature.ConstBytes(),
    1804              :                                                 static_cast<uint32_t>(data.tbsData3Signature.Length())));
    1805            8 :         ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    1806            8 :         ReturnErrorOnFailure(tlvWriter.Finalize());
    1807            8 :         data.msg_r3_encrypted_len = static_cast<size_t>(tlvWriter.GetLengthWritten());
    1808              :     }
    1809              : 
    1810            8 :     return CHIP_NO_ERROR;
    1811              : }
    1812              : 
    1813            8 : CHIP_ERROR CASESession::SendSigma3c(SendSigma3Data & data, CHIP_ERROR status)
    1814              : {
    1815            8 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1816              : 
    1817            8 :     System::PacketBufferHandle msg_R3;
    1818              :     size_t data_len;
    1819              : 
    1820              :     uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length];
    1821              : 
    1822            8 :     AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore());
    1823              : 
    1824            8 :     VerifyOrDieWithMsg(data.keystore == nullptr || mState == State::kSendSigma3Pending, SecureChannel, "Bad internal state.");
    1825              : 
    1826            8 :     SuccessOrExit(err = status);
    1827              : 
    1828              :     // Generate S3K key
    1829              :     {
    1830            8 :         MutableByteSpan saltSpan(msg_salt);
    1831            8 :         SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan));
    1832            8 :         SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k));
    1833              :     }
    1834              : 
    1835              :     // Generated Encrypted data blob
    1836            8 :     SuccessOrExit(err =
    1837              :                       AES_CCM_encrypt(data.msg_R3_Encrypted.Get(), data.msg_r3_encrypted_len, nullptr, 0, sr3k.KeyHandle(),
    1838              :                                       kTBEData3_Nonce, kTBEDataNonceLength, data.msg_R3_Encrypted.Get(),
    1839              :                                       data.msg_R3_Encrypted.Get() + data.msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
    1840              : 
    1841              :     // Generate Sigma3 Msg
    1842            8 :     data_len = TLV::EstimateStructOverhead(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, data.msg_r3_encrypted_len);
    1843              : 
    1844            8 :     msg_R3 = System::PacketBufferHandle::New(data_len);
    1845            8 :     VerifyOrExit(!msg_R3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
    1846              : 
    1847              :     {
    1848            8 :         System::PacketBufferTLVWriter tlvWriter;
    1849            8 :         TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
    1850              : 
    1851            8 :         tlvWriter.Init(std::move(msg_R3));
    1852            8 :         err = tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType);
    1853            8 :         SuccessOrExit(err);
    1854            8 :         CHIP_FAULT_INJECT(FaultInjection::kFault_CASECorruptTBEData3Encrypted, *data.msg_R3_Encrypted.Get() ^= 0xFF);
    1855            8 :         err = tlvWriter.PutBytes(AsTlvContextTag(Sigma3Tags::kEncrypted3), data.msg_R3_Encrypted.Get(),
    1856            8 :                                  static_cast<uint32_t>(data.msg_r3_encrypted_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
    1857            8 :         SuccessOrExit(err);
    1858            8 :         err = tlvWriter.EndContainer(outerContainerType);
    1859            8 :         SuccessOrExit(err);
    1860            8 :         err = tlvWriter.Finalize(&msg_R3);
    1861            8 :         SuccessOrExit(err);
    1862            8 :     }
    1863              : 
    1864            8 :     err = mCommissioningHash.AddData(ByteSpan{ msg_R3->Start(), msg_R3->DataLength() });
    1865            8 :     SuccessOrExit(err);
    1866              : 
    1867              :     // Call delegate to send the Msg3 to peer
    1868           16 :     err = mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma3, std::move(msg_R3),
    1869            8 :                                              SendFlags(SendMessageFlags::kExpectResponse));
    1870            8 :     SuccessOrExit(err);
    1871              : 
    1872            8 :     ChipLogProgress(SecureChannel, "Sent Sigma3 msg");
    1873              : 
    1874              :     {
    1875            8 :         MutableByteSpan messageDigestSpan(mMessageDigest);
    1876            8 :         SuccessOrExit(err = mCommissioningHash.Finish(messageDigestSpan));
    1877              :     }
    1878              : 
    1879            8 :     mState = State::kSentSigma3;
    1880              : 
    1881            8 : exit:
    1882            8 :     mSendSigma3Helper.reset();
    1883              : 
    1884              :     // If data.keystore is set, processing occurred in the background, so if an error occurred,
    1885              :     // need to send status report (normally occurs in SendSigma3a), and discard exchange and
    1886              :     // abort pending establish (normally occurs in OnMessageReceived).
    1887            8 :     if (data.keystore != nullptr && err != CHIP_NO_ERROR)
    1888              :     {
    1889            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
    1890            0 :         DiscardExchange();
    1891            0 :         AbortPendingEstablish(err);
    1892              :     }
    1893              : 
    1894           16 :     return err;
    1895            8 : }
    1896              : 
    1897            8 : CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg)
    1898              : {
    1899              :     MATTER_TRACE_SCOPE("HandleSigma3", "CASESession");
    1900            8 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1901            8 :     ContiguousBufferTLVReader decryptedDataTlvReader;
    1902            8 :     TLVType containerType = kTLVType_Structure;
    1903              : 
    1904            8 :     const uint8_t * buf = msg->Start();
    1905            8 :     const size_t bufLen = msg->DataLength();
    1906              : 
    1907            8 :     AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore());
    1908              : 
    1909              :     uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length];
    1910              : 
    1911            8 :     ChipLogProgress(SecureChannel, "Received Sigma3 msg");
    1912              :     MATTER_TRACE_COUNTER("Sigma3");
    1913              :     MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err);
    1914              : 
    1915            8 :     auto helper = WorkHelper<HandleSigma3Data>::Create(*this, &HandleSigma3b, &CASESession::HandleSigma3c);
    1916            8 :     VerifyOrExit(helper, err = CHIP_ERROR_NO_MEMORY);
    1917              :     {
    1918            8 :         auto & data = helper->mData;
    1919              : 
    1920              :         {
    1921            8 :             VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    1922            8 :             const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
    1923            8 :             VerifyOrExit(fabricInfo != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
    1924            8 :             data.fabricId = fabricInfo->GetFabricId();
    1925              :         }
    1926              : 
    1927            8 :         VerifyOrExit(mEphemeralKey != nullptr, err = CHIP_ERROR_INTERNAL);
    1928              : 
    1929              :         // Step 1
    1930              :         // msgR3Encrypted will be allocated and initialised within ParseSigma3()
    1931            8 :         Platform::ScopedMemoryBufferWithSize<uint8_t> msgR3Encrypted;
    1932              :         // both msgR3EncryptedPayload and msgR3MIC will become backed by msgR3Encrypted in ParseSigma3()
    1933            8 :         MutableByteSpan msgR3EncryptedPayload;
    1934            8 :         ByteSpan msgR3MIC;
    1935              :         {
    1936            8 :             System::PacketBufferTLVReader tlvReader;
    1937            8 :             tlvReader.Init(std::move(msg));
    1938            8 :             SuccessOrExit(err = ParseSigma3(tlvReader, msgR3Encrypted, msgR3EncryptedPayload, msgR3MIC));
    1939              : 
    1940              :             // Generate the S3K key
    1941            8 :             MutableByteSpan saltSpan(msg_salt);
    1942            8 :             SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan));
    1943            8 :             SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k));
    1944              : 
    1945              :             // Add Sigma3 to the TranscriptHash which will be used to generate the Session Encryption Keys
    1946            8 :             SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, bufLen }));
    1947            8 :         }
    1948              :         // Step 2 - Decrypt data blob
    1949            8 :         SuccessOrExit(err = AES_CCM_decrypt(msgR3EncryptedPayload.data(), msgR3EncryptedPayload.size(), nullptr, 0, msgR3MIC.data(),
    1950              :                                             msgR3MIC.size(), sr3k.KeyHandle(), kTBEData3_Nonce, kTBEDataNonceLength,
    1951              :                                             msgR3EncryptedPayload.data()));
    1952              : 
    1953            8 :         decryptedDataTlvReader.Init(msgR3EncryptedPayload.data(), msgR3EncryptedPayload.size());
    1954            8 :         SuccessOrExit(err = ParseSigma3TBEData(decryptedDataTlvReader, data));
    1955              : 
    1956              :         // Step 3 - Construct Sigma3 TBS Data
    1957            8 :         size_t msgR3SignedLen = TLV::EstimateStructOverhead(data.initiatorNOC.size(),  // initiatorNOC
    1958              :                                                             data.initiatorICAC.size(), // initiatorICAC
    1959              :                                                             kP256_PublicKey_Length,    // initiatorEphPubKey
    1960              :                                                             kP256_PublicKey_Length     // responderEphPubKey
    1961              :         );
    1962              : 
    1963            8 :         VerifyOrExit(data.msgR3Signed.Alloc(msgR3SignedLen), err = CHIP_ERROR_NO_MEMORY);
    1964            8 :         data.msgR3SignedSpan = MutableByteSpan{ data.msgR3Signed.Get(), msgR3SignedLen };
    1965              : 
    1966            8 :         SuccessOrExit(err = ConstructTBSData(data.initiatorNOC, data.initiatorICAC, ByteSpan(mRemotePubKey, mRemotePubKey.Length()),
    1967              :                                              ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
    1968              :                                              data.msgR3SignedSpan));
    1969              : 
    1970              :         // Prepare for Step 4/5
    1971              :         {
    1972            8 :             MutableByteSpan fabricRCAC{ data.rootCertBuf };
    1973            8 :             SuccessOrExit(err = mFabricsTable->FetchRootCert(mFabricIndex, fabricRCAC));
    1974            8 :             data.fabricRCAC = fabricRCAC;
    1975              :             // TODO probably should make SetEffectiveTime static and call closer to VerifyCredentials
    1976            8 :             SuccessOrExit(err = SetEffectiveTime());
    1977              :         }
    1978              : 
    1979              :         // Copy remaining needed data into work structure
    1980              :         {
    1981            8 :             data.validContext = mValidContext;
    1982              : 
    1983              :             // initiatorNOC and initiatorICAC are spans into msgR3Encrypted
    1984              :             // which is going away, so to save memory, redirect them to their
    1985              :             // copies in msgR3Signed, which is staying around
    1986            8 :             TLV::ContiguousBufferTLVReader signedDataTlvReader;
    1987            8 :             signedDataTlvReader.Init(data.msgR3SignedSpan);
    1988            8 :             SuccessOrExit(err = signedDataTlvReader.Next(containerType, AnonymousTag()));
    1989            8 :             SuccessOrExit(err = signedDataTlvReader.EnterContainer(containerType));
    1990              : 
    1991            8 :             SuccessOrExit(err = signedDataTlvReader.Next(AsTlvContextTag(TBSDataTags::kSenderNOC)));
    1992            8 :             SuccessOrExit(err = signedDataTlvReader.GetByteView(data.initiatorNOC));
    1993              : 
    1994            8 :             if (!data.initiatorICAC.empty())
    1995              :             {
    1996            0 :                 SuccessOrExit(err = signedDataTlvReader.Next(AsTlvContextTag(TBSDataTags::kSenderICAC)));
    1997            0 :                 SuccessOrExit(err = signedDataTlvReader.GetByteView(data.initiatorICAC));
    1998              :             }
    1999              : 
    2000            8 :             SuccessOrExit(err = signedDataTlvReader.ExitContainer(containerType));
    2001              :         }
    2002              : 
    2003            8 :         SuccessOrExit(err = helper->ScheduleWork());
    2004            8 :         mHandleSigma3Helper = helper;
    2005            8 :         mExchangeCtxt.Value()->WillSendMessage();
    2006            8 :         mState = State::kHandleSigma3Pending;
    2007            8 :     }
    2008              : 
    2009            8 : exit:
    2010            8 :     if (err != CHIP_NO_ERROR)
    2011              :     {
    2012            0 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
    2013              :     }
    2014              : 
    2015           16 :     return err;
    2016            8 : }
    2017              : 
    2018           15 : CHIP_ERROR CASESession::ParseSigma3(ContiguousBufferTLVReader & tlvReader,
    2019              :                                     Platform::ScopedMemoryBufferWithSize<uint8_t> & outMsgR3Encrypted,
    2020              :                                     MutableByteSpan & outMsgR3EncryptedPayload, ByteSpan & outMsgR3MIC)
    2021              : {
    2022           15 :     TLVType containerType = kTLVType_Structure;
    2023              : 
    2024           15 :     ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag()));
    2025           15 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
    2026              : 
    2027              :     // Fetch encrypted data
    2028           15 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma3Tags::kEncrypted3)));
    2029              : 
    2030           14 :     size_t maxMsgR3SignedEncLen = EstimateStructOverhead(kMaxCHIPCertLength,           // initiatorNOC
    2031              :                                                          kMaxCHIPCertLength,           // initiatorICAC
    2032              :                                                          kMax_ECDSA_Signature_Length,  // signature
    2033              :                                                          kCaseOverheadForFutureTBEData // extra bytes for future-proofing
    2034              :     );
    2035              : 
    2036           14 :     size_t msgR3EncryptedLenWithTag = tlvReader.GetLength();
    2037              : 
    2038              :     // Validate we did not receive a buffer larger than legal
    2039           14 :     VerifyOrReturnError(msgR3EncryptedLenWithTag <= maxMsgR3SignedEncLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
    2040           13 :     VerifyOrReturnError(msgR3EncryptedLenWithTag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_TLV_ELEMENT);
    2041           12 :     VerifyOrReturnError(outMsgR3Encrypted.Alloc(msgR3EncryptedLenWithTag), CHIP_ERROR_NO_MEMORY);
    2042           12 :     ReturnErrorOnFailure(tlvReader.GetBytes(outMsgR3Encrypted.Get(), outMsgR3Encrypted.AllocatedSize()));
    2043              : 
    2044           12 :     size_t msgR3EncryptedPayloadLen = msgR3EncryptedLenWithTag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES;
    2045           12 :     outMsgR3EncryptedPayload        = MutableByteSpan(outMsgR3Encrypted.Get(), msgR3EncryptedPayloadLen);
    2046           12 :     outMsgR3MIC = ByteSpan(outMsgR3Encrypted.Get() + msgR3EncryptedPayloadLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
    2047              : 
    2048           12 :     ReturnErrorOnFailure(tlvReader.ExitContainer(containerType));
    2049              : 
    2050           10 :     return CHIP_NO_ERROR;
    2051              : }
    2052              : 
    2053           17 : CHIP_ERROR CASESession::ParseSigma3TBEData(ContiguousBufferTLVReader & decryptedDataTlvReader,
    2054              :                                            HandleSigma3Data & outHandleSigma3TBEData)
    2055              : {
    2056              : 
    2057           17 :     TLVType containerType = kTLVType_Structure;
    2058           17 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next(containerType, TLV::AnonymousTag()));
    2059           17 :     ReturnErrorOnFailure(decryptedDataTlvReader.EnterContainer(containerType));
    2060              : 
    2061           17 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next(AsTlvContextTag(TBEDataTags::kSenderNOC)));
    2062           16 :     ReturnErrorOnFailure(decryptedDataTlvReader.GetByteView(outHandleSigma3TBEData.initiatorNOC));
    2063           16 :     VerifyOrReturnError(outHandleSigma3TBEData.initiatorNOC.size() <= kMaxCHIPCertLength, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2064              : 
    2065           15 :     ReturnErrorOnFailure(decryptedDataTlvReader.Next());
    2066           15 :     if (decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSenderICAC))
    2067              :     {
    2068            7 :         ReturnErrorOnFailure(decryptedDataTlvReader.GetByteView(outHandleSigma3TBEData.initiatorICAC));
    2069            7 :         VerifyOrReturnError(outHandleSigma3TBEData.initiatorICAC.size() <= kMaxCHIPCertLength, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2070            6 :         ReturnErrorOnFailure(decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSignature)));
    2071              :     }
    2072              : 
    2073           14 :     VerifyOrReturnError(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), CHIP_ERROR_INVALID_TLV_TAG);
    2074           14 :     size_t signatureLen = decryptedDataTlvReader.GetLength();
    2075           14 :     VerifyOrReturnError(outHandleSigma3TBEData.tbsData3Signature.Capacity() == signatureLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
    2076           12 :     outHandleSigma3TBEData.tbsData3Signature.SetLength(signatureLen);
    2077           12 :     ReturnErrorOnFailure(decryptedDataTlvReader.GetBytes(outHandleSigma3TBEData.tbsData3Signature.Bytes(),
    2078              :                                                          outHandleSigma3TBEData.tbsData3Signature.Length()));
    2079              : 
    2080           12 :     ReturnErrorOnFailure(decryptedDataTlvReader.ExitContainer(containerType));
    2081              : 
    2082           10 :     return CHIP_NO_ERROR;
    2083              : }
    2084              : 
    2085            8 : CHIP_ERROR CASESession::HandleSigma3b(HandleSigma3Data & data, bool & cancel)
    2086              : {
    2087              :     // Step 5/6
    2088              :     // Validate initiator identity located in msg->Start()
    2089              :     // Constructing responder identity
    2090              :     CompressedFabricId unused;
    2091              :     FabricId initiatorFabricId;
    2092            8 :     P256PublicKey initiatorPublicKey;
    2093            8 :     ReturnErrorOnFailure(FabricTable::VerifyCredentials(data.initiatorNOC, data.initiatorICAC, data.fabricRCAC, data.validContext,
    2094              :                                                         unused, initiatorFabricId, data.initiatorNodeId, initiatorPublicKey));
    2095            8 :     VerifyOrReturnError(data.fabricId == initiatorFabricId, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2096              : 
    2097              :     // Step 7 - Validate Signature
    2098            8 :     ReturnErrorOnFailure(initiatorPublicKey.ECDSA_validate_msg_signature(data.msgR3SignedSpan.data(), data.msgR3SignedSpan.size(),
    2099              :                                                                          data.tbsData3Signature));
    2100              : 
    2101            7 :     return CHIP_NO_ERROR;
    2102            8 : }
    2103              : 
    2104            8 : CHIP_ERROR CASESession::HandleSigma3c(HandleSigma3Data & data, CHIP_ERROR status)
    2105              : {
    2106            8 :     CHIP_ERROR err = CHIP_NO_ERROR;
    2107              : 
    2108            8 :     VerifyOrExit(mState == State::kHandleSigma3Pending, err = CHIP_ERROR_INCORRECT_STATE);
    2109              : 
    2110            8 :     SuccessOrExit(err = status);
    2111              : 
    2112            7 :     mPeerNodeId = data.initiatorNodeId;
    2113              : 
    2114              :     {
    2115            7 :         MutableByteSpan messageDigestSpan(mMessageDigest);
    2116            7 :         SuccessOrExit(err = mCommissioningHash.Finish(messageDigestSpan));
    2117              :     }
    2118              : 
    2119              :     // Retrieve peer CASE Authenticated Tags (CATs) from peer's NOC.
    2120              :     {
    2121            7 :         SuccessOrExit(err = ExtractCATsFromOpCert(data.initiatorNOC, mPeerCATs));
    2122              :     }
    2123              : 
    2124            7 :     if (mSessionResumptionStorage != nullptr)
    2125              :     {
    2126            3 :         CHIP_ERROR err2 = mSessionResumptionStorage->Save(GetPeer(), mNewResumptionId, mSharedSecret, mPeerCATs);
    2127            3 :         if (err2 != CHIP_NO_ERROR)
    2128              :         {
    2129            0 :             ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
    2130              :         }
    2131              :     }
    2132              : 
    2133              :     MATTER_LOG_METRIC(kMetricDeviceCASESessionSigmaFinished);
    2134            7 :     SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
    2135              : 
    2136            7 :     mState = State::kFinished;
    2137            7 :     Finish();
    2138              : 
    2139            8 : exit:
    2140            8 :     mHandleSigma3Helper.reset();
    2141              : 
    2142            8 :     if (err != CHIP_NO_ERROR)
    2143              :     {
    2144            1 :         SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
    2145              :         // Abort the pending establish, which is normally done by CASESession::OnMessageReceived,
    2146              :         // but in the background processing case must be done here.
    2147            1 :         DiscardExchange();
    2148            1 :         AbortPendingEstablish(err);
    2149              :     }
    2150              : 
    2151            8 :     return err;
    2152              : }
    2153              : 
    2154           42 : CHIP_ERROR CASESession::DeriveSigmaKey(const ByteSpan & salt, const ByteSpan & info, AutoReleaseSessionKey & key) const
    2155              : {
    2156           42 :     return mSessionManager->GetSessionKeystore()->DeriveKey(mSharedSecret, salt, info, key.KeyHandle());
    2157              : }
    2158              : 
    2159           19 : CHIP_ERROR CASESession::ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk,
    2160              :                                             MutableByteSpan & salt)
    2161              : {
    2162              :     uint8_t md[kSHA256_Hash_Length];
    2163           19 :     memset(salt.data(), 0, salt.size());
    2164           19 :     Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
    2165              : 
    2166           19 :     bbuf.Put(ipk.data(), ipk.size());
    2167           19 :     bbuf.Put(rand.data(), kSigmaParamRandomNumberSize);
    2168           19 :     bbuf.Put(pubkey, pubkey.Length());
    2169           19 :     MutableByteSpan messageDigestSpan(md);
    2170           19 :     ReturnErrorOnFailure(mCommissioningHash.GetDigest(messageDigestSpan));
    2171           19 :     bbuf.Put(messageDigestSpan.data(), messageDigestSpan.size());
    2172              : 
    2173           19 :     size_t saltWritten = 0;
    2174           19 :     VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
    2175           19 :     salt = salt.SubSpan(0, saltWritten);
    2176              : 
    2177           19 :     return CHIP_NO_ERROR;
    2178              : }
    2179              : 
    2180           16 : CHIP_ERROR CASESession::ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpan & salt)
    2181              : {
    2182              :     uint8_t md[kSHA256_Hash_Length];
    2183           16 :     memset(salt.data(), 0, salt.size());
    2184           16 :     Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
    2185              : 
    2186           16 :     bbuf.Put(ipk.data(), ipk.size());
    2187           16 :     MutableByteSpan messageDigestSpan(md);
    2188           16 :     ReturnErrorOnFailure(mCommissioningHash.GetDigest(messageDigestSpan));
    2189           16 :     bbuf.Put(messageDigestSpan.data(), messageDigestSpan.size());
    2190              : 
    2191           16 :     size_t saltWritten = 0;
    2192           16 :     VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
    2193           16 :     salt = salt.SubSpan(0, saltWritten);
    2194              : 
    2195           16 :     return CHIP_NO_ERROR;
    2196              : }
    2197              : 
    2198            7 : CHIP_ERROR CASESession::ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
    2199              :                                                 const ByteSpan & skInfo, const ByteSpan & nonce, AutoReleaseSessionKey & resumeKey)
    2200              : {
    2201            7 :     constexpr size_t saltSize = kSigmaParamRandomNumberSize + SessionResumptionStorage::kResumptionIdSize;
    2202              :     uint8_t salt[saltSize];
    2203              : 
    2204            7 :     memset(salt, 0, saltSize);
    2205            7 :     Encoding::LittleEndian::BufferWriter bbuf(salt, saltSize);
    2206              : 
    2207            7 :     bbuf.Put(initiatorRandom.data(), initiatorRandom.size());
    2208            7 :     bbuf.Put(resumptionID.data(), resumptionID.size());
    2209              : 
    2210            7 :     size_t saltWritten = 0;
    2211            7 :     VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
    2212              : 
    2213            7 :     return DeriveSigmaKey(ByteSpan(salt, saltWritten), skInfo, resumeKey);
    2214              : }
    2215              : 
    2216            4 : CHIP_ERROR CASESession::GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
    2217              :                                                const ByteSpan & skInfo, const ByteSpan & nonce, MutableByteSpan & resumeMIC)
    2218              : {
    2219            4 :     VerifyOrReturnError(resumeMIC.size() >= CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
    2220              : 
    2221            4 :     AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore());
    2222            4 :     ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk));
    2223            4 :     ReturnErrorOnFailure(AES_CCM_encrypt(nullptr, 0, nullptr, 0, srk.KeyHandle(), nonce.data(), nonce.size(), nullptr,
    2224              :                                          resumeMIC.data(), CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
    2225            4 :     resumeMIC.reduce_size(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
    2226              : 
    2227            4 :     return CHIP_NO_ERROR;
    2228            4 : }
    2229              : 
    2230            3 : CHIP_ERROR CASESession::ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const ByteSpan & initiatorRandom,
    2231              :                                                const ByteSpan & resumptionID, const ByteSpan & skInfo, const ByteSpan & nonce)
    2232              : {
    2233            3 :     VerifyOrReturnError(resumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
    2234              : 
    2235            3 :     AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore());
    2236            3 :     ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk));
    2237            3 :     ReturnErrorOnFailure(AES_CCM_decrypt(nullptr, 0, nullptr, 0, resumeMIC.data(), resumeMIC.size(), srk.KeyHandle(), nonce.data(),
    2238              :                                          nonce.size(), nullptr));
    2239              : 
    2240            2 :     return CHIP_NO_ERROR;
    2241            3 : }
    2242              : 
    2243           35 : CHIP_ERROR CASESession::ConstructTBSData(const ByteSpan & senderNOC, const ByteSpan & senderICAC, const ByteSpan & senderPubKey,
    2244              :                                          const ByteSpan & receiverPubKey, MutableByteSpan & outTbsData)
    2245              : {
    2246           35 :     TLVWriter tlvWriter;
    2247           35 :     TLVType outerContainerType = kTLVType_NotSpecified;
    2248              : 
    2249           35 :     tlvWriter.Init(outTbsData);
    2250           35 :     ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType));
    2251           35 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderNOC), senderNOC));
    2252           35 :     if (!senderICAC.empty())
    2253              :     {
    2254           19 :         ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderICAC), senderICAC));
    2255              :     }
    2256           35 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderPubKey), senderPubKey));
    2257           35 :     ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kReceiverPubKey), receiverPubKey));
    2258           35 :     ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    2259           35 :     ReturnErrorOnFailure(tlvWriter.Finalize());
    2260           35 :     outTbsData.reduce_size(static_cast<size_t>(tlvWriter.GetLengthWritten()));
    2261              : 
    2262           35 :     return CHIP_NO_ERROR;
    2263              : }
    2264              : 
    2265           17 : CHIP_ERROR CASESession::SetEffectiveTime()
    2266              : {
    2267              :     System::Clock::Milliseconds64 currentUnixTimeMS;
    2268           17 :     CHIP_ERROR err = System::SystemClock().GetClock_RealTimeMS(currentUnixTimeMS);
    2269              : 
    2270           17 :     if (err == CHIP_NO_ERROR)
    2271              :     {
    2272              :         // If the system has given us a wall clock time, we must use it or
    2273              :         // fail.  Conversion failures here are therefore always an error.
    2274           17 :         System::Clock::Seconds32 currentUnixTime = std::chrono::duration_cast<System::Clock::Seconds32>(currentUnixTimeMS);
    2275           17 :         ReturnErrorOnFailure(mValidContext.SetEffectiveTimeFromUnixTime<CurrentChipEpochTime>(currentUnixTime));
    2276              :     }
    2277              :     else
    2278              :     {
    2279              :         // If we don't have wall clock time, the spec dictates that we should
    2280              :         // fall back to Last Known Good Time.  Ultimately, the calling application's
    2281              :         // validity policy will determine whether this is permissible.
    2282              :         System::Clock::Seconds32 lastKnownGoodChipEpochTime;
    2283            0 :         ChipLogError(SecureChannel,
    2284              :                      "The device does not support GetClock_RealTimeMS() API: %" CHIP_ERROR_FORMAT
    2285              :                      ".  Falling back to Last Known Good UTC Time",
    2286              :                      err.Format());
    2287            0 :         VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
    2288            0 :         err = mFabricsTable->GetLastKnownGoodChipEpochTime(lastKnownGoodChipEpochTime);
    2289            0 :         if (err != CHIP_NO_ERROR)
    2290              :         {
    2291              :             // If we have no time available, the Validity Policy will
    2292              :             // determine what to do.
    2293            0 :             ChipLogError(SecureChannel, "Failed to retrieve Last Known Good UTC Time");
    2294              :         }
    2295              :         else
    2296              :         {
    2297            0 :             mValidContext.SetEffectiveTime<LastKnownGoodChipEpochTime>(lastKnownGoodChipEpochTime);
    2298              :         }
    2299              :     }
    2300           17 :     return CHIP_NO_ERROR;
    2301              : }
    2302              : 
    2303            8 : void CASESession::OnSuccessStatusReport()
    2304              : {
    2305            8 :     ChipLogProgress(SecureChannel, "Success status report received. Session was established");
    2306              : 
    2307            8 :     if (mSessionResumptionStorage != nullptr)
    2308              :     {
    2309            4 :         CHIP_ERROR err2 = mSessionResumptionStorage->Save(GetPeer(), mNewResumptionId, mSharedSecret, mPeerCATs);
    2310            4 :         if (err2 != CHIP_NO_ERROR)
    2311            0 :             ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
    2312              :     }
    2313              : 
    2314            8 :     switch (mState)
    2315              :     {
    2316            7 :     case State::kSentSigma3:
    2317            7 :         mState = State::kFinished;
    2318            7 :         break;
    2319            1 :     case State::kSentSigma2Resume:
    2320            1 :         mState = State::kFinishedViaResume;
    2321            1 :         break;
    2322            0 :     default:
    2323            0 :         VerifyOrDie(false && "Reached invalid internal state keeping in CASE session");
    2324              :         break;
    2325              :     }
    2326              : 
    2327            8 :     Finish();
    2328            8 : }
    2329              : 
    2330            3 : CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
    2331              :                                               Optional<uintptr_t> protocolData)
    2332              : {
    2333            3 :     CHIP_ERROR err = CHIP_NO_ERROR;
    2334            3 :     switch (protocolCode)
    2335              :     {
    2336            2 :     case kProtocolCodeInvalidParam:
    2337            2 :         err = CHIP_ERROR_INVALID_CASE_PARAMETER;
    2338            2 :         break;
    2339              : 
    2340            0 :     case kProtocolCodeNoSharedRoot:
    2341            0 :         err = CHIP_ERROR_NO_SHARED_TRUSTED_ROOT;
    2342            0 :         break;
    2343              : 
    2344            1 :     case kProtocolCodeBusy:
    2345            1 :         err = CHIP_ERROR_BUSY;
    2346            1 :         if (protocolData.HasValue())
    2347              :         {
    2348            1 :             mDelegate->OnResponderBusy(System::Clock::Milliseconds16(static_cast<uint16_t>(protocolData.Value())));
    2349              :         }
    2350            1 :         break;
    2351              : 
    2352            0 :     default:
    2353            0 :         err = CHIP_ERROR_INTERNAL;
    2354            0 :         break;
    2355              :     };
    2356            3 :     mState = State::kInitialized;
    2357            3 :     ChipLogError(SecureChannel, "Received error (protocol code %d) during pairing process: %" CHIP_ERROR_FORMAT, protocolCode,
    2358              :                  err.Format());
    2359            3 :     return err;
    2360              : }
    2361              : 
    2362           34 : CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma1 & outParsedSigma1)
    2363              : {
    2364              : 
    2365           34 :     TLVType containerType = kTLVType_Structure;
    2366           34 :     ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag()));
    2367           34 :     ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
    2368              : 
    2369           34 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorRandom)));
    2370           33 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorRandom));
    2371           33 :     VerifyOrReturnError(outParsedSigma1.initiatorRandom.size() == kSigmaParamRandomNumberSize, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2372              : 
    2373           31 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorSessionId)));
    2374           31 :     ReturnErrorOnFailure(tlvReader.Get(outParsedSigma1.initiatorSessionId));
    2375              : 
    2376           30 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kDestinationId)));
    2377           30 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.destinationId));
    2378           30 :     VerifyOrReturnError(outParsedSigma1.destinationId.size() == kSHA256_Hash_Length, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2379              : 
    2380           28 :     ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorEphPubKey)));
    2381           28 :     ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorEphPubKey));
    2382           28 :     VerifyOrReturnError(outParsedSigma1.initiatorEphPubKey.size() == kP256_PublicKey_Length, CHIP_ERROR_INVALID_CASE_PARAMETER);
    2383              : 
    2384              :     // Optional members start here.
    2385           26 :     CHIP_ERROR err = tlvReader.Next();
    2386           26 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams))
    2387              :     {
    2388           13 :         ReturnErrorOnFailure(DecodeSessionParametersIfPresent(AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams), tlvReader,
    2389              :                                                               outParsedSigma1.initiatorSessionParams));
    2390           13 :         outParsedSigma1.initiatorSessionParamStructPresent = true;
    2391              : 
    2392           13 :         err = tlvReader.Next();
    2393              :     }
    2394              : 
    2395           26 :     bool resumptionIDTagFound = false;
    2396           26 :     bool resume1MICTagFound   = false;
    2397              : 
    2398           26 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kResumptionID))
    2399              :     {
    2400           10 :         resumptionIDTagFound = true;
    2401           10 :         ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.resumptionId));
    2402           10 :         VerifyOrReturnError(outParsedSigma1.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize,
    2403              :                             CHIP_ERROR_INVALID_CASE_PARAMETER);
    2404            7 :         err = tlvReader.Next();
    2405              :     }
    2406              : 
    2407           23 :     if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kResume1MIC))
    2408              :     {
    2409            7 :         resume1MICTagFound = true;
    2410            7 :         ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorResumeMIC));
    2411            7 :         VerifyOrReturnError(outParsedSigma1.initiatorResumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,
    2412              :                             CHIP_ERROR_INVALID_CASE_PARAMETER);
    2413            6 :         err = tlvReader.Next();
    2414              :     }
    2415              : 
    2416           22 :     if (err == CHIP_END_OF_TLV)
    2417              :     {
    2418              :         // We ran out of struct members, but that's OK, because they were optional.
    2419           20 :         err = CHIP_NO_ERROR;
    2420              :     }
    2421              : 
    2422           22 :     ReturnErrorOnFailure(err);
    2423           22 :     ReturnErrorOnFailure(tlvReader.ExitContainer(containerType));
    2424              : 
    2425           20 :     if (resumptionIDTagFound && resume1MICTagFound)
    2426              :     {
    2427            5 :         outParsedSigma1.sessionResumptionRequested = true;
    2428              :     }
    2429           15 :     else if (!resumptionIDTagFound && !resume1MICTagFound)
    2430              :     {
    2431           13 :         outParsedSigma1.sessionResumptionRequested = false;
    2432              :     }
    2433              :     else
    2434              :     {
    2435            2 :         return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
    2436              :     }
    2437              : 
    2438           18 :     return CHIP_NO_ERROR;
    2439              : }
    2440              : 
    2441           42 : CHIP_ERROR CASESession::ValidateReceivedMessage(ExchangeContext * ec, const PayloadHeader & payloadHeader,
    2442              :                                                 const System::PacketBufferHandle & msg)
    2443              : {
    2444           42 :     VerifyOrReturnError(ec != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
    2445              : 
    2446              :     // mExchangeCtxt can be nullptr if this is the first message (CASE_Sigma1) received by CASESession
    2447              :     // via UnsolicitedMessageHandler. The exchange context is allocated by exchange manager and provided
    2448              :     // to the handler (CASESession object).
    2449           42 :     if (mExchangeCtxt.HasValue())
    2450              :     {
    2451           30 :         if (&mExchangeCtxt.Value().Get() != ec)
    2452              :         {
    2453            0 :             ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
    2454              :         }
    2455              :     }
    2456              :     else
    2457              :     {
    2458           12 :         mExchangeCtxt.Emplace(*ec);
    2459              :     }
    2460           42 :     mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedHighProcessingTime);
    2461              : 
    2462           42 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
    2463           42 :     return CHIP_NO_ERROR;
    2464              : }
    2465              : 
    2466           42 : CHIP_ERROR CASESession::OnMessageReceived(ExchangeContext * ec, const PayloadHeader & payloadHeader,
    2467              :                                           System::PacketBufferHandle && msg)
    2468              : {
    2469              :     MATTER_TRACE_SCOPE("OnMessageReceived", "CASESession");
    2470           42 :     CHIP_ERROR err                            = ValidateReceivedMessage(ec, payloadHeader, msg);
    2471           42 :     Protocols::SecureChannel::MsgType msgType = static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType());
    2472           42 :     SuccessOrExit(err);
    2473              : 
    2474              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
    2475           42 :     if (mStopHandshakeAtState.HasValue() && mState == mStopHandshakeAtState.Value())
    2476              :     {
    2477            1 :         mStopHandshakeAtState = Optional<State>::Missing();
    2478              :         // For testing purposes we are trying to stop a successful CASESession from happening by dropping part of the
    2479              :         // handshake in the middle. We are trying to keep both sides of the CASESession establishment in an active
    2480              :         // pending state. In order to keep this side open we have to tell the exchange context that we will send an
    2481              :         // async message.
    2482              :         //
    2483              :         // Should you need to resume the CASESession, you could theoretically pass along the msg to a callback that gets
    2484              :         // registered when setting mStopHandshakeAtState.
    2485            1 :         mExchangeCtxt.Value()->WillSendMessage();
    2486            1 :         return CHIP_NO_ERROR;
    2487              :     }
    2488              : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
    2489              : 
    2490              : #if CHIP_CONFIG_SLOW_CRYPTO
    2491              :     if ((msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1 || msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2 ||
    2492              :          msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2Resume ||
    2493              :          msgType == Protocols::SecureChannel::MsgType::CASE_Sigma3) &&
    2494              :         mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress().GetTransportType() !=
    2495              :             Transport::Type::kTcp)
    2496              :     {
    2497              :         // TODO: Rename FlushAcks() to something more semantically correct and
    2498              :         // call unconditionally for TCP or MRP from here. Inside, the
    2499              :         // PeerAddress type could be consulted to selectively flush MRP Acks
    2500              :         // when transport is not TCP. Issue #33183
    2501              :         SuccessOrExit(err = mExchangeCtxt.Value()->FlushAcks());
    2502              :     }
    2503              : #endif // CHIP_CONFIG_SLOW_CRYPTO
    2504              : 
    2505              :     // By default, CHIP_ERROR_INVALID_MESSAGE_TYPE is returned if in the current state
    2506              :     // a message handler is not defined for the received message type.
    2507           41 :     err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
    2508              : 
    2509           41 :     switch (mState)
    2510              :     {
    2511           12 :     case State::kInitialized:
    2512           12 :         if (msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1)
    2513              :         {
    2514           12 :             err = HandleSigma1_and_SendSigma2(std::move(msg));
    2515              :         }
    2516           12 :         break;
    2517            8 :     case State::kSentSigma1:
    2518            8 :         switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
    2519              :         {
    2520            7 :         case Protocols::SecureChannel::MsgType::CASE_Sigma2:
    2521            7 :             err = HandleSigma2_and_SendSigma3(std::move(msg));
    2522            7 :             break;
    2523              : 
    2524            1 :         case MsgType::StatusReport:
    2525            1 :             err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
    2526              :             MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
    2527            1 :             break;
    2528              : 
    2529            0 :         default:
    2530              :             // Return the default error that was set above
    2531            0 :             break;
    2532              :         };
    2533            8 :         break;
    2534            3 :     case State::kSentSigma1Resume:
    2535            3 :         switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
    2536              :         {
    2537            2 :         case Protocols::SecureChannel::MsgType::CASE_Sigma2:
    2538            2 :             err = HandleSigma2_and_SendSigma3(std::move(msg));
    2539            2 :             break;
    2540              : 
    2541            1 :         case Protocols::SecureChannel::MsgType::CASE_Sigma2Resume:
    2542            1 :             err = HandleSigma2Resume(std::move(msg));
    2543            1 :             break;
    2544              : 
    2545            0 :         case MsgType::StatusReport:
    2546            0 :             err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
    2547              :             MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
    2548            0 :             break;
    2549              : 
    2550            0 :         default:
    2551              :             // Return the default error that was set above
    2552            0 :             break;
    2553              :         };
    2554            3 :         break;
    2555            9 :     case State::kSentSigma2:
    2556            9 :         switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
    2557              :         {
    2558            8 :         case Protocols::SecureChannel::MsgType::CASE_Sigma3:
    2559            8 :             err = HandleSigma3a(std::move(msg));
    2560            8 :             break;
    2561              : 
    2562            1 :         case MsgType::StatusReport:
    2563            1 :             err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
    2564              :             MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err);
    2565            1 :             break;
    2566              : 
    2567            0 :         default:
    2568              :             // Return the default error that was set above
    2569            0 :             break;
    2570              :         };
    2571            9 :         break;
    2572            9 :     case State::kSentSigma3:
    2573              :     case State::kSentSigma2Resume:
    2574            9 :         if (msgType == Protocols::SecureChannel::MsgType::StatusReport)
    2575              :         {
    2576              :             // Need to capture before invoking status report since 'this' might be deallocated on successful completion of
    2577              :             // sigma3
    2578            9 :             MetricKey key = (mState == State::kSentSigma3) ? kMetricDeviceCASESessionSigma3 : kMetricDeviceCASESessionSigma2Resume;
    2579            9 :             err           = HandleStatusReport(std::move(msg), /* successExpected*/ true);
    2580              :             MATTER_LOG_METRIC_END(key, err);
    2581              :             IgnoreUnusedVariable(key);
    2582              :         }
    2583            9 :         break;
    2584            0 :     default:
    2585              :         // Return the default error that was set above
    2586            0 :         break;
    2587              :     };
    2588              : 
    2589           41 : exit:
    2590              : 
    2591           41 :     if (err == CHIP_ERROR_INVALID_MESSAGE_TYPE)
    2592              :     {
    2593            0 :         ChipLogError(SecureChannel, "Received message (type %d) cannot be handled in %d state.", to_underlying(msgType),
    2594              :                      to_underlying(mState));
    2595              :     }
    2596              : 
    2597              :     // Call delegate to indicate session establishment failure.
    2598           41 :     if (err != CHIP_NO_ERROR)
    2599              :     {
    2600              :         // Discard the exchange so that Clear() doesn't try aborting it.  The
    2601              :         // exchange will handle that.
    2602            5 :         DiscardExchange();
    2603            5 :         AbortPendingEstablish(err);
    2604              :     }
    2605           41 :     return err;
    2606              : }
    2607              : 
    2608              : namespace {
    2609            1 : System::Clock::Timeout ComputeRoundTripTimeout(ExchangeContext::Timeout serverProcessingTime,
    2610              :                                                const ReliableMessageProtocolConfig & remoteMrpConfig, bool isFirstMessageOnExchange)
    2611              : {
    2612              :     // TODO: This is duplicating logic from Session::ComputeRoundTripTimeout.  Unfortunately, it's called by
    2613              :     // consumers who do not have a session.
    2614            1 :     const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
    2615            1 :     const auto & defaultMRRPConfig   = GetDefaultMRPConfig();
    2616            1 :     const auto & localMRPConfig      = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
    2617            1 :     return GetRetransmissionTimeout(remoteMrpConfig.mActiveRetransTimeout, remoteMrpConfig.mIdleRetransTimeout,
    2618              :                                     // The activity time only matters when isFirstMessageOnExchange is false,
    2619              :                                     // which only happens for Sigma1.  In that case, assume peer is idle,
    2620              :                                     // as a worst-case assumption, and pass System::Clock::kZero.
    2621            1 :                                     System::Clock::kZero, remoteMrpConfig.mActiveThresholdTime, isFirstMessageOnExchange) +
    2622            1 :         serverProcessingTime +
    2623            1 :         GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
    2624              :                                  // Peer will be responding to our message, so isFirstMessageOnExchange should be false
    2625              :                                  // and the timestamp does not matter.
    2626            2 :                                  System::SystemClock().GetMonotonicTimestamp(), localMRPConfig.mActiveThresholdTime,
    2627            1 :                                  false /*isFirstMessageOnExchange*/);
    2628              : }
    2629              : } // anonymous namespace
    2630              : 
    2631            0 : System::Clock::Timeout CASESession::ComputeSigma1ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig)
    2632              : {
    2633              :     // Sigma1 is the first message on the exchange.
    2634            0 :     return ComputeRoundTripTimeout(kExpectedSigma1ProcessingTime, remoteMrpConfig, true /*isFirstMessageOnExchange*/);
    2635              : }
    2636              : 
    2637            1 : System::Clock::Timeout CASESession::ComputeSigma2ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig)
    2638              : {
    2639              :     // Sigma2 is never the first message on the exchange.
    2640            1 :     return ComputeRoundTripTimeout(kExpectedHighProcessingTime, remoteMrpConfig, false /*isFirstMessageOnExchange*/);
    2641              : }
    2642              : 
    2643            1 : bool CASESession::InvokeBackgroundWorkWatchdog()
    2644              : {
    2645            1 :     bool watchdogFired = false;
    2646              : 
    2647            1 :     if (mSendSigma3Helper && mSendSigma3Helper->UnableToScheduleAfterWorkCallback())
    2648              :     {
    2649            0 :         ChipLogError(SecureChannel, "SendSigma3Helper was unable to schedule the AfterWorkCallback");
    2650            0 :         mSendSigma3Helper->DoAfterWork();
    2651            0 :         watchdogFired = true;
    2652              :     }
    2653              : 
    2654            1 :     if (mHandleSigma3Helper && mHandleSigma3Helper->UnableToScheduleAfterWorkCallback())
    2655              :     {
    2656            0 :         ChipLogError(SecureChannel, "HandleSigma3Helper was unable to schedule the AfterWorkCallback");
    2657            0 :         mHandleSigma3Helper->DoAfterWork();
    2658            0 :         watchdogFired = true;
    2659              :     }
    2660              : 
    2661            1 :     return watchdogFired;
    2662              : }
    2663              : 
    2664              : // Helper function to map CASESession::State to SessionEstablishmentStage
    2665            8 : SessionEstablishmentStage CASESession::MapCASEStateToSessionEstablishmentStage(State caseState)
    2666              : {
    2667            8 :     switch (caseState)
    2668              :     {
    2669            5 :     case State::kInitialized:
    2670            5 :         return SessionEstablishmentStage::kNotInKeyExchange;
    2671            1 :     case State::kSentSigma1:
    2672              :     case State::kSentSigma1Resume:
    2673            1 :         return SessionEstablishmentStage::kSentSigma1;
    2674            1 :     case State::kSentSigma2:
    2675              :     case State::kSentSigma2Resume:
    2676            1 :         return SessionEstablishmentStage::kSentSigma2;
    2677            0 :     case State::kSendSigma3Pending:
    2678            0 :         return SessionEstablishmentStage::kReceivedSigma2;
    2679            0 :     case State::kSentSigma3:
    2680            0 :         return SessionEstablishmentStage::kSentSigma3;
    2681            1 :     case State::kHandleSigma3Pending:
    2682            1 :         return SessionEstablishmentStage::kReceivedSigma3;
    2683              :     // Add more mappings here for other states
    2684            0 :     default:
    2685            0 :         return SessionEstablishmentStage::kUnknown; // Default mapping
    2686              :     }
    2687              : }
    2688              : 
    2689              : } // namespace chip
        

Generated by: LCOV version 2.0-1