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/SecureSessionTable.h>
45 : #include <transport/Session.h>
46 : #include <transport/SessionDelegate.h>
47 : #include <transport/SessionHolder.h>
48 : #include <transport/SessionMessageDelegate.h>
49 : #include <transport/TransportMgr.h>
50 : #include <transport/UnauthenticatedSessionTable.h>
51 : #include <transport/raw/Base.h>
52 : #include <transport/raw/PeerAddress.h>
53 : #include <transport/raw/Tuple.h>
54 :
55 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
56 : #include <transport/SessionConnectionDelegate.h>
57 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
58 :
59 : namespace chip {
60 :
61 : /*
62 : * This enum indicates whether a session needs to be established over a
63 : * suitable transport that meets certain payload size requirements for
64 : * transmitted messages.
65 : *
66 : */
67 : enum class TransportPayloadCapability : uint8_t
68 : {
69 : kMRPPayload, // Transport requires the maximum payload size to fit within a single
70 : // IPv6 packet(1280 bytes).
71 : kLargePayload, // Transport needs to handle payloads larger than the single IPv6
72 : // packet, as supported by MRP. The transport of choice, in this
73 : // case, is TCP.
74 : kMRPOrTCPCompatiblePayload // This option provides the ability to use MRP
75 : // as the preferred transport, but use a large
76 : // payload transport if that is already
77 : // available.
78 : };
79 : /**
80 : * @brief
81 : * Tracks ownership of a encrypted packet buffer.
82 : *
83 : * EncryptedPacketBufferHandle is a kind of PacketBufferHandle class and used to hold a packet buffer
84 : * object whose payload has already been encrypted.
85 : */
86 : class EncryptedPacketBufferHandle final : private System::PacketBufferHandle
87 : {
88 : public:
89 9778 : EncryptedPacketBufferHandle() {}
90 : EncryptedPacketBufferHandle(EncryptedPacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)) {}
91 :
92 9823 : void operator=(EncryptedPacketBufferHandle && aBuffer) { PacketBufferHandle::operator=(std::move(aBuffer)); }
93 :
94 : using System::PacketBufferHandle::IsNull;
95 : // Pass-through to HasChainedBuffer on our underlying buffer without
96 : // exposing operator->
97 : bool HasChainedBuffer() const { return (*this)->HasChainedBuffer(); }
98 :
99 : uint32_t GetMessageCounter() const;
100 :
101 : /**
102 : * Creates a copy of the data in this packet.
103 : *
104 : * Does NOT support chained buffers.
105 : *
106 : * @returns empty handle on allocation failure.
107 : */
108 : EncryptedPacketBufferHandle CloneData() { return EncryptedPacketBufferHandle(PacketBufferHandle::CloneData()); }
109 :
110 : #ifdef CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
111 : /**
112 : * Extracts the (unencrypted) packet header from this encrypted packet
113 : * buffer. Returns error if a packet header cannot be extracted (e.g. if
114 : * there are not enough bytes in this packet buffer). After this call the
115 : * buffer does not have a packet header. This API is meant for
116 : * unit tests only. The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
117 : * should not be defined normally.
118 : */
119 : CHIP_ERROR ExtractPacketHeader(PacketHeader & aPacketHeader) { return aPacketHeader.DecodeAndConsume(*this); }
120 :
121 : /**
122 : * Inserts a new (unencrypted) packet header in the encrypted packet buffer
123 : * based on the given PacketHeader. This API is meant for
124 : * unit tests only. The CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API define
125 : * should not be defined normally.
126 : */
127 : CHIP_ERROR InsertPacketHeader(const PacketHeader & aPacketHeader) { return aPacketHeader.EncodeBeforeData(*this); }
128 : #endif // CHIP_ENABLE_TEST_ENCRYPTED_BUFFER_API
129 :
130 9823 : static EncryptedPacketBufferHandle MarkEncrypted(PacketBufferHandle && aBuffer)
131 : {
132 9823 : return EncryptedPacketBufferHandle(std::move(aBuffer));
133 : }
134 :
135 : /**
136 : * Get a handle to the data that allows mutating the bytes. This should
137 : * only be used if absolutely necessary, because EncryptedPacketBufferHandle
138 : * represents a buffer that we want to resend as-is.
139 : */
140 9857 : PacketBufferHandle CastToWritable() const { return PacketBufferHandle::Retain(); }
141 :
142 : private:
143 9777 : EncryptedPacketBufferHandle(PacketBufferHandle && aBuffer) : PacketBufferHandle(std::move(aBuffer)) {}
144 : };
145 :
146 : class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTable::Delegate
147 : {
148 : public:
149 : SessionManager();
150 : ~SessionManager() override;
151 :
152 : /**
153 : * @brief
154 : * This function takes the payload and returns an encrypted message which can be sent multiple times.
155 : *
156 : * @details
157 : * It does the following:
158 : * 1. Encrypt the msgBuf
159 : * 2. construct the packet header
160 : * 3. Encode the packet header and prepend it to message.
161 : * Returns a encrypted message in encryptedMessage.
162 : */
163 : CHIP_ERROR PrepareMessage(const SessionHandle & session, PayloadHeader & payloadHeader, System::PacketBufferHandle && msgBuf,
164 : EncryptedPacketBufferHandle & encryptedMessage);
165 :
166 : /**
167 : * @brief
168 : * Send a prepared message to a currently connected peer.
169 : */
170 : CHIP_ERROR SendPreparedMessage(const SessionHandle & session, const EncryptedPacketBufferHandle & preparedMessage);
171 :
172 : /// @brief Set the delegate for handling incoming messages. There can be only one message delegate (probably the
173 : /// ExchangeManager)
174 98 : void SetMessageDelegate(SessionMessageDelegate * cb) { mCB = cb; }
175 :
176 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
177 345 : void SetConnectionDelegate(SessionConnectionDelegate * cb) { mConnDelegate = cb; }
178 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
179 :
180 : // Test-only: create a session on the fly.
181 : CHIP_ERROR InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId,
182 : uint16_t peerSessionId, FabricIndex fabricIndex,
183 : const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role);
184 : CHIP_ERROR InjectCaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, uint16_t peerSessionId,
185 : NodeId localNodeId, NodeId peerNodeId, FabricIndex fabric,
186 : const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role,
187 : const CATValues & cats = CATValues{});
188 :
189 : /**
190 : * @brief
191 : * Allocate a secure session and non-colliding session ID in the secure
192 : * session table.
193 : *
194 : * If we're either establishing or just finished establishing a session to a peer in either initiator or responder
195 : * roles, the node id of that peer should be provided in sessionEvictionHint. Else, it should be initialized
196 : * to a default-constructed ScopedNodeId().
197 : *
198 : * @return SessionHandle with a reference to a SecureSession, else NullOptional on failure
199 : */
200 : CHECK_RETURN_VALUE
201 : Optional<SessionHandle> AllocateSession(Transport::SecureSession::Type secureSessionType,
202 : const ScopedNodeId & sessionEvictionHint);
203 :
204 : /**
205 : * A set of templated helper function that call a provided lambda
206 : * on all sessions in the underlying session table that match the provided
207 : * query criteria.
208 : *
209 : */
210 :
211 : /**
212 : * Call the provided lambda on sessions whose remote side match the provided ScopedNodeId.
213 : *
214 : */
215 : template <typename Function>
216 7 : void ForEachMatchingSession(const ScopedNodeId & node, Function && function)
217 : {
218 7 : mSecureSessions.ForEachSession([&](auto * session) {
219 28 : if (session->GetPeer() == node)
220 : {
221 7 : function(session);
222 : }
223 :
224 28 : return Loop::Continue;
225 : });
226 7 : }
227 :
228 : /**
229 : * Call the provided lambda on sessions that match the provided fabric index.
230 : *
231 : */
232 : template <typename Function>
233 2 : void ForEachMatchingSession(FabricIndex fabricIndex, Function && function)
234 : {
235 2 : mSecureSessions.ForEachSession([&](auto * session) {
236 16 : if (session->GetFabricIndex() == fabricIndex)
237 : {
238 6 : function(session);
239 : }
240 :
241 16 : return Loop::Continue;
242 : });
243 2 : }
244 :
245 : /**
246 : * Call the provided lambda on all sessions whose remote side match the logical fabric
247 : * associated with the provided ScopedNodeId and target the same logical remote node.
248 : *
249 : * *NOTE* This is identical in behavior to ForEachMatchingSession(const ScopedNodeId ..)
250 : * EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
251 : * on the same logical fabric (i.e root public key + fabric ID tuple).
252 : * This can ONLY happen if multiple controller instances on the same fabric is permitted
253 : * and each is assigned a unique fabric index.
254 : */
255 : template <typename Function>
256 0 : CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(const ScopedNodeId & node, Function && function)
257 : {
258 0 : Crypto::P256PublicKey targetPubKey;
259 :
260 0 : auto * targetFabric = mFabricTable->FindFabricWithIndex(node.GetFabricIndex());
261 0 : VerifyOrReturnError(targetFabric != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
262 :
263 0 : auto err = targetFabric->FetchRootPubkey(targetPubKey);
264 0 : VerifyOrDie(err == CHIP_NO_ERROR);
265 :
266 0 : mSecureSessions.ForEachSession([&](auto * session) {
267 0 : Crypto::P256PublicKey comparePubKey;
268 :
269 : //
270 : // It's entirely possible to either come across a PASE session OR, a CASE session
271 : // that has yet to be activated (i.e a CASEServer holding onto a SecureSession object
272 : // waiting for a Sigma1 message to arrive). Let's skip those.
273 : //
274 0 : if (!session->IsCASESession() || session->GetFabricIndex() == kUndefinedFabricIndex)
275 : {
276 0 : return Loop::Continue;
277 : }
278 :
279 0 : auto * compareFabric = mFabricTable->FindFabricWithIndex(session->GetFabricIndex());
280 0 : VerifyOrDie(compareFabric != nullptr);
281 :
282 0 : err = compareFabric->FetchRootPubkey(comparePubKey);
283 0 : VerifyOrDie(err == CHIP_NO_ERROR);
284 :
285 0 : if (comparePubKey.Matches(targetPubKey) && targetFabric->GetFabricId() == compareFabric->GetFabricId() &&
286 0 : session->GetPeerNodeId() == node.GetNodeId())
287 : {
288 0 : function(session);
289 : }
290 :
291 0 : return Loop::Continue;
292 0 : });
293 :
294 0 : return CHIP_NO_ERROR;
295 0 : }
296 :
297 : /**
298 : * Call the provided lambda on all sessions that match the logical fabric
299 : * associated with the provided fabric index.
300 : *
301 : * *NOTE* This is identical in behavior to ForEachMatchingSession(FabricIndex ..)
302 : * EXCEPT if there are multiple FabricInfo instances in the FabricTable that collide
303 : * on the same logical fabric (i.e root public key + fabric ID tuple).
304 : * This can ONLY happen if multiple controller instances on the same fabric is permitted
305 : * and each is assigned a unique fabric index.
306 : */
307 : template <typename Function>
308 0 : CHIP_ERROR ForEachMatchingSessionOnLogicalFabric(FabricIndex fabricIndex, Function && function)
309 : {
310 0 : Crypto::P256PublicKey targetPubKey;
311 :
312 0 : auto * targetFabric = mFabricTable->FindFabricWithIndex(fabricIndex);
313 0 : VerifyOrReturnError(targetFabric != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX);
314 :
315 0 : auto err = targetFabric->FetchRootPubkey(targetPubKey);
316 0 : VerifyOrDie(err == CHIP_NO_ERROR);
317 :
318 0 : mSecureSessions.ForEachSession([&](auto * session) {
319 0 : Crypto::P256PublicKey comparePubKey;
320 :
321 : //
322 : // It's entirely possible to either come across a PASE session OR, a CASE session
323 : // that has yet to be activated (i.e a CASEServer holding onto a SecureSession object
324 : // waiting for a Sigma1 message to arrive). Let's skip those.
325 : //
326 0 : if (!session->IsCASESession() || session->GetFabricIndex() == kUndefinedFabricIndex)
327 : {
328 0 : return Loop::Continue;
329 : }
330 :
331 0 : auto * compareFabric = mFabricTable->FindFabricWithIndex(session->GetFabricIndex());
332 0 : VerifyOrDie(compareFabric != nullptr);
333 :
334 0 : err = compareFabric->FetchRootPubkey(comparePubKey);
335 0 : VerifyOrDie(err == CHIP_NO_ERROR);
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 17853 : 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 : 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::ActiveTCPConnectionState ** peerConnState);
479 :
480 : CHIP_ERROR TCPDisconnect(const Transport::PeerAddress & peerAddress);
481 :
482 : void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0);
483 :
484 : void HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn) override;
485 :
486 : void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override;
487 :
488 : void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override;
489 :
490 : // Functors for callbacks into higher layers
491 : using OnTCPConnectionReceivedCallback = void (*)(Transport::ActiveTCPConnectionState * conn);
492 :
493 : using OnTCPConnectionCompleteCallback = void (*)(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
494 :
495 : using OnTCPConnectionClosedCallback = void (*)(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
496 :
497 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
498 :
499 0 : Optional<SessionHandle> CreateUnauthenticatedSession(const Transport::PeerAddress & peerAddress,
500 : const ReliableMessageProtocolConfig & config)
501 : {
502 : // Allocate ephemeralInitiatorNodeID in Operational Node ID range
503 : NodeId ephemeralInitiatorNodeID;
504 : do
505 : {
506 0 : ephemeralInitiatorNodeID = static_cast<NodeId>(Crypto::GetRandU64());
507 0 : } while (!IsOperationalNodeId(ephemeralInitiatorNodeID));
508 0 : return mUnauthenticatedSessions.AllocInitiator(ephemeralInitiatorNodeID, peerAddress, config);
509 : }
510 :
511 : //
512 : // Find an existing secure session given a peer's scoped NodeId and a type of session to match against.
513 : // If matching against all types of sessions is desired, NullOptional should be passed into type.
514 : //
515 : // If a valid session is found, an Optional<SessionHandle> with the value set to the SessionHandle of the session
516 : // is returned. Otherwise, an Optional<SessionHandle> with no value set is returned.
517 : //
518 : //
519 : Optional<SessionHandle>
520 : FindSecureSessionForNode(ScopedNodeId peerNodeId, const Optional<Transport::SecureSession::Type> & type = NullOptional,
521 : TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload);
522 :
523 : using SessionHandleCallback = bool (*)(void * context, SessionHandle & sessionHandle);
524 : CHIP_ERROR ForEachSessionHandle(void * context, SessionHandleCallback callback);
525 :
526 : //// FabricTable::Delegate Implementation ////
527 5 : void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override
528 : {
529 : (void) fabricTable;
530 5 : this->FabricRemoved(fabricIndex);
531 5 : }
532 :
533 19232 : FabricTable * GetFabricTable() const { return mFabricTable; }
534 :
535 149 : Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; }
536 :
537 : private:
538 : /**
539 : * The State of a secure transport object.
540 : */
541 : enum class State
542 : {
543 : kNotReady, /**< State before initialization. */
544 : kInitialized, /**< State when the object is ready connect to other peers. */
545 : };
546 :
547 : enum class EncryptionState
548 : {
549 : kPayloadIsEncrypted,
550 : kPayloadIsUnencrypted,
551 : };
552 :
553 : System::Layer * mSystemLayer = nullptr;
554 : FabricTable * mFabricTable = nullptr;
555 : Crypto::SessionKeystore * mSessionKeystore = nullptr;
556 : Transport::UnauthenticatedSessionTable<CHIP_CONFIG_UNAUTHENTICATED_CONNECTION_POOL_SIZE> mUnauthenticatedSessions;
557 : Transport::SecureSessionTable mSecureSessions;
558 : State mState; // < Initialization state of the object
559 : chip::Transport::GroupOutgoingCounters mGroupClientCounter;
560 :
561 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
562 : OnTCPConnectionReceivedCallback mConnReceivedCb = nullptr;
563 : OnTCPConnectionCompleteCallback mConnCompleteCb = nullptr;
564 : OnTCPConnectionClosedCallback mConnClosedCb = nullptr;
565 :
566 : // Hold the TCPConnection callback context for the receiver application in the SessionManager.
567 : // On receipt of a connection from a peer, the SessionManager
568 : Transport::AppTCPConnectionCallbackCtxt * mServerTCPConnCbCtxt = nullptr;
569 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
570 :
571 : SessionMessageDelegate * mCB = nullptr;
572 :
573 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
574 : SessionConnectionDelegate * mConnDelegate = nullptr;
575 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
576 :
577 : TransportMgrBase * mTransportMgr = nullptr;
578 : Transport::MessageCounterManagerInterface * mMessageCounterManager = nullptr;
579 :
580 : GlobalUnencryptedMessageCounter mGlobalUnencryptedMessageCounter;
581 :
582 : /**
583 : * @brief Parse, decrypt, validate, and dispatch a secure unicast message.
584 : *
585 : * @param[in] partialPacketHeader The partial PacketHeader of the message after processing with DecodeFixed.
586 : * If the message decrypts successfully, this will be filled with a fully decoded PacketHeader.
587 : * @param[in] peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
588 : * @param msg The full message buffer, including header fields.
589 : * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer
590 : * to the underlying connection object.
591 : */
592 : void SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
593 : System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr);
594 :
595 : /**
596 : * @brief Parse, decrypt, validate, and dispatch a secure group message.
597 : *
598 : * @param partialPacketHeader The partial PacketHeader of the message once processed with DecodeFixed.
599 : * @param peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
600 : * @param msg The full message buffer, including header fields.
601 : */
602 : void SecureGroupMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
603 : System::PacketBufferHandle && msg);
604 :
605 : /**
606 : * @brief Parse, decrypt, validate, and dispatch an unsecured message.
607 : *
608 : * @param partialPacketHeader The partial PacketHeader of the message after processing with DecodeFixed.
609 : * @param peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint.
610 : * @param msg The full message buffer, including header fields.
611 : * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer
612 : * to the underlying connection object.
613 : */
614 : void UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress,
615 : System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr);
616 :
617 : void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source);
618 :
619 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
620 : void MarkSecureSessionOverTCPForEviction(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
621 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
622 :
623 9825 : static bool IsControlMessage(PayloadHeader & payloadHeader)
624 : {
625 19650 : return payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncReq) ||
626 19650 : payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::MsgCounterSyncRsp);
627 : }
628 : };
629 :
630 : namespace MessagePacketBuffer {
631 : /**
632 : * Maximum size of a message footer, in bytes.
633 : */
634 : inline constexpr uint16_t kMaxFooterSize = kMaxTagLen;
635 :
636 : /**
637 : * Allocates a packet buffer with space for message headers and footers.
638 : *
639 : * Fails and returns \c nullptr if no memory is available, or if the size requested is too large.
640 : *
641 : * @param[in] aAvailableSize Minimum number of octets to for application data.
642 : *
643 : * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
644 : */
645 1631 : inline System::PacketBufferHandle New(size_t aAvailableSize)
646 : {
647 : static_assert(System::PacketBuffer::kMaxSize > kMaxFooterSize, "inadequate capacity");
648 1631 : if (aAvailableSize > System::PacketBuffer::kMaxSize - kMaxFooterSize)
649 : {
650 0 : return System::PacketBufferHandle();
651 : }
652 1631 : return System::PacketBufferHandle::New(aAvailableSize + kMaxFooterSize);
653 : }
654 :
655 : /**
656 : * Allocates a packet buffer with initial contents.
657 : *
658 : * @param[in] aData Initial buffer contents.
659 : * @param[in] aDataSize Size of initial buffer contents.
660 : *
661 : * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
662 : */
663 0 : inline System::PacketBufferHandle NewWithData(const void * aData, size_t aDataSize)
664 : {
665 0 : return System::PacketBufferHandle::NewWithData(aData, aDataSize, kMaxFooterSize);
666 : }
667 :
668 : /**
669 : * Check whether a packet buffer has enough space for a message footer.
670 : *
671 : * @returns true if there is space, false otherwise.
672 : */
673 2 : inline bool HasFooterSpace(const System::PacketBufferHandle & aBuffer)
674 : {
675 2 : return aBuffer->AvailableDataLength() >= kMaxFooterSize;
676 : }
677 :
678 : } // namespace MessagePacketBuffer
679 :
680 : } // namespace chip
|