Skip to content

Commit 114ea1a

Browse files
committed
Mitigation to unauthenticated TCP support advertisement in DNS-SD
that made it susceptible to potential DoS attacks. As part of this resolution, Add TCP support and Max receive size info within negotiated CASE Session parameters. --Nodes publish TCP support information during CASE session(over MRP) negotiations. --Add TCP param storage logic to persist received TCP support info to storage during CASE session establishment and retrieve it during future TCP session setup. --During TCP session setup, first check if the TCP support info for peer is available in storage before, going to the DNS-SD advertised values.
1 parent 96ee61e commit 114ea1a

15 files changed

+782
-12
lines changed

src/app/OperationalSessionSetup.cpp

+32-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <lib/address_resolve/AddressResolve.h>
3434
#include <lib/core/CHIPCore.h>
3535
#include <lib/core/CHIPEncoding.h>
36+
#include <lib/dnssd/Advertiser.h>
3637
#include <lib/dnssd/Resolver.h>
3738
#include <lib/support/CodeUtils.h>
3839
#include <lib/support/logging/CHIPLogging.h>
@@ -300,19 +301,40 @@ CHIP_ERROR OperationalSessionSetup::EstablishConnection(const ResolveResult & re
300301
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
301302
if (mTransportPayloadCapability == TransportPayloadCapability::kLargePayload)
302303
{
303-
if (result.supportsTcpServer)
304+
// First check if the TCPSupport information is available from prior
305+
// CASE session negotiations with peer.
306+
// Else, fall back to TCP support information from DNS-SD
307+
// advertisements.
308+
uint16_t supportedTransports;
309+
uint32_t maxTCPMessageSize;
310+
VerifyOrDie(mInitParams.sessionManager != nullptr);
311+
CHIP_ERROR err = mInitParams.sessionManager->GetPeerTCPParamsStorage().FindByScopedNodeId(mPeerId, supportedTransports,
312+
maxTCPMessageSize);
313+
if (err == CHIP_NO_ERROR)
304314
{
305-
// Set the transport type for carrying large payloads
306-
mDeviceAddress.SetTransportType(chip::Transport::Type::kTcp);
315+
if ((supportedTransports & to_underlying(Dnssd::TCPModeAdvertise::kTCPServer)) != 0)
316+
{
317+
// Set the transport type for carrying large payloads
318+
mDeviceAddress.SetTransportType(chip::Transport::Type::kTcp);
319+
}
307320
}
308-
else
321+
else // Failed to retrieve TCP Params from storage
309322
{
310-
// we should not set the large payload while the TCP support is not enabled
311-
ChipLogError(
312-
Discovery,
313-
"LargePayload session requested but peer does not support TCP server, PeerNodeId=" ChipLogFormatScopedNodeId,
314-
ChipLogValueScopedNodeId(mPeerId));
315-
return CHIP_ERROR_INTERNAL;
323+
// Check DNS-SD advertisement values if information not available via CASE session parameters
324+
if (result.supportsTcpServer)
325+
{
326+
// Set the transport type for carrying large payloads
327+
mDeviceAddress.SetTransportType(chip::Transport::Type::kTcp);
328+
}
329+
else
330+
{
331+
// we should not set the large payload while the TCP support is not enabled from the peer's side.
332+
ChipLogError(
333+
Discovery,
334+
"LargePayload session requested but peer does not support TCP server, PeerNodeId=" ChipLogFormatScopedNodeId,
335+
ChipLogValueScopedNodeId(mPeerId));
336+
return CHIP_ERROR_INTERNAL;
337+
}
316338
}
317339
}
318340
#endif

src/controller/python/chip/utils/DeviceProxyUtils.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ struct __attribute__((packed)) SessionParametersStruct
4444
uint16_t interactionModelRevision = 0;
4545
uint32_t specificationVersion = 0;
4646
uint16_t maxPathsPerInvoke = 0;
47+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
48+
uint16_t supportedTransports = 0;
49+
uint32_t maxTCPMessageSize = 0;
50+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
4751
};
4852

