Coverage Report

Created: 2026-03-27 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/connectedhomeip/src/transport/SessionManager.h
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2020-2021 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 secure transport layer which adds encryption to data
22
 *   sent over a transport.
23
 *
24
 */
25
26
#pragma once
27
28
#include <utility>
29
30
#include <credentials/FabricTable.h>
31
#include <crypto/RandUtils.h>
32
#include <crypto/SessionKeystore.h>
33
#include <inet/IPAddress.h>
34
#include <lib/core/CHIPCore.h>
35
#include <lib/core/CHIPPersistentStorageDelegate.h>
36
#include <lib/support/CodeUtils.h>
37
#include <lib/support/DLLUtil.h>
38
#include <messaging/ReliableMessageProtocolConfig.h>
39
#include <protocols/secure_channel/Constants.h>
40
#include <transport/CryptoContext.h>
41
#include <transport/GroupPeerMessageCounter.h>
42
#include <transport/GroupSession.h>
43
#include <transport/MessageCounterManagerInterface.h>
44
#include <transport/MessageStats.h>
45
#include <transport/SecureSessionTable.h>
46
#include <transport/Session.h>
47
#include <transport/SessionDelegate.h>
48
#include <transport/SessionHolder.h>
49
#include <transport/SessionMessageDelegate.h>
50
#include <transport/TransportMgr.h>
51
#include <transport/UnauthenticatedSessionTable.h>
52
#include <transport/raw/Base.h>
53
#include <transport/raw/PeerAddress.h>
54
#include <transport/raw/Tuple.h>
55
56
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
57
#include <transport/SessionConnectionDelegate.h>
58
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
59
60
namespace chip {
61
62
/*
63
 * This enum indicates whether a session needs to be established over a
64
 * suitable transport that meets certain payload size requirements for
65
 * transmitted messages.
66
 *
67
 */
68
enum class TransportPayloadCapability : uint8_t
69
{
70
    kMRPPayload,               // Transport requires the maximum payload size to fit within a single
71
                               // IPv6 packet(1280 bytes).
72
    kLargePayload,             // Transport needs to handle payloads larger than the single IPv6
73
                               // packet, as supported by MRP. The transport of choice, in this
74
                               // case, is TCP.
75
    kMRPOrTCPCompatiblePayload // This option provides the ability to use MRP
76
                               // as the preferred transport, but use a large
77
                               // payload transport if that is already
78
                               // available.
79
};
80
/**
81
 * @brief
82
 *  Tracks ownership of a encrypted packet buffer.
83
 *
84
 *  EncryptedPacketBufferHandle is a kind of PacketBufferHandle class and used to hold a packet buffer
85
 *  object whose payload has already been encrypted.
86
 */
87
class EncryptedPacketBufferHandle final : private System::PacketBufferHandle
88
{
89
public:
90
0
    EncryptedPacketBufferHandle() {}
91
0
    EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)) {}
92
93
0
    void operator=(EncryptedPacketBufferHandle && aBuffer) { PacketBufferHandle::operator=(std::move(aBuffer)); }
94
95
    using System::PacketBufferHandle::IsNull;
96
    // Pass-through to HasChainedBuffer on our underlying buffer without
97
    // exposing operator->
98
0
    bool HasChainedBuffer() const { return (*this)->HasChainedBuffer(); }
99
100
    uint32_t GetMessageCounter() const;
101
102
    /**
103
     * Creates a copy of the data in this packet.
104
     *
105
     * Does NOT support chained buffers.
106
     *
107
     * @returns empty handle on allocation failure.
108
     */
109
0
    EncryptedPacketBufferHandle CloneData() { return EncryptedPacketBufferHandle(PacketBufferHandle::CloneData()); }
110
111
#ifdef CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
112
    /**
113
     * Extracts the (unencrypted) packet header from this encrypted packet
114
     * buffer.  Returns error if a packet header cannot be extracted (e.g. if
115
     * there are not enough bytes in this packet buffer).  After this call the
116
     * buffer does not have a packet header.  This API is meant for
117
     * unit tests only.   The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
118
     * should not be defined normally.
119
     */
120
    CHIP_ERROR ExtractPacketHeader(PacketHeader & aPacketHeader) { return aPacketHeader.DecodeAndConsume(*this); }
