Matter SDK Coverage Report
Current view: top level - protocols/secure_channel - CASESession.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 82.4 % 17 14
Test Date: 2025-01-17 19:00:11 Functions: 90.9 % 11 10

            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 defines 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              : #pragma once
      27              : 
      28              : #include <credentials/CHIPCert.h>
      29              : #include <credentials/CertificateValidityPolicy.h>
      30              : #include <credentials/FabricTable.h>
      31              : #include <credentials/GroupDataProvider.h>
      32              : #include <crypto/CHIPCryptoPAL.h>
      33              : #include <lib/core/ScopedNodeId.h>
      34              : #include <lib/core/TLV.h>
      35              : #include <lib/support/Base64.h>
      36              : #include <lib/support/CHIPMem.h>
      37              : #include <messaging/ExchangeContext.h>
      38              : #include <messaging/ExchangeDelegate.h>
      39              : #include <messaging/ReliableMessageProtocolConfig.h>
      40              : #include <protocols/secure_channel/CASEDestinationId.h>
      41              : #include <protocols/secure_channel/Constants.h>
      42              : #include <protocols/secure_channel/PairingSession.h>
      43              : #include <protocols/secure_channel/SessionEstablishmentExchangeDispatch.h>
      44              : #include <protocols/secure_channel/SessionResumptionStorage.h>
      45              : #include <system/SystemClock.h>
      46              : #include <system/SystemPacketBuffer.h>
      47              : #include <transport/CryptoContext.h>
      48              : #include <transport/raw/MessageHeader.h>
      49              : #include <transport/raw/PeerAddress.h>
      50              : 
      51              : namespace chip {
      52              : 
      53              : // TODO: temporary derive from Messaging::UnsolicitedMessageHandler, actually the CASEServer should be the umh, it will be fixed
      54              : // when implementing concurrent CASE session.
      55              : class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler,
      56              :                                public Messaging::ExchangeDelegate,
      57              :                                public FabricTable::Delegate,
      58              :                                public PairingSession
      59              : {
      60              : public:
      61              :     ~CASESession() override;
      62              : 
      63            1 :     Transport::SecureSession::Type GetSecureSessionType() const override { return Transport::SecureSession::Type::kCASE; }
      64          105 :     ScopedNodeId GetPeer() const override { return ScopedNodeId(mPeerNodeId, GetFabricIndex()); }
      65           16 :     ScopedNodeId GetLocalScopedNodeId() const override { return ScopedNodeId(mLocalNodeId, GetFabricIndex()); }
      66           16 :     CATValues GetPeerCATs() const override { return mPeerCATs; };
      67              : 
      68              :     /**
      69              :      * @brief
      70              :      *   Initialize using configured fabrics and wait for session establishment requests (as a responder).
      71              :      *
      72              :      * @param sessionManager                session manager from which to allocate a secure session object
      73              :      * @param fabricTable                   Table of fabrics that are currently configured on the device
      74              :      * @param policy                        Optional application-provided certificate validity policy
      75              :      * @param delegate                      Callback object
      76              :      * @param previouslyEstablishedPeer     If a session had previously been established successfully to a peer, this should
      77              :      *                                      be set to its scoped node-id. Else, this should be initialized to a
      78              :      *                                      default-constructed ScopedNodeId().
      79              :      * @param mrpLocalConfig                MRP configuration to encode into Sigma2. If not provided, it won't be encoded.
      80              :      *
      81              :      * @return CHIP_ERROR     The result of initialization
      82              :      */
      83              :     CHIP_ERROR PrepareForSessionEstablishment(SessionManager & sessionManager, FabricTable * fabricTable,
      84              :                                               SessionResumptionStorage * sessionResumptionStorage,
      85              :                                               Credentials::CertificateValidityPolicy * policy,
      86              :                                               SessionEstablishmentDelegate * delegate,
      87              :                                               const ScopedNodeId & previouslyEstablishedPeer,
      88              :                                               Optional<ReliableMessageProtocolConfig> mrpLocalConfig);
      89              : 
      90              :     /**
      91              :      * @brief
      92              :      *   Create and send session establishment request (as an initiator) using device's operational credentials.
      93              :      *
      94              :      * @param sessionManager                session manager from which to allocate a secure session object
      95              :      * @param fabricTable                   The fabric table that contains a fabric in common with the peer
      96              :      * @param peerScopedNodeId              Node to which we want to establish a session
      97              :      * @param exchangeCtxt                  The exchange context to send and receive messages with the peer
      98              :      * @param policy                        Optional application-provided certificate validity policy
      99              :      * @param delegate                      Callback object
     100              :      *
     101              :      * @return CHIP_ERROR      The result of initialization
     102              :      */
     103              :     CHIP_ERROR
     104              :     EstablishSession(SessionManager & sessionManager, FabricTable * fabricTable, ScopedNodeId peerScopedNodeId,
     105              :                      Messaging::ExchangeContext * exchangeCtxt, SessionResumptionStorage * sessionResumptionStorage,
     106              :                      Credentials::CertificateValidityPolicy * policy, SessionEstablishmentDelegate * delegate,
     107              :                      Optional<ReliableMessageProtocolConfig> mrpLocalConfig);
     108              : 
     109              :     /**
     110              :      * @brief Set the Group Data Provider which will be used to look up IPKs
     111              :      *
     112              :      * The GroupDataProvider set MUST have key sets available through `GetIpkKeySet` method
     113              :      * for the FabricIndex that is associated with the CASESession's FabricInfo.
     114              :      *
     115              :      * @param groupDataProvider - Pointer to the group data provider (if nullptr, will error at start of
     116              :      *                            establishment, not here).
     117              :      */
     118            1 :     void SetGroupDataProvider(Credentials::GroupDataProvider * groupDataProvider) { mGroupDataProvider = groupDataProvider; }
     119              : 
     120              :     /**
     121              :      * Parse a sigma1 message.  This function will return success only if the
     122              :      * message passes schema checks.  Specifically:
     123              :      *   * The tags come in order.
     124              :      *   * The required tags are present.
     125              :      *   * The values for the tags that are present satisfy schema requirements
     126              :      *     (e.g. constraints on octet string lengths)
     127              :      *   * Either resumptionID and initiatorResume1MIC are both present or both
     128              :      *     absent.
     129              :      *
     130              :      * On success, the initiatorRandom, initiatorSessionId, destinationId,
     131              :      * initiatorEphPubKey outparams will be set to the corresponding values in
     132              :      * the message.
     133              :      *
     134              :      * On success, either the resumptionRequested outparam will be set to true
     135              :      * and the  resumptionID and initiatorResumeMIC outparams will be set to
     136              :      * valid values, or the resumptionRequested outparam will be set to false.
     137              :      */
     138              :     CHIP_ERROR ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ByteSpan & initiatorRandom, uint16_t & initiatorSessionId,
     139              :                            ByteSpan & destinationId, ByteSpan & initiatorEphPubKey, bool & resumptionRequested,
     140              :                            ByteSpan & resumptionId, ByteSpan & initiatorResumeMIC);
     141              : 
     142              :     /**
     143              :      * @brief
     144              :      *   Derive a secure session from the established session. The API will return error if called before session is established.
     145              :      *
     146              :      * @param session     Reference to the secure session that will be initialized once session establishment is complete
     147              :      * @return CHIP_ERROR The result of session derivation
     148              :      */
     149              :     CHIP_ERROR DeriveSecureSession(CryptoContext & session) override;
     150              : 
     151              :     //// UnsolicitedMessageHandler Implementation ////
     152            3 :     CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate) override
     153              :     {
     154            3 :         newDelegate = this;
     155            3 :         return CHIP_NO_ERROR;
     156              :     }
     157              : 
     158              :     //// ExchangeDelegate Implementation ////
     159              :     CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
     160              :                                  System::PacketBufferHandle && payload) override;
     161              :     void OnResponseTimeout(Messaging::ExchangeContext * ec) override;
     162           23 :     Messaging::ExchangeMessageDispatch & GetMessageDispatch() override { return SessionEstablishmentExchangeDispatch::Instance(); }
     163              : 
     164              :     //// SessionDelegate ////
     165              :     void OnSessionReleased() override;
     166              : 
     167              :     //// FabricTable::Delegate Implementation ////
     168            0 :     void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override
     169              :     {
     170              :         (void) fabricTable;
     171            0 :         InvalidateIfPendingEstablishmentOnFabric(fabricIndex);
     172            0 :     }
     173            5 :     void OnFabricUpdated(const chip::FabricTable & fabricTable, chip::FabricIndex fabricIndex) override
     174              :     {
     175              :         (void) fabricTable;
     176            5 :         InvalidateIfPendingEstablishmentOnFabric(fabricIndex);
     177            5 :     }
     178              : 
     179          121 :     FabricIndex GetFabricIndex() const { return mFabricIndex; }
     180              : 
     181              :     // Compute our Sigma1 response timeout.  This can give consumers an idea of
     182              :     // how long it will take to detect that our Sigma1 did not get through.
     183              :     static System::Clock::Timeout ComputeSigma1ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig);
     184              : 
     185              :     // Compute our Sigma2 response timeout.  This can give consumers an idea of
     186              :     // how long it will take to detect that our Sigma1 did not get through.
     187              :     static System::Clock::Timeout ComputeSigma2ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig);
     188              : 
     189              :     // TODO: remove Clear, we should create a new instance instead reset the old instance.
     190              :     /** @brief This function zeroes out and resets the memory used by the object.
     191              :      **/
     192              :     void Clear();
     193              : 
     194              :     enum class State : uint8_t
     195              :     {
     196              :         kInitialized         = 0,
     197              :         kSentSigma1          = 1,
     198              :         kSentSigma2          = 2,
     199              :         kSentSigma3          = 3,
     200              :         kSentSigma1Resume    = 4,
     201              :         kSentSigma2Resume    = 5,
     202              :         kFinished            = 6,
     203              :         kFinishedViaResume   = 7,
     204              :         kSendSigma3Pending   = 8,
     205              :         kHandleSigma3Pending = 9,
     206              :     };
     207              : 
     208            9 :     State GetState() { return mState; }
     209              : 
     210              :     // Returns true if the CASE session handshake was stuck due to failing to schedule work on the Matter thread.
     211              :     // If this function returns true, the CASE session has been reset and is ready for a new session establishment.
     212              :     bool InvokeBackgroundWorkWatchdog();
     213              : 
     214              : private:
     215              :     friend class TestCASESession;
     216              : 
     217              :     using AutoReleaseSessionKey = Crypto::AutoReleaseSymmetricKey<Crypto::Aes128KeyHandle>;
     218              : 
     219              :     /*
     220              :      * Initialize the object given a reference to the SessionManager, certificate validity policy and a delegate which will be
     221              :      * notified of any further progress on this session.
     222              :      *
     223              :      * If we're either establishing or finished establishing a session to a peer in either initiator or responder
     224              :      * roles, the node id of that peer should be provided in sessionEvictionHint. Else, it should be initialized
     225              :      * to a default-constructed ScopedNodeId().
     226              :      *
     227              :      */
     228              :     CHIP_ERROR Init(SessionManager & sessionManager, Credentials::CertificateValidityPolicy * policy,
     229              :                     SessionEstablishmentDelegate * delegate, const ScopedNodeId & sessionEvictionHint);
     230              : 
     231              :     // On success, sets mIpk to the correct value for outgoing Sigma1 based on internal state
     232              :     CHIP_ERROR RecoverInitiatorIpk();
     233              :     // On success, sets locally maching mFabricInfo in internal state to the entry matched by
     234              :     // destinationId/initiatorRandom from processing of Sigma1, and sets mIpk to the right IPK.
     235              :     CHIP_ERROR FindLocalNodeFromDestinationId(const ByteSpan & destinationId, const ByteSpan & initiatorRandom);
     236              : 
     237              :     CHIP_ERROR SendSigma1();
     238              :     CHIP_ERROR HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg);
     239              :     CHIP_ERROR HandleSigma1(System::PacketBufferHandle && msg);
     240              :     CHIP_ERROR TryResumeSession(SessionResumptionStorage::ConstResumptionIdView resumptionId, ByteSpan resume1MIC,
     241              :                                 ByteSpan initiatorRandom);
     242              :     CHIP_ERROR SendSigma2();
     243              :     CHIP_ERROR HandleSigma2_and_SendSigma3(System::PacketBufferHandle && msg);
     244              :     CHIP_ERROR HandleSigma2(System::PacketBufferHandle && msg);
     245              :     CHIP_ERROR HandleSigma2Resume(System::PacketBufferHandle && msg);
     246              : 
     247              :     struct SendSigma3Data;
     248              :     CHIP_ERROR SendSigma3a();
     249              :     static CHIP_ERROR SendSigma3b(SendSigma3Data & data, bool & cancel);
     250              :     CHIP_ERROR SendSigma3c(SendSigma3Data & data, CHIP_ERROR status);
     251              : 
     252              :     struct HandleSigma3Data;
     253              :     CHIP_ERROR HandleSigma3a(System::PacketBufferHandle && msg);
     254              :     static CHIP_ERROR HandleSigma3b(HandleSigma3Data & data, bool & cancel);
     255              :     CHIP_ERROR HandleSigma3c(HandleSigma3Data & data, CHIP_ERROR status);
     256              : 
     257              :     CHIP_ERROR SendSigma2Resume();
     258              : 
     259              :     CHIP_ERROR DeriveSigmaKey(const ByteSpan & salt, const ByteSpan & info, AutoReleaseSessionKey & key) const;
     260              :     CHIP_ERROR ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk,
     261              :                                    MutableByteSpan & salt);
     262              :     CHIP_ERROR ConstructTBSData(const ByteSpan & senderNOC, const ByteSpan & senderICAC, const ByteSpan & senderPubKey,
     263              :                                 const ByteSpan & receiverPubKey, uint8_t * tbsData, size_t & tbsDataLen);
     264              :     CHIP_ERROR ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpan & salt);
     265              : 
     266              :     CHIP_ERROR ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo,
     267              :                                        const ByteSpan & nonce, AutoReleaseSessionKey & resumeKey);
     268              : 
     269              :     CHIP_ERROR GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo,
     270              :                                       const ByteSpan & nonce, MutableByteSpan & resumeMIC);
     271              :     CHIP_ERROR ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
     272              :                                       const ByteSpan & skInfo, const ByteSpan & nonce);
     273              : 
     274              :     void OnSuccessStatusReport() override;
     275              :     CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
     276              :                                      Optional<uintptr_t> protocolData) override;
     277              : 
     278              :     void AbortPendingEstablish(CHIP_ERROR err);
     279              : 
     280              :     CHIP_ERROR GetHardcodedTime();
     281              : 
     282              :     CHIP_ERROR SetEffectiveTime();
     283              : 
     284              :     CHIP_ERROR ValidateReceivedMessage(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
     285              :                                        const System::PacketBufferHandle & msg);
     286              : 
     287              :     void InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex);
     288              : 
     289              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     290              :     static void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
     291              :     static void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
     292              : 
     293              :     // Context to pass down when connecting to peer
     294              :     Transport::AppTCPConnectionCallbackCtxt mTCPConnCbCtxt;
     295              :     // Pointer to the underlying TCP connection state. Returned by the
     296              :     // TCPConnect() method (on the connection Initiator side) when an
     297              :     // ActiveTCPConnectionState object is allocated. This connection
     298              :     // context is used on the CASE Initiator side to facilitate the
     299              :     // invocation of the callbacks when the connection is established/closed.
     300              :     //
     301              :     // This pointer must be nulled out when the connection is closed.
     302              :     Transport::ActiveTCPConnectionState * mPeerConnState = nullptr;
     303              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     304              : 
     305              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     306              :     void SetStopSigmaHandshakeAt(Optional<State> state) { mStopHandshakeAtState = state; }
     307              : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
     308              : 
     309              :     Crypto::Hash_SHA256_stream mCommissioningHash;
     310              :     Crypto::P256PublicKey mRemotePubKey;
     311              :     Crypto::P256Keypair * mEphemeralKey = nullptr;
     312              :     Crypto::P256ECDHDerivedSecret mSharedSecret;
     313              :     Credentials::ValidationContext mValidContext;
     314              :     Credentials::GroupDataProvider * mGroupDataProvider = nullptr;
     315              : 
     316              :     uint8_t mMessageDigest[Crypto::kSHA256_Hash_Length];
     317              :     uint8_t mIPK[kIPKSize];
     318              : 
     319              :     SessionResumptionStorage * mSessionResumptionStorage = nullptr;
     320              :     SessionManager * mSessionManager                     = nullptr;
     321              : 
     322              :     FabricTable * mFabricsTable = nullptr;
     323              :     FabricIndex mFabricIndex    = kUndefinedFabricIndex;
     324              :     NodeId mPeerNodeId          = kUndefinedNodeId;
     325              :     NodeId mLocalNodeId         = kUndefinedNodeId;
     326              :     CATValues mPeerCATs;
     327              : 
     328              :     SessionResumptionStorage::ResumptionIdStorage mResumeResumptionId; // ResumptionId which is used to resume this session
     329              :     SessionResumptionStorage::ResumptionIdStorage mNewResumptionId;    // ResumptionId which is stored to resume future session
     330              :     // Sigma1 initiator random, maintained to be reused post-Sigma1, such as when generating Sigma2 S2RK key
     331              :     uint8_t mInitiatorRandom[kSigmaParamRandomNumberSize];
     332              : 
     333              :     template <class DATA>
     334              :     class WorkHelper;
     335              :     Platform::SharedPtr<WorkHelper<SendSigma3Data>> mSendSigma3Helper;
     336              :     Platform::SharedPtr<WorkHelper<HandleSigma3Data>> mHandleSigma3Helper;
     337              : 
     338              :     State mState;
     339              : 
     340              : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     341              :     Optional<State> mStopHandshakeAtState = Optional<State>::Missing();
     342              : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
     343              : 
     344              :     SessionEstablishmentStage MapCASEStateToSessionEstablishmentStage(State caseState);
     345              : };
     346              : 
     347              : } // namespace chip
        

Generated by: LCOV version 2.0-1