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