4953
} // namespace python
@@ -99,6 +103,11 @@ PyChipError pychip_DeviceProxy_GetRemoteSessionParameters(DeviceProxy * device,
99103
sessionParam->interactionModelRevision = remoteSessionParameters.GetInteractionModelRevision().ValueOr(0);
100104
sessionParam->specificationVersion = remoteSessionParameters.GetSpecificationVersion().ValueOr(0);
101105
sessionParam->maxPathsPerInvoke = remoteSessionParameters.GetMaxPathsPerInvoke();
106+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
107+
sessionParam->supportedTransports = remoteSessionParameters.GetSupportedTransports().ValueOr(0);
108+
sessionParam->maxTCPMessageSize =
109+
remoteSessionParameters.GetMaxTCPMessageSize().ValueOr(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve - 4);
110+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
102111
return ToPyChipError(CHIP_NO_ERROR);
103112
}
104113
}

src/lib/support/DefaultStorageKeyAllocator.h

+8
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ class DefaultStorageKeyAllocator
256256
// when new fabric is created, this list needs to be updated,
257257
// when client init DefaultICDClientStorage, this table needs to be loaded.
258258
static StorageKeyName ICDFabricList() { return StorageKeyName::FromConst("g/icdfl"); }
259+
260+
// TCP peer parameters
261+
static StorageKeyName TCPPeerParams(FabricIndex fabric, NodeId nodeId)
262+
{
263+
return StorageKeyName::Formatted("f/%x/tcp/%08" PRIX32 "%08" PRIX32, fabric, static_cast<uint32_t>(nodeId >> 32),
264+
static_cast<uint32_t>(nodeId));
265+
}
266+
static StorageKeyName TCPPeerList() { return StorageKeyName::FromConst("g/tcpl"); }
259267
};
260268

261269
} // namespace chip

src/messaging/SessionParameters.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,19 @@ class SessionParameters
4141
static constexpr size_t kSizeOfInteractionModelRevision = sizeof(uint16_t);
4242
static constexpr size_t kSizeOfSpecificationVersion = sizeof(uint32_t);
4343
static constexpr size_t kSizeOfMaxPathsPerInvoke = sizeof(uint16_t);
44+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
45+
static constexpr size_t kSizeOfSupportedTransports = sizeof(uint16_t);
46+
static constexpr size_t kSizeOfMaxTCPMessageSize = sizeof(uint32_t);
47+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
4448

4549
static constexpr size_t kEstimatedTLVSize = TLV::EstimateStructOverhead(
4650
kSizeOfSessionIdleInterval, kSizeOfSessionActiveInterval, kSizeOfSessionActiveThreshold, kSizeOfDataModelRevision,
47-
kSizeOfInteractionModelRevision, kSizeOfSpecificationVersion, kSizeOfMaxPathsPerInvoke);
51+
kSizeOfInteractionModelRevision, kSizeOfSpecificationVersion, kSizeOfMaxPathsPerInvoke
52+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
53+
,
54+
kSizeOfSupportedTransports, kSizeOfMaxTCPMessageSize
55+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
56+
);
4857

4958
// From Section 4.12.8 "Parameters and Constants" in chapter "Secure Channel".
5059
enum Tag : uint32_t
@@ -56,6 +65,8 @@ class SessionParameters
5665
kInteractionModelRevision = 5,
5766
kSpecificationVersion = 6,
5867
kMaxPathsPerInvoke = 7,
68+
kSupportedTransports = 8,
69+
kMaxTCPMessageSize = 9,
5970
};
6071

6172
const ReliableMessageProtocolConfig & GetMRPConfig() const { return mMRPConfig; }
@@ -91,6 +102,13 @@ class SessionParameters
91102
uint16_t GetMaxPathsPerInvoke() const { return mMaxPathsPerInvoke; }
92103
void SetMaxPathsPerInvoke(const uint16_t maxPathsPerInvoke) { mMaxPathsPerInvoke = maxPathsPerInvoke; }
93104

