From 0a974c057b1a56e571ae52d9fae298b77ce2f05b Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 22 Jan 2020 09:00:13 -0800 Subject: [PATCH] quic: unify stateless reset handling PR-URL: https://github.com/nodejs/quic/pull/294 Reviewed-By: Anna Henningsen --- src/quic/node_quic_session-inl.h | 31 ++++++++-------------------- src/quic/node_quic_session.cc | 35 +++----------------------------- src/quic/node_quic_session.h | 17 ---------------- src/quic/node_quic_socket.cc | 5 ++--- src/quic/node_quic_util-inl.h | 14 +++++++++++++ src/quic/node_quic_util.h | 15 ++++++++++++-- 6 files changed, 41 insertions(+), 76 deletions(-) diff --git a/src/quic/node_quic_session-inl.h b/src/quic/node_quic_session-inl.h index da7b305008..84074cdd08 100644 --- a/src/quic/node_quic_session-inl.h +++ b/src/quic/node_quic_session-inl.h @@ -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) { @@ -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; diff --git a/src/quic/node_quic_session.cc b/src/quic/node_quic_session.cc index c0517ed2a9..13c35a9703 100644 --- a/src/quic/node_quic_session.cc +++ b/src/quic/node_quic_session.cc @@ -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() @@ -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)); @@ -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; } @@ -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_); diff --git a/src/quic/node_quic_session.h b/src/quic/node_quic_session.h index e163b7710a..3d484aeabf 100644 --- a/src/quic/node_quic_session.h +++ b/src/quic/node_quic_session.h @@ -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); @@ -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); @@ -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); @@ -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, @@ -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; diff --git a/src/quic/node_quic_socket.cc b/src/quic/node_quic_socket.cc index e7465fc00a..6b58240dfe 100644 --- a/src/quic/node_quic_socket.cc +++ b/src/quic/node_quic_socket.cc @@ -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 @@ -658,7 +657,7 @@ 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); @@ -666,7 +665,7 @@ bool QuicSocket::SendStatelessReset( ngtcp2_pkt_write_stateless_reset( reinterpret_cast(packet->data()), NGTCP2_MAX_PKTLEN_IPV4, - token, + const_cast(token.data()), random, kRandlen); if (nwrite < static_cast(kMinStatelessResetLen)) diff --git a/src/quic/node_quic_util-inl.h b/src/quic/node_quic_util-inl.h index 5c1c91b825..793ed75fc4 100644 --- a/src/quic/node_quic_util-inl.h +++ b/src/quic/node_quic_util-inl.h @@ -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 dest(NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1); dest[dest.size() - 1] = '\0'; diff --git a/src/quic/node_quic_util.h b/src/quic/node_quic_util.h index 1cfae84940..ba66ac96d1 100644 --- a/src/quic/node_quic_util.h +++ b/src/quic/node_quic_util.h @@ -294,11 +294,21 @@ class Timer final : public MemoryRetainer { using TimerPointer = DeleteFnPtr; -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; @@ -315,6 +325,7 @@ class StatelessResetToken : public MemoryRetainer{ SET_SELF_SIZE(StatelessResetToken) private: + uint8_t buf_[NGTCP2_STATELESS_RESET_TOKENLEN]; const uint8_t* token_; };