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