Change QuicCryptoStream to track crypto-substreams by packet number space instead of encryption level such that ZERO_RTT and FORWARD_SECURE crypto data are sent/received/re-transmitted on the same stream. PiperOrigin-RevId: 447566612
diff --git a/quiche/quic/core/frames/quic_crypto_frame.h b/quiche/quic/core/frames/quic_crypto_frame.h index bc76da1..19fb579 100644 --- a/quiche/quic/core/frames/quic_crypto_frame.h +++ b/quiche/quic/core/frames/quic_crypto_frame.h
@@ -25,6 +25,8 @@ friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const QuicCryptoFrame& s); + // TODO(haoyuewang) Consider replace the EncryptionLevel here with + // PacketNumberSpace. // When writing a crypto frame to a packet, the packet must be encrypted at // |level|. When a crypto frame is read, the encryption level of the packet it // was received in is put in |level|.
diff --git a/quiche/quic/core/http/quic_spdy_session_test.cc b/quiche/quic/core/http/quic_spdy_session_test.cc index a8fb322..accd1b0 100644 --- a/quiche/quic/core/http/quic_spdy_session_test.cc +++ b/quiche/quic/core/http/quic_spdy_session_test.cc
@@ -199,11 +199,25 @@ EncryptionLevel level) const override { return level != ENCRYPTION_ZERO_RTT; } + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } + } bool ExportKeyingMaterial(absl::string_view /*label*/, absl::string_view /*context*/, - size_t /*result_len*/, - std::string* /*result*/) override { + size_t /*result_len*/, std::string* + /*result*/) override { return false; }
diff --git a/quiche/quic/core/http/quic_spdy_stream_test.cc b/quiche/quic/core/http/quic_spdy_stream_test.cc index 281f359..de8a5be 100644 --- a/quiche/quic/core/http/quic_spdy_stream_test.cc +++ b/quiche/quic/core/http/quic_spdy_stream_test.cc
@@ -192,6 +192,21 @@ return level != ENCRYPTION_ZERO_RTT; } + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } + } + private: using QuicCryptoStream::session;
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index 73f5763..3913635 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -4120,6 +4120,21 @@ visitor_->OnAckNeedsRetransmittableFrame(); } +EncryptionLevel QuicConnection::GetEncryptionLevelToSendPingForSpace( + PacketNumberSpace space) const { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return framer_.GetEncryptionLevelToSendApplicationData(); + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } +} + void QuicConnection::OnRetransmissionTimeout() { ScopedRetransmissionTimeoutIndicator indicator(this); #ifndef NDEBUG @@ -4182,7 +4197,8 @@ if (sent_packet_manager_ .GetEarliestPacketSentTimeForPto(&packet_number_space) .IsInitialized()) { - SendPingAtLevel(QuicUtils::GetEncryptionLevel(packet_number_space)); + SendPingAtLevel( + GetEncryptionLevelToSendPingForSpace(packet_number_space)); } else { // The client must PTO when there is nothing in flight if the server // could be blocked from sending by the amplification limit @@ -5911,7 +5927,8 @@ << PacketNumberSpaceToString( static_cast<PacketNumberSpace>(i)); ScopedEncryptionLevelContext context( - this, QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i))); + this, QuicUtils::GetEncryptionLevelToSendAckofSpace( + static_cast<PacketNumberSpace>(i))); QuicFrames frames; frames.push_back(uber_received_packet_manager_.GetUpdatedAckFrame( static_cast<PacketNumberSpace>(i), clock_->ApproximateNow()));
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h index 28d5747..b214361 100644 --- a/quiche/quic/core/quic_connection.h +++ b/quiche/quic/core/quic_connection.h
@@ -1863,6 +1863,10 @@ bool ShouldSetRetransmissionAlarmOnPacketSent(bool in_flight, EncryptionLevel level) const; + // Determines encryption level to send ping in `packet_number_space`. + EncryptionLevel GetEncryptionLevelToSendPingForSpace( + PacketNumberSpace space) const; + QuicConnectionContext context_; QuicFramer framer_;
diff --git a/quiche/quic/core/quic_crypto_client_handshaker.cc b/quiche/quic/core/quic_crypto_client_handshaker.cc index 6a9fa6c..4ec9b48 100644 --- a/quiche/quic/core/quic_crypto_client_handshaker.cc +++ b/quiche/quic/core/quic_crypto_client_handshaker.cc
@@ -11,9 +11,11 @@ #include "quiche/quic/core/crypto/crypto_protocol.h" #include "quiche/quic/core/crypto/crypto_utils.h" #include "quiche/quic/core/quic_session.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/platform/api/quic_client_stats.h" #include "quiche/quic/platform/api/quic_flags.h" #include "quiche/quic/platform/api/quic_logging.h" +#include "quiche/common/platform/api/quiche_logging.h" namespace quic { @@ -149,6 +151,16 @@ return true; } +EncryptionLevel +QuicCryptoClientHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const { + if (space == INITIAL_DATA) { + return ENCRYPTION_INITIAL; + } + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; +} + bool QuicCryptoClientHandshaker::one_rtt_keys_available() const { return one_rtt_keys_available_; }
diff --git a/quiche/quic/core/quic_crypto_client_handshaker.h b/quiche/quic/core/quic_crypto_client_handshaker.h index 9c19f89..dbbd942 100644 --- a/quiche/quic/core/quic_crypto_client_handshaker.h +++ b/quiche/quic/core/quic_crypto_client_handshaker.h
@@ -11,6 +11,7 @@ #include "quiche/quic/core/crypto/quic_crypto_client_config.h" #include "quiche/quic/core/quic_crypto_client_stream.h" #include "quiche/quic/core/quic_server_id.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/platform/api/quic_export.h" #include "quiche/common/platform/api/quiche_logging.h" @@ -45,6 +46,8 @@ bool encryption_established() const override; bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const override; + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override; bool one_rtt_keys_available() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override;
diff --git a/quiche/quic/core/quic_crypto_client_stream.cc b/quiche/quic/core/quic_crypto_client_stream.cc index a241ecb..3c6dbe7 100644 --- a/quiche/quic/core/quic_crypto_client_stream.cc +++ b/quiche/quic/core/quic_crypto_client_stream.cc
@@ -169,4 +169,10 @@ return handshaker_->IsCryptoFrameExpectedForEncryptionLevel(level); } +EncryptionLevel +QuicCryptoClientStream::GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const { + return handshaker_->GetEncryptionLevelToSendCryptoDataOfSpace(space); +} + } // namespace quic
diff --git a/quiche/quic/core/quic_crypto_client_stream.h b/quiche/quic/core/quic_crypto_client_stream.h index d3da4db..0a3e5e4 100644 --- a/quiche/quic/core/quic_crypto_client_stream.h +++ b/quiche/quic/core/quic_crypto_client_stream.h
@@ -17,6 +17,7 @@ #include "quiche/quic/core/quic_crypto_stream.h" #include "quiche/quic/core/quic_server_id.h" #include "quiche/quic/core/quic_session.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/core/quic_versions.h" #include "quiche/quic/platform/api/quic_export.h" @@ -173,6 +174,10 @@ virtual bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const = 0; + // Returns the encryption level to send CRYPTO_FRAME for `space`. + virtual EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const = 0; + // Returns true once 1RTT keys are available. virtual bool one_rtt_keys_available() const = 0; @@ -289,6 +294,9 @@ SSL* GetSsl() const override; bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const override; + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override; + bool ExportKeyingMaterial(absl::string_view label, absl::string_view context, size_t result_len, std::string* result) override; std::string chlo_hash() const;
diff --git a/quiche/quic/core/quic_crypto_server_stream.cc b/quiche/quic/core/quic_crypto_server_stream.cc index 11a5728..5d41e47 100644 --- a/quiche/quic/core/quic_crypto_server_stream.cc +++ b/quiche/quic/core/quic_crypto_server_stream.cc
@@ -10,6 +10,7 @@ #include "absl/base/macros.h" #include "absl/strings/string_view.h" #include "openssl/sha.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/platform/api/quic_flag_utils.h" #include "quiche/quic/platform/api/quic_testvalue.h" #include "quiche/common/platform/api/quiche_logging.h" @@ -532,4 +533,17 @@ return true; } +EncryptionLevel +QuicCryptoServerStream::GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const { + if (space == INITIAL_DATA) { + return ENCRYPTION_INITIAL; + } + if (space == APPLICATION_DATA) { + return ENCRYPTION_ZERO_RTT; + } + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; +} + } // namespace quic
diff --git a/quiche/quic/core/quic_crypto_server_stream.h b/quiche/quic/core/quic_crypto_server_stream.h index 5bdfb54..f91ceba 100644 --- a/quiche/quic/core/quic_crypto_server_stream.h +++ b/quiche/quic/core/quic_crypto_server_stream.h
@@ -12,6 +12,7 @@ #include "quiche/quic/core/quic_crypto_handshaker.h" #include "quiche/quic/core/quic_crypto_server_stream_base.h" #include "quiche/quic/core/quic_session.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/platform/api/quic_export.h" namespace quic { @@ -74,6 +75,8 @@ SSL* GetSsl() const override; bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const override; + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override; // From QuicCryptoHandshaker void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/quiche/quic/core/quic_crypto_stream.cc b/quiche/quic/core/quic_crypto_stream.cc index 33eb543..3839db3 100644 --- a/quiche/quic/core/quic_crypto_stream.cc +++ b/quiche/quic/core/quic_crypto_stream.cc
@@ -37,10 +37,7 @@ QuicVersionUsesCryptoFrames(session->transport_version()) ? CRYPTO : BIDIRECTIONAL), - substreams_{{{this, ENCRYPTION_INITIAL}, - {this, ENCRYPTION_HANDSHAKE}, - {this, ENCRYPTION_ZERO_RTT}, - {this, ENCRYPTION_FORWARD_SECURE}}} { + substreams_{{{this}, {this}, {this}}} { // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } @@ -82,9 +79,11 @@ absl::StrCat("CRYPTO_FRAME is unexpectedly received at level ", level)); return; } - substreams_[level].sequencer.OnCryptoFrame(frame); + CryptoSubstream& substream = + substreams_[QuicUtils::GetPacketNumberSpace(level)]; + substream.sequencer.OnCryptoFrame(frame); EncryptionLevel frame_level = level; - if (substreams_[level].sequencer.NumBytesBuffered() > + if (substream.sequencer.NumBytesBuffered() > BufferSizeLimitForLevel(frame_level)) { OnUnrecoverableError(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, "Too much crypto data received"); @@ -109,7 +108,8 @@ OnDataAvailableInSequencer(sequencer(), level); return; } - OnDataAvailableInSequencer(&substreams_[level].sequencer, level); + OnDataAvailableInSequencer( + &substreams_[QuicUtils::GetPacketNumberSpace(level)].sequencer, level); } void QuicCryptoStream::OnDataAvailableInSequencer( @@ -146,7 +146,8 @@ } const bool had_buffered_data = HasBufferedCryptoFrames(); // Append |data| to the send buffer for this encryption level. - QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; + QuicStreamSendBuffer* send_buffer = + &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer; QuicStreamOffset offset = send_buffer->stream_offset(); send_buffer->SaveStreamData(data); if (kMaxStreamLength - offset < data.length()) { @@ -173,8 +174,9 @@ bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame, QuicTime::Delta /*ack_delay_time*/) { QuicByteCount newly_acked_length = 0; - if (!substreams_[frame.level].send_buffer.OnStreamDataAcked( - frame.offset, frame.data_length, &newly_acked_length)) { + if (!substreams_[QuicUtils::GetPacketNumberSpace(frame.level)] + .send_buffer.OnStreamDataAcked(frame.offset, frame.data_length, + &newly_acked_length)) { OnUnrecoverableError(QUIC_INTERNAL_ERROR, "Trying to ack unsent crypto data."); return false; @@ -201,9 +203,10 @@ } return; } - QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; - // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to - // replace the following code. + QuicStreamSendBuffer* send_buffer = + &substreams_[QuicUtils::GetPacketNumberSpace(level)].send_buffer; + // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer + // to replace the following code. QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked(); to_ack.Complement(0, send_buffer->stream_offset()); for (const auto& interval : to_ack) { @@ -225,22 +228,13 @@ QuicStream::OnStreamDataConsumed(bytes_consumed); } -namespace { - -constexpr std::array<EncryptionLevel, NUM_ENCRYPTION_LEVELS> -AllEncryptionLevels() { - return {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, - ENCRYPTION_FORWARD_SECURE}; -} - -} // namespace bool QuicCryptoStream::HasPendingCryptoRetransmission() const { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { return false; } - for (EncryptionLevel level : AllEncryptionLevels()) { - if (substreams_[level].send_buffer.HasPendingRetransmission()) { + for (const auto& substream : substreams_) { + if (substream.send_buffer.HasPendingRetransmission()) { return true; } } @@ -251,12 +245,15 @@ QUIC_BUG_IF(quic_bug_12573_3, !QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't write CRYPTO frames"; - for (EncryptionLevel level : AllEncryptionLevels()) { - QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; + for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) { + auto packet_number_space = static_cast<PacketNumberSpace>(i); + QuicStreamSendBuffer* send_buffer = + &substreams_[packet_number_space].send_buffer; while (send_buffer->HasPendingRetransmission()) { auto pending = send_buffer->NextPendingRetransmission(); size_t bytes_consumed = stream_delegate()->SendCryptoData( - level, pending.length, pending.offset, HANDSHAKE_RETRANSMISSION); + GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space), + pending.length, pending.offset, HANDSHAKE_RETRANSMISSION); send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed); if (bytes_consumed < pending.length) { return; @@ -351,14 +348,17 @@ return stream_bytes_read(); } uint64_t bytes_read = 0; - for (EncryptionLevel level : AllEncryptionLevels()) { - bytes_read += substreams_[level].sequencer.NumBytesConsumed(); + for (const CryptoSubstream& substream : substreams_) { + bytes_read += substream.sequencer.NumBytesConsumed(); } return bytes_read; } +// TODO(haoyuewang) Move this test-only method under +// quiche/quic/test_tools. uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const { - return substreams_[level].sequencer.NumBytesConsumed(); + return substreams_[QuicUtils::GetPacketNumberSpace(level)] + .sequencer.NumBytesConsumed(); } bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level, @@ -368,16 +368,17 @@ QUIC_BUG_IF(quic_bug_12573_4, !QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't write CRYPTO frames (2)"; - return substreams_[level].send_buffer.WriteStreamData(offset, data_length, - writer); + return substreams_[QuicUtils::GetPacketNumberSpace(level)] + .send_buffer.WriteStreamData(offset, data_length, writer); } void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) { QUIC_BUG_IF(quic_bug_12573_5, !QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't lose CRYPTO frames"; - substreams_[crypto_frame->level].send_buffer.OnStreamDataLost( - crypto_frame->offset, crypto_frame->data_length); + substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)] + .send_buffer.OnStreamDataLost(crypto_frame->offset, + crypto_frame->data_length); } bool QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame, @@ -388,7 +389,8 @@ QuicIntervalSet<QuicStreamOffset> retransmission( crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length); QuicStreamSendBuffer* send_buffer = - &substreams_[crypto_frame->level].send_buffer; + &substreams_[QuicUtils::GetPacketNumberSpace(crypto_frame->level)] + .send_buffer; retransmission.Difference(send_buffer->bytes_acked()); if (retransmission.Empty()) { return true; @@ -396,9 +398,12 @@ for (const auto& interval : retransmission) { size_t retransmission_offset = interval.min(); size_t retransmission_length = interval.max() - interval.min(); + EncryptionLevel retransmission_encryption_level = + GetEncryptionLevelToSendCryptoDataOfSpace( + QuicUtils::GetPacketNumberSpace(crypto_frame->level)); size_t bytes_consumed = stream_delegate()->SendCryptoData( - crypto_frame->level, retransmission_length, retransmission_offset, - type); + retransmission_encryption_level, retransmission_length, + retransmission_offset, type); send_buffer->OnStreamDataRetransmitted(retransmission_offset, bytes_consumed); if (bytes_consumed < retransmission_length) { @@ -412,8 +417,10 @@ QUIC_BUG_IF(quic_bug_12573_7, !QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't use CRYPTO frames"; - for (EncryptionLevel level : AllEncryptionLevels()) { - QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; + for (uint8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) { + auto packet_number_space = static_cast<PacketNumberSpace>(i); + QuicStreamSendBuffer* send_buffer = + &substreams_[packet_number_space].send_buffer; const size_t data_length = send_buffer->stream_offset() - send_buffer->stream_bytes_written(); if (data_length == 0) { @@ -421,8 +428,8 @@ continue; } size_t bytes_consumed = stream_delegate()->SendCryptoData( - level, data_length, send_buffer->stream_bytes_written(), - NOT_RETRANSMISSION); + GetEncryptionLevelToSendCryptoDataOfSpace(packet_number_space), + data_length, send_buffer->stream_bytes_written(), NOT_RETRANSMISSION); send_buffer->OnStreamDataConsumed(bytes_consumed); if (bytes_consumed < data_length) { // Connection is write blocked. @@ -435,8 +442,8 @@ QUIC_BUG_IF(quic_bug_12573_8, !QuicVersionUsesCryptoFrames(session()->transport_version())) << "Versions less than 47 don't use CRYPTO frames"; - for (EncryptionLevel level : AllEncryptionLevels()) { - const QuicStreamSendBuffer& send_buffer = substreams_[level].send_buffer; + for (const CryptoSubstream& substream : substreams_) { + const QuicStreamSendBuffer& send_buffer = substream.send_buffer; QUICHE_DCHECK_GE(send_buffer.stream_offset(), send_buffer.stream_bytes_written()); if (send_buffer.stream_offset() > send_buffer.stream_bytes_written()) { @@ -457,15 +464,16 @@ // the wrong transport version. return false; } - return substreams_[level].send_buffer.IsStreamDataOutstanding(offset, length); + return substreams_[QuicUtils::GetPacketNumberSpace(level)] + .send_buffer.IsStreamDataOutstanding(offset, length); } bool QuicCryptoStream::IsWaitingForAcks() const { if (!QuicVersionUsesCryptoFrames(session()->transport_version())) { return QuicStream::IsWaitingForAcks(); } - for (EncryptionLevel level : AllEncryptionLevels()) { - if (substreams_[level].send_buffer.stream_bytes_outstanding()) { + for (const CryptoSubstream& substream : substreams_) { + if (substream.send_buffer.stream_bytes_outstanding()) { return true; } } @@ -473,7 +481,7 @@ } QuicCryptoStream::CryptoSubstream::CryptoSubstream( - QuicCryptoStream* crypto_stream, EncryptionLevel) + QuicCryptoStream* crypto_stream) : sequencer(crypto_stream), send_buffer(crypto_stream->session() ->connection()
diff --git a/quiche/quic/core/quic_crypto_stream.h b/quiche/quic/core/quic_crypto_stream.h index be61a82..6d29d4b 100644 --- a/quiche/quic/core/quic_crypto_stream.h +++ b/quiche/quic/core/quic_crypto_stream.h
@@ -236,8 +236,9 @@ virtual void OnDataAvailableInSequencer(QuicStreamSequencer* sequencer, EncryptionLevel level); - QuicStreamSequencer* GetStreamSequencerForLevel(EncryptionLevel level) { - return &substreams_[level].sequencer; + QuicStreamSequencer* GetStreamSequencerForPacketNumberSpace( + PacketNumberSpace packet_number_space) { + return &substreams_[packet_number_space].sequencer; } // Called by OnCryptoFrame to check if a CRYPTO frame is received at an @@ -245,13 +246,17 @@ virtual bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const = 0; + // Called to determine the encryption level to send/retransmit crypto data. + virtual EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const = 0; + private: - // Data sent and received in CRYPTO frames is sent at multiple encryption - // levels. Some of the state for the single logical crypto stream is split - // across encryption levels, and a CryptoSubstream is used to manage that - // state for a particular encryption level. + // Data sent and received in CRYPTO frames is sent at multiple packet number + // spaces. Some of the state for the single logical crypto stream is split + // across packet number spaces, and a CryptoSubstream is used to manage that + // state for a particular packet number space. struct QUIC_EXPORT_PRIVATE CryptoSubstream { - CryptoSubstream(QuicCryptoStream* crypto_stream, EncryptionLevel); + CryptoSubstream(QuicCryptoStream* crypto_stream); QuicStreamSequencer sequencer; QuicStreamSendBuffer send_buffer; @@ -262,9 +267,9 @@ // TLS 1.3, which never encrypts crypto data. QuicIntervalSet<QuicStreamOffset> bytes_consumed_[NUM_ENCRYPTION_LEVELS]; - // Keeps state for data sent/received in CRYPTO frames at each encryption - // level. - std::array<CryptoSubstream, NUM_ENCRYPTION_LEVELS> substreams_; + // Keeps state for data sent/received in CRYPTO frames at each packet number + // space; + std::array<CryptoSubstream, NUM_PACKET_NUMBER_SPACES> substreams_; }; } // namespace quic
diff --git a/quiche/quic/core/quic_crypto_stream_test.cc b/quiche/quic/core/quic_crypto_stream_test.cc index 7e27d77..ea99926 100644 --- a/quiche/quic/core/quic_crypto_stream_test.cc +++ b/quiche/quic/core/quic_crypto_stream_test.cc
@@ -13,6 +13,7 @@ #include "quiche/quic/core/crypto/crypto_handshake.h" #include "quiche/quic/core/crypto/crypto_protocol.h" #include "quiche/quic/core/crypto/null_encrypter.h" +#include "quiche/quic/core/quic_types.h" #include "quiche/quic/core/quic_utils.h" #include "quiche/quic/platform/api/quic_socket_address.h" #include "quiche/quic/platform/api/quic_test.h" @@ -101,6 +102,22 @@ return level != ENCRYPTION_ZERO_RTT; } + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return QuicCryptoStream::session() + ->GetEncryptionLevelToSendApplicationData(); + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } + } + private: quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; std::vector<CryptoHandshakeMessage> messages_; @@ -266,6 +283,17 @@ .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); + + // Before encryption moves to ENCRYPTION_FORWARD_SECURE, ZERO RTT data are + // retranmitted at ENCRYPTION_ZERO_RTT. + QuicCryptoFrame lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650); + stream_->OnCryptoFrameLost(&lost_frame); + + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WritePendingCryptoRetransmission(); + connection_->SetEncrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); @@ -273,7 +301,7 @@ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); // Lost [0, 1000). - QuicCryptoFrame lost_frame(ENCRYPTION_INITIAL, 0, 1000); + lost_frame = QuicCryptoFrame(ENCRYPTION_INITIAL, 0, 1000); stream_->OnCryptoFrameLost(&lost_frame); EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); // Lost [1200, 2000). @@ -289,7 +317,7 @@ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 150, 1200)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); - EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0)) + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 650, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WritePendingCryptoRetransmission(); @@ -533,7 +561,7 @@ stream_->OnCryptoFrameAcked(acked_frame, QuicTime::Delta::Zero())); // Retransmit only [1350, 1500). - EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 150, 0)) + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 150, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); QuicCryptoFrame frame_to_retransmit(ENCRYPTION_ZERO_RTT, 0, 150); @@ -543,10 +571,11 @@ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); // Retransmit [1350, 2700) again and all data is sent. - EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0)) + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_FORWARD_SECURE, 650, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); - EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 200, 1150)) + EXPECT_CALL(*connection_, + SendCryptoData(ENCRYPTION_FORWARD_SECURE, 200, 1150)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); frame_to_retransmit = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 1350);
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc index 6450da0..807bfdd 100644 --- a/quiche/quic/core/quic_session.cc +++ b/quiche/quic/core/quic_session.cc
@@ -1558,7 +1558,7 @@ bool set_alternative_decrypter, bool latch_once_used) { if (connection_->version().handshake_protocol == PROTOCOL_TLS1_3 && !connection()->framer().HasEncrypterOfEncryptionLevel( - QuicUtils::GetEncryptionLevel( + QuicUtils::GetEncryptionLevelToSendAckofSpace( QuicUtils::GetPacketNumberSpace(level)))) { // This should never happen because connection should never decrypt a packet // while an ACK for it cannot be encrypted.
diff --git a/quiche/quic/core/quic_session_test.cc b/quiche/quic/core/quic_session_test.cc index bb198e4..9b90c4f 100644 --- a/quiche/quic/core/quic_session_test.cc +++ b/quiche/quic/core/quic_session_test.cc
@@ -38,6 +38,7 @@ #include "quiche/quic/test_tools/quic_stream_peer.h" #include "quiche/quic/test_tools/quic_stream_send_buffer_peer.h" #include "quiche/quic/test_tools/quic_test_utils.h" +#include "quiche/common/platform/api/quiche_logging.h" #include "quiche/common/quiche_mem_slice_storage.h" using spdy::kV3HighestPriority; @@ -186,6 +187,21 @@ return level != ENCRYPTION_ZERO_RTT; } + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } + } + private: using QuicCryptoStream::session; @@ -2959,7 +2975,11 @@ EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000)) .WillOnce(Return(350)); - EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0)) + EXPECT_CALL( + *connection_, + SendCryptoData(crypto_stream->GetEncryptionLevelToSendCryptoDataOfSpace( + QuicUtils::GetPacketNumberSpace(ENCRYPTION_ZERO_RTT)), + 1350, 0)) .WillOnce(Return(1350)); session_.OnCanWrite(); EXPECT_FALSE(session_.HasPendingHandshake());
diff --git a/quiche/quic/core/quic_utils.cc b/quiche/quic/core/quic_utils.cc index 6113c91..e1b1797 100644 --- a/quiche/quic/core/quic_utils.cc +++ b/quiche/quic/core/quic_utils.cc
@@ -595,7 +595,7 @@ } // static -EncryptionLevel QuicUtils::GetEncryptionLevel( +EncryptionLevel QuicUtils::GetEncryptionLevelToSendAckofSpace( PacketNumberSpace packet_number_space) { switch (packet_number_space) { case INITIAL_DATA:
diff --git a/quiche/quic/core/quic_utils.h b/quiche/quic/core/quic_utils.h index 202dc4b..2d4d5e8 100644 --- a/quiche/quic/core/quic_utils.h +++ b/quiche/quic/core/quic_utils.h
@@ -209,8 +209,8 @@ static PacketNumberSpace GetPacketNumberSpace( EncryptionLevel encryption_level); - // Determines encryption level to send packets in |packet_number_space|. - static EncryptionLevel GetEncryptionLevel( + // Determines encryption level to send ACK in |packet_number_space|. + static EncryptionLevel GetEncryptionLevelToSendAckofSpace( PacketNumberSpace packet_number_space); // Get the maximum value for a V99/IETF QUIC stream count. If a count
diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_client_handshaker.cc index 7460263..36edcac 100644 --- a/quiche/quic/core/tls_client_handshaker.cc +++ b/quiche/quic/core/tls_client_handshaker.cc
@@ -361,6 +361,19 @@ return level != ENCRYPTION_ZERO_RTT; } +EncryptionLevel TlsClientHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } +} + bool TlsClientHandshaker::one_rtt_keys_available() const { return state_ >= HANDSHAKE_COMPLETE; }
diff --git a/quiche/quic/core/tls_client_handshaker.h b/quiche/quic/core/tls_client_handshaker.h index 21b6033..06581b5 100644 --- a/quiche/quic/core/tls_client_handshaker.h +++ b/quiche/quic/core/tls_client_handshaker.h
@@ -56,6 +56,8 @@ bool encryption_established() const override; bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const override; + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override; bool one_rtt_keys_available() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override;
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc index cee7a71..3274fa5 100644 --- a/quiche/quic/core/tls_server_handshaker.cc +++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -1130,4 +1130,19 @@ return level != ENCRYPTION_ZERO_RTT; } +EncryptionLevel TlsServerHandshaker::GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } +} + } // namespace quic
diff --git a/quiche/quic/core/tls_server_handshaker.h b/quiche/quic/core/tls_server_handshaker.h index fa5ca75..68abf73 100644 --- a/quiche/quic/core/tls_server_handshaker.h +++ b/quiche/quic/core/tls_server_handshaker.h
@@ -73,6 +73,8 @@ SSL* GetSsl() const override; bool IsCryptoFrameExpectedForEncryptionLevel( EncryptionLevel level) const override; + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override; // From QuicCryptoServerStreamBase and TlsHandshaker ssl_early_data_reason_t EarlyDataReason() const override;
diff --git a/quiche/quic/core/uber_received_packet_manager_test.cc b/quiche/quic/core/uber_received_packet_manager_test.cc index 030e55c..5474421 100644 --- a/quiche/quic/core/uber_received_packet_manager_test.cc +++ b/quiche/quic/core/uber_received_packet_manager_test.cc
@@ -33,6 +33,20 @@ const QuicTime::Delta kDelayedAckTime = QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); +EncryptionLevel GetEncryptionLevel(PacketNumberSpace packet_number_space) { + switch (packet_number_space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } +} + class UberReceivedPacketManagerTest : public QuicTest { protected: UberReceivedPacketManagerTest() { @@ -108,7 +122,7 @@ continue; } manager_->ResetAckStates( - QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i))); + GetEncryptionLevel(static_cast<PacketNumberSpace>(i))); } }
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h index f43b12d..df742be 100644 --- a/quiche/quic/test_tools/quic_test_utils.h +++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -859,6 +859,20 @@ quic::EncryptionLevel level) const override { return level != ENCRYPTION_ZERO_RTT; } + EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace( + PacketNumberSpace space) const override { + switch (space) { + case INITIAL_DATA: + return ENCRYPTION_INITIAL; + case HANDSHAKE_DATA: + return ENCRYPTION_HANDSHAKE; + case APPLICATION_DATA: + return ENCRYPTION_FORWARD_SECURE; + default: + QUICHE_DCHECK(false); + return NUM_ENCRYPTION_LEVELS; + } + } private: quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;