Skip to content

Commit

Permalink
quic: unify stateless reset handling
Browse files Browse the repository at this point in the history
PR-URL: nodejs#294
Reviewed-By: Anna Henningsen <[email protected]>
  • Loading branch information
jasnell committed Feb 3, 2020
1 parent efce2bd commit 0a974c0
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 76 deletions.
31 changes: 9 additions & 22 deletions src/quic/node_quic_session-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,26 @@ using crypto::SecureContext;
namespace quic {

void QuicSessionConfig::GenerateStatelessResetToken(
StatelessResetTokenStrategy strategy,
QuicSession* session,
const QuicCID& cid) {
transport_params.stateless_reset_token_present = 1;
strategy(
session,
cid,
transport_params.stateless_reset_token,
NGTCP2_STATELESS_RESET_TOKENLEN);
StatelessResetToken(
transport_params.stateless_reset_token,
session->socket()->session_reset_secret(),
cid);
}

void QuicSessionConfig::GeneratePreferredAddressToken(
ConnectionIDStrategy connection_id_strategy,
StatelessResetTokenStrategy stateless_reset_strategy,
QuicSession* session,
QuicCID* pscid) {

connection_id_strategy(session, pscid->cid(), kScidLen);
stateless_reset_strategy(
session,
*pscid,
transport_params.preferred_address.stateless_reset_token,
NGTCP2_STATELESS_RESET_TOKENLEN);
transport_params.preferred_address.cid = **pscid;

StatelessResetToken(
transport_params.preferred_address.stateless_reset_token,
session->socket()->session_reset_secret(),
*pscid);
}

void QuicSessionConfig::set_original_connection_id(const QuicCID& ocid) {
Expand Down Expand Up @@ -376,15 +372,6 @@ void QuicSession::set_connection_id_strategy(ConnectionIDStrategy strategy) {
connection_id_strategy_ = strategy;
}

// The stateless reset token strategy is a function that generates
// stateless reset tokens. By default these are cryptographically
// derived by the CID.
void QuicSession::set_stateless_reset_token_strategy(
StatelessResetTokenStrategy strategy) {
CHECK_NOT_NULL(strategy);
stateless_reset_strategy_ = strategy;
}

void QuicSession::set_preferred_address_strategy(
PreferredAddressStrategy strategy) {
preferred_address_strategy_ = strategy;
Expand Down
35 changes: 3 additions & 32 deletions src/quic/node_quic_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -709,26 +709,6 @@ void QuicSession::RandomConnectionIDStrategy(
EntropySource(cid->data, cidlen);
}

// Generates a stateless reset token as a function of the reset
// secret (generated randomly by default or set by config option)
// and the provided cid. The stateless reset is generated
// cryptographically and can be recreated later without storing
// additional state.
void QuicSession::CryptoStatelessResetTokenStrategy(
QuicSession* session,
const QuicCID& cid,
uint8_t* token,
size_t tokenlen) {
// For the current time, we limit stateless reset token lengths to
// NGTCP2_STATELESS_RESET_TOKENLEN. The tokenlen argument is largely
// for future proofing in case that restriction changes.
CHECK_EQ(tokenlen, NGTCP2_STATELESS_RESET_TOKENLEN);
CHECK(GenerateResetToken(
token,
session->socket()->session_reset_secret(),
cid));
}

// Check required capabilities were not excluded from the OpenSSL build:
// - OPENSSL_NO_SSL_TRACE excludes SSL_trace()
// - OPENSSL_NO_STDIO excludes BIO_new_fp()
Expand Down Expand Up @@ -1352,7 +1332,6 @@ QuicSession::QuicSession(
state_(env()->isolate(), IDX_QUIC_SESSION_STATE_COUNT) {
PushListener(&default_listener_);
set_connection_id_strategy(RandomConnectionIDStrategy);
set_stateless_reset_token_strategy(CryptoStatelessResetTokenStrategy);
set_preferred_address_strategy(preferred_address_strategy);
crypto_context_.reset(new QuicCryptoContext(this, ctx, side, options));
application_.reset(SelectApplication(this));
Expand Down Expand Up @@ -1630,7 +1609,7 @@ int QuicSession::GetNewConnectionID(
CHECK_NOT_NULL(connection_id_strategy_);
connection_id_strategy_(this, cid, cidlen);
QuicCID cid_(cid);
stateless_reset_strategy_(this, cid_, token, NGTCP2_STATELESS_RESET_TOKENLEN);
StatelessResetToken(token, socket()->session_reset_secret(), cid_);
AssociateCID(cid_);
return 0;
}
Expand Down Expand Up @@ -2629,16 +2608,8 @@ void QuicSession::InitServer(

connection_id_strategy_(this, scid_.cid(), kScidLen);

config.GenerateStatelessResetToken(
stateless_reset_strategy_,
this,
scid_);

config.GeneratePreferredAddressToken(
connection_id_strategy_,
stateless_reset_strategy_,
this,
&pscid_);
config.GenerateStatelessResetToken(this, scid_);
config.GeneratePreferredAddressToken(connection_id_strategy_, this, &pscid_);

QuicPath path(local_addr, remote_address_);

Expand Down
17 changes: 0 additions & 17 deletions src/quic/node_quic_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ typedef void(*ConnectionIDStrategy)(
ngtcp2_cid* cid,
size_t cidlen);

typedef void(*StatelessResetTokenStrategy)(
QuicSession* session,
const QuicCID& cid,
uint8_t* token,
size_t tokenlen);

typedef void(*PreferredAddressStrategy)(
QuicSession* session,
const QuicPreferredAddress& preferred_address);
Expand Down Expand Up @@ -91,14 +85,12 @@ class QuicSessionConfig : public ngtcp2_settings {

// Generates the stateless reset token for the settings_
inline void GenerateStatelessResetToken(
StatelessResetTokenStrategy strategy,
QuicSession* session,
const QuicCID& cid);

// If the preferred address is set, generates the associated tokens
inline void GeneratePreferredAddressToken(
ConnectionIDStrategy connection_id_strategy,
StatelessResetTokenStrategy stateless_reset_strategy,
QuicSession* session,
QuicCID* pscid);

Expand Down Expand Up @@ -1015,8 +1007,6 @@ class QuicSession : public AsyncWrap,

inline void set_connection_id_strategy(
ConnectionIDStrategy strategy);
inline void set_stateless_reset_token_strategy(
StatelessResetTokenStrategy strategy);
inline void set_preferred_address_strategy(
PreferredAddressStrategy strategy);

Expand Down Expand Up @@ -1078,12 +1068,6 @@ class QuicSession : public AsyncWrap,
ngtcp2_cid* cid,
size_t cidlen);

static void CryptoStatelessResetTokenStrategy(
QuicSession* session,
const QuicCID& cid,
uint8_t* token,
size_t tokenlen);

// Initialize the QuicSession as a server
void InitServer(
QuicSessionConfig config,
Expand Down Expand Up @@ -1415,7 +1399,6 @@ class QuicSession : public AsyncWrap,
size_t connection_close_limit_ = 1;

ConnectionIDStrategy connection_id_strategy_ = nullptr;
StatelessResetTokenStrategy stateless_reset_strategy_ = nullptr;
PreferredAddressStrategy preferred_address_strategy_ = nullptr;

QuicSessionListener* listener_ = nullptr;
Expand Down
5 changes: 2 additions & 3 deletions src/quic/node_quic_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,6 @@ bool QuicSocket::SendStatelessReset(
return false;
constexpr static size_t kRandlen = NGTCP2_MIN_STATELESS_RESET_RANDLEN * 5;
constexpr static size_t kMinStatelessResetLen = 41;
uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
uint8_t random[kRandlen];

// Per the QUIC spec, we need to protect against sending too
Expand All @@ -658,15 +657,15 @@ bool QuicSocket::SendStatelessReset(
if (pktlen < kMinStatelessResetLen)
return false;

GenerateResetToken(token, reset_token_secret_, cid);
StatelessResetToken token(reset_token_secret_, cid);
EntropySource(random, kRandlen);

auto packet = QuicPacket::Create("stateless reset", pktlen);
ssize_t nwrite =
ngtcp2_pkt_write_stateless_reset(
reinterpret_cast<uint8_t*>(packet->data()),
NGTCP2_MAX_PKTLEN_IPV4,
token,
const_cast<uint8_t*>(token.data()),
random,
kRandlen);
if (nwrite < static_cast<ssize_t>(kMinStatelessResetLen))
Expand Down
14 changes: 14 additions & 0 deletions src/quic/node_quic_util-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,20 @@ bool QuicPreferredAddress::ResolvePreferredAddress(
req->addrinfo != nullptr;
}

StatelessResetToken::StatelessResetToken(
uint8_t* token,
const uint8_t* secret,
const QuicCID& cid) : token_(token) {
GenerateResetToken(token, secret, cid);
}

StatelessResetToken::StatelessResetToken(
const uint8_t* secret,
const QuicCID& cid)
: token_(buf_) {
GenerateResetToken(buf_, secret, cid);
}

std::string StatelessResetToken::ToHex() const {
std::vector<char> dest(NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1);
dest[dest.size() - 1] = '\0';
Expand Down
15 changes: 13 additions & 2 deletions src/quic/node_quic_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,21 @@ class Timer final : public MemoryRetainer {

using TimerPointer = DeleteFnPtr<Timer, Timer::Free>;

class StatelessResetToken : public MemoryRetainer{
class StatelessResetToken : public MemoryRetainer {
public:
explicit StatelessResetToken(const uint8_t* token) : token_(token) {}
inline StatelessResetToken(
uint8_t* token,
const uint8_t* secret,
const QuicCID& cid);
inline StatelessResetToken(
const uint8_t* secret,
const QuicCID& cid);
explicit StatelessResetToken(
const uint8_t* token)
: token_(token) {}

inline std::string ToHex() const;
const uint8_t* data() const { return token_; }

struct Hash {
inline size_t operator()(const StatelessResetToken& token) const;
Expand All @@ -315,6 +325,7 @@ class StatelessResetToken : public MemoryRetainer{
SET_SELF_SIZE(StatelessResetToken)

private:
uint8_t buf_[NGTCP2_STATELESS_RESET_TOKENLEN];
const uint8_t* token_;
};

Expand Down

0 comments on commit 0a974c0

Please sign in to comment.