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

Generated by: LCOV version 2.0-1