Limit the amount of incoming crypto data that will be buffered.
gfe-relnote: protected by disabled flag-protected QUIC_VERSION_48
PiperOrigin-RevId: 266019141
Change-Id: Ife996bdf80a28b3bcce4b02cda49bff0fd23a071
diff --git a/quic/core/crypto/tls_connection.h b/quic/core/crypto/tls_connection.h
index c15d920..4774ba6 100644
--- a/quic/core/crypto/tls_connection.h
+++ b/quic/core/crypto/tls_connection.h
@@ -69,7 +69,7 @@
static enum ssl_encryption_level_t BoringEncryptionLevel(
EncryptionLevel level);
- SSL* ssl() { return ssl_.get(); }
+ SSL* ssl() const { return ssl_.get(); }
protected:
// TlsConnection does not take ownership of any of its arguments; they must
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index 158285d..ac15301 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -141,6 +141,11 @@
return QuicCryptoHandshaker::crypto_message_parser();
}
+size_t QuicCryptoClientHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage(
const CryptoHandshakeMessage& server_config_update) {
DCHECK(server_config_update.tag() == kSCUP);
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h
index 5b7ce35..d33ebfe 100644
--- a/quic/core/quic_crypto_client_handshaker.h
+++ b/quic/core/quic_crypto_client_handshaker.h
@@ -44,6 +44,7 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/quic/core/quic_crypto_client_stream.cc b/quic/core/quic_crypto_client_stream.cc
index 93f2a61..8f89e9a 100644
--- a/quic/core/quic_crypto_client_stream.cc
+++ b/quic/core/quic_crypto_client_stream.cc
@@ -84,6 +84,11 @@
return handshaker_->crypto_message_parser();
}
+size_t QuicCryptoClientStream::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return handshaker_->BufferSizeLimitForLevel(level);
+}
+
std::string QuicCryptoClientStream::chlo_hash() const {
return handshaker_->chlo_hash();
}
diff --git a/quic/core/quic_crypto_client_stream.h b/quic/core/quic_crypto_client_stream.h
index b8dff7e..89f0d2e 100644
--- a/quic/core/quic_crypto_client_stream.h
+++ b/quic/core/quic_crypto_client_stream.h
@@ -99,6 +99,10 @@
// Used by QuicCryptoStream to parse data received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+
+ // Used by QuicCryptoStream to know how much unprocessed data can be
+ // buffered at each encryption level.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0;
};
// ProofHandler is an interface that handles callbacks from the crypto
@@ -142,6 +146,7 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
std::string chlo_hash() const;
diff --git a/quic/core/quic_crypto_handshaker.cc b/quic/core/quic_crypto_handshaker.cc
index fa0f78a..d608ead 100644
--- a/quic/core/quic_crypto_handshaker.cc
+++ b/quic/core/quic_crypto_handshaker.cc
@@ -45,5 +45,9 @@
return &crypto_framer_;
}
+size_t QuicCryptoHandshaker::BufferSizeLimitForLevel(EncryptionLevel) const {
+ return GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes);
+}
+
#undef ENDPOINT // undef for jumbo builds
} // namespace quic
diff --git a/quic/core/quic_crypto_handshaker.h b/quic/core/quic_crypto_handshaker.h
index 231acfc..e5d8d51 100644
--- a/quic/core/quic_crypto_handshaker.h
+++ b/quic/core/quic_crypto_handshaker.h
@@ -27,6 +27,7 @@
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
CryptoMessageParser* crypto_message_parser();
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
protected:
QuicTag last_sent_handshake_message_tag() const {
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index 26134d7..ab381d7 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -373,6 +373,11 @@
return QuicCryptoHandshaker::crypto_message_parser();
}
+size_t QuicCryptoServerHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return QuicCryptoHandshaker::BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoServerHandshaker::ProcessClientHello(
QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
result,
diff --git a/quic/core/quic_crypto_server_handshaker.h b/quic/core/quic_crypto_server_handshaker.h
index f664408..4b7b3ba 100644
--- a/quic/core/quic_crypto_server_handshaker.h
+++ b/quic/core/quic_crypto_server_handshaker.h
@@ -58,6 +58,7 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
// From QuicCryptoHandshaker
void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc
index 09344cd..353de98 100644
--- a/quic/core/quic_crypto_server_stream.cc
+++ b/quic/core/quic_crypto_server_stream.cc
@@ -111,6 +111,11 @@
return handshaker()->crypto_message_parser();
}
+size_t QuicCryptoServerStream::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return handshaker()->BufferSizeLimitForLevel(level);
+}
+
void QuicCryptoServerStream::OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) {
DCHECK_EQ(version, session()->connection()->version());
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 60a162c..3a7d6e7 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -119,6 +119,10 @@
// Used by QuicCryptoStream to parse data received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+
+ // Used by QuicCryptoStream to know how much unprocessed data can be
+ // buffered at each encryption level.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0;
};
class Helper {
@@ -172,6 +176,7 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
void OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& version) override;
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 9d70139..e5b13f1 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -78,6 +78,11 @@
<< "Versions less than 47 shouldn't receive CRYPTO frames";
EncryptionLevel level = session()->connection()->last_decrypted_level();
substreams_[level].sequencer.OnCryptoFrame(frame);
+ if (substreams_[level].sequencer.NumBytesBuffered() >
+ BufferSizeLimitForLevel(frame.level)) {
+ CloseConnectionWithDetails(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA,
+ "Too much crypto data received");
+ }
}
void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) {
@@ -181,6 +186,10 @@
send_buffer->OnStreamDataConsumed(bytes_consumed);
}
+size_t QuicCryptoStream::BufferSizeLimitForLevel(EncryptionLevel) const {
+ return GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes);
+}
+
void QuicCryptoStream::OnSuccessfulVersionNegotiation(
const ParsedQuicVersion& /*version*/) {}
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h
index 01523ee..12a36f8 100644
--- a/quic/core/quic_crypto_stream.h
+++ b/quic/core/quic_crypto_stream.h
@@ -80,6 +80,10 @@
// Provides the message parser to use when data is received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
+ // Returns the maximum number of bytes that can be buffered at a particular
+ // encryption level |level|.
+ virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
+
// Called when the underlying QuicConnection has agreed upon a QUIC version to
// use.
virtual void OnSuccessfulVersionNegotiation(const ParsedQuicVersion& version);
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc
index 9d3bda5..af5a8cc 100644
--- a/quic/core/quic_crypto_stream_test.cc
+++ b/quic/core/quic_crypto_stream_test.cc
@@ -570,6 +570,23 @@
EXPECT_FALSE(stream_->HasBufferedCryptoFrames());
}
+TEST_F(QuicCryptoStreamTest, LimitBufferedCryptoData) {
+ if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) {
+ return;
+ }
+
+ EXPECT_CALL(*connection_,
+ CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _));
+ std::string large_frame(2 * GetQuicFlag(FLAGS_quic_max_buffered_crypto_bytes),
+ 'a');
+
+ // Set offset to 1 so that we guarantee the data gets buffered instead of
+ // immediately processed.
+ QuicStreamOffset offset = 1;
+ stream_->OnCryptoFrame(
+ QuicCryptoFrame(ENCRYPTION_INITIAL, offset, large_frame));
+}
+
} // namespace
} // namespace test
} // namespace quic
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index f362f1a..8e2d2bb 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -208,6 +208,11 @@
return TlsHandshaker::crypto_message_parser();
}
+size_t TlsClientHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return TlsHandshaker::BufferSizeLimitForLevel(level);
+}
+
void TlsClientHandshaker::AdvanceHandshake() {
if (state_ == STATE_CONNECTION_CLOSED) {
QUIC_LOG(INFO)
diff --git a/quic/core/tls_client_handshaker.h b/quic/core/tls_client_handshaker.h
index d2d0a4a..47faf81 100644
--- a/quic/core/tls_client_handshaker.h
+++ b/quic/core/tls_client_handshaker.h
@@ -52,9 +52,12 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
protected:
- TlsConnection* tls_connection() override { return &tls_connection_; }
+ const TlsConnection* tls_connection() const override {
+ return &tls_connection_;
+ }
void AdvanceHandshake() override;
void CloseConnection(QuicErrorCode error,
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc
index db50f5a..e6e59fd 100644
--- a/quic/core/tls_handshaker.cc
+++ b/quic/core/tls_handshaker.cc
@@ -54,6 +54,11 @@
return true;
}
+size_t TlsHandshaker::BufferSizeLimitForLevel(EncryptionLevel level) const {
+ return SSL_quic_max_handshake_flight_len(
+ ssl(), TlsConnection::BoringEncryptionLevel(level));
+}
+
const EVP_MD* TlsHandshaker::Prf() {
return EVP_get_digestbynid(
SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl())));
diff --git a/quic/core/tls_handshaker.h b/quic/core/tls_handshaker.h
index b4f16e8..7d5b9bc 100644
--- a/quic/core/tls_handshaker.h
+++ b/quic/core/tls_handshaker.h
@@ -50,6 +50,7 @@
virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const = 0;
virtual CryptoMessageParser* crypto_message_parser() { return this; }
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const;
protected:
virtual void AdvanceHandshake() = 0;
@@ -65,9 +66,9 @@
std::unique_ptr<QuicDecrypter> CreateDecrypter(
const std::vector<uint8_t>& pp_secret);
- virtual TlsConnection* tls_connection() = 0;
+ virtual const TlsConnection* tls_connection() const = 0;
- SSL* ssl() { return tls_connection()->ssl(); }
+ SSL* ssl() const { return tls_connection()->ssl(); }
QuicCryptoStream* stream() { return stream_; }
QuicSession* session() { return session_; }
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index eea6f55..a2ea397 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -136,6 +136,11 @@
return TlsHandshaker::crypto_message_parser();
}
+size_t TlsServerHandshaker::BufferSizeLimitForLevel(
+ EncryptionLevel level) const {
+ return TlsHandshaker::BufferSizeLimitForLevel(level);
+}
+
void TlsServerHandshaker::AdvanceHandshake() {
if (state_ == STATE_CONNECTION_CLOSED) {
QUIC_LOG(INFO) << "TlsServerHandshaker received handshake message after "
diff --git a/quic/core/tls_server_handshaker.h b/quic/core/tls_server_handshaker.h
index 5ce699f..829aeaf 100644
--- a/quic/core/tls_server_handshaker.h
+++ b/quic/core/tls_server_handshaker.h
@@ -58,9 +58,12 @@
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
+ size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
protected:
- TlsConnection* tls_connection() override { return &tls_connection_; }
+ const TlsConnection* tls_connection() const override {
+ return &tls_connection_;
+ }
// Called when a new message is received on the crypto stream and is available
// for the TLS stack to read.