121
122
    /**
123
     * Inserts a new (unencrypted) packet header in the encrypted packet buffer
124
     * based on the given PacketHeader.  This API is meant for
125
     * unit tests only.   The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
126
     * should not be defined normally.
127
     */
128
    CHIP_ERROR InsertPacketHeader(const PacketHeader & aPacketHeader) { return aPacketHeader.EncodeBeforeData(*this); }
129
#endif // CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
130
131
    static EncryptedPacketBufferHandle MarkEncrypted(PacketBufferHandle && aBuffer)
132
0
    {
133
0
        return EncryptedPacketBufferHandle(std::move(aBuffer));
134
0
    }
135
136
    /**
137
     * Get a handle to the data that allows mutating the bytes.  This should
138
     * only be used if absolutely necessary, because EncryptedPacketBufferHandle
139
     * represents a buffer that we want to resend as-is.
140
     */
141
0
    PacketBufferHandle CastToWritable() const { return PacketBufferHandle::Retain(); }
142
143
private:
144
0
    EncryptedPacketBufferHandle(PacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)) {}
145
};
146
147
class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTable::Delegate
148
{
149
public:
150
    SessionManager();
151
    ~SessionManager() override;
152
153
    /**
154
     * @brief
155
     *   This function takes the payload and returns an encrypted message which can be sent multiple times.
156
     *   Every successful call to this function MUST be followed by a send attempt with the prepared message.
157
     *
158
     * @details
159
     *   It does the following:
160
     *    1. Encrypt the msgBuf
161
     *    2. construct the packet header
162
     *    3. Encode the packet header and prepend it to message.
163
     *   Returns a encrypted message in encryptedMessage.
164
     */
165
    CHIP_ERROR PrepareMessage(const SessionHandle & session, PayloadHeader & payloadHeader, System::PacketBufferHandle && msgBuf,
166
                              EncryptedPacketBufferHandle & encryptedMessage);
167
168
    /**
169
     * @brief
170
     *   Send a prepared message to a currently connected peer.
171
     */
172
    CHIP_ERROR SendPreparedMessage(const SessionHandle & session, const EncryptedPacketBufferHandle & preparedMessage);
173
174
    /// @brief Set the delegate for handling incoming messages. There can be only one message delegate (probably the
175
    /// ExchangeManager)
176
0
    void SetMessageDelegate(SessionMessageDelegate * cb) { mCB = cb; }
177
178
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
179
0
    void SetConnectionDelegate(SessionConnectionDelegate * cb) { mConnDelegate = cb; }
180
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
181
182
    // Test-only: create a session on the fly.
183
    CHIP_ERROR InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId,
184
                                            uint16_t peerSessionId, FabricIndex fabricIndex,
185
                                            const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role);
186
    CHIP_ERROR InjectCaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, uint16_t peerSessionId,
187
                                            NodeId localNodeId, NodeId peerNodeId, FabricIndex fabric,
188
                                            const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role,
189
                                            const CATValues & cats = CATValues{});
190
191
    /**
192
     * @brief
193
     *   Allocate a secure session and non-colliding session ID in the secure
194
     *   session table.
195
     *
196
     *   If we're either establishing or just finished establishing a session to a peer in either initiator or responder
197
     *   roles, the node id of that peer should be provided in sessionEvictionHint. Else, it should be initialized
198
     *   to a default-constructed ScopedNodeId().
199
     *
200
     * @return SessionHandle with a reference to a SecureSession, else NullOptional on failure
201
     */
202
    CHECK_RETURN_VALUE
203
    Optional<SessionHandle> AllocateSession(Transport::SecureSession::Type secureSessionType,
204
                                            const ScopedNodeId & sessionEvictionHint);
205
206
    /**
207
     *  A set of templated helper function that call a provided lambda
208
     *  on all sessions in the underlying session table that match the provided
209
     *  query criteria.
210
     *
211
     */
212
213
    /**
214
     * Call the provided lambda on sessions whose remote side match the provided ScopedNodeId.
215
     *
216
     */
217
    template <typename Function>
218
    void ForEachMatchingSession(const ScopedNodeId & node, Function && function)
