Line data Source code
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 15060 : EncryptedPacketBufferHandle() {}
91 : EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)) {}
92 :
93 15096 : 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 : 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 2 : 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 2 : 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 2 : CHIP_ERROR InsertPacketHeader(const PacketHeader & aPacketHeader) { return aPacketHeader.EncodeBeforeData(*this); }
129 : #endif // CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
130 :
131 15096 : static EncryptedPacketBufferHandle MarkEncrypted(PacketBufferHandle && aBuffer)
132 : {
133 15096 : return EncryptedPacketBufferHandle(std::move(aBuffer));
134 : }
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 15126 : PacketBufferHandle CastToWritable() const { return PacketBufferHandle::Retain(); }
142 :
143 : private:
144 15098 : 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 863 : void SetMessageDelegate(SessionMessageDelegate * cb) { mCB = cb; }
177 :
178 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
179 422 : 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 9 : void ForEachMatchingSession(const ScopedNodeId & node, Function && function)
219 : {
220 9 : mSecureSessions.ForEachSession([&](auto * session) {
221 36 : if (session->GetPeer() == node)
222 : {
223 9 : function(session);
224 : }
225 :
226 36 : return Loop::Continue;
227 : });
228 9 : }
229 :
230 : /**
231 : * Call the provided lambda on sessions that match the provided fabric index.
232 : *
233 : */
234 : template <typename Function>
235 2 : void ForEachMatchingSession(FabricIndex fabricIndex, Function && function)
236 : {
237 2 : mSecureSessions.ForEachSession([&](auto * session) {
238 16 : if (session->GetFabricIndex() == fabricIndex)
239 : {
240 6 : function(session);
241 : }
242 :
243 16 : return Loop::Continue;
244 : });
245 2 : }
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 0 : CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(const ScopedNodeId & node, Function && function)
259 : {
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 : {
278 0 : return Loop::Continue;
279 : }
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 : {
290 0 : function(session);
291 : }
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 0 : CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(FabricIndex fabricIndex, Function && function)
311 : {
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 : {
329 0 : return Loop::Continue;
330 : }
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 : {
339 0 : function(session);
340 : }
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 25358 : 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 : TransportMgrBase * GetTransportManager() const { return mTransportMgr; }
462 1 : 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 27 : Optional<SessionHandle> CreateUnauthenticatedSession(const Transport::PeerAddress & peerAddress,
496 : const ReliableMessageProtocolConfig & config)
497 : {
498 : // Allocate ephemeralInitiatorNodeID in Operational Node ID range
499 : NodeId ephemeralInitiatorNodeID;
500 : do
501 : {
502 27 : ephemeralInitiatorNodeID = static_cast<NodeId>(Crypto::GetRandU64());
503 27 : } while (!IsOperationalNodeId(ephemeralInitiatorNodeID));
504 27 : return mUnauthenticatedSessions.AllocInitiator(ephemeralInitiatorNodeID, peerAddress, config);
505 : }
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 7 : void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override
524 : {
525 : (void) fabricTable;
526 7 : this->FabricRemoved(fabricIndex);
527 7 : }
528 :
529 29742 : FabricTable * GetFabricTable() const { return mFabricTable; }
530 :
531 169 : Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; }
532 :
533 2 : 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 15098 : static bool IsControlMessage(PayloadHeader & payloadHeader)
623 : {
624 30196 : return payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq) ||
625 30196 : payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp);
626 : }
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 2500 : inline System::PacketBufferHandle New(size_t aAvailableSize)
648 : {
649 : static_assert(System::PacketBuffer::kMaxSize > kMaxFooterSize, "inadequate capacity");
650 2500 : if (aAvailableSize > System::PacketBuffer::kMaxSize - kMaxFooterSize)
651 : {
652 0 : return System::PacketBufferHandle();
653 : }
654 2500 : return System::PacketBufferHandle::New(aAvailableSize + kMaxFooterSize);
655 : }
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 127 : inline System::PacketBufferHandle NewWithData(const void * aData, size_t aDataSize)
666 : {
667 127 : return System::PacketBufferHandle::NewWithData(aData, aDataSize, kMaxFooterSize);
668 : }
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 2 : inline bool HasFooterSpace(const System::PacketBufferHandle & aBuffer)
676 : {
677 2 : return aBuffer->AvailableDataLength() >= kMaxFooterSize;
678 : }
679 :
680 : } // namespace MessagePacketBuffer
681 :
682 : } // namespace chip
|