105+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
106+
const Optional<uint16_t> & GetSupportedTransports() const { return mSupportedTransports; }
107+
void SetSupportedTransports(const uint16_t supportedTransports) { mSupportedTransports = MakeOptional(supportedTransports); }
108+
109+
const Optional<uint32_t> & GetMaxTCPMessageSize() const { return mMaxTCPMessageSize; }
110+
void SetMaxTCPMessageSize(const uint32_t maxTCPMessageSize) { mMaxTCPMessageSize = MakeOptional(maxTCPMessageSize); }
111+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
94112
private:
95113
ReliableMessageProtocolConfig mMRPConfig;
96114
// For legacy reasons if we do not get DataModelRevision it means either 16 or 17. But there isn't
@@ -104,6 +122,11 @@ class SessionParameters
104122
Optional<uint32_t> mSpecificationVersion;
105123
// When maxPathsPerInvoke is not provided legacy is always 1
106124
uint16_t mMaxPathsPerInvoke = 1;
125+
126+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
127+
Optional<uint16_t> mSupportedTransports;
128+
Optional<uint32_t> mMaxTCPMessageSize;
129+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
107130
};
108131

109132
} // namespace chip

src/protocols/secure_channel/CASESession.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <tracing/macros.h>
5050
#include <tracing/metric_event.h>
5151
#include <transport/SessionManager.h>
52+
#include <transport/raw/PeerTCPParamsStorage.h>
5253

5354
namespace {
5455

@@ -696,6 +697,25 @@ CHIP_ERROR CASESession::RecoverInitiatorIpk()
696697
}
697698

698699
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
700+
CHIP_ERROR CASESession::SaveTCPInfoFromRemoteSessionParams()
701+
{
702+
if (GetRemoteSessionParameters().GetSupportedTransports().HasValue() &&
703+
GetRemoteSessionParameters().GetMaxTCPMessageSize().HasValue())
704+
{
705+
ReturnErrorOnFailure(mSessionManager->GetPeerTCPParamsStorage().SaveTCPParams(
706+
GetPeer(), GetRemoteSessionParameters().GetSupportedTransports().Value(),
707+
GetRemoteSessionParameters().GetMaxTCPMessageSize().Value()));
708+
}
709+
else
710+
{
711+
// Store zeroes for the TCP parameters as sentinel values from CASE
712+
// session for no TCP support.
713+
ReturnErrorOnFailure(mSessionManager->GetPeerTCPParamsStorage().SaveTCPParams(GetPeer(), 0, 0));
714+
}
715+
716+
return CHIP_NO_ERROR;
717+
}
718+
699719
void CASESession::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR err)
700720
{
701721
VerifyOrReturn(conn != nullptr);
@@ -1298,6 +1318,10 @@ CHIP_ERROR CASESession::HandleSigma2Resume(System::PacketBufferHandle && msg)
12981318
SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(4), tlvReader));
12991319
mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
13001320
GetRemoteSessionParameters());
1321+
1322+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
1323+
ReturnErrorOnFailure(SaveTCPInfoFromRemoteSessionParams());
1324+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
13011325
}
13021326

13031327
ChipLogDetail(SecureChannel, "Peer assigned session session ID %d", responderSessionId);
@@ -1500,6 +1524,10 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)
15001524
SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(kTag_Sigma2_ResponderMRPParams), tlvReader));
15011525
mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
15021526
GetRemoteSessionParameters());
1527+
1528+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
1529+
ReturnErrorOnFailure(SaveTCPInfoFromRemoteSessionParams());
1530+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
15031531
}
15041532

15051533
exit:
@@ -2198,6 +2226,11 @@ CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader,
21982226
ReturnErrorOnFailure(DecodeMRPParametersIfPresent(TLV::ContextTag(kInitiatorMRPParamsTag), tlvReader));
21992227
mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
22002228
GetRemoteSessionParameters());
2229+
2230+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
2231+
ReturnErrorOnFailure(SaveTCPInfoFromRemoteSessionParams());
2232+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
2233+
22012234
err = tlvReader.Next();
22022235
}
22032236

src/protocols/secure_channel/CASESession.h

+1
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler,
287287
void InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex);
288288

289289
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
290+
CHIP_ERROR SaveTCPInfoFromRemoteSessionParams();
290291
static void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
291292
static void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
292293