219
0
    {
220
0
        mSecureSessions.ForEachSession([&](auto * session) {
221
0
            if (session->GetPeer() == node)
222
0
            {
223
0
                function(session);
224
0
            }
225
226
0
            return Loop::Continue;
227
0
        });
Unexecuted instantiation: SessionManager.cpp:auto chip::SessionManager::ForEachMatchingSession<chip::SessionManager::ExpireAllSessions(chip::ScopedNodeId const&)::$_0>(chip::ScopedNodeId const&, chip::SessionManager::ExpireAllSessions(chip::ScopedNodeId const&)::$_0&&)::{lambda(auto:1*)#1}::operator()<chip::Transport::SecureSession>(chip::Transport::SecureSession*) const
Unexecuted instantiation: ReadClient.cpp:auto chip::SessionManager::ForEachMatchingSession<chip::app::ReadClient::TriggerResubscriptionForLivenessTimeout(chip::ChipError)::$_0>(chip::ScopedNodeId const&, chip::app::ReadClient::TriggerResubscriptionForLivenessTimeout(chip::ChipError)::$_0&&)::{lambda(auto:1*)#1}::operator()<chip::Transport::SecureSession>(chip::Transport::SecureSession*) const
228
0
    }
Unexecuted instantiation: SessionManager.cpp:void chip::SessionManager::ForEachMatchingSession<chip::SessionManager::ExpireAllSessions(chip::ScopedNodeId const&)::$_0>(chip::ScopedNodeId const&, chip::SessionManager::ExpireAllSessions(chip::ScopedNodeId const&)::$_0&&)
Unexecuted instantiation: ReadClient.cpp:void chip::SessionManager::ForEachMatchingSession<chip::app::ReadClient::TriggerResubscriptionForLivenessTimeout(chip::ChipError)::$_0>(chip::ScopedNodeId const&, chip::app::ReadClient::TriggerResubscriptionForLivenessTimeout(chip::ChipError)::$_0&&)
229
230
    /**
231
     * Call the provided lambda on sessions that match the provided fabric index.
232
     *
233
     */
234
    template <typename Function>
235
    void ForEachMatchingSession(FabricIndex fabricIndex, Function && function)
236
0
    {
237
0
        mSecureSessions.ForEachSession([&](auto * session) {
238
0
            if (session->GetFabricIndex() == fabricIndex)
239
0
            {
240
0
                function(session);
241
0
            }
242
243
0
            return Loop::Continue;
244
0
        });
245
0
    }
246
247
    /**
248
     * Call the provided lambda on all sessions whose remote side match the logical fabric
249
     * associated with the provided ScopedNodeId and target the same logical remote node.
250
     *
251
     * *NOTE* This is identical in behavior to ForEachMatchingSession(const ScopedNodeId ..)
252
     *        EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
253
     *        on the same logical fabric (i.e root public key + fabric ID tuple).
254
     *        This can ONLY happen if multiple controller instances on the same fabric is permitted
255
     *        and each is assigned a unique fabric index.
256
     */
257
    template <typename Function>
258
    CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(const ScopedNodeId & node, Function && function)
259
0
    {
260
0
        Crypto::P256PublicKey targetPubKey;
261
262
0
        auto * targetFabric = mFabricTable->FindFabricWithIndex(node.GetFabricIndex());
263
0
        VerifyOrReturnError(targetFabric != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
264
265
0
        auto err = targetFabric->FetchRootPubkey(targetPubKey);
266
0
        VerifyOrDie(err == CHIP_NO_ERROR);
267
268
0
        mSecureSessions.ForEachSession([&](auto * session) {
269
0
            Crypto::P256PublicKey comparePubKey;
270
271
            //
272
            // It's entirely possible to either come across a PASE session OR, a CASE session
273
            // that has yet to be activated (i.e a CASEServer holding onto a SecureSession object
274
            // waiting for a Sigma1 message to arrive). Let's skip those.
275
            //
276
0
            if (!session->IsCASESession() || session->GetFabricIndex() == kUndefinedFabricIndex)
277
0
            {
278
0
                return Loop::Continue;
279
0
            }
280
281
0
            auto * compareFabric = mFabricTable->FindFabricWithIndex(session->GetFabricIndex());
282
0
            VerifyOrDie(compareFabric != nullptr);
283
284
0
            err = compareFabric->FetchRootPubkey(comparePubKey);
285
0
            VerifyOrDie(err == CHIP_NO_ERROR);
286
287
0
            if (comparePubKey.Matches(targetPubKey) && targetFabric->GetFabricId() == compareFabric->GetFabricId() &&
288
0
                session->GetPeerNodeId() == node.GetNodeId())
289
0
            {
290
0
                function(session);
291
0
            }
292
293
0
            return Loop::Continue;
294
0
        });
295
296
0
        return CHIP_NO_ERROR;
297
0
    }
298
299
    /**
300
     * Call the provided lambda on all sessions that match the logical fabric
301
     * associated with the provided fabric index.
302
     *
303
     * *NOTE* This is identical in behavior to ForEachMatchingSession(FabricIndex ..)
304
     *        EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
305
     *        on the same logical fabric (i.e root public key + fabric ID tuple).
306
     *        This can ONLY happen if multiple controller instances on the same fabric is permitted
307
     *        and each is assigned a unique fabric index.
308
     */
309
    template <typename Function>
310
    CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(FabricIndex fabricIndex, Function && function)
311
0
    {
312
0
        Crypto::P256PublicKey targetPubKey;
313
314
0
        auto * targetFabric = mFabricTable->FindFabricWithIndex(fabricIndex);
315
0
        VerifyOrReturnError(targetFabric != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
316
317
0
        SuccessOrDie(targetFabric->FetchRootPubkey(targetPubKey));
318
319
0
        mSecureSessions.ForEachSession([&](auto * session) {
320
0
            Crypto::P256PublicKey comparePubKey;
321
322
            //
323
            // It's entirely possible to either come across a PASE session OR, a CASE session
324
            // that has yet to be activated (i.e a CASEServer holding onto a SecureSession object
325
            // waiting for a Sigma1 message to arrive). Let's skip those.
326
            //
327
0
            if (!session->IsCASESession() || session->GetFabricIndex() == kUndefinedFabricIndex)
328
0
            {
329
0
                return Loop::Continue;
330
0
            }
331
332
0
            auto * compareFabric = mFabricTable->FindFabricWithIndex(session->GetFabricIndex());
333
0
            VerifyOrDie(compareFabric != nullptr);
334
335
0
            SuccessOrDie(compareFabric->FetchRootPubkey(comparePubKey));
336
337
0
            if (comparePubKey.Matches(targetPubKey) && targetFabric->GetFabricId() == compareFabric->GetFabricId())
338
0
            {
339
0
                function(session);
340
0
            }
341
342
0
            return Loop::Continue;
343
0
        });
344
345
0
        return CHIP_NO_ERROR;
346
0
    }
347
348
    /**
349
     * Expire all sessions for a given peer, as identified by a specific fabric
350
     * index and node ID.
351
     */
352
    void ExpireAllSessions(const ScopedNodeId & node);
353
354
    /**
355
     * Expire all sessions associated with the given fabric index.
356
     *
357
     * *NOTE* This is generally all sessions for a given fabric _EXCEPT_ if there are multiple
358
     *        FabricInfo instances in the FabricTable that collide on the same logical fabric (i.e
359
     *        root public key + fabric ID tuple).  This can ONLY happen if multiple controller
360
     *        instances on the same fabric is permitted and each is assigned a unique fabric index.
361
     */
362
    void ExpireAllSessionsForFabric(FabricIndex fabricIndex);
363
364
    /**
365
     * Expire all sessions whose remote side matches the logical fabric
366
     * associated with the provided ScopedNodeId and target the same logical remote node.
367
     *
368
     * *NOTE* This is identical in behavior to ExpireAllSessions(const ScopedNodeId ..)
369
     *        EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
370
     *        on the same logical fabric (i.e root public key + fabric ID tuple).  This can ONLY happen
371
     *        if multiple controller instances on the same fabric is permitted and each is assigned
372
     *        a unique fabric index.
373
     *
374
     */
375
    CHIP_ERROR ExpireAllSessionsOnLogicalFabric(const ScopedNodeId & node);
376
377
    /**
378
     * Expire all sessions whose remote side matches the logical fabric
379
     * associated with the provided fabric index.
380
     *
381
     * *NOTE* This is identical in behavior to ExpireAllSessExpireAllSessionsForFabricions(FabricIndex ..)
382
     *        EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
383
     *        on the same logical fabric (i.e root public key + fabric ID tuple).  This can ONLY happen
384
     *        if multiple controller instances on the same fabric is permitted and each is assigned
385
     *        a unique fabric index.
386
     *
387
     */
388
    CHIP_ERROR ExpireAllSessionsOnLogicalFabric(FabricIndex fabricIndex);
389
390
    void ExpireAllPASESessions();
391
392
    /**
393
     * Expire all secure sessions.  See documentation for Shutdown on when it's
394
     * appropriate to use this.
395
     */
396
    void ExpireAllSecureSessions();
397
398
    /**
399
     * @brief
400
     *   Marks all active sessions that match provided arguments as defunct.
401
     *
402
     * @param node    Scoped node ID of the active sessions we should mark as defunct.
403
     * @param type    Type of session we are looking to mark as defunct. If matching
404
     *                against all types of sessions is desired, NullOptional should
405
     *                be passed into type.
406
     */
407
    void MarkSessionsAsDefunct(const ScopedNodeId & node, const Optional<Transport::SecureSession::Type> & type);
408
409
    /**
410
     * @brief
411
     *   Update all CASE sessions that match `node` with the provided transport peer address.
412
     *
413
     * @param node    Scoped node ID of the active sessions we want to update.
414
     * @param addr    Transport peer address that we want to update to.
415
     */
416
    void UpdateAllSessionsPeerAddress(const ScopedNodeId & node, const Transport::PeerAddress & addr);
417
418
    /**
419
     * @brief
420
     *   Return the System Layer pointer used by current SessionManager.
421
     */
422
0
    System::Layer * SystemLayer() { return mSystemLayer; }
423
424
    /**
425
     * @brief
426
     *   Initialize a Secure Session Manager
427
     *
428
     * @param systemLayer           System layer to use
429
     * @param transportMgr          Transport to use
430
     * @param messageCounterManager The message counter manager
431
     * @param storageDelegate       Persistent storage implementation
432
     * @param fabricTable           Fabric table to hold information about joined fabrics
433
     * @param sessionKeystore       Session keystore for management of symmetric encryption keys
434
     */
435
    CHIP_ERROR Init(System::Layer * systemLayer, TransportMgrBase * transportMgr,
436
                    Transport::MessageCounterManagerInterface * messageCounterManager,
437
                    chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable,
438
                    Crypto::SessionKeystore & sessionKeystore);
439
440
    /**
441
     * @brief
442
     *  Shutdown the Secure Session Manager. This terminates this instance
443
     *  of the object and reset it's state.
444
     *
445
     * The proper order of shutdown for SessionManager is as follows:
446
     *
447
     * 1) Call ExpireAllSecureSessions() on the SessionManager, and ensure that any unauthenticated
448
     *    sessions (e.g. CASEServer and CASESessionManager instances, or anything that does PASE
449
     *    handshakes) are released.
450
     * 2) Shut down the exchange manager, so that it's no longer referencing
451
     *    the to-be-shut-down SessionManager.
452
     * 3) Shut down the SessionManager.
453
     */
454
    void Shutdown();
455
456
    /**
457
     * @brief Notification that a fabric was removed.
458
     */
459
    void FabricRemoved(FabricIndex fabricIndex);
460
461
0
    TransportMgrBase * GetTransportManager() const { return mTransportMgr; }
462
0
    Transport::SecureSessionTable & GetSecureSessions() { return mSecureSessions; }
463
464
    /**
465
     * @brief
466
     *   Handle received secure message. Implements TransportMgrDelegate
467
     *
468
     * @param source    the source address of the package
469
     * @param msgBuf    the buffer containing a full CHIP message (except for the optional length field).
470
     * @param ctxt      pointer to additional context on the underlying transport. For TCP, it is a pointer
471
     *                  to the underlying connection object.
472
     */
473
    void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf,
474
                           Transport::MessageTransportContext * ctxt = nullptr) override;
475
476
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
477
    CHIP_ERROR TCPConnect(const Transport::PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState,
478
                          Transport::ActiveTCPConnectionHandle & peerConnState);
479
480
    void HandleConnectionReceived(Transport::ActiveTCPConnectionState & conn) override;
481
482
    void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionHandle & conn, CHIP_ERROR conErr) override;
483
484
    void HandleConnectionClosed(Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr) override;
485
486
    // Functors for callbacks into higher layers
487
    using OnTCPConnectionReceivedCallback = void (*)(Transport::ActiveTCPConnectionHandle & conn);
488
489
    using OnTCPConnectionCompleteCallback = void (*)(Transport::ActiveTCPConnectionHandle & conn, CHIP_ERROR conErr);
490
491
    using OnTCPConnectionClosedCallback = void (*)(Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr);
492
493
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
494
495
    Optional<SessionHandle> CreateUnauthenticatedSession(const Transport::PeerAddress & peerAddress,
496
                                                         const ReliableMessageProtocolConfig & config)
497
0
    {
498
        // Allocate ephemeralInitiatorNodeID in Operational Node ID range
499
0
        NodeId ephemeralInitiatorNodeID;
500
0
        do
501
0
        {
502
0
            ephemeralInitiatorNodeID = static_cast<NodeId>(Crypto::GetRandU64());
503
0
        } while (!IsOperationalNodeId(ephemeralInitiatorNodeID));
504
0
        return mUnauthenticatedSessions.AllocInitiator(ephemeralInitiatorNodeID, peerAddress, config);
505
0
    }
506
507
    //
508
    // Find an existing secure session given a peer's scoped NodeId and a type of session to match against.
509
    // If matching against all types of sessions is desired, NullOptional should be passed into type.
510
    //
511
    // If a valid session is found, an Optional<SessionHandle> with the value set to the SessionHandle of the session
512
    // is returned. Otherwise, an Optional<SessionHandle> with no value set is returned.
513
    //
514
    //
515
    Optional<SessionHandle>
516
    FindSecureSessionForNode(ScopedNodeId peerNodeId, const Optional<Transport::SecureSession::Type> & type = NullOptional,
517
                             TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload);
518
519
    using SessionHandleCallback = bool (*)(void * context, SessionHandle & sessionHandle);
520
    CHIP_ERROR ForEachSessionHandle(void * context, SessionHandleCallback callback);
521
522
    //// FabricTable::Delegate Implementation ////
523
    void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override
524
0
    {
525
0
        (void) fabricTable;
526
0
        this->FabricRemoved(fabricIndex);
527
0
    }
528
529
0
    FabricTable * GetFabricTable() const { return mFabricTable; }
530
531
0
    Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; }
532
533
0
    MessageStats GetMessageStats() const { return mMessageStats; }
534
535
private:
536
    /**
537
     *    The State of a secure transport object.
538
     */
539
    enum class State
540
    {
541
        kNotReady,    /**< State before initialization. */
542
        kInitialized, /**< State when the object is ready connect to other peers. */
543
    };
544
545
    enum class EncryptionState
546
    {
547
        kPayloadIsEncrypted,
548
        kPayloadIsUnencrypted,
549
    };
550
551
    System::Layer * mSystemLayer               = nullptr;
552
    FabricTable * mFabricTable                 = nullptr;
553
    Crypto::SessionKeystore * mSessionKeystore = nullptr;
554
    Transport::UnauthenticatedSessionTable<CHIP_CONFIG_UNAUTHENTICATED_CONNECTION_POOL_SIZE> mUnauthenticatedSessions;
555
    Transport::SecureSessionTable mSecureSessions;
556
    State mState; // < Initialization state of the object
557
    chip::Transport::GroupOutgoingCounters mGroupClientCounter;
558
    MessageStats mMessageStats;
559
560
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
561
    OnTCPConnectionReceivedCallback mConnReceivedCb = nullptr;
562
    OnTCPConnectionCompleteCallback mConnCompleteCb = nullptr;
563
    OnTCPConnectionClosedCallback mConnClosedCb     = nullptr;
564
565
    // Hold the TCPConnection callback context for the receiver application in the SessionManager.
566
    // On receipt of a connection from a peer, the SessionManager
567
    Transport::AppTCPConnectionCallbackCtxt * mServerTCPConnCbCtxt = nullptr;
568
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
569
570
    SessionMessageDelegate * mCB = nullptr;
571
572
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
573
    SessionConnectionDelegate * mConnDelegate = nullptr;
574
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
575
576
    TransportMgrBase * mTransportMgr                                   = nullptr;
577
    Transport::MessageCounterManagerInterface * mMessageCounterManager = nullptr;
578
579
    GlobalUnencryptedMessageCounter mGlobalUnencryptedMessageCounter;
580
581
    /**
582
     * @brief Parse, decrypt, validate, and dispatch a secure unicast message.
583
     *
584
     * @param[in] partialPacketHeader The partial PacketHeader of the message after processing with DecodeFixed.
585
     * If the message decrypts successfully, this will be filled with a fully decoded PacketHeader.
586
     * @param[in] peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
587
     * @param msg The full message buffer, including header fields.
588
     * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer
589
     *             to the underlying connection object.
590
     */
591
    void SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
592
                                      System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr);
