Skip to content

Commit

Permalink
quiche: remove google quic support (#17465)
Browse files Browse the repository at this point in the history
Commit Message: Remove support of Google QUIC. QUICHE supports both IETF QUIC and Google QUIC. Given that IETF QUIC has been launched by Google and Google QUIC will be deprecated soon, remove the support of Google QUIC will lower the future maintenance burden.

Risk Level: low
Testing: existing tests passed
Fixes #16642

Signed-off-by: Dan Zhang <danzh@google.com>
  • Loading branch information
danzh2010 authored Jul 29, 2021
1 parent 012c57b commit 110559f
Show file tree
Hide file tree
Showing 40 changed files with 490 additions and 1,560 deletions.
5 changes: 0 additions & 5 deletions docs/root/configuration/http/http_conn_man/stats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,6 @@ On the upstream side all http3 statistics are rooted at *cluster.<name>.http3.*
rx_reset, Counter, Total number of reset stream frames received by Envoy
tx_reset, Counter, Total number of reset stream frames transmitted by Envoy
metadata_not_supported_error, Counter, Total number of metadata dropped during HTTP/3 encoding
quic_version_43, Counter, Total number of quic connections that use transport version 43. This is expected to be removed when this version is deprecated.
quic_version_46, Counter, Total number of quic connections that use transport version 46. This is expected to be removed when this version is deprecated.
quic_version_50, Counter, Total number of quic connections that use transport version 50. This is expected to be removed when this version is deprecated.
quic_version_51, Counter, Total number of quic connections that use transport version 51. This is expected to be removed when this version is deprecated.
quic_version_h3_29, Counter, Total number of quic connections that use transport version h3-29. This is expected to be removed when this version is deprecated.
quic_version_rfc_v1, Counter, Total number of quic connections that use transport version rfc-v1.


Expand Down
5 changes: 0 additions & 5 deletions source/common/http/http3/codec_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ namespace Http3 {
COUNTER(rx_reset) \
COUNTER(tx_reset) \
COUNTER(metadata_not_supported_error) \
COUNTER(quic_version_43) \
COUNTER(quic_version_46) \
COUNTER(quic_version_50) \
COUNTER(quic_version_51) \
COUNTER(quic_version_h3_29) \
COUNTER(quic_version_rfc_v1)

/**
Expand Down
2 changes: 1 addition & 1 deletion source/common/quic/active_quic_listener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ActiveQuicListener::ActiveQuicListener(
listen_socket, *this,
listener_config.udpListenerConfig()->config().downstream_socket_config()),
&listener_config),
dispatcher_(dispatcher), version_manager_(quic::CurrentSupportedVersions()),
dispatcher_(dispatcher), version_manager_(quic::CurrentSupportedHttp3Versions()),
kernel_worker_routing_(kernel_worker_routing),
packets_to_read_to_connection_count_ratio_(packets_to_read_to_connection_count_ratio),
crypto_server_stream_factory_(crypto_server_stream_factory) {
Expand Down
13 changes: 6 additions & 7 deletions source/common/quic/client_connection_factory_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,17 @@ createQuicNetworkConnection(Http::PersistentQuicInfo& info, Event::Dispatcher& d
if (config == nullptr) {
return nullptr; // no secrets available yet.
}

quic::ParsedQuicVersionVector quic_versions = quic::CurrentSupportedHttp3Versions();
ASSERT(!quic_versions.empty());
auto connection = std::make_unique<EnvoyQuicClientConnection>(
quic::QuicUtils::CreateRandomConnectionId(), server_addr, info_impl->conn_helper_,
info_impl->alarm_factory_, quic::ParsedQuicVersionVector{info_impl->supported_versions_[0]},
local_addr, dispatcher, nullptr);
info_impl->alarm_factory_, quic_versions, local_addr, dispatcher, nullptr);

ASSERT(!info_impl->supported_versions_.empty());
// QUICHE client session always use the 1st version to start handshake.
auto ret = std::make_unique<EnvoyQuicClientSession>(
info_impl->quic_config_, info_impl->supported_versions_, std::move(connection),
info_impl->server_id_, std::move(config), &info_impl->push_promise_index_, dispatcher,
info_impl->buffer_limit_, info_impl->crypto_stream_factory_, quic_stat_names, scope);
info_impl->quic_config_, quic_versions, std::move(connection), info_impl->server_id_,
std::move(config), &info_impl->push_promise_index_, dispatcher, info_impl->buffer_limit_,
info_impl->crypto_stream_factory_, quic_stat_names, scope);
return ret;
}

Expand Down
1 change: 0 additions & 1 deletion source/common/quic/client_connection_factory_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ struct PersistentQuicInfoImpl : public Http::PersistentQuicInfo {
Envoy::Ssl::ClientContextSharedPtr client_context_;
// If client context changes, client config will be updated as well.
std::shared_ptr<quic::QuicCryptoClientConfig> client_config_;
const quic::ParsedQuicVersionVector supported_versions_{quic::CurrentSupportedVersions()};
quic::QuicConfig quic_config_;
// The cluster buffer limits.
const uint32_t buffer_limit_;
Expand Down
12 changes: 2 additions & 10 deletions source/common/quic/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,11 @@ void QuicHttpServerConnectionImpl::onUnderlyingConnectionBelowWriteBufferLowWate
}

void QuicHttpServerConnectionImpl::shutdownNotice() {
if (quic::VersionUsesHttp3(quic_server_session_.transport_version())) {
quic_server_session_.SendHttp3GoAway(quic::QUIC_PEER_GOING_AWAY, "Server shutdown");
} else {
ENVOY_CONN_LOG(debug, "Shutdown notice is not propagated to QUIC.", quic_server_session_);
}
quic_server_session_.SendHttp3GoAway(quic::QUIC_PEER_GOING_AWAY, "Server shutdown");
}

void QuicHttpServerConnectionImpl::goAway() {
if (quic::VersionUsesHttp3(quic_server_session_.transport_version())) {
quic_server_session_.SendHttp3GoAway(quic::QUIC_PEER_GOING_AWAY, "server shutdown imminent");
} else {
quic_server_session_.SendGoAway(quic::QUIC_PEER_GOING_AWAY, "server shutdown imminent");
}
quic_server_session_.SendHttp3GoAway(quic::QUIC_PEER_GOING_AWAY, "server shutdown imminent");
}

QuicHttpClientConnectionImpl::QuicHttpClientConnectionImpl(
Expand Down
3 changes: 0 additions & 3 deletions source/common/quic/envoy_quic_client_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ void EnvoyQuicClientConnection::processPacket(
Network::Address::InstanceConstSharedPtr local_address,
Network::Address::InstanceConstSharedPtr peer_address, Buffer::InstancePtr buffer,
MonotonicTime receive_time) {
if (!connected()) {
return;
}
quic::QuicTime timestamp =
quic::QuicTime::Zero() +
quic::QuicTime::Delta::FromMicroseconds(
Expand Down
35 changes: 2 additions & 33 deletions source/common/quic/envoy_quic_client_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,10 @@ void EnvoyQuicClientSession::Initialize() {
}

void EnvoyQuicClientSession::OnCanWrite() {
if (quic::VersionUsesHttp3(transport_version())) {
quic::QuicSpdyClientSession::OnCanWrite();
} else {
// This will cause header stream flushing. It is the only place to discount bytes buffered in
// header stream from connection watermark buffer during writing.
SendBufferMonitor::ScopedWatermarkBufferUpdater updater(headers_stream(), this);
quic::QuicSpdyClientSession::OnCanWrite();
}
quic::QuicSpdyClientSession::OnCanWrite();
maybeApplyDelayClosePolicy();
}

void EnvoyQuicClientSession::OnGoAway(const quic::QuicGoAwayFrame& frame) {
ENVOY_CONN_LOG(debug, "GOAWAY received with error {}: {}", *this,
quic::QuicErrorCodeToString(frame.error_code), frame.reason_phrase);
quic::QuicSpdyClientSession::OnGoAway(frame);
if (http_connection_callbacks_ != nullptr) {
http_connection_callbacks_->onGoAway(quicErrorCodeToEnvoyErrorCode(frame.error_code));
}
}

void EnvoyQuicClientSession::OnHttp3GoAway(uint64_t stream_id) {
ENVOY_CONN_LOG(debug, "HTTP/3 GOAWAY received", *this);
quic::QuicSpdyClientSession::OnHttp3GoAway(stream_id);
Expand Down Expand Up @@ -128,25 +112,10 @@ quic::QuicConnection* EnvoyQuicClientSession::quicConnection() {
}

void EnvoyQuicClientSession::OnTlsHandshakeComplete() {
quic::QuicSpdyClientSession::OnTlsHandshakeComplete();
raiseConnectionEvent(Network::ConnectionEvent::Connected);
}

size_t EnvoyQuicClientSession::WriteHeadersOnHeadersStream(
quic::QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin,
const spdy::SpdyStreamPrecedence& precedence,
quic::QuicReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener) {
ASSERT(!quic::VersionUsesHttp3(transport_version()));
// gQUIC headers are sent on a dedicated stream. Only count the bytes sent against
// connection level watermark buffer. Do not count them into stream level
// watermark buffer, because it is impossible to identify which byte belongs
// to which stream when the buffered bytes are drained in headers stream.
// This updater may be in the scope of another one in OnCanWrite(), in such
// case, this one doesn't update the watermark.
SendBufferMonitor::ScopedWatermarkBufferUpdater updater(headers_stream(), this);
return quic::QuicSpdyClientSession::WriteHeadersOnHeadersStream(id, std::move(headers), fin,
precedence, ack_listener);
}

std::unique_ptr<quic::QuicCryptoClientStreamBase> EnvoyQuicClientSession::CreateQuicCryptoStream() {
return crypto_stream_factory_.createEnvoyQuicCryptoClientStream(
server_id(), this, crypto_config()->proof_verifier()->CreateDefaultContext(), crypto_config(),
Expand Down
5 changes: 0 additions & 5 deletions source/common/quic/envoy_quic_client_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,8 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl,
quic::ConnectionCloseSource source) override;
void Initialize() override;
void OnCanWrite() override;
void OnGoAway(const quic::QuicGoAwayFrame& frame) override;
void OnHttp3GoAway(uint64_t stream_id) override;
void OnTlsHandshakeComplete() override;
size_t WriteHeadersOnHeadersStream(
quic::QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin,
const spdy::SpdyStreamPrecedence& precedence,
quic::QuicReferenceCountedPointer<quic::QuicAckListenerInterface> ack_listener) override;
void MaybeSendRstStreamFrame(quic::QuicStreamId id, quic::QuicRstStreamErrorCode error,
quic::QuicStreamOffset bytes_written) override;
void OnRstStream(const quic::QuicRstStreamFrame& frame) override;
Expand Down
9 changes: 2 additions & 7 deletions source/common/quic/envoy_quic_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,16 @@
namespace Envoy {
namespace Quic {

// Envoy specific provider of server connection id and decision maker of
// accepting new connection or not.
// Dummy implementation only used by Google Quic.
class EnvoyQuicCryptoServerStreamHelper : public quic::QuicCryptoServerStreamBase::Helper {
public:
~EnvoyQuicCryptoServerStreamHelper() override = default;

// quic::QuicCryptoServerStream::Helper
bool CanAcceptClientHello(const quic::CryptoHandshakeMessage& /*message*/,
const quic::QuicSocketAddress& /*client_address*/,
const quic::QuicSocketAddress& /*peer_address*/,
const quic::QuicSocketAddress& /*self_address*/,
std::string* /*error_details*/) const override {
// TODO(danzh): decide to accept or not based on information from given handshake message, i.e.
// user agent and SNI.
return true;
NOT_REACHED_GCOVR_EXCL_LINE;
}
};

