mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

In the example below, the association is being established between peer A and Z, and A is the initiating party. Before this CL, when an association was about to be established, Z would after having received the INIT chunk, persist state in the socket about which verification tag and initial TSN that was picked. These would be re-generated on every incoming INIT (that's fine), but when A had extracted the cookie from INIT_ACK and sent a reply (COOKIE_ECHO) with the state cookie, that could fail validation when it's received by Z, if the sent cookie was not the most recent one or if the COOKIE_ECHO had a verification tag coming not from the most recent INIT_ACK, because Z had replaced the state in the socket with the one generated when the second INIT_ACK chunk was generated - state it used for validation of future received data. In other words: A -> INIT 1 <timeout> A -> INIT 2 (retransmission of INIT 1) INIT 1 -> Z - sends INIT_ACK 1 with verification_tag=1, initial_tsn=1, cookie 1 (and records these to socket state) INIT 2 -> Z - sends INIT_ACK 2 with verification_tag=2, initial_tsn=2, cookie 2 (replaces socket state with the new data) INIT_ACK 1 -> A -> sends COOKIE_ECHO with verification_tag=1, cookie 1 COOKIE_ECHO (cookie 1) -> Z <FAILS, as the state isn't as expected>. The solution is really to do what RFC4960 says, to not maintain any state as the receiving peer until COOKIE_ECHO has been received. This was initially not done because the underlying reason why this is important in SCTP is to avoid denial of service, and this is why SCTP has the four-way handshake. But for Data Channels - SCTP over DTLS - this attack vector isn't available. So the implementation was "simplified" by keeping socket state instead of encoding it in the state cookie, but that obviously had downsides. So with this CL, the non-initiating peer in connection establishment doesn't keep any socket state, and puts all that state in the state cookie instead. This allows any COOKIE_ECHO to be received by Z. Bug: webrtc:15712 Change-Id: I596c7330ce27292612d3c9f86b21c712f6f4e408 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/330440 Commit-Queue: Victor Boivie <boivie@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41340}
75 lines
2.5 KiB
C++
75 lines
2.5 KiB
C++
/*
|
|
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
#ifndef NET_DCSCTP_SOCKET_STATE_COOKIE_H_
|
|
#define NET_DCSCTP_SOCKET_STATE_COOKIE_H_
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "api/array_view.h"
|
|
#include "net/dcsctp/common/internal_types.h"
|
|
#include "net/dcsctp/socket/capabilities.h"
|
|
|
|
namespace dcsctp {
|
|
|
|
// This is serialized as a state cookie and put in INIT_ACK. The client then
|
|
// responds with this in COOKIE_ECHO.
|
|
//
|
|
// NOTE: Expect that the client will modify it to try to exploit the library.
|
|
// Do not trust anything in it; no pointers or anything like that.
|
|
class StateCookie {
|
|
public:
|
|
static constexpr size_t kCookieSize = 45;
|
|
|
|
StateCookie(VerificationTag peer_tag,
|
|
VerificationTag my_tag,
|
|
TSN peer_initial_tsn,
|
|
TSN my_initial_tsn,
|
|
uint32_t a_rwnd,
|
|
TieTag tie_tag,
|
|
Capabilities capabilities)
|
|
: peer_tag_(peer_tag),
|
|
my_tag_(my_tag),
|
|
peer_initial_tsn_(peer_initial_tsn),
|
|
my_initial_tsn_(my_initial_tsn),
|
|
a_rwnd_(a_rwnd),
|
|
tie_tag_(tie_tag),
|
|
capabilities_(capabilities) {}
|
|
|
|
// Returns a serialized version of this cookie.
|
|
std::vector<uint8_t> Serialize();
|
|
|
|
// Deserializes the cookie, and returns absl::nullopt if that failed.
|
|
static absl::optional<StateCookie> Deserialize(
|
|
rtc::ArrayView<const uint8_t> cookie);
|
|
|
|
VerificationTag peer_tag() const { return peer_tag_; }
|
|
VerificationTag my_tag() const { return my_tag_; }
|
|
TSN peer_initial_tsn() const { return peer_initial_tsn_; }
|
|
TSN my_initial_tsn() const { return my_initial_tsn_; }
|
|
uint32_t a_rwnd() const { return a_rwnd_; }
|
|
TieTag tie_tag() const { return tie_tag_; }
|
|
const Capabilities& capabilities() const { return capabilities_; }
|
|
|
|
private:
|
|
// Also called "Tag_A" in RFC4960.
|
|
const VerificationTag peer_tag_;
|
|
// Also called "Tag_Z" in RFC4960.
|
|
const VerificationTag my_tag_;
|
|
const TSN peer_initial_tsn_;
|
|
const TSN my_initial_tsn_;
|
|
const uint32_t a_rwnd_;
|
|
const TieTag tie_tag_;
|
|
const Capabilities capabilities_;
|
|
};
|
|
} // namespace dcsctp
|
|
|
|
#endif // NET_DCSCTP_SOCKET_STATE_COOKIE_H_
|