Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CASESession.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 87.6 % 1082 948
Test Date: 2025-01-17 19:00:11 Functions: 78.3 % 69 54

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

Generated by: LCOV version 2.0-1