src/protocols/secure_channel/PairingSession.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <app/SpecificationDefinedRevisions.h>
2222
#include <lib/core/CHIPConfig.h>
2323
#include <lib/core/TLVTypes.h>
24+
#include <lib/dnssd/Advertiser.h>
2425
#include <lib/support/SafeInt.h>
2526
#include <lib/support/TypeTraits.h>
2627
#include <platform/CHIPDeviceEvent.h>
@@ -142,6 +143,16 @@ CHIP_ERROR PairingSession::EncodeSessionParameters(TLV::Tag tag, const ReliableM
142143

143144
uint16_t maxPathsPerInvoke = CHIP_CONFIG_MAX_PATHS_PER_INVOKE;
144145
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxPathsPerInvoke), maxPathsPerInvoke));
146+
147+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
148+
// Support for both TCP CLient and Server(0x06)
149+
uint16_t supportedTransports = to_underlying(Dnssd::TCPModeAdvertise::kTCPClientServer);
150+
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSupportedTransports), supportedTransports));
151+
152+
uint32_t maxTCPMessageSize = System::PacketBuffer::kLargeBufMaxSizeWithoutReserve - 4 /* Framing length field of 4 bytes */;
153+
ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxTCPMessageSize), maxTCPMessageSize));
154+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
155+
145156
return tlvWriter.EndContainer(mrpParamsContainer);
146157
}
147158

@@ -234,6 +245,31 @@ CHIP_ERROR PairingSession::DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TL
234245
SuccessOrExit(err = tlvReader.Next());
235246
}
236247

248+
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
249+
250+
if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSupportedTransports)
251+
{
252+
ChipLogDetail(SecureChannel, "Found TCPSupport parameter in the message");
253+
uint16_t supportedTransports;
254+
ReturnErrorOnFailure(tlvReader.Get(supportedTransports));
255+
mRemoteSessionParams.SetSupportedTransports(supportedTransports);
256+
257+
// The next element is optional. If it's not present, return CHIP_NO_ERROR.
258+
SuccessOrExit(err = tlvReader.Next());
259+
}
260+
261+
if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kMaxTCPMessageSize)
262+
{
263+
ChipLogDetail(SecureChannel, "Found TCP Max message size parameter in the message");
264+
uint32_t maxTCPMessageSize;
265+
ReturnErrorOnFailure(tlvReader.Get(maxTCPMessageSize));
266+
mRemoteSessionParams.SetMaxTCPMessageSize(maxTCPMessageSize);
267+
268+
// The next element is optional. If it's not present, return CHIP_NO_ERROR.
269+
SuccessOrExit(err = tlvReader.Next());
270+
}
271+
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
272+
237273
// Future proofing - Don't error out if there are other tags
238274
exit:
239275
if (err == CHIP_END_OF_TLV)

src/transport/SessionManager.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase *
150150
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
151151
mConnCompleteCb = nullptr;
152152
mConnClosedCb = nullptr;
153+
154+
ReturnErrorOnFailure(mPeerTCPParamsStorage.Init(storageDelegate));
153155
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
154156

155157
return CHIP_NO_ERROR;

src/transport/SessionManager.h

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
5656
#include <transport/SessionConnectionDelegate.h>
57+
#include <transport/raw/PeerTCPParamsStorage.h>
5758
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
5859

5960
namespace chip {
@@ -494,6 +495,7 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl
494495

495496
using OnTCPConnectionClosedCallback = void (*)(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr);
496497

498+
Transport::PeerTCPParamsStorage & GetPeerTCPParamsStorage() { return mPeerTCPParamsStorage; }
497499
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
498500

499501
Optional<SessionHandle> CreateUnauthenticatedSession(const Transport::PeerAddress & peerAddress,
@@ -566,6 +568,7 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl
566568
// Hold the TCPConnection callback context for the receiver application in the SessionManager.
567569
// On receipt of a connection from a peer, the SessionManager
568570
Transport::AppTCPConnectionCallbackCtxt * mServerTCPConnCbCtxt = nullptr;
571+
Transport::PeerTCPParamsStorage mPeerTCPParamsStorage;
569572
#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
570573

571574
SessionMessageDelegate * mCB = nullptr;

src/transport/raw/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ static_library("raw") {
3333
if (chip_inet_config_enable_tcp_endpoint) {
3434
sources += [
3535
"ActiveTCPConnectionState.h",
36+
"PeerTCPParamsStorage.cpp",
37+
"PeerTCPParamsStorage.h",
3638
"TCP.cpp",
3739
"TCP.h",
3840
"TCPConfig.h",

0 commit comments

Comments
 (0)