Expand Down
20 changes: 18 additions & 2 deletions source/common/quic/envoy_quic_proof_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,24 @@ EnvoyQuicProofSource::GetCertChain(const quic::QuicSocketAddress& server_address
const std::string& chain_str = cert_config.certificateChain();
std::stringstream pem_stream(chain_str);
std::vector<std::string> chain = quic::CertificateView::LoadPemFromStream(&pem_stream);
return quic::QuicReferenceCountedPointer<quic::ProofSource::Chain>(

quic::QuicReferenceCountedPointer<quic::ProofSource::Chain> cert_chain(
new quic::ProofSource::Chain(chain));
std::string error_details;
bssl::UniquePtr<X509> cert = parseDERCertificate(cert_chain->certs[0], &error_details);
if (cert == nullptr) {
ENVOY_LOG(warn, absl::StrCat("Invalid leaf cert: ", error_details));
return nullptr;
}

bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(cert.get()));
int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
if (sign_alg == 0) {
ENVOY_LOG(warn, absl::StrCat("Failed to deduce signature algorithm from public key: ",
error_details));
return nullptr;
}
return cert_chain;
}

void EnvoyQuicProofSource::signPayload(
Expand Down Expand Up @@ -82,7 +98,7 @@ EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(const quic::QuicSocketAddre
ENVOY_LOG(trace, "Getting cert chain for {}", hostname);
// TODO(danzh) modify QUICHE to make quic session or ALPN accessible to avoid hard-coded ALPN.
Network::ConnectionSocketPtr connection_socket = createServerConnectionSocket(
listen_socket_.ioHandle(), server_address, client_address, hostname, "h3-29");
listen_socket_.ioHandle(), server_address, client_address, hostname, "h3");
const Network::FilterChain* filter_chain =
filter_chain_manager_.findFilterChain(*connection_socket);

Expand Down
60 changes: 8 additions & 52 deletions source/common/quic/envoy_quic_proof_source_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,15 @@
namespace Envoy {
namespace Quic {

void EnvoyQuicProofSourceBase::GetProof(const quic::QuicSocketAddress& server_address,
const quic::QuicSocketAddress& client_address,
const std::string& hostname,
const std::string& server_config,
void EnvoyQuicProofSourceBase::GetProof(const quic::QuicSocketAddress& /*server_address*/,
const quic::QuicSocketAddress& /*client_address*/,
const std::string& /*hostname*/,
const std::string& /*server_config*/,
quic::QuicTransportVersion /*transport_version*/,
absl::string_view chlo_hash,
std::unique_ptr<quic::ProofSource::Callback> callback) {
quic::QuicReferenceCountedPointer<quic::ProofSource::Chain> chain =
GetCertChain(server_address, client_address, hostname);

if (chain == nullptr || chain->certs.empty()) {
quic::QuicCryptoProof proof;
callback->Run(/*ok=*/false, nullptr, proof, nullptr);
return;
}
size_t payload_size = sizeof(quic::kProofSignatureLabel) + sizeof(uint32_t) + chlo_hash.size() +
server_config.size();
auto payload = std::make_unique<char[]>(payload_size);
quic::QuicDataWriter payload_writer(payload_size, payload.get(),
quiche::Endianness::HOST_BYTE_ORDER);
bool success =
payload_writer.WriteBytes(quic::kProofSignatureLabel, sizeof(quic::kProofSignatureLabel)) &&
payload_writer.WriteUInt32(chlo_hash.size()) && payload_writer.WriteStringPiece(chlo_hash) &&
payload_writer.WriteStringPiece(server_config);
if (!success) {
quic::QuicCryptoProof proof;
callback->Run(/*ok=*/false, nullptr, proof, nullptr);
return;
}

std::string error_details;
bssl::UniquePtr<X509> cert = parseDERCertificate(chain->certs[0], &error_details);
if (cert == nullptr) {
ENVOY_LOG(warn, absl::StrCat("Invalid leaf cert: ", error_details));
quic::QuicCryptoProof proof;
callback->Run(/*ok=*/false, nullptr, proof, nullptr);
return;
}

bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(cert.get()));
int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
if (sign_alg == 0) {
ENVOY_LOG(warn, absl::StrCat("Failed to deduce signature algorithm from public key: ",
error_details));
quic::QuicCryptoProof proof;
callback->Run(/*ok=*/false, nullptr, proof, nullptr);
return;
}

auto signature_callback = std::make_unique<SignatureCallback>(std::move(callback), chain);

signPayload(server_address, client_address, hostname, sign_alg,
absl::string_view(payload.get(), payload_size), std::move(signature_callback));
absl::string_view /*chlo_hash*/,
std::unique_ptr<quic::ProofSource::Callback> /*callback*/) {
// Only reachable in Google QUIC which is not supported by Envoy.
NOT_REACHED_GCOVR_EXCL_LINE;
}

void EnvoyQuicProofSourceBase::ComputeTlsSignature(
Expand Down
31 changes: 0 additions & 31 deletions source/common/quic/envoy_quic_proof_source_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ class EnvoyQuicProofSourceDetails : public quic::ProofSource::Details {
public:
explicit EnvoyQuicProofSourceDetails(const Network::FilterChain& filter_chain)
: filter_chain_(filter_chain) {}
EnvoyQuicProofSourceDetails(const EnvoyQuicProofSourceDetails& other)
: filter_chain_(other.filter_chain_) {}

const Network::FilterChain& filterChain() const { return filter_chain_; }

Expand All @@ -50,8 +48,6 @@ class EnvoyQuicProofSourceBase : public quic::ProofSource,
~EnvoyQuicProofSourceBase() override = default;

// quic::ProofSource
// Returns a certs chain and its fake SCT "Fake timestamp" and TLS signature wrapped
// in QuicCryptoProof.
void GetProof(const quic::QuicSocketAddress& server_address,
const quic::QuicSocketAddress& client_address, const std::string& hostname,
const std::string& server_config, quic::QuicTransportVersion /*transport_version*/,
Expand All @@ -72,33 +68,6 @@ class EnvoyQuicProofSourceBase : public quic::ProofSource,
const std::string& hostname, uint16_t signature_algorithm,
absl::string_view in,
std::unique_ptr<quic::ProofSource::SignatureCallback> callback) PURE;

private:
// Used by GetProof() to get signature.
class SignatureCallback : public quic::ProofSource::SignatureCallback {
public:
// TODO(danzh) Pass in Details to retain the certs chain, and quic::ProofSource::Callback to be
// triggered in Run().
SignatureCallback(std::unique_ptr<quic::ProofSource::Callback> callback,
quic::QuicReferenceCountedPointer<quic::ProofSource::Chain> chain)
: callback_(std::move(callback)), chain_(chain) {}

// quic::ProofSource::SignatureCallback
void Run(bool ok, std::string signature, std::unique_ptr<Details> details) override {
quic::QuicCryptoProof proof;
if (!ok) {
callback_->Run(false, chain_, proof, nullptr);
return;
}
proof.signature = signature;
proof.leaf_cert_scts = "Fake timestamp";
callback_->Run(true, chain_, proof, std::move(details));
}

private:
std::unique_ptr<quic::ProofSource::Callback> callback_;
quic::QuicReferenceCountedPointer<quic::ProofSource::Chain> chain_;
};
};

} // namespace Quic
Expand Down
10 changes: 7 additions & 3 deletions source/common/quic/envoy_quic_proof_verifier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain(
sk_X509_push(intermediates.get(), cert.release());
}
}
std::unique_ptr<quic::CertificateView> cert_view =
quic::CertificateView::ParseSingleCertificate(certs[0]);
ASSERT(cert_view != nullptr);
int sign_alg = deduceSignatureAlgorithmFromPublicKey(cert_view->public_key(), error_details);
if (sign_alg == 0) {
return quic::QUIC_FAILURE;
}
// We down cast rather than add verifyCertChain to Envoy::Ssl::Context because
// verifyCertChain uses a bunch of SSL-specific structs which we want to keep
// out of the interface definition.
Expand All @@ -37,9 +44,6 @@ quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain(
return quic::QUIC_FAILURE;
}

std::unique_ptr<quic::CertificateView> cert_view =
quic::CertificateView::ParseSingleCertificate(certs[0]);
ASSERT(cert_view != nullptr);
for (const absl::string_view& config_san : cert_view->subject_alt_name_domains()) {
if (Extensions::TransportSockets::Tls::DefaultCertValidator::dnsNameMatch(hostname,
config_san)) {
Expand Down
Loading

0 comments on commit 110559f

Please sign in to comment.