diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index bfea0bcd9..304a268fa 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc @@ -14416,7 +14416,7 @@ TEST_P(QuicConnectionTest, NewTokenFrameInstigateAcks) { } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - QuicNewTokenFrame* new_token = new QuicNewTokenFrame(); + QuicNewTokenFrame* new_token = new QuicNewTokenFrame(1, "new_token"); EXPECT_CALL(visitor_, OnNewTokenReceived(_)); ProcessFramePacket(QuicFrame(new_token)); @@ -14429,7 +14429,7 @@ TEST_P(QuicConnectionTest, ServerClosesConnectionOnNewTokenFrame) { return; } set_perspective(Perspective::IS_SERVER); - QuicNewTokenFrame* new_token = new QuicNewTokenFrame(); + QuicNewTokenFrame* new_token = new QuicNewTokenFrame(1, "new_token"); EXPECT_CALL(visitor_, OnNewTokenReceived(_)).Times(0); EXPECT_CALL(visitor_, OnConnectionClosed(_, _)); EXPECT_CALL(visitor_, BeforeConnectionCloseSent()); @@ -16201,7 +16201,7 @@ TEST_P(QuicConnectionTest, AckElicitingFrames) { EXPECT_CALL(visitor_, OnStreamsBlockedFrame(_)); EXPECT_CALL(visitor_, OnStopSendingFrame(_)); EXPECT_CALL(visitor_, OnDatagramReceived("")); - EXPECT_CALL(visitor_, OnNewTokenReceived("")); + EXPECT_CALL(visitor_, OnNewTokenReceived("new_token")); SetClientConnectionId(TestConnectionId(12)); connection_.CreateConnectionIdManager(); @@ -16221,7 +16221,7 @@ TEST_P(QuicConnectionTest, AckElicitingFrames) { QuicStopSendingFrame stop_sending_frame; QuicPathResponseFrame path_response_frame; QuicDatagramFrame message_frame; - QuicNewTokenFrame new_token_frame; + QuicNewTokenFrame new_token_frame(1, "new_token"); QuicAckFrequencyFrame ack_frequency_frame; QuicResetStreamAtFrame reset_stream_at_frame; QuicBlockedFrame blocked_frame; diff --git a/quiche/quic/core/quic_framer.cc b/quiche/quic/core/quic_framer.cc index 5884abe1b..ffba7be2f 100644 --- a/quiche/quic/core/quic_framer.cc +++ b/quiche/quic/core/quic_framer.cc @@ -3073,6 +3073,13 @@ bool QuicFramer::ProcessIetfFrameData(QuicDataReader* reader, if (!ProcessNewTokenFrame(reader, &frame)) { return RaiseError(QUIC_INVALID_NEW_TOKEN); } + if (frame.token.empty()) { + // RFC 9000, Section 19.7: the token in a NEW_TOKEN frame MUST NOT + // be empty, and a client MUST treat receipt of an empty Token + // field as a connection error of type FRAME_ENCODING_ERROR. + set_detailed_error("New token frame has empty token."); + return RaiseError(QUIC_INVALID_FRAME_DATA); + } QUIC_DVLOG(2) << ENDPOINT << "Processing IETF new token frame " << frame; if (!visitor_->OnNewTokenFrame(frame)) { diff --git a/quiche/quic/core/quic_framer_test.cc b/quiche/quic/core/quic_framer_test.cc index 0ceec4ec8..cddb8807e 100644 --- a/quiche/quic/core/quic_framer_test.cc +++ b/quiche/quic/core/quic_framer_test.cc @@ -11297,6 +11297,39 @@ TEST_P(QuicFramerTest, NewTokenFrame) { CheckFramingBoundaries(packet, QUIC_INVALID_NEW_TOKEN); } +TEST_P(QuicFramerTest, NewTokenFrameEmptyToken) { + if (!VersionIsIetfQuic(framer_.transport_version())) { + // This frame is only for IETF QUIC only. + return; + } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); + // clang-format off + PacketFragments packet = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (IETF_NEW_TOKEN frame) + {"", + {0x07}}, + // Length (0 = empty token) + {"New token frame has empty token.", + {0x00}} + }; + // clang-format on + + std::unique_ptr encrypted( + AssemblePacketFromFragments(packet)); + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_FRAME_DATA)); + EXPECT_EQ("New token frame has empty token.", framer_.detailed_error()); +} + TEST_P(QuicFramerTest, BuildNewTokenFramePacket) { if (!VersionIsIetfQuic(framer_.transport_version())) { // This frame is only for IETF QUIC only.