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