Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:09f6fdf93a7e847a42518c076e487f336877a722 Lines: 89.5 % 1188 1063
Test Date: 2025-06-07 07:10:33 Functions: 82.4 % 85 70

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

Generated by: LCOV version 2.0-1