Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements the CHIP Connection object that maintains a UDP connection.
23 : * TODO This class should be extended to support TCP as well...
24 : *
25 : */
26 :
27 : #include "SessionManager.h"
28 :
29 : #include <inttypes.h>
30 : #include <string.h>
31 :
32 : #include "transport/TraceMessage.h"
33 : #include <app/util/basic-types.h>
34 : #include <credentials/GroupDataProvider.h>
35 : #include <inttypes.h>
36 : #include <lib/core/CHIPKeyIds.h>
37 : #include <lib/core/Global.h>
38 : #include <lib/support/AutoRelease.h>
39 : #include <lib/support/CodeUtils.h>
40 : #include <lib/support/SafeInt.h>
41 : #include <lib/support/logging/CHIPLogging.h>
42 : #include <platform/CHIPDeviceLayer.h>
43 : #include <protocols/Protocols.h>
44 : #include <protocols/secure_channel/Constants.h>
45 : #include <tracing/macros.h>
46 : #include <transport/GroupPeerMessageCounter.h>
47 : #include <transport/GroupSession.h>
48 : #include <transport/SecureMessageCodec.h>
49 : #include <transport/TracingStructs.h>
50 : #include <transport/TransportMgr.h>
51 :
52 : namespace chip {
53 :
54 : using System::PacketBufferHandle;
55 : using Transport::GroupPeerTable;
56 : using Transport::PeerAddress;
57 : using Transport::SecureSession;
58 :
59 : namespace {
60 : Global<GroupPeerTable> gGroupPeerTable;
61 :
62 : // Helper function that strips off the interface ID from a peer address that is
63 : // not an IPv6 link-local address. For any other address type we should rely on
64 : // the device's routing table to route messages sent. Forcing messages down a
65 : // specific interface might fail with "no route to host".
66 14919 : void CorrectPeerAddressInterfaceID(Transport::PeerAddress & peerAddress)
67 : {
68 14919 : if (peerAddress.GetIPAddress().IsIPv6LinkLocal())
69 : {
70 0 : return;
71 : }
72 14919 : peerAddress.SetInterface(Inet::InterfaceId::Null());
73 : }
74 :
75 : } // namespace
76 :
77 25381 : uint32_t EncryptedPacketBufferHandle::GetMessageCounter() const
78 : {
79 25381 : PacketHeader header;
80 25381 : uint16_t headerSize = 0;
81 25381 : CHIP_ERROR err = header.Decode((*this)->Start(), (*this)->DataLength(), &headerSize);
82 :
83 25381 : if (err == CHIP_NO_ERROR)
84 : {
85 25381 : return header.GetMessageCounter();
86 : }
87 :
88 0 : ChipLogError(Inet, "Failed to decode EncryptedPacketBufferHandle header with error: %" CHIP_ERROR_FORMAT, err.Format());
89 :
90 0 : return 0;
91 : }
92 :
93 466 : SessionManager::SessionManager() : mState(State::kNotReady) {}
94 :
95 466 : SessionManager::~SessionManager()
96 : {
97 466 : this->Shutdown();
98 466 : }
99 :
100 403 : CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * transportMgr,
101 : Transport::MessageCounterManagerInterface * messageCounterManager,
102 : chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable,
103 : Crypto::SessionKeystore & sessionKeystore)
104 : {
105 403 : VerifyOrReturnError(mState == State::kNotReady, CHIP_ERROR_INCORRECT_STATE);
106 403 : VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
107 403 : VerifyOrReturnError(storageDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
108 403 : VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
109 403 : ReturnErrorOnFailure(fabricTable->AddFabricDelegate(this));
110 :
111 403 : mState = State::kInitialized;
112 403 : mSystemLayer = systemLayer;
113 403 : mTransportMgr = transportMgr;
114 403 : mMessageCounterManager = messageCounterManager;
115 403 : mFabricTable = fabricTable;
116 403 : mSessionKeystore = &sessionKeystore;
117 :
118 403 : mSecureSessions.Init();
119 :
120 403 : mGlobalUnencryptedMessageCounter.Init();
121 :
122 403 : ReturnErrorOnFailure(mGroupClientCounter.Init(storageDelegate));
123 :
124 403 : mTransportMgr->SetSessionManager(this);
125 :
126 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
127 403 : mConnCompleteCb = nullptr;
128 403 : mConnClosedCb = nullptr;
129 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
130 :
131 403 : return CHIP_NO_ERROR;
132 : }
133 :
134 868 : void SessionManager::Shutdown()
135 : {
136 868 : if (mFabricTable != nullptr)
137 : {
138 403 : mFabricTable->RemoveFabricDelegate(this);
139 403 : mFabricTable = nullptr;
140 : }
141 :
142 : // Ensure that we don't create new sessions as we iterate our session table.
143 868 : mState = State::kNotReady;
144 :
145 : // Just in case some consumer forgot to do it, expire all our secure
146 : // sessions. Note that this stands a good chance of crashing with a
147 : // null-deref if there are in fact any secure sessions left, since they will
148 : // try to notify their exchanges, which will then try to operate on
149 : // partially-shut-down objects.
150 868 : ExpireAllSecureSessions();
151 :
152 : // We don't have a safe way to check or affect the state of our
153 : // mUnauthenticatedSessions. We can only hope they got shut down properly.
154 :
155 868 : mMessageCounterManager = nullptr;
156 :
157 868 : mSystemLayer = nullptr;
158 868 : mTransportMgr = nullptr;
159 868 : mCB = nullptr;
160 868 : }
161 :
162 : /**
163 : * @brief Notification that a fabric was removed.
164 : * This function doesn't call ExpireAllSessionsForFabric
165 : * since the CASE session might still be open to send a response
166 : * on the removed fabric.
167 : */
168 7 : void SessionManager::FabricRemoved(FabricIndex fabricIndex)
169 : {
170 7 : gGroupPeerTable->FabricRemoved(fabricIndex);
171 7 : }
172 :
173 15018 : CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, PayloadHeader & payloadHeader,
174 : System::PacketBufferHandle && message, EncryptedPacketBufferHandle & preparedMessage)
175 : {
176 : MATTER_TRACE_SCOPE("PrepareMessage", "SessionManager");
177 :
178 15018 : PacketHeader packetHeader;
179 15018 : bool isControlMsg = IsControlMessage(payloadHeader);
180 15018 : if (isControlMsg)
181 : {
182 0 : packetHeader.SetSecureSessionControlMsg(true);
183 : }
184 :
185 15018 : if (sessionHandle->AllowsLargePayload())
186 : {
187 0 : VerifyOrReturnError(message->TotalLength() <= kMaxLargeAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG);
188 : }
189 : else
190 : {
191 15018 : VerifyOrReturnError(message->TotalLength() <= kMaxAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG);
192 : }
193 :
194 : #if CHIP_PROGRESS_LOGGING
195 : NodeId destination;
196 : FabricIndex fabricIndex;
197 : #endif // CHIP_PROGRESS_LOGGING
198 :
199 15017 : NodeId sourceNodeId = kUndefinedNodeId;
200 15017 : PeerAddress destination_address;
201 :
202 15017 : switch (sessionHandle->GetSessionType())
203 : {
204 2 : case Transport::Session::SessionType::kGroupOutgoing: {
205 2 : auto groupSession = sessionHandle->AsOutgoingGroupSession();
206 2 : auto * groups = Credentials::GetGroupDataProvider();
207 2 : VerifyOrReturnError(nullptr != groups, CHIP_ERROR_INTERNAL);
208 :
209 2 : const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
210 2 : VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
211 :
212 2 : packetHeader.SetDestinationGroupId(groupSession->GetGroupId());
213 2 : packetHeader.SetMessageCounter(mGroupClientCounter.GetCounter(isControlMsg));
214 2 : mGroupClientCounter.IncrementCounter(isControlMsg);
215 2 : packetHeader.SetSessionType(Header::SessionType::kGroupSession);
216 2 : sourceNodeId = fabric->GetNodeId();
217 2 : packetHeader.SetSourceNodeId(sourceNodeId);
218 :
219 2 : if (!packetHeader.IsValidGroupMsg())
220 : {
221 0 : return CHIP_ERROR_INTERNAL;
222 : }
223 :
224 2 : destination_address = Transport::PeerAddress::Multicast(fabric->GetFabricId(), groupSession->GetGroupId());
225 :
226 : // Trace before any encryption
227 : MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kGroupMessage, &payloadHeader, &packetHeader,
228 : chip::ByteSpan(message->Start(), message->TotalLength()));
229 :
230 2 : CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
231 :
232 : Crypto::SymmetricKeyContext * keyContext =
233 2 : groups->GetKeyContext(groupSession->GetFabricIndex(), groupSession->GetGroupId());
234 2 : VerifyOrReturnError(nullptr != keyContext, CHIP_ERROR_INTERNAL);
235 :
236 2 : packetHeader.SetSessionId(keyContext->GetKeyHash());
237 : CryptoContext::NonceStorage nonce;
238 2 : CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(), sourceNodeId);
239 2 : CHIP_ERROR err = SecureMessageCodec::Encrypt(CryptoContext(keyContext), nonce, payloadHeader, packetHeader, message);
240 2 : keyContext->Release();
241 2 : ReturnErrorOnFailure(err);
242 :
243 : #if CHIP_PROGRESS_LOGGING
244 2 : destination = NodeIdFromGroupId(groupSession->GetGroupId());
245 2 : fabricIndex = groupSession->GetFabricIndex();
246 : #endif // CHIP_PROGRESS_LOGGING
247 : }
248 2 : break;
249 14906 : case Transport::Session::SessionType::kSecure: {
250 14906 : SecureSession * session = sessionHandle->AsSecureSession();
251 14906 : if (session == nullptr)
252 : {
253 1 : return CHIP_ERROR_NOT_CONNECTED;
254 : }
255 :
256 14906 : MessageCounter & counter = session->GetSessionMessageCounter().GetLocalMessageCounter();
257 : uint32_t messageCounter;
258 14906 : ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
259 : packetHeader
260 14905 : .SetMessageCounter(messageCounter) //
261 14905 : .SetSessionId(session->GetPeerSessionId()) //
262 14905 : .SetSessionType(Header::SessionType::kUnicastSession);
263 :
264 14905 : destination_address = session->GetPeerAddress();
265 :
266 : // Trace before any encryption
267 : MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kSecureSession, &payloadHeader, &packetHeader,
268 : chip::ByteSpan(message->Start(), message->TotalLength()));
269 14905 : CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
270 :
271 : CryptoContext::NonceStorage nonce;
272 14905 : sourceNodeId = session->GetLocalScopedNodeId().GetNodeId();
273 14905 : CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), messageCounter, sourceNodeId);
274 :
275 14905 : ReturnErrorOnFailure(SecureMessageCodec::Encrypt(session->GetCryptoContext(), nonce, payloadHeader, packetHeader, message));
276 :
277 : #if CHIP_PROGRESS_LOGGING
278 14905 : destination = session->GetPeerNodeId();
279 14905 : fabricIndex = session->GetFabricIndex();
280 : #endif // CHIP_PROGRESS_LOGGING
281 : }
282 14905 : break;
283 109 : case Transport::Session::SessionType::kUnauthenticated: {
284 109 : MessageCounter & counter = mGlobalUnencryptedMessageCounter;
285 : uint32_t messageCounter;
286 109 : ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
287 109 : packetHeader.SetMessageCounter(messageCounter);
288 109 : Transport::UnauthenticatedSession * session = sessionHandle->AsUnauthenticatedSession();
289 109 : switch (session->GetSessionRole())
290 : {
291 64 : case Transport::UnauthenticatedSession::SessionRole::kInitiator:
292 64 : packetHeader.SetSourceNodeId(session->GetEphemeralInitiatorNodeID());
293 64 : break;
294 45 : case Transport::UnauthenticatedSession::SessionRole::kResponder:
295 45 : packetHeader.SetDestinationNodeId(session->GetEphemeralInitiatorNodeID());
296 45 : break;
297 : }
298 :
299 109 : auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
300 109 : destination_address = unauthenticated->GetPeerAddress();
301 :
302 : // Trace after all headers are settled.
303 : MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
304 : chip::ByteSpan(message->Start(), message->TotalLength()));
305 109 : CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
306 :
307 109 : ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(message));
308 :
309 : #if CHIP_PROGRESS_LOGGING
310 109 : destination = kUndefinedNodeId;
311 109 : fabricIndex = kUndefinedFabricIndex;
312 109 : if (session->GetSessionRole() == Transport::UnauthenticatedSession::SessionRole::kResponder)
313 : {
314 45 : destination = session->GetEphemeralInitiatorNodeID();
315 : }
316 64 : else if (session->GetSessionRole() == Transport::UnauthenticatedSession::SessionRole::kInitiator)
317 : {
318 64 : sourceNodeId = session->GetEphemeralInitiatorNodeID();
319 : }
320 : #endif // CHIP_PROGRESS_LOGGING
321 : }
322 109 : break;
323 0 : default:
324 0 : return CHIP_ERROR_INTERNAL;
325 : }
326 :
327 15016 : ReturnErrorOnFailure(packetHeader.EncodeBeforeData(message));
328 :
329 : #if CHIP_PROGRESS_LOGGING
330 15016 : CompressedFabricId compressedFabricId = kUndefinedCompressedFabricId;
331 :
332 15016 : if (fabricIndex != kUndefinedFabricIndex && mFabricTable != nullptr)
333 : {
334 14860 : auto fabricInfo = mFabricTable->FindFabricWithIndex(fabricIndex);
335 14860 : if (fabricInfo)
336 : {
337 14860 : compressedFabricId = fabricInfo->GetCompressedFabricId();
338 : }
339 : }
340 :
341 15016 : auto * protocolName = Protocols::GetProtocolName(payloadHeader.GetProtocolID());
342 15016 : auto * msgTypeName = Protocols::GetMessageTypeName(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType());
343 :
344 : //
345 : // 32-bit value maximum = 10 chars + text preamble (6) + trailer (1) + null (1) + 2 buffer = 20
346 : //
347 : char ackBuf[20];
348 15016 : ackBuf[0] = '\0';
349 15016 : if (payloadHeader.GetAckMessageCounter().HasValue())
350 : {
351 12614 : snprintf(ackBuf, sizeof(ackBuf), " (Ack:" ChipLogFormatMessageCounter ")", payloadHeader.GetAckMessageCounter().Value());
352 : }
353 :
354 15016 : char addressStr[Transport::PeerAddress::kMaxToStringSize] = { 0 };
355 15016 : destination_address.ToString(addressStr);
356 :
357 : // Work around pigweed not allowing more than 14 format args in a log
358 : // message when using tokenized logs.
359 : char typeStr[4 + 1 + 2 + 1];
360 15016 : snprintf(typeStr, sizeof(typeStr), "%04X:%02X", payloadHeader.GetProtocolID().GetProtocolId(), payloadHeader.GetMessageType());
361 :
362 : // More work around pigweed not allowing more than 14 format args in a log
363 : // message when using tokenized logs.
364 : // ChipLogFormatExchangeId logs the numeric exchange ID (at most 5 chars,
365 : // since it's a uint16_t) and one char for initiator/responder. Plus we
366 : // need a null-terminator.
367 : char exchangeStr[5 + 1 + 1];
368 15016 : snprintf(exchangeStr, sizeof(exchangeStr), ChipLogFormatExchangeId, ChipLogValueExchangeIdFromSentHeader(payloadHeader));
369 :
370 : // More work around pigweed not allowing more than 14 format args in a log
371 : // message when using tokenized logs.
372 : // text(5) + source(16) + text(4) + fabricIndex(uint16_t, at most 5 chars) + text(1) + destination(16) + text(2) + compressed
373 : // fabric id(4) + text(1) + null-terminator
374 : char sourceDestinationStr[5 + 16 + 4 + 5 + 1 + 16 + 2 + 4 + 1 + 1];
375 15016 : snprintf(sourceDestinationStr, sizeof(sourceDestinationStr), "from " ChipLogFormatX64 " to %u:" ChipLogFormatX64 " [%04X]",
376 15016 : ChipLogValueX64(sourceNodeId), fabricIndex, ChipLogValueX64(destination), static_cast<uint16_t>(compressedFabricId));
377 :
378 : //
379 : // Legend that can be used to decode this log line can be found in messaging/README.md
380 : //
381 15016 : ChipLogProgress(ExchangeManager,
382 : "<<< [E:%s S:%u M:" ChipLogFormatMessageCounter "%s] (%s) Msg TX %s [%s] --- Type %s (%s:%s) (B:%u)",
383 : exchangeStr, sessionHandle->SessionIdForLogging(), packetHeader.GetMessageCounter(), ackBuf,
384 : Transport::GetSessionTypeString(sessionHandle), sourceDestinationStr, addressStr, typeStr, protocolName,
385 : msgTypeName, static_cast<unsigned>(message->TotalLength()));
386 : #endif
387 :
388 15016 : preparedMessage = EncryptedPacketBufferHandle::MarkEncrypted(std::move(message));
389 :
390 15016 : return CHIP_NO_ERROR;
391 : }
392 :
393 15070 : CHIP_ERROR SessionManager::SendPreparedMessage(const SessionHandle & sessionHandle,
394 : const EncryptedPacketBufferHandle & preparedMessage)
395 : {
396 15070 : VerifyOrReturnError(mState == State::kInitialized, CHIP_ERROR_INCORRECT_STATE);
397 15070 : VerifyOrReturnError(!preparedMessage.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
398 :
399 15070 : Transport::PeerAddress multicastAddress; // Only used for the group case
400 : const Transport::PeerAddress * destination;
401 :
402 15070 : switch (sessionHandle->GetSessionType())
403 : {
404 2 : case Transport::Session::SessionType::kGroupOutgoing: {
405 2 : auto groupSession = sessionHandle->AsOutgoingGroupSession();
406 :
407 2 : const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
408 2 : VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
409 :
410 2 : multicastAddress = Transport::PeerAddress::Multicast(fabric->GetFabricId(), groupSession->GetGroupId());
411 2 : destination = &multicastAddress;
412 : }
413 2 : break;
414 14956 : case Transport::Session::SessionType::kSecure: {
415 : // Find an active connection to the specified peer node
416 14956 : SecureSession * secure = sessionHandle->AsSecureSession();
417 :
418 : // This marks any connection where we send data to as 'active'
419 14956 : secure->MarkActive();
420 :
421 14956 : destination = &secure->GetPeerAddress();
422 : }
423 14956 : break;
424 112 : case Transport::Session::SessionType::kUnauthenticated: {
425 112 : auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
426 112 : unauthenticated->MarkActive();
427 112 : destination = &unauthenticated->GetPeerAddress();
428 : }
429 112 : break;
430 0 : default:
431 0 : return CHIP_ERROR_INTERNAL;
432 : }
433 :
434 30140 : PacketBufferHandle msgBuf = preparedMessage.CastToWritable();
435 15070 : VerifyOrReturnError(!msgBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
436 15070 : VerifyOrReturnError(!msgBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
437 :
438 : #if CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
439 15070 : if (sessionHandle->GetSessionType() == Transport::Session::SessionType::kGroupOutgoing)
440 : {
441 2 : chip::Inet::InterfaceIterator interfaceIt;
442 2 : chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
443 : chip::Inet::IPAddress addr;
444 2 : bool interfaceFound = false;
445 :
446 6 : while (interfaceIt.Next())
447 : {
448 : char name[Inet::InterfaceId::kMaxIfNameLength];
449 4 : interfaceIt.GetInterfaceName(name, Inet::InterfaceId::kMaxIfNameLength);
450 4 : if (interfaceIt.SupportsMulticast() && interfaceIt.IsUp())
451 : {
452 2 : interfaceId = interfaceIt.GetInterfaceId();
453 2 : if (CHIP_NO_ERROR == interfaceId.GetLinkLocalAddr(&addr))
454 : {
455 2 : ChipLogDetail(Inet, "Interface %s has a link local address", name);
456 :
457 2 : interfaceFound = true;
458 2 : PacketBufferHandle tempBuf = msgBuf.CloneData();
459 2 : VerifyOrReturnError(!tempBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
460 2 : VerifyOrReturnError(!tempBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
461 :
462 2 : destination = &(multicastAddress.SetInterface(interfaceId));
463 2 : if (mTransportMgr != nullptr)
464 : {
465 2 : if (CHIP_NO_ERROR != mTransportMgr->SendMessage(*destination, std::move(tempBuf)))
466 : {
467 0 : ChipLogError(Inet, "Failed to send Multicast message on interface %s", name);
468 : }
469 : else
470 : {
471 2 : ChipLogDetail(Inet, "Successfully send Multicast message on interface %s", name);
472 : }
473 : }
474 2 : }
475 : }
476 : }
477 :
478 2 : if (!interfaceFound)
479 : {
480 0 : ChipLogError(Inet, "No valid Interface found.. Sending to the default one.. ");
481 : }
482 : else
483 : {
484 : // Always return No error, because we expect some interface to fails and others to always succeed (e.g. lo interface)
485 2 : return CHIP_NO_ERROR;
486 : }
487 2 : }
488 :
489 : #endif // CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
490 :
491 15068 : if (mTransportMgr != nullptr)
492 : {
493 15068 : CHIP_ERROR err = mTransportMgr->SendMessage(*destination, std::move(msgBuf));
494 : #if CHIP_ERROR_LOGGING
495 15068 : if (err != CHIP_NO_ERROR)
496 : {
497 5 : char addressStr[Transport::PeerAddress::kMaxToStringSize] = { 0 };
498 5 : destination->ToString(addressStr);
499 5 : ChipLogError(Inet, "SendMessage() to %s failed: %" CHIP_ERROR_FORMAT, addressStr, err.Format());
500 : }
501 : #endif // CHIP_ERROR_LOGGING
502 15068 : return err;
503 : }
504 :
505 0 : ChipLogError(Inet, "The transport manager is not initialized. Unable to send the message");
506 0 : return CHIP_ERROR_INCORRECT_STATE;
507 : }
508 :
509 0 : void SessionManager::ExpireAllSessions(const ScopedNodeId & node)
510 : {
511 0 : ChipLogDetail(Inet, "Expiring all sessions for node " ChipLogFormatScopedNodeId "!!", ChipLogValueScopedNodeId(node));
512 :
513 0 : ForEachMatchingSession(node, [](auto * session) { session->MarkForEviction(); });
514 0 : }
515 :
516 2 : void SessionManager::ExpireAllSessionsForFabric(FabricIndex fabricIndex)
517 : {
518 2 : ChipLogDetail(Inet, "Expiring all sessions for fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
519 :
520 8 : ForEachMatchingSession(fabricIndex, [](auto * session) { session->MarkForEviction(); });
521 2 : }
522 :
523 0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(const ScopedNodeId & node)
524 : {
525 0 : ChipLogDetail(Inet, "Expiring all sessions to peer " ChipLogFormatScopedNodeId " that are on the same logical fabric!!",
526 : ChipLogValueScopedNodeId(node));
527 :
528 0 : return ForEachMatchingSessionOnLogicalFabric(node, [](auto * session) { session->MarkForEviction(); });
529 : }
530 :
531 0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(FabricIndex fabricIndex)
532 : {
533 0 : ChipLogDetail(Inet, "Expiring all sessions on the same logical fabric as fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
534 :
535 0 : return ForEachMatchingSessionOnLogicalFabric(fabricIndex, [](auto * session) { session->MarkForEviction(); });
536 : }
537 :
538 0 : void SessionManager::ExpireAllPASESessions()
539 : {
540 0 : ChipLogDetail(Inet, "Expiring all PASE sessions");
541 0 : mSecureSessions.ForEachSession([&](auto session) {
542 0 : if (session->GetSecureSessionType() == Transport::SecureSession::Type::kPASE)
543 : {
544 0 : session->MarkForEviction();
545 : }
546 0 : return Loop::Continue;
547 : });
548 0 : }
549 :
550 869 : void SessionManager::ExpireAllSecureSessions()
551 : {
552 869 : mSecureSessions.ForEachSession([&](auto session) {
553 1433 : session->MarkForEviction();
554 1433 : return Loop::Continue;
555 : });
556 869 : }
557 :
558 0 : void SessionManager::MarkSessionsAsDefunct(const ScopedNodeId & node, const Optional<Transport::SecureSession::Type> & type)
559 : {
560 0 : mSecureSessions.ForEachSession([&node, &type](auto session) {
561 0 : if (session->IsActiveSession() && session->GetPeer() == node &&
562 0 : (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
563 : {
564 0 : session->MarkAsDefunct();
565 : }
566 0 : return Loop::Continue;
567 : });
568 0 : }
569 :
570 0 : void SessionManager::UpdateAllSessionsPeerAddress(const ScopedNodeId & node, const Transport::PeerAddress & addr)
571 : {
572 0 : mSecureSessions.ForEachSession([&node, &addr](auto session) {
573 : // Arguably we should only be updating active and defunct sessions, but there is no harm
574 : // in updating evicted sessions.
575 0 : if (session->GetPeer() == node && Transport::SecureSession::Type::kCASE == session->GetSecureSessionType())
576 : {
577 0 : session->SetPeerAddress(addr);
578 : }
579 0 : return Loop::Continue;
580 : });
581 0 : }
582 :
583 133657 : Optional<SessionHandle> SessionManager::AllocateSession(SecureSession::Type secureSessionType,
584 : const ScopedNodeId & sessionEvictionHint)
585 : {
586 133657 : VerifyOrReturnValue(mState == State::kInitialized, NullOptional);
587 133657 : return mSecureSessions.CreateNewSecureSession(secureSessionType, sessionEvictionHint);
588 : }
589 :
590 1503 : CHIP_ERROR SessionManager::InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId,
591 : uint16_t peerSessionId, FabricIndex fabric,
592 : const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role)
593 : {
594 1503 : NodeId localNodeId = kUndefinedNodeId;
595 : Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
596 : chip::Transport::SecureSession::Type::kPASE, localSessionId, localNodeId, peerNodeId, CATValues{}, peerSessionId, fabric,
597 1503 : GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
598 1503 : VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
599 1503 : SecureSession * secureSession = session.Value()->AsSecureSession();
600 1503 : secureSession->SetPeerAddress(peerAddress);
601 :
602 1503 : size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
603 1503 : ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
604 1503 : ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
605 : *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
606 1503 : secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
607 1503 : sessionHolder.Grab(session.Value());
608 1503 : return CHIP_NO_ERROR;
609 1503 : }
610 :
611 23 : CHIP_ERROR SessionManager::InjectCaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId,
612 : uint16_t peerSessionId, NodeId localNodeId, NodeId peerNodeId,
613 : FabricIndex fabric, const Transport::PeerAddress & peerAddress,
614 : CryptoContext::SessionRole role, const CATValues & cats)
615 : {
616 : Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
617 : chip::Transport::SecureSession::Type::kCASE, localSessionId, localNodeId, peerNodeId, cats, peerSessionId, fabric,
618 23 : GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
619 23 : VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
620 23 : SecureSession * secureSession = session.Value()->AsSecureSession();
621 23 : secureSession->SetPeerAddress(peerAddress);
622 :
623 23 : size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
624 23 : ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
625 23 : ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
626 : *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
627 23 : secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
628 23 : sessionHolder.Grab(session.Value());
629 23 : return CHIP_NO_ERROR;
630 23 : }
631 :
632 14936 : void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System::PacketBufferHandle && msg,
633 : Transport::MessageTransportContext * ctxt)
634 : {
635 14936 : PacketHeader partialPacketHeader;
636 :
637 14936 : CHIP_ERROR err = partialPacketHeader.DecodeFixed(msg);
638 14936 : if (err != CHIP_NO_ERROR)
639 : {
640 0 : ChipLogError(Inet, "Failed to decode packet header: %" CHIP_ERROR_FORMAT, err.Format());
641 0 : return;
642 : }
643 :
644 14936 : if (partialPacketHeader.IsEncrypted())
645 : {
646 14829 : if (partialPacketHeader.IsGroupSession())
647 : {
648 7 : SecureGroupMessageDispatch(partialPacketHeader, peerAddress, std::move(msg));
649 : }
650 : else
651 : {
652 14822 : SecureUnicastMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt);
653 : }
654 : }
655 : else
656 : {
657 107 : UnauthenticatedMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt);
658 : }
659 : }
660 :
661 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
662 0 : void SessionManager::HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn)
663 : {
664 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
665 :
666 0 : VerifyOrReturn(conn != nullptr);
667 0 : conn->mPeerAddr.ToString(peerAddrBuf);
668 0 : ChipLogProgress(Inet, "Received TCP connection request from %s.", peerAddrBuf);
669 :
670 0 : Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState;
671 0 : if (appTCPConnCbCtxt != nullptr && appTCPConnCbCtxt->connReceivedCb != nullptr)
672 : {
673 0 : appTCPConnCbCtxt->connReceivedCb(conn);
674 : }
675 : }
676 :
677 0 : void SessionManager::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr)
678 : {
679 0 : VerifyOrReturn(conn != nullptr);
680 :
681 0 : Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState;
682 0 : if (appTCPConnCbCtxt == nullptr)
683 : {
684 0 : TCPDisconnect(conn, /* shouldAbort = */ true);
685 0 : return;
686 : }
687 :
688 0 : if (appTCPConnCbCtxt->connCompleteCb != nullptr)
689 : {
690 0 : appTCPConnCbCtxt->connCompleteCb(conn, conErr);
691 : }
692 : else
693 : {
694 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
695 0 : conn->mPeerAddr.ToString(peerAddrBuf);
696 :
697 0 : ChipLogProgress(Inet, "TCP Connection established with peer %s, but no registered handler. Disconnecting.", peerAddrBuf);
698 :
699 : // Close the connection
700 0 : TCPDisconnect(conn, /* shouldAbort = */ true);
701 : }
702 : }
703 :
704 0 : void SessionManager::HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr)
705 : {
706 0 : VerifyOrReturn(conn != nullptr);
707 :
708 0 : MarkSecureSessionOverTCPForEviction(conn, conErr);
709 :
710 : // TODO: A mechanism to mark an unauthenticated session as unusable when
711 : // the underlying connection is broken. Issue #32323
712 :
713 0 : Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState;
714 0 : VerifyOrReturn(appTCPConnCbCtxt != nullptr);
715 :
716 0 : if (appTCPConnCbCtxt->connClosedCb != nullptr)
717 : {
718 0 : appTCPConnCbCtxt->connClosedCb(conn, conErr);
719 : }
720 : }
721 :
722 0 : CHIP_ERROR SessionManager::TCPConnect(const PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState,
723 : Transport::ActiveTCPConnectionState ** peerConnState)
724 : {
725 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
726 0 : peerAddress.ToString(peerAddrBuf);
727 0 : if (mTransportMgr != nullptr)
728 : {
729 0 : ChipLogProgress(Inet, "Connecting over TCP with peer at %s.", peerAddrBuf);
730 0 : return mTransportMgr->TCPConnect(peerAddress, appState, peerConnState);
731 : }
732 :
733 0 : ChipLogError(Inet, "The transport manager is not initialized. Unable to connect to peer at %s.", peerAddrBuf);
734 :
735 0 : return CHIP_ERROR_INCORRECT_STATE;
736 : }
737 :
738 0 : CHIP_ERROR SessionManager::TCPDisconnect(const PeerAddress & peerAddress)
739 : {
740 0 : if (mTransportMgr != nullptr)
741 : {
742 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
743 0 : peerAddress.ToString(peerAddrBuf);
744 0 : ChipLogProgress(Inet, "Disconnecting TCP connection from peer at %s.", peerAddrBuf);
745 0 : mTransportMgr->TCPDisconnect(peerAddress);
746 : }
747 :
748 0 : return CHIP_NO_ERROR;
749 : }
750 :
751 0 : void SessionManager::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort)
752 : {
753 0 : if (mTransportMgr != nullptr && conn != nullptr)
754 : {
755 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
756 0 : conn->mPeerAddr.ToString(peerAddrBuf);
757 0 : ChipLogProgress(Inet, "Disconnecting TCP connection from peer at %s.", peerAddrBuf);
758 0 : mTransportMgr->TCPDisconnect(conn, shouldAbort);
759 :
760 0 : MarkSecureSessionOverTCPForEviction(conn, CHIP_NO_ERROR);
761 : }
762 0 : }
763 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
764 :
765 107 : void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader,
766 : const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg,
767 : Transport::MessageTransportContext * ctxt)
768 : {
769 : MATTER_TRACE_SCOPE("Unauthenticated Message Dispatch", "SessionManager");
770 :
771 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
772 107 : if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn == nullptr)
773 : {
774 0 : ChipLogError(Inet, "Connection object is missing for received message.");
775 0 : return;
776 : }
777 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
778 :
779 : // Drop unsecured messages with privacy enabled.
780 107 : if (partialPacketHeader.HasPrivacyFlag())
781 : {
782 0 : ChipLogError(Inet, "Dropping unauthenticated message with privacy flag set");
783 0 : return;
784 : }
785 :
786 107 : PacketHeader packetHeader;
787 107 : ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
788 :
789 107 : Optional<NodeId> source = packetHeader.GetSourceNodeId();
790 107 : Optional<NodeId> destination = packetHeader.GetDestinationNodeId();
791 :
792 107 : if ((source.HasValue() && destination.HasValue()) || (!source.HasValue() && !destination.HasValue()))
793 : {
794 0 : ChipLogProgress(Inet,
795 : "Received malformed unsecure packet with source 0x" ChipLogFormatX64 " destination 0x" ChipLogFormatX64,
796 : ChipLogValueX64(source.ValueOr(kUndefinedNodeId)), ChipLogValueX64(destination.ValueOr(kUndefinedNodeId)));
797 0 : return; // ephemeral node id is only assigned to the initiator, there should be one and only one node id exists.
798 : }
799 :
800 107 : Optional<SessionHandle> optionalSession;
801 107 : if (source.HasValue())
802 : {
803 : // Assume peer is the initiator, we are the responder.
804 62 : optionalSession = mUnauthenticatedSessions.FindOrAllocateResponder(source.Value(), GetDefaultMRPConfig(), peerAddress);
805 62 : if (!optionalSession.HasValue())
806 : {
807 0 : ChipLogError(Inet, "UnauthenticatedSession exhausted");
808 0 : return;
809 : }
810 : }
811 : else
812 : {
813 : // Assume peer is the responder, we are the initiator.
814 45 : optionalSession = mUnauthenticatedSessions.FindInitiator(destination.Value(), peerAddress);
815 45 : if (!optionalSession.HasValue())
816 : {
817 0 : ChipLogProgress(Inet, "Received unknown unsecure packet for initiator 0x" ChipLogFormatX64,
818 : ChipLogValueX64(destination.Value()));
819 0 : return;
820 : }
821 : }
822 :
823 107 : const SessionHandle & session = optionalSession.Value();
824 107 : Transport::UnauthenticatedSession * unsecuredSession = session->AsUnauthenticatedSession();
825 107 : Transport::PeerAddress mutablePeerAddress = peerAddress;
826 107 : CorrectPeerAddressInterfaceID(mutablePeerAddress);
827 107 : unsecuredSession->SetPeerAddress(mutablePeerAddress);
828 107 : SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
829 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
830 : // Associate the unauthenticated session with the connection, if not done already.
831 107 : if (peerAddress.GetTransportType() == Transport::Type::kTcp)
832 : {
833 0 : Transport::ActiveTCPConnectionState * sessionConn = unsecuredSession->GetTCPConnection();
834 0 : if (sessionConn == nullptr)
835 : {
836 0 : unsecuredSession->SetTCPConnection(ctxt->conn);
837 : }
838 : else
839 : {
840 0 : if (sessionConn != ctxt->conn)
841 : {
842 0 : ChipLogError(Inet, "Data received over wrong connection %p. Dropping it!", ctxt->conn);
843 0 : return;
844 : }
845 : }
846 : }
847 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
848 :
849 107 : unsecuredSession->MarkActiveRx();
850 :
851 107 : PayloadHeader payloadHeader;
852 107 : ReturnOnFailure(payloadHeader.DecodeAndConsume(msg));
853 :
854 : // Verify message counter
855 107 : CHIP_ERROR err = unsecuredSession->GetPeerMessageCounter().VerifyUnencrypted(packetHeader.GetMessageCounter());
856 107 : if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
857 : {
858 0 : ChipLogDetail(Inet,
859 : "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
860 : " on exchange " ChipLogFormatExchangeId,
861 : packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
862 0 : isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
863 0 : err = CHIP_NO_ERROR;
864 : }
865 : else
866 : {
867 : // VerifyUnencrypted always returns one of CHIP_NO_ERROR or
868 : // CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED.
869 107 : unsecuredSession->GetPeerMessageCounter().CommitUnencrypted(packetHeader.GetMessageCounter());
870 : }
871 107 : if (mCB != nullptr)
872 : {
873 : MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
874 : unsecuredSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
875 :
876 107 : CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, unsecuredSession, peerAddress, msg->Start(), msg->TotalLength());
877 107 : mCB->OnMessageReceived(packetHeader, payloadHeader, session, isDuplicate, std::move(msg));
878 : }
879 : else
880 : {
881 0 : ChipLogError(Inet, "Received UNSECURED message was not processed.");
882 : }
883 107 : }
884 :
885 14822 : void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader,
886 : const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg,
887 : Transport::MessageTransportContext * ctxt)
888 : {
889 : MATTER_TRACE_SCOPE("Secure Unicast Message Dispatch", "SessionManager");
890 :
891 14822 : CHIP_ERROR err = CHIP_NO_ERROR;
892 :
893 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
894 14822 : if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn == nullptr)
895 : {
896 0 : ChipLogError(Inet, "Connection object is missing for received message.");
897 16 : return;
898 : }
899 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
900 :
901 14822 : Optional<SessionHandle> session = mSecureSessions.FindSecureSessionByLocalKey(partialPacketHeader.GetSessionId());
902 14822 : if (!session.HasValue())
903 : {
904 10 : ChipLogError(Inet, "Data received on an unknown session (LSID=%d). Dropping it!", partialPacketHeader.GetSessionId());
905 10 : return;
906 : }
907 :
908 14812 : Transport::SecureSession * secureSession = session.Value()->AsSecureSession();
909 14812 : Transport::PeerAddress mutablePeerAddress = peerAddress;
910 14812 : CorrectPeerAddressInterfaceID(mutablePeerAddress);
911 14812 : if (secureSession->GetPeerAddress() != mutablePeerAddress)
912 : {
913 5 : secureSession->SetPeerAddress(mutablePeerAddress);
914 : }
915 :
916 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
917 : // Associate the secure session with the connection, if not done already.
918 14812 : if (peerAddress.GetTransportType() == Transport::Type::kTcp)
919 : {
920 0 : Transport::ActiveTCPConnectionState * sessionConn = secureSession->GetTCPConnection();
921 0 : if (sessionConn == nullptr)
922 : {
923 0 : secureSession->SetTCPConnection(ctxt->conn);
924 : }
925 : else
926 : {
927 0 : if (sessionConn != ctxt->conn)
928 : {
929 0 : ChipLogError(Inet, "Data received over wrong connection %p. Dropping it!", ctxt->conn);
930 0 : return;
931 : }
932 : }
933 : }
934 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
935 :
936 14812 : PayloadHeader payloadHeader;
937 :
938 : // Drop secure unicast messages with privacy enabled.
939 14812 : if (partialPacketHeader.HasPrivacyFlag())
940 : {
941 1 : ChipLogError(Inet, "Dropping secure unicast message with privacy flag set");
942 1 : return;
943 : }
944 :
945 14811 : PacketHeader packetHeader;
946 14811 : ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
947 :
948 14811 : SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
949 :
950 14811 : if (msg.IsNull())
951 : {
952 0 : ChipLogError(Inet, "Secure transport received Unicast NULL packet, discarding");
953 0 : return;
954 : }
955 :
956 : // We need to allow through messages even on sessions that are pending
957 : // evictions, because for some cases (UpdateNOC, RemoveFabric, etc) there
958 : // can be a single exchange alive on the session waiting for a MRP ack, and
959 : // we need to make sure to send the ack through. The exchange manager is
960 : // responsible for ensuring that such messages do not lead to new exchange
961 : // creation.
962 14811 : if (!secureSession->IsDefunct() && !secureSession->IsActiveSession() && !secureSession->IsPendingEviction())
963 : {
964 0 : ChipLogError(Inet, "Secure transport received message on a session in an invalid state (state = '%s')",
965 : secureSession->GetStateStr());
966 0 : return;
967 : }
968 :
969 : // Decrypt and verify the message before message counter verification or any further processing.
970 : CryptoContext::NonceStorage nonce;
971 : // PASE Sessions use the undefined node ID of all zeroes, since there is no node ID to use
972 : // and the key is short-lived and always different for each PASE session.
973 14821 : CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(),
974 14821 : secureSession->GetSecureSessionType() == SecureSession::Type::kCASE ? secureSession->GetPeerNodeId()
975 : : kUndefinedNodeId);
976 14811 : if (SecureMessageCodec::Decrypt(secureSession->GetCryptoContext(), nonce, payloadHeader, packetHeader, msg) != CHIP_NO_ERROR)
977 : {
978 3 : ChipLogError(Inet, "Secure transport received message, but failed to decode/authenticate it, discarding");
979 3 : return;
980 : }
981 :
982 14808 : err =
983 14808 : secureSession->GetSessionMessageCounter().GetPeerMessageCounter().VerifyEncryptedUnicast(packetHeader.GetMessageCounter());
984 14808 : if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
985 : {
986 8 : ChipLogDetail(Inet,
987 : "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
988 : " on exchange " ChipLogFormatExchangeId,
989 : packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
990 8 : isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
991 8 : err = CHIP_NO_ERROR;
992 : }
993 14808 : if (err != CHIP_NO_ERROR)
994 : {
995 0 : ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
996 0 : return;
997 : }
998 :
999 14808 : secureSession->MarkActiveRx();
1000 :
1001 14808 : if (isDuplicate == SessionMessageDelegate::DuplicateMessage::Yes && !payloadHeader.NeedsAck())
1002 : {
1003 : // If it's a duplicate message, but doesn't require an ack, let's drop it right here to save CPU
1004 : // cycles on further message processing.
1005 2 : return;
1006 : }
1007 :
1008 14806 : if (isDuplicate == SessionMessageDelegate::DuplicateMessage::No)
1009 : {
1010 14800 : secureSession->GetSessionMessageCounter().GetPeerMessageCounter().CommitEncryptedUnicast(packetHeader.GetMessageCounter());
1011 : }
1012 :
1013 14806 : if (mCB != nullptr)
1014 : {
1015 : MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kSecureUnicast, &payloadHeader, &packetHeader,
1016 : secureSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
1017 14806 : CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, secureSession, peerAddress, msg->Start(), msg->TotalLength());
1018 :
1019 : // Always recompute whether a message is for a commissioning session based on the latest knowledge of
1020 : // the fabric table.
1021 14806 : if (secureSession->IsCASESession())
1022 : {
1023 20 : secureSession->SetCaseCommissioningSessionStatus(secureSession->GetFabricIndex() ==
1024 10 : mFabricTable->GetPendingNewFabricIndex());
1025 : }
1026 14806 : mCB->OnMessageReceived(packetHeader, payloadHeader, session.Value(), isDuplicate, std::move(msg));
1027 : }
1028 : else
1029 : {
1030 0 : ChipLogError(Inet, "Received SECURED message was not processed.");
1031 : }
1032 14822 : }
1033 :
1034 : /**
1035 : * Helper function to implement a single attempt to decrypt a groupcast message
1036 : * using the given group key and privacy setting.
1037 : *
1038 : * @param[in] partialPacketHeader The partial packet header with non-obfuscated message fields (result of calling DecodeFixed).
1039 : * @param[out] packetHeaderCopy A copy of the packet header, to be filled with privacy decrypted fields
1040 : * @param[out] payloadHeader The payload header of the decrypted message
1041 : * @param[in] applyPrivacy Whether to apply privacy deobfuscation
1042 : * @param[out] msgCopy A copy of the message, to be filled with the decrypted message
1043 : * @param[in] mac The MAC of the message
1044 : * @param[in] groupContext The group context to use for decryption key material
1045 : *
1046 : * @return true if the message was decrypted successfully
1047 : * @return false if the message could not be decrypted
1048 : */
1049 9 : static bool GroupKeyDecryptAttempt(const PacketHeader & partialPacketHeader, PacketHeader & packetHeaderCopy,
1050 : PayloadHeader & payloadHeader, bool applyPrivacy, System::PacketBufferHandle & msgCopy,
1051 : const MessageAuthenticationCode & mac,
1052 : const Credentials::GroupDataProvider::GroupSession & groupContext)
1053 : {
1054 9 : bool decrypted = false;
1055 9 : CryptoContext context(groupContext.keyContext);
1056 :
1057 9 : if (applyPrivacy)
1058 : {
1059 : // Perform privacy deobfuscation, if applicable.
1060 3 : uint8_t * privacyHeader = partialPacketHeader.PrivacyHeader(msgCopy->Start());
1061 3 : size_t privacyLength = partialPacketHeader.PrivacyHeaderLength();
1062 3 : if (CHIP_NO_ERROR != context.PrivacyDecrypt(privacyHeader, privacyLength, privacyHeader, partialPacketHeader, mac))
1063 : {
1064 0 : return false;
1065 : }
1066 : }
1067 :
1068 9 : if (packetHeaderCopy.DecodeAndConsume(msgCopy) != CHIP_NO_ERROR)
1069 : {
1070 0 : ChipLogError(Inet, "Failed to decode Groupcast packet header. Discarding.");
1071 0 : return false;
1072 : }
1073 :
1074 : // Optimization to reduce number of decryption attempts
1075 9 : GroupId groupId = packetHeaderCopy.GetDestinationGroupId().Value();
1076 9 : if (groupId != groupContext.group_id)
1077 : {
1078 3 : return false;
1079 : }
1080 :
1081 : CryptoContext::NonceStorage nonce;
1082 6 : CryptoContext::BuildNonce(nonce, packetHeaderCopy.GetSecurityFlags(), packetHeaderCopy.GetMessageCounter(),
1083 6 : packetHeaderCopy.GetSourceNodeId().Value());
1084 6 : decrypted = (CHIP_NO_ERROR == SecureMessageCodec::Decrypt(context, nonce, payloadHeader, packetHeaderCopy, msgCopy));
1085 :
1086 6 : return decrypted;
1087 9 : }
1088 :
1089 7 : void SessionManager::SecureGroupMessageDispatch(const PacketHeader & partialPacketHeader,
1090 : const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg)
1091 : {
1092 : MATTER_TRACE_SCOPE("Group Message Dispatch", "SessionManager");
1093 :
1094 7 : PayloadHeader payloadHeader;
1095 7 : PacketHeader packetHeaderCopy; /// Packet header decoded per group key, with privacy decrypted fields
1096 7 : System::PacketBufferHandle msgCopy;
1097 7 : Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider();
1098 7 : VerifyOrReturn(nullptr != groups);
1099 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1100 :
1101 7 : if (!partialPacketHeader.HasDestinationGroupId())
1102 : {
1103 0 : return; // malformed packet
1104 : }
1105 :
1106 : // Check if Message Header is valid first
1107 7 : if (!(partialPacketHeader.IsValidMCSPMsg() || partialPacketHeader.IsValidGroupMsg()))
1108 : {
1109 0 : ChipLogError(Inet, "Invalid condition found in packet header");
1110 0 : return;
1111 : }
1112 :
1113 : // Trial decryption with GroupDataProvider
1114 7 : Credentials::GroupDataProvider::GroupSession groupContext;
1115 :
1116 : AutoRelease<Credentials::GroupDataProvider::GroupSessionIterator> iter(
1117 7 : groups->IterateGroupSessions(partialPacketHeader.GetSessionId()));
1118 :
1119 7 : if (iter.IsNull())
1120 : {
1121 0 : ChipLogError(Inet, "Failed to retrieve Groups iterator. Discarding everything");
1122 0 : return;
1123 : }
1124 :
1125 : // Extract MIC from the end of the message.
1126 7 : uint8_t * data = msg->Start();
1127 7 : size_t len = msg->DataLength();
1128 7 : uint16_t footerLen = partialPacketHeader.MICTagLength();
1129 7 : VerifyOrReturn(footerLen <= len);
1130 :
1131 7 : uint16_t taglen = 0;
1132 : MessageAuthenticationCode mac;
1133 7 : ReturnOnFailure(mac.Decode(partialPacketHeader, &data[len - footerLen], footerLen, &taglen));
1134 7 : VerifyOrReturn(taglen == footerLen);
1135 :
1136 7 : bool decrypted = false;
1137 14 : while (!decrypted && iter->Next(groupContext))
1138 : {
1139 7 : CryptoContext context(groupContext.keyContext);
1140 7 : msgCopy = msg.CloneData();
1141 7 : if (msgCopy.IsNull())
1142 : {
1143 0 : ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
1144 0 : return;
1145 : }
1146 :
1147 7 : bool privacy = partialPacketHeader.HasPrivacyFlag();
1148 : decrypted =
1149 7 : GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, privacy, msgCopy, mac, groupContext);
1150 :
1151 : #if CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
1152 7 : if (privacy && !decrypted)
1153 : {
1154 : // Try processing the P=1 message again without privacy as a work-around for invalid early-SVE2 nodes.
1155 2 : msgCopy = msg.CloneData();
1156 2 : if (msgCopy.IsNull())
1157 : {
1158 0 : ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
1159 0 : return;
1160 : }
1161 : decrypted =
1162 2 : GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, false, msgCopy, mac, groupContext);
1163 : }
1164 : #endif // CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
1165 7 : }
1166 7 : iter.Release();
1167 :
1168 7 : if (!decrypted)
1169 : {
1170 1 : ChipLogError(Inet, "Failed to decrypt group message. Discarding everything");
1171 1 : return;
1172 : }
1173 6 : msg = std::move(msgCopy);
1174 :
1175 : // MCSP check
1176 6 : if (packetHeaderCopy.IsValidMCSPMsg())
1177 : {
1178 : // TODO: When MCSP Msg, create Secure Session instead of a Group session
1179 :
1180 : // TODO
1181 : // if (packetHeaderCopy.GetDestinationNodeId().Value() == ThisDeviceNodeID)
1182 : // {
1183 : // MCSP processing..
1184 : // }
1185 :
1186 0 : return;
1187 : }
1188 :
1189 : // Group Messages should never send an Ack
1190 6 : if (payloadHeader.NeedsAck())
1191 : {
1192 0 : ChipLogError(Inet, "Unexpected ACK requested for group message");
1193 0 : return;
1194 : }
1195 :
1196 : // Handle Group message counter here spec 4.7.3
1197 : // spec 4.5.1.2 for msg counter
1198 6 : Transport::PeerMessageCounter * counter = nullptr;
1199 :
1200 6 : if (CHIP_NO_ERROR ==
1201 18 : gGroupPeerTable->FindOrAddPeer(groupContext.fabric_index, packetHeaderCopy.GetSourceNodeId().Value(),
1202 12 : packetHeaderCopy.IsSecureSessionControlMsg(), counter))
1203 : {
1204 6 : if (Credentials::GroupDataProvider::SecurityPolicy::kTrustFirst == groupContext.security_policy)
1205 : {
1206 4 : err = counter->VerifyOrTrustFirstGroup(packetHeaderCopy.GetMessageCounter());
1207 : }
1208 : else
1209 : {
1210 :
1211 : // TODO support cache and sync with MCSP. Issue #11689
1212 2 : ChipLogError(Inet, "Received Group Msg with key policy Cache and Sync, but MCSP is not implemented");
1213 2 : return;
1214 :
1215 : // cache and sync
1216 : // err = counter->VerifyGroup(packetHeaderCopy.GetMessageCounter());
1217 : }
1218 :
1219 4 : if (err != CHIP_NO_ERROR)
1220 : {
1221 : // Exit now, since Group Messages don't have acks or responses of any kind.
1222 1 : ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
1223 1 : return;
1224 : }
1225 : }
1226 : else
1227 : {
1228 0 : ChipLogError(Inet,
1229 : "Group Counter Tables full or invalid NodeId/FabricIndex after decryption of message, dropping everything");
1230 0 : return;
1231 : }
1232 :
1233 3 : counter->CommitGroup(packetHeaderCopy.GetMessageCounter());
1234 :
1235 3 : if (mCB != nullptr)
1236 : {
1237 : // TODO : When MCSP is done, clean up session creation logic
1238 3 : Transport::IncomingGroupSession groupSession(groupContext.group_id, groupContext.fabric_index,
1239 3 : packetHeaderCopy.GetSourceNodeId().Value());
1240 :
1241 : MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kGroupMessage, &payloadHeader, &packetHeaderCopy,
1242 : &groupSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()));
1243 :
1244 3 : CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeaderCopy, &groupSession, peerAddress, msg->Start(), msg->TotalLength());
1245 3 : mCB->OnMessageReceived(packetHeaderCopy, payloadHeader, SessionHandle(groupSession),
1246 3 : SessionMessageDelegate::DuplicateMessage::No, std::move(msg));
1247 3 : }
1248 : else
1249 : {
1250 0 : ChipLogError(Inet, "Received GROUP message was not processed.");
1251 : }
1252 11 : }
1253 :
1254 1 : Optional<SessionHandle> SessionManager::FindSecureSessionForNode(ScopedNodeId peerNodeId,
1255 : const Optional<Transport::SecureSession::Type> & type,
1256 : TransportPayloadCapability transportPayloadCapability)
1257 : {
1258 1 : SecureSession * mrpSession = nullptr;
1259 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
1260 1 : SecureSession * tcpSession = nullptr;
1261 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
1262 :
1263 1 : mSecureSessions.ForEachSession([&peerNodeId, &type, &mrpSession,
1264 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
1265 : &tcpSession,
1266 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
1267 15 : &transportPayloadCapability](auto session) {
1268 4 : if (session->IsActiveSession() && session->GetPeer() == peerNodeId &&
1269 2 : (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
1270 : {
1271 2 : if (transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload ||
1272 2 : transportPayloadCapability == TransportPayloadCapability::kLargePayload)
1273 : {
1274 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
1275 : // Set up a TCP transport based session as standby
1276 0 : if ((tcpSession == nullptr || tcpSession->GetLastPeerActivityTime() < session->GetLastPeerActivityTime()) &&
1277 0 : session->GetTCPConnection() != nullptr)
1278 : {
1279 0 : tcpSession = session;
1280 : }
1281 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
1282 : }
1283 :
1284 2 : if ((mrpSession == nullptr) || (mrpSession->GetLastPeerActivityTime() < session->GetLastPeerActivityTime()))
1285 : {
1286 2 : mrpSession = session;
1287 : }
1288 : }
1289 :
1290 2 : return Loop::Continue;
1291 : });
1292 :
1293 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
1294 1 : if (transportPayloadCapability == TransportPayloadCapability::kLargePayload)
1295 : {
1296 0 : return tcpSession != nullptr ? MakeOptional<SessionHandle>(*tcpSession) : Optional<SessionHandle>::Missing();
1297 : }
1298 :
1299 1 : if (transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload)
1300 : {
1301 : // If MRP-based session is available, use it.
1302 0 : if (mrpSession != nullptr)
1303 : {
1304 0 : return MakeOptional<SessionHandle>(*mrpSession);
1305 : }
1306 :
1307 : // Otherwise, look for a tcp-based session
1308 0 : if (tcpSession != nullptr)
1309 : {
1310 0 : return MakeOptional<SessionHandle>(*tcpSession);
1311 : }
1312 :
1313 0 : return Optional<SessionHandle>::Missing();
1314 : }
1315 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
1316 :
1317 1 : return mrpSession != nullptr ? MakeOptional<SessionHandle>(*mrpSession) : Optional<SessionHandle>::Missing();
1318 : }
1319 :
1320 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
1321 0 : void SessionManager::MarkSecureSessionOverTCPForEviction(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr)
1322 : {
1323 : // Mark the corresponding secure sessions for eviction
1324 0 : mSecureSessions.ForEachSession([&](auto session) {
1325 0 : if (session->IsActiveSession() && session->GetTCPConnection() == conn)
1326 : {
1327 0 : SessionHandle handle(*session);
1328 : // Notify the SessionConnection delegate of the connection
1329 : // closure.
1330 0 : if (mConnDelegate != nullptr)
1331 : {
1332 0 : mConnDelegate->OnTCPConnectionClosed(handle, conErr);
1333 : }
1334 :
1335 : // Dis-associate the connection from session by setting it to a
1336 : // nullptr.
1337 0 : session->SetTCPConnection(nullptr);
1338 : // Mark session for eviction.
1339 0 : session->MarkForEviction();
1340 0 : }
1341 :
1342 0 : return Loop::Continue;
1343 : });
1344 0 : }
1345 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
1346 :
1347 : /**
1348 : * Provides a means to get diagnostic information such as number of sessions.
1349 : */
1350 0 : [[maybe_unused]] CHIP_ERROR SessionManager::ForEachSessionHandle(void * context, SessionHandleCallback lambda)
1351 : {
1352 0 : mSecureSessions.ForEachSession([&](auto session) {
1353 0 : SessionHandle handle(*session);
1354 0 : lambda(context, handle);
1355 0 : return Loop::Continue;
1356 0 : });
1357 0 : return CHIP_NO_ERROR;
1358 : }
1359 :
1360 : } // namespace chip
|