LCOV - code coverage report
Current view: top level - protocols/secure_channel - PairingSession.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 51 59 86.4 %
Date: 2024-02-15 08:20:41 Functions: 10 15 66.7 %

          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 a common interface to access various types of secure
      22             :  *      pairing sessions (e.g. PASE, CASE)
      23             :  *
      24             :  */
      25             : 
      26             : #pragma once
      27             : 
      28             : #include <lib/core/CHIPError.h>
      29             : #include <lib/core/TLV.h>
      30             : #include <messaging/ExchangeContext.h>
      31             : #include <messaging/SessionParameters.h>
      32             : #include <protocols/secure_channel/Constants.h>
      33             : #include <protocols/secure_channel/SessionEstablishmentDelegate.h>
      34             : #include <protocols/secure_channel/StatusReport.h>
      35             : #include <transport/CryptoContext.h>
      36             : #include <transport/SecureSession.h>
      37             : 
      38             : namespace chip {
      39             : 
      40             : class SessionManager;
      41             : 
      42             : class DLL_EXPORT PairingSession : public SessionDelegate
      43             : {
      44             : public:
      45           2 :     PairingSession() : mSecureSessionHolder(*this) {}
      46          50 :     virtual ~PairingSession() { Clear(); }
      47             : 
      48             :     virtual Transport::SecureSession::Type GetSecureSessionType() const = 0;
      49             :     virtual ScopedNodeId GetPeer() const                                = 0;
      50             :     virtual ScopedNodeId GetLocalScopedNodeId() const                   = 0;
      51             :     virtual CATValues GetPeerCATs() const                               = 0;
      52             : 
      53             :     // Implement SessionDelegate
      54           1 :     NewSessionHandlingPolicy GetNewSessionHandlingPolicy() override { return NewSessionHandlingPolicy::kStayAtOldSession; }
      55             :     void OnSessionReleased() override;
      56             : 
      57         114 :     Optional<uint16_t> GetLocalSessionId() const
      58             :     {
      59         114 :         Optional<uint16_t> localSessionId;
      60         114 :         VerifyOrExit(mSecureSessionHolder, localSessionId = NullOptional);
      61         114 :         VerifyOrExit(mSecureSessionHolder->GetSessionType() == Transport::Session::SessionType::kSecure,
      62             :                      localSessionId = Optional<uint16_t>::Missing());
      63         114 :         localSessionId.SetValue(mSecureSessionHolder->AsSecureSession()->GetLocalSessionId());
      64         114 :     exit:
      65         114 :         return localSessionId;
      66             :     }
      67             : 
      68             :     /**
      69             :      * Copy the underlying session (if present) into a SessionHandle that a caller can use to
      70             :      * obtain a reference to the session.
      71             :      */
      72          16 :     Optional<SessionHandle> CopySecureSession()
      73             :     {
      74          16 :         if (mSecureSessionHolder)
      75             :         {
      76          16 :             VerifyOrDie(mSecureSessionHolder->GetSessionType() == Transport::Session::SessionType::kSecure);
      77          16 :             return MakeOptional<SessionHandle>(*mSecureSessionHolder->AsSecureSession());
      78             :         }
      79             : 
      80           0 :         return Optional<SessionHandle>::Missing();
      81             :     }
      82             : 
      83          26 :     uint16_t GetPeerSessionId() const
      84             :     {
      85          26 :         VerifyOrDie(mPeerSessionId.HasValue());
      86          26 :         return mPeerSessionId.Value();
      87             :     }
      88             : 
      89             :     bool IsValidPeerSessionId() const { return mPeerSessionId.HasValue(); }
      90             : 
      91             :     /**
      92             :      * @brief
      93             :      *   Derive a secure session from the paired session. The API will return error if called before pairing is established.
      94             :      *
      95             :      * @param session     Reference to the secure session that will be initialized once pairing is complete
      96             :      * @return CHIP_ERROR The result of session derivation
      97             :      */
      98             :     virtual CHIP_ERROR DeriveSecureSession(CryptoContext & session) const = 0;
      99             : 
     100           0 :     const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteSessionParams.GetMRPConfig(); }
     101          55 :     const SessionParameters & GetRemoteSessionParameters() const { return mRemoteSessionParams; }
     102           0 :     void SetRemoteMRPConfig(const ReliableMessageProtocolConfig & config) { mRemoteSessionParams.SetMRPConfig(config); }
     103             : 
     104             :     /**
     105             :      * Encode the Session Parameters using the provided TLV tag.
     106             :      */
     107             :     static CHIP_ERROR EncodeSessionParameters(TLV::Tag tag, const Optional<ReliableMessageProtocolConfig> & mrpLocalConfig,
     108             :                                               TLV::TLVWriter & tlvWriter);
     109             : 
     110             : protected:
     111             :     /**
     112             :      * Allocate a secure session object from the passed session manager for the
     113             :      * pending session establishment operation.
     114             :      *
     115             :      * @param sessionManager        Session manager from which to allocate a secure session object
     116             :      * @param sessionEvictionHint   If we're either establishing or just finished establishing a session to a peer in either
     117             :      * initiator or responder roles, the node id of that peer should be provided in this argument. Else, it should be initialized to
     118             :      * a default-constructed ScopedNodeId().
     119             :      *
     120             :      * @return CHIP_ERROR The outcome of the allocation attempt
     121             :      */
     122             :     CHIP_ERROR AllocateSecureSession(SessionManager & sessionManager, const ScopedNodeId & sessionEvictionHint = ScopedNodeId());
     123             : 
     124             :     CHIP_ERROR ActivateSecureSession(const Transport::PeerAddress & peerAddress);
     125             : 
     126             :     void Finish();
     127             : 
     128             :     void DiscardExchange(); // Clear our reference to our exchange context pointer so that it can close itself at some later time.
     129             : 
     130          30 :     void SetPeerSessionId(uint16_t id) { mPeerSessionId.SetValue(id); }
     131           0 :     virtual void OnSuccessStatusReport() {}
     132           0 :     virtual CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode)
     133             :     {
     134           0 :         return CHIP_ERROR_INTERNAL;
     135             :     }
     136             : 
     137          15 :     void SendStatusReport(Messaging::ExchangeContext * exchangeCtxt, uint16_t protocolCode)
     138             :     {
     139          15 :         Protocols::SecureChannel::GeneralStatusCode generalCode = (protocolCode == Protocols::SecureChannel::kProtocolCodeSuccess)
     140          15 :             ? Protocols::SecureChannel::GeneralStatusCode::kSuccess
     141             :             : Protocols::SecureChannel::GeneralStatusCode::kFailure;
     142             : 
     143          15 :         ChipLogDetail(SecureChannel, "Sending status report. Protocol code %d, exchange %d", protocolCode,
     144             :                       exchangeCtxt->GetExchangeId());
     145             : 
     146          15 :         Protocols::SecureChannel::StatusReport statusReport(generalCode, Protocols::SecureChannel::Id, protocolCode);
     147             : 
     148          15 :         auto handle = System::PacketBufferHandle::New(statusReport.Size());
     149          15 :         VerifyOrReturn(!handle.IsNull(), ChipLogError(SecureChannel, "Failed to allocate status report message"));
     150          15 :         Encoding::LittleEndian::PacketBufferWriter bbuf(std::move(handle));
     151             : 
     152          15 :         statusReport.WriteToBuffer(bbuf);
     153             : 
     154          15 :         System::PacketBufferHandle msg = bbuf.Finalize();
     155          15 :         VerifyOrReturn(!msg.IsNull(), ChipLogError(SecureChannel, "Failed to allocate status report message"));
     156             : 
     157          15 :         CHIP_ERROR err = exchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::StatusReport, std::move(msg));
     158          15 :         if (err != CHIP_NO_ERROR)
     159             :         {
     160           0 :             ChipLogError(SecureChannel, "Failed to send status report message: %" CHIP_ERROR_FORMAT, err.Format());
     161             :         }
     162          15 :     }
     163             : 
     164          15 :     CHIP_ERROR HandleStatusReport(System::PacketBufferHandle && msg, bool successExpected)
     165             :     {
     166          15 :         Protocols::SecureChannel::StatusReport report;
     167          15 :         ReturnErrorOnFailure(report.Parse(std::move(msg)));
     168          15 :         VerifyOrReturnError(report.GetProtocolId() == Protocols::SecureChannel::Id, CHIP_ERROR_INVALID_ARGUMENT);
     169             : 
     170          28 :         if (report.GetGeneralCode() == Protocols::SecureChannel::GeneralStatusCode::kSuccess &&
     171          28 :             report.GetProtocolCode() == Protocols::SecureChannel::kProtocolCodeSuccess && successExpected)
     172             :         {
     173          13 :             OnSuccessStatusReport();
     174          13 :             return CHIP_NO_ERROR;
     175             :         }
     176             : 
     177           3 :         if (report.GetGeneralCode() == Protocols::SecureChannel::GeneralStatusCode::kBusy &&
     178           1 :             report.GetProtocolCode() == Protocols::SecureChannel::kProtocolCodeBusy)
     179             :         {
     180           1 :             if (!report.GetProtocolData().IsNull())
     181             :             {
     182           1 :                 Encoding::LittleEndian::Reader reader(report.GetProtocolData()->Start(), report.GetProtocolData()->DataLength());
     183             : 
     184           1 :                 uint16_t minimumWaitTime = 0;
     185           1 :                 CHIP_ERROR waitTimeErr   = reader.Read16(&minimumWaitTime).StatusCode();
     186           1 :                 if (waitTimeErr != CHIP_NO_ERROR)
     187             :                 {
     188           0 :                     ChipLogError(SecureChannel, "Failed to read the minimum wait time: %" CHIP_ERROR_FORMAT, waitTimeErr.Format());
     189             :                 }
     190             :                 else
     191             :                 {
     192             :                     // TODO: CASE: Notify minimum wait time to clients on receiving busy status report #28290
     193           1 :                     ChipLogProgress(SecureChannel, "Received busy status report with minimum wait time: %u ms", minimumWaitTime);
     194             :                 }
     195             :             }
     196             :         }
     197             : 
     198             :         // It's very important that we propagate the return value from
     199             :         // OnFailureStatusReport out to the caller.  Make sure we return it directly.
     200           2 :         return OnFailureStatusReport(report.GetGeneralCode(), report.GetProtocolCode());
     201          15 :     }
     202             : 
     203             :     /**
     204             :      * Try to decode the current element (pointed by the TLV reader) as MRP parameters.
     205             :      * If the MRP parameters are found, mRemoteSessionParams is updated with the devoded values.
     206             :      *
     207             :      * MRP parameters are optional. So, if the TLV reader is not pointing to the MRP parameters,
     208             :      * the function is a noop.
     209             :      *
     210             :      * If the parameters are present, but TLV reader fails to correctly parse it, the function will
     211             :      * return the corresponding error.
     212             :      */
     213             :     CHIP_ERROR DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TLV::ContiguousBufferTLVReader & tlvReader);
     214             : 
     215             :     bool IsSessionEstablishmentInProgress();
     216             : 
     217             :     // TODO: remove Clear, we should create a new instance instead reset the old instance.
     218             :     void Clear();
     219             : 
     220             :     /**
     221             :      * Notify our delegate about a session establishment error and the stage when the error occurs
     222             :      * if we have not already notified it of an error or success before.
     223             :      *
     224             :      * @param error The error code to report.
     225             :      * @param stage The stage of the session when the error occurs, defaults to kNotInKeyExchange.
     226             :      */
     227             :     void NotifySessionEstablishmentError(CHIP_ERROR error,
     228             :                                          SessionEstablishmentStage stage = SessionEstablishmentStage::kNotInKeyExchange);
     229             : 
     230             : protected:
     231             :     CryptoContext::SessionRole mRole;
     232             :     SessionHolderWithDelegate mSecureSessionHolder;
     233             :     // mSessionManager is set if we actually allocate a secure session, so we
     234             :     // can clean it up later as needed.
     235             :     SessionManager * mSessionManager           = nullptr;
     236             :     Messaging::ExchangeContext * mExchangeCtxt = nullptr;
     237             :     SessionEstablishmentDelegate * mDelegate   = nullptr;
     238             : 
     239             :     // mLocalMRPConfig is our config which is sent to the other end and used by the peer session.
     240             :     // mRemoteSessionParams is received from other end and set to our session.
     241             :     Optional<ReliableMessageProtocolConfig> mLocalMRPConfig;
     242             :     SessionParameters mRemoteSessionParams;
     243             : 
     244             : private:
     245             :     Optional<uint16_t> mPeerSessionId;
     246             : };
     247             : 
     248             : } // namespace chip

Generated by: LCOV version 1.14