Skip to content

Commit 393e250

Browse files
larseggertCopilot
andauthored
fix: prevent TP caching from affecting greasing behavior (mozilla#3095)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 105d921 commit 393e250

2 files changed

Lines changed: 45 additions & 8 deletions

File tree

neqo-transport/src/connection/mod.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,13 +2257,9 @@ impl Connection {
22572257

22582258
fn can_grease_quic_bit(&self) -> bool {
22592259
let tph = self.tps.borrow();
2260-
tph.remote_handshake().as_ref().map_or_else(
2261-
|| {
2262-
tph.remote_0rtt()
2263-
.is_some_and(|r| r.get_empty(GreaseQuicBit))
2264-
},
2265-
|r| r.get_empty(GreaseQuicBit),
2266-
)
2260+
tph.remote_handshake()
2261+
.as_ref()
2262+
.is_some_and(|r| r.get_empty(GreaseQuicBit))
22672263
}
22682264

22692265
/// Write the frames that are exchanged in the application data space.

neqo-transport/src/connection/tests/handshake.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use crate::{
3838
stats::FrameStats,
3939
tparams::{TransportParameter, TransportParameterId::*},
4040
tracking::DEFAULT_LOCAL_ACK_DELAY,
41-
CloseReason, ConnectionParameters, Error, Pmtud, StreamType, Version,
41+
CloseReason, ConnectionParameters, EmptyConnectionIdGenerator, Error, Pmtud, StreamType,
42+
Version,
4243
};
4344

4445
const ECH_CONFIG_ID: u8 = 7;
@@ -1564,3 +1565,43 @@ fn zero_rtt_with_ech() {
15641565
assert!(client.tls_info().unwrap().early_data_accepted());
15651566
assert!(server.tls_info().unwrap().early_data_accepted());
15661567
}
1568+
1569+
/// RFC 9287 Section 3.1 states: "A server MUST NOT remember that a client negotiated
1570+
/// the extension in a previous connection and set the QUIC Bit to 0 based on that information."
1571+
///
1572+
/// This test verifies that the client complies with RFC 9287 Section 3.1 by ensuring
1573+
/// it does not grease the QUIC Bit based on cached (0-RTT) transport parameters.
1574+
/// Regression test for the `handshakeloss` interop test failure, where client Initial
1575+
/// packets with the fixed bit cleared (due to cached parameters) were discarded by the server.
1576+
#[test]
1577+
fn grease_quic_bit_respects_current_handshake() {
1578+
fixture_init();
1579+
1580+
// Create a client connection.
1581+
let client = Connection::new_client(
1582+
test_fixture::DEFAULT_SERVER_NAME,
1583+
test_fixture::DEFAULT_ALPN,
1584+
Rc::new(RefCell::new(EmptyConnectionIdGenerator::default())),
1585+
DEFAULT_ADDR,
1586+
DEFAULT_ADDR,
1587+
ConnectionParameters::default(),
1588+
now(),
1589+
)
1590+
.unwrap();
1591+
1592+
// Simulate having cached 0-RTT transport parameters that include grease_quic_bit.
1593+
// In reality, this would come from a previous connection's session ticket.
1594+
let mut tp = crate::tparams::TransportParameters::default();
1595+
tp.set_empty(GreaseQuicBit);
1596+
client.tps.borrow_mut().set_remote_0rtt(Some(tp));
1597+
1598+
// At this point:
1599+
// - We have remote_0rtt params with GreaseQuicBit
1600+
// - We do NOT have remote_handshake params (no current handshake confirmation)
1601+
1602+
// With only cached 0-RTT params, no greasing is allowed.
1603+
assert!(
1604+
!client.can_grease_quic_bit(),
1605+
"Must not grease with only cached 0-RTT params (RFC 9287 Section 3.1)"
1606+
);
1607+
}

0 commit comments

Comments
 (0)