593
594
    /**
595
     * @brief Parse, decrypt, validate, and dispatch a secure group message.
596
     *
597
     * @param partialPacketHeader The partial PacketHeader of the message once processed with DecodeFixed.
598
     * @param peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
599
     * @param msg The full message buffer, including header fields.
600
     */
601
    void SecureGroupMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
602
                                    System::PacketBufferHandle && msg);
603
604
    /**
605
     * @brief Parse, decrypt, validate, and dispatch an unsecured message.
606
     *
607
     * @param partialPacketHeader The partial PacketHeader of the message after processing with DecodeFixed.
608
     * @param peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
609
     * @param msg The full message buffer, including header fields.
610
     * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer
611
     *             to the underlying connection object.
612
     */
613
    void UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
614
                                        System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr);
615
616
    void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source);
617
618
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
619
    void MarkSecureSessionOverTCPForEviction(Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr);
620
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
621
622
    static bool IsControlMessage(PayloadHeader & payloadHeader)
623
0
    {
624
0
        return payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq) ||
625
0
            payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp);
626
0
    }
627
628
    void CountMessagesReceived(const SessionHandle & sessionHandle, const PayloadHeader & payloadHeader);
629
    void CountMessagesSent(const SessionHandle & sessionHandle, const PayloadHeader & payloadHeader);
