Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:704d97f9c619242ad76fcf75aeabc67802fa72d4 Lines: 90.1 % 1180 1063
Test Date: 2026-05-18 07:37:39 Functions: 81.8 % 88 72

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

Generated by: LCOV version 2.0-1