LCOV - code coverage report
Current view: top level - protocols/secure_channel - CASESession.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 910 1017 89.5 %
Date: 2024-02-15 08:20:41 Functions: 53 66 80.3 %

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

Generated by: LCOV version 1.14