630
};
631
632
namespace MessagePacketBuffer {
633
/**
634
 * Maximum size of a message footer, in bytes.
635
 */
636
inline constexpr uint16_t kMaxFooterSize = kMaxTagLen;
637
638
/**
639
 * Allocates a packet buffer with space for message headers and footers.
640
 *
641
 *  Fails and returns \c nullptr if no memory is available, or if the size requested is too large.
642
 *
643
 *  @param[in]  aAvailableSize  Minimum number of octets to for application data.
644
 *
645
 *  @return     On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
646
 */
647
inline System::PacketBufferHandle New(size_t aAvailableSize)
648
0
{
649
0
    static_assert(System::PacketBuffer::kMaxSize > kMaxFooterSize, "inadequate capacity");
650
0
    if (aAvailableSize > System::PacketBuffer::kMaxSize - kMaxFooterSize)
651
0
    {
652
0
        return System::PacketBufferHandle();
653
0
    }
654
0
    return System::PacketBufferHandle::New(aAvailableSize + kMaxFooterSize);
655
0
}
656
657
/**
658
 * Allocates a packet buffer with initial contents.
659
 *
660
 *  @param[in]  aData           Initial buffer contents.
661
 *  @param[in]  aDataSize       Size of initial buffer contents.
662
 *
663
 *  @return     On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
664
 */
665
inline System::PacketBufferHandle NewWithData(const void * aData, size_t aDataSize)
666
0
{
667
0
    return System::PacketBufferHandle::NewWithData(aData, aDataSize, kMaxFooterSize);
668
0
}
669
670
/**
671
 * Check whether a packet buffer has enough space for a message footer.
672
 *
673
 * @returns true if there is space, false otherwise.
674
 */
675
inline bool HasFooterSpace(const System::PacketBufferHandle & aBuffer)
676
0
{
677
0
    return aBuffer->AvailableDataLength() >= kMaxFooterSize;
678
0
}
679
680
} // namespace MessagePacketBuffer
681
682
} // namespace chip