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