From beb5a93b08bd0c48a2a7dd2f40ca13bcdb0ed40e Mon Sep 17 00:00:00 2001 From: danzh Date: Thu, 10 Jun 2021 11:36:59 -0400 Subject: [PATCH] quiche: make quic proof source and crypto stream pluggable (#16658) Commit Message: make quic proof source and crypto streams extensions. Add config for default ones. If not specified in config, the default ones will be used. Risk Level: low Testing: existing tests passed Part of #2557 Co-authored-by: Dan Zhang --- CODEOWNERS | 2 +- api/BUILD | 3 +- .../config/listener/v3/quic_config.proto | 13 +++- .../config/listener/v4alpha/quic_config.proto | 13 +++- .../extensions/quic/crypto_stream/v3/BUILD | 9 +++ .../quic/crypto_stream/v3/crypto_stream.proto | 17 ++++++ .../extensions/quic/proof_source/v3/BUILD | 9 +++ .../quic/proof_source/v3/proof_source.proto | 17 ++++++ api/versioning/BUILD | 2 + bazel/envoy_library.bzl | 1 + bazel/external/quiche.BUILD | 1 + docs/root/api-v3/config/config.rst | 1 + .../api-v3/config/quic/quic_extensions.rst | 9 +++ generated_api_shadow/BUILD | 3 +- .../config/listener/v3/quic_config.proto | 13 +++- .../config/listener/v4alpha/quic_config.proto | 13 +++- .../extensions/quic/crypto_stream/v3/BUILD | 9 +++ .../quic/crypto_stream/v3/crypto_stream.proto | 17 ++++++ .../extensions/quic/proof_source/v3/BUILD | 9 +++ .../quic/proof_source/v3/proof_source.proto | 17 ++++++ source/common/quic/BUILD | 32 +++++++++- source/common/quic/active_quic_listener.cc | 61 +++++++++++++++---- source/common/quic/active_quic_listener.h | 15 ++++- .../quic/client_connection_factory_impl.cc | 2 +- .../quic/client_connection_factory_impl.h | 3 + .../common/quic/envoy_quic_client_session.cc | 11 +++- .../common/quic/envoy_quic_client_session.h | 6 +- .../quic/envoy_quic_crypto_stream_factory.h | 50 +++++++++++++++ source/common/quic/envoy_quic_dispatcher.cc | 10 ++- source/common/quic/envoy_quic_dispatcher.h | 5 +- ...nvoy_quic_proof_source_factory_interface.h | 38 ++++++++++++ .../common/quic/envoy_quic_server_session.cc | 9 ++- .../common/quic/envoy_quic_server_session.h | 6 +- source/extensions/extensions_build_config.bzl | 7 +++ source/extensions/extensions_metadata.yaml | 10 +++ source/extensions/quic/crypto_stream/BUILD | 59 ++++++++++++++++++ .../envoy_quic_crypto_client_stream.cc | 18 ++++++ .../envoy_quic_crypto_client_stream.h | 19 ++++++ .../envoy_quic_crypto_server_stream.cc | 18 ++++++ .../envoy_quic_crypto_server_stream.h | 27 ++++++++ source/extensions/quic/proof_source/BUILD | 46 ++++++++++++++ .../envoy_quic_proof_source_factory_impl.cc | 16 +++++ .../envoy_quic_proof_source_factory_impl.h | 28 +++++++++ test/common/quic/BUILD | 4 ++ test/common/quic/active_quic_listener_test.cc | 14 ++++- .../quic/envoy_quic_client_session_test.cc | 32 +++++----- .../common/quic/envoy_quic_dispatcher_test.cc | 5 +- .../quic/envoy_quic_server_session_test.cc | 43 +++++++------ test/integration/BUILD | 5 +- .../integration/quic_http_integration_test.cc | 3 +- tools/extensions/extensions_check.py | 11 ++-- 51 files changed, 711 insertions(+), 80 deletions(-) create mode 100644 api/envoy/extensions/quic/crypto_stream/v3/BUILD create mode 100644 api/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto create mode 100644 api/envoy/extensions/quic/proof_source/v3/BUILD create mode 100644 api/envoy/extensions/quic/proof_source/v3/proof_source.proto create mode 100644 docs/root/api-v3/config/quic/quic_extensions.rst create mode 100644 generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/BUILD create mode 100644 generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto create mode 100644 generated_api_shadow/envoy/extensions/quic/proof_source/v3/BUILD create mode 100644 generated_api_shadow/envoy/extensions/quic/proof_source/v3/proof_source.proto create mode 100644 source/common/quic/envoy_quic_crypto_stream_factory.h create mode 100644 source/common/quic/envoy_quic_proof_source_factory_interface.h create mode 100644 source/extensions/quic/crypto_stream/BUILD create mode 100644 source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.cc create mode 100644 source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h create mode 100644 source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.cc create mode 100644 source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h create mode 100644 source/extensions/quic/proof_source/BUILD create mode 100644 source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.cc create mode 100644 source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h diff --git a/CODEOWNERS b/CODEOWNERS index 3bc6d20ffa7a..971e9976a9e9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -67,7 +67,7 @@ extensions/filters/common/original_src @snowp @klarose # postgres_proxy extension /*/extensions/filters/network/postgres_proxy @fabriziomello @cpakulski @dio # quic extension -/*/extensions/quic_listeners/ @alyssawilk @danzh2010 @mattklein123 @mpwarres @wu-bin @ggreenway +/*/extensions/quic/ @alyssawilk @danzh2010 @mattklein123 @mpwarres @wu-bin @ggreenway # zookeeper_proxy extension /*/extensions/filters/network/zookeeper_proxy @rgs1 @snowp # redis cluster extension diff --git a/api/BUILD b/api/BUILD index 1e093ea09ab9..179af01ca9ef 100644 --- a/api/BUILD +++ b/api/BUILD @@ -54,7 +54,6 @@ proto_library( "//envoy/config/filter/http/rate_limit/v2:pkg", "//envoy/config/filter/http/rbac/v2:pkg", "//envoy/config/filter/http/router/v2:pkg", - "//envoy/config/filter/http/squash/v2:pkg", "//envoy/config/filter/http/tap/v2alpha:pkg", "//envoy/config/filter/http/transcoder/v2:pkg", "//envoy/config/filter/listener/http_inspector/v2:pkg", @@ -256,6 +255,8 @@ proto_library( "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", + "//envoy/extensions/quic/crypto_stream/v3:pkg", + "//envoy/extensions/quic/proof_source/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", "//envoy/extensions/request_id/uuid/v3:pkg", "//envoy/extensions/resource_monitors/fixed_heap/v3:pkg", diff --git a/api/envoy/config/listener/v3/quic_config.proto b/api/envoy/config/listener/v3/quic_config.proto index d1e62cdaaf15..1432e1911b5d 100644 --- a/api/envoy/config/listener/v3/quic_config.proto +++ b/api/envoy/config/listener/v3/quic_config.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.config.listener.v3; import "envoy/config/core/v3/base.proto"; +import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/protocol.proto"; import "google/protobuf/duration.proto"; @@ -20,7 +21,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: QUIC listener config] // Configuration specific to the UDP QUIC listener. -// [#next-free-field: 6] +// [#next-free-field: 8] message QuicProtocolOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.QuicProtocolOptions"; @@ -48,4 +49,14 @@ message QuicProtocolOptions { // bound by 6000, regardless of this field or how many connections there are. google.protobuf.UInt32Value packets_to_read_to_connection_count_ratio = 5 [(validate.rules).uint32 = {gte: 1}]; + + // Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + // If not specified the :ref:`QUICHE default one configured by ` will be used. + // [#extension-category: envoy.quic.server.crypto_stream] + core.v3.TypedExtensionConfig crypto_stream_config = 6; + + // Configure which implementation of `quic::ProofSource` to be used for this listener. + // If not specified the :ref:`default one configured by ` will be used. + // [#extension-category: envoy.quic.proof_source] + core.v3.TypedExtensionConfig proof_source_config = 7; } diff --git a/api/envoy/config/listener/v4alpha/quic_config.proto b/api/envoy/config/listener/v4alpha/quic_config.proto index 6d0f5e51493b..0b6d6bd7584c 100644 --- a/api/envoy/config/listener/v4alpha/quic_config.proto +++ b/api/envoy/config/listener/v4alpha/quic_config.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.config.listener.v4alpha; import "envoy/config/core/v4alpha/base.proto"; +import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/core/v4alpha/protocol.proto"; import "google/protobuf/duration.proto"; @@ -20,7 +21,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // [#protodoc-title: QUIC listener config] // Configuration specific to the UDP QUIC listener. -// [#next-free-field: 6] +// [#next-free-field: 8] message QuicProtocolOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.config.listener.v3.QuicProtocolOptions"; @@ -48,4 +49,14 @@ message QuicProtocolOptions { // bound by 6000, regardless of this field or how many connections there are. google.protobuf.UInt32Value packets_to_read_to_connection_count_ratio = 5 [(validate.rules).uint32 = {gte: 1}]; + + // Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + // If not specified the :ref:`QUICHE default one configured by ` will be used. + // [#extension-category: envoy.quic.server.crypto_stream] + core.v4alpha.TypedExtensionConfig crypto_stream_config = 6; + + // Configure which implementation of `quic::ProofSource` to be used for this listener. + // If not specified the :ref:`default one configured by ` will be used. + // [#extension-category: envoy.quic.proof_source] + core.v4alpha.TypedExtensionConfig proof_source_config = 7; } diff --git a/api/envoy/extensions/quic/crypto_stream/v3/BUILD b/api/envoy/extensions/quic/crypto_stream/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/api/envoy/extensions/quic/crypto_stream/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto b/api/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto new file mode 100644 index 000000000000..6313f79861e8 --- /dev/null +++ b/api/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.quic.crypto_stream.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.quic.crypto_stream.v3"; +option java_outer_classname = "CryptoStreamProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: QUIC server crypto stream config] +// [#extension: envoy.quic.crypto_stream.server.quiche] + +// Configuration for the default QUIC server crypto stream provided by QUICHE. +message CryptoServerStreamConfig { +} diff --git a/api/envoy/extensions/quic/proof_source/v3/BUILD b/api/envoy/extensions/quic/proof_source/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/api/envoy/extensions/quic/proof_source/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/quic/proof_source/v3/proof_source.proto b/api/envoy/extensions/quic/proof_source/v3/proof_source.proto new file mode 100644 index 000000000000..1459142d4091 --- /dev/null +++ b/api/envoy/extensions/quic/proof_source/v3/proof_source.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.quic.proof_source.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.quic.proof_source.v3"; +option java_outer_classname = "ProofSourceProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: QUIC proof source config] +// [#extension: envoy.quic.proof_source.filter_chain] + +// Configuration for the default QUIC proof source. +message ProofSourceConfig { +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 96da35bec983..867fe05efa53 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -139,6 +139,8 @@ proto_library( "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", + "//envoy/extensions/quic/crypto_stream/v3:pkg", + "//envoy/extensions/quic/proof_source/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", "//envoy/extensions/request_id/uuid/v3:pkg", "//envoy/extensions/resource_monitors/fixed_heap/v3:pkg", diff --git a/bazel/envoy_library.bzl b/bazel/envoy_library.bzl index a6e77598f912..e150bb28ef0a 100644 --- a/bazel/envoy_library.bzl +++ b/bazel/envoy_library.bzl @@ -62,6 +62,7 @@ def envoy_cc_extension( ) cc_library( name = ext_name, + tags = tags, deps = select({ ":is_enabled": [":" + name], "//conditions:default": [], diff --git a/bazel/external/quiche.BUILD b/bazel/external/quiche.BUILD index a30a9c8d64a5..e8c84f7a145c 100644 --- a/bazel/external/quiche.BUILD +++ b/bazel/external/quiche.BUILD @@ -2031,6 +2031,7 @@ envoy_cc_library( external_deps = ["ssl"], repository = "@envoy", tags = ["nofips"], + visibility = ["//visibility:public"], deps = [ ":quic_core_crypto_hkdf_lib", ":quic_core_data_lib", diff --git a/docs/root/api-v3/config/config.rst b/docs/root/api-v3/config/config.rst index 712ed03fa278..16a562963760 100644 --- a/docs/root/api-v3/config/config.rst +++ b/docs/root/api-v3/config/config.rst @@ -28,3 +28,4 @@ Extensions request_id/request_id http/header_formatters http/original_ip_detection + quic/quic_extensions diff --git a/docs/root/api-v3/config/quic/quic_extensions.rst b/docs/root/api-v3/config/quic/quic_extensions.rst new file mode 100644 index 000000000000..4f3ab247bb6d --- /dev/null +++ b/docs/root/api-v3/config/quic/quic_extensions.rst @@ -0,0 +1,9 @@ +Quic Extensions +================= + +.. toctree:: + :glob: + :maxdepth: 2 + + ../../extensions/quic/crypto_stream/v3/* + ../../extensions/quic/proof_source/v3/* diff --git a/generated_api_shadow/BUILD b/generated_api_shadow/BUILD index 1e093ea09ab9..179af01ca9ef 100644 --- a/generated_api_shadow/BUILD +++ b/generated_api_shadow/BUILD @@ -54,7 +54,6 @@ proto_library( "//envoy/config/filter/http/rate_limit/v2:pkg", "//envoy/config/filter/http/rbac/v2:pkg", "//envoy/config/filter/http/router/v2:pkg", - "//envoy/config/filter/http/squash/v2:pkg", "//envoy/config/filter/http/tap/v2alpha:pkg", "//envoy/config/filter/http/transcoder/v2:pkg", "//envoy/config/filter/listener/http_inspector/v2:pkg", @@ -256,6 +255,8 @@ proto_library( "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", + "//envoy/extensions/quic/crypto_stream/v3:pkg", + "//envoy/extensions/quic/proof_source/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", "//envoy/extensions/request_id/uuid/v3:pkg", "//envoy/extensions/resource_monitors/fixed_heap/v3:pkg", diff --git a/generated_api_shadow/envoy/config/listener/v3/quic_config.proto b/generated_api_shadow/envoy/config/listener/v3/quic_config.proto index d1e62cdaaf15..1432e1911b5d 100644 --- a/generated_api_shadow/envoy/config/listener/v3/quic_config.proto +++ b/generated_api_shadow/envoy/config/listener/v3/quic_config.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.config.listener.v3; import "envoy/config/core/v3/base.proto"; +import "envoy/config/core/v3/extension.proto"; import "envoy/config/core/v3/protocol.proto"; import "google/protobuf/duration.proto"; @@ -20,7 +21,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // [#protodoc-title: QUIC listener config] // Configuration specific to the UDP QUIC listener. -// [#next-free-field: 6] +// [#next-free-field: 8] message QuicProtocolOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.QuicProtocolOptions"; @@ -48,4 +49,14 @@ message QuicProtocolOptions { // bound by 6000, regardless of this field or how many connections there are. google.protobuf.UInt32Value packets_to_read_to_connection_count_ratio = 5 [(validate.rules).uint32 = {gte: 1}]; + + // Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + // If not specified the :ref:`QUICHE default one configured by ` will be used. + // [#extension-category: envoy.quic.server.crypto_stream] + core.v3.TypedExtensionConfig crypto_stream_config = 6; + + // Configure which implementation of `quic::ProofSource` to be used for this listener. + // If not specified the :ref:`default one configured by ` will be used. + // [#extension-category: envoy.quic.proof_source] + core.v3.TypedExtensionConfig proof_source_config = 7; } diff --git a/generated_api_shadow/envoy/config/listener/v4alpha/quic_config.proto b/generated_api_shadow/envoy/config/listener/v4alpha/quic_config.proto index 6d0f5e51493b..0b6d6bd7584c 100644 --- a/generated_api_shadow/envoy/config/listener/v4alpha/quic_config.proto +++ b/generated_api_shadow/envoy/config/listener/v4alpha/quic_config.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package envoy.config.listener.v4alpha; import "envoy/config/core/v4alpha/base.proto"; +import "envoy/config/core/v4alpha/extension.proto"; import "envoy/config/core/v4alpha/protocol.proto"; import "google/protobuf/duration.proto"; @@ -20,7 +21,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // [#protodoc-title: QUIC listener config] // Configuration specific to the UDP QUIC listener. -// [#next-free-field: 6] +// [#next-free-field: 8] message QuicProtocolOptions { option (udpa.annotations.versioning).previous_message_type = "envoy.config.listener.v3.QuicProtocolOptions"; @@ -48,4 +49,14 @@ message QuicProtocolOptions { // bound by 6000, regardless of this field or how many connections there are. google.protobuf.UInt32Value packets_to_read_to_connection_count_ratio = 5 [(validate.rules).uint32 = {gte: 1}]; + + // Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + // If not specified the :ref:`QUICHE default one configured by ` will be used. + // [#extension-category: envoy.quic.server.crypto_stream] + core.v4alpha.TypedExtensionConfig crypto_stream_config = 6; + + // Configure which implementation of `quic::ProofSource` to be used for this listener. + // If not specified the :ref:`default one configured by ` will be used. + // [#extension-category: envoy.quic.proof_source] + core.v4alpha.TypedExtensionConfig proof_source_config = 7; } diff --git a/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/BUILD b/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto b/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto new file mode 100644 index 000000000000..6313f79861e8 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/quic/crypto_stream/v3/crypto_stream.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.quic.crypto_stream.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.quic.crypto_stream.v3"; +option java_outer_classname = "CryptoStreamProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: QUIC server crypto stream config] +// [#extension: envoy.quic.crypto_stream.server.quiche] + +// Configuration for the default QUIC server crypto stream provided by QUICHE. +message CryptoServerStreamConfig { +} diff --git a/generated_api_shadow/envoy/extensions/quic/proof_source/v3/BUILD b/generated_api_shadow/envoy/extensions/quic/proof_source/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/quic/proof_source/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/generated_api_shadow/envoy/extensions/quic/proof_source/v3/proof_source.proto b/generated_api_shadow/envoy/extensions/quic/proof_source/v3/proof_source.proto new file mode 100644 index 000000000000..1459142d4091 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/quic/proof_source/v3/proof_source.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.quic.proof_source.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.quic.proof_source.v3"; +option java_outer_classname = "ProofSourceProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: QUIC proof source config] +// [#extension: envoy.quic.proof_source.filter_chain] + +// Configuration for the default QUIC proof source. +message ProofSourceConfig { +} diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD index 8b055f8afb5b..435a1ac486b9 100644 --- a/source/common/quic/BUILD +++ b/source/common/quic/BUILD @@ -178,6 +178,7 @@ envoy_cc_library( "//envoy/http:codec_interface", "//envoy/registry", "//source/common/http/http3:quic_client_connection_factory_lib", + "//source/extensions/quic/crypto_stream:envoy_quic_crypto_client_stream_lib", "//source/extensions/transport_sockets/tls:ssl_socket_lib", "@com_googlesource_quiche//:quic_core_http_spdy_session_lib", ], @@ -232,6 +233,7 @@ envoy_cc_library( ], tags = ["nofips"], deps = [ + ":envoy_quic_crypto_stream_factory_lib", ":envoy_quic_proof_source_lib", ":envoy_quic_server_connection_lib", ":envoy_quic_stream_lib", @@ -259,6 +261,7 @@ envoy_cc_library( tags = ["nofips"], deps = [ ":envoy_quic_client_connection_lib", + ":envoy_quic_crypto_stream_factory_lib", ":envoy_quic_stream_lib", ":envoy_quic_utils_lib", ":quic_filter_manager_connection_lib", @@ -328,10 +331,11 @@ envoy_cc_library( hdrs = ["envoy_quic_dispatcher.h"], tags = ["nofips"], deps = [ - "quic_stat_names_lib", + ":envoy_quic_crypto_stream_factory_lib", ":envoy_quic_proof_source_lib", ":envoy_quic_server_connection_lib", ":envoy_quic_server_session_lib", + ":quic_stat_names_lib", "//envoy/network:listener_interface", "//source/server:connection_handler_lib", "@com_googlesource_quiche//:quic_core_server_lib", @@ -355,6 +359,7 @@ envoy_cc_library( ":envoy_quic_connection_helper_lib", ":envoy_quic_dispatcher_lib", ":envoy_quic_packet_writer_lib", + ":envoy_quic_proof_source_factory_interface", ":envoy_quic_proof_source_lib", ":envoy_quic_utils_lib", "//envoy/network:listener_interface", @@ -363,6 +368,8 @@ envoy_cc_library( "//source/common/runtime:runtime_lib", "//source/server:connection_handler_lib", "@envoy_api//envoy/config/listener/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/quic/crypto_stream/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/quic/proof_source/v3:pkg_cc_proto", ], ) @@ -420,6 +427,8 @@ envoy_cc_library( "//conditions:default": [ ":codec_lib", ":quic_transport_socket_factory_lib", + "//source/extensions/quic/crypto_stream:envoy_quic_crypto_server_stream_lib", + "//source/extensions/quic/proof_source:envoy_quic_proof_source_factory_impl_lib", ], }), ) @@ -464,3 +473,24 @@ envoy_cc_library( "@com_googlesource_quiche//:quic_core_session_lib", ], ) + +envoy_cc_library( + name = "envoy_quic_crypto_stream_factory_lib", + hdrs = ["envoy_quic_crypto_stream_factory.h"], + tags = ["nofips"], + deps = [ + "//envoy/config:typed_config_interface", + "@com_googlesource_quiche//:quic_core_http_spdy_session_lib", + ], +) + +envoy_cc_library( + name = "envoy_quic_proof_source_factory_interface", + hdrs = ["envoy_quic_proof_source_factory_interface.h"], + tags = ["nofips"], + deps = [ + "//envoy/config:typed_config_interface", + "//source/server:connection_handler_lib", + "@com_googlesource_quiche//:quic_core_crypto_proof_source_lib", + ], +) diff --git a/source/common/quic/active_quic_listener.cc b/source/common/quic/active_quic_listener.cc index 835b371457f4..f8389c5a54b6 100644 --- a/source/common/quic/active_quic_listener.cc +++ b/source/common/quic/active_quic_listener.cc @@ -17,8 +17,11 @@ #include "source/common/quic/envoy_quic_proof_source.h" #include "source/common/quic/envoy_quic_utils.h" #include "source/common/quic/envoy_quic_utils.h" +#include "source/common/config/utility.h" #include "source/common/quic/quic_network_connection.h" #include "source/common/runtime/runtime_features.h" +#include "envoy/extensions/quic/crypto_stream/v3/crypto_stream.pb.h" +#include "envoy/extensions/quic/proof_source/v3/proof_source.pb.h" namespace Envoy { namespace Quic { @@ -28,11 +31,14 @@ ActiveQuicListener::ActiveQuicListener( Network::UdpConnectionHandler& parent, Network::ListenerConfig& listener_config, const quic::QuicConfig& quic_config, Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing, const envoy::config::core::v3::RuntimeFeatureFlag& enabled, - QuicStatNames& quic_stat_names, uint32_t packets_received_to_connection_count_ratio) + QuicStatNames& quic_stat_names, uint32_t packets_received_to_connection_count_ratio, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory, + EnvoyQuicProofSourceFactoryInterface& proof_source_factory) : ActiveQuicListener(worker_index, concurrency, dispatcher, parent, listener_config.listenSocketFactory().getListenSocket(), listener_config, quic_config, std::move(options), kernel_worker_routing, enabled, - quic_stat_names, packets_received_to_connection_count_ratio) {} + quic_stat_names, packets_received_to_connection_count_ratio, + crypto_server_stream_factory, proof_source_factory) {} ActiveQuicListener::ActiveQuicListener( uint32_t worker_index, uint32_t concurrency, Event::Dispatcher& dispatcher, @@ -40,7 +46,9 @@ ActiveQuicListener::ActiveQuicListener( Network::ListenerConfig& listener_config, const quic::QuicConfig& quic_config, Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing, const envoy::config::core::v3::RuntimeFeatureFlag& enabled, QuicStatNames& quic_stat_names, - uint32_t packets_to_read_to_connection_count_ratio) + uint32_t packets_to_read_to_connection_count_ratio, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory, + EnvoyQuicProofSourceFactoryInterface& proof_source_factory) : Server::ActiveUdpListenerBase( worker_index, concurrency, parent, *listen_socket, dispatcher.createUdpListener( @@ -49,7 +57,8 @@ ActiveQuicListener::ActiveQuicListener( &listener_config), dispatcher_(dispatcher), version_manager_(quic::CurrentSupportedVersions()), kernel_worker_routing_(kernel_worker_routing), - packets_to_read_to_connection_count_ratio_(packets_to_read_to_connection_count_ratio) { + packets_to_read_to_connection_count_ratio_(packets_to_read_to_connection_count_ratio), + crypto_server_stream_factory_(crypto_server_stream_factory) { // This flag fix a QUICHE issue which may crash Envoy during connection close. SetQuicReloadableFlag(quic_single_ack_in_packet2, true); // Do not include 32-byte per-entry overhead while counting header size. @@ -76,8 +85,8 @@ ActiveQuicListener::ActiveQuicListener( crypto_config_ = std::make_unique( absl::string_view(reinterpret_cast(random_seed_), sizeof(random_seed_)), quic::QuicRandom::GetInstance(), - std::make_unique(listen_socket_, listener_config.filterChainManager(), - stats_), + proof_source_factory.createQuicProofSource(listen_socket_, + listener_config.filterChainManager(), stats_), quic::KeyExchangeSource::Default()); auto connection_helper = std::make_unique(dispatcher_); crypto_config_->AddDefaultConfig(random, connection_helper->GetClock(), @@ -87,7 +96,8 @@ ActiveQuicListener::ActiveQuicListener( quic_dispatcher_ = std::make_unique( crypto_config_.get(), quic_config, &version_manager_, std::move(connection_helper), std::move(alarm_factory), quic::kQuicDefaultConnectionIdLength, parent, *config_, stats_, - per_worker_stats_, dispatcher, listen_socket_, quic_stat_names); + per_worker_stats_, dispatcher, listen_socket_, quic_stat_names, + crypto_server_stream_factory_); // Create udp_packet_writer Network::UdpPacketWriterPtr udp_packet_writer = @@ -249,6 +259,32 @@ ActiveQuicListenerFactory::ActiveQuicListenerFactory( quic_config_.SetMaxBidirectionalStreamsToSend(max_streams); quic_config_.SetMaxUnidirectionalStreamsToSend(max_streams); configQuicInitialFlowControlWindow(config.quic_protocol_options(), quic_config_); + + // Initialize crypto stream factory. + envoy::config::core::v3::TypedExtensionConfig crypto_stream_config; + if (!config.has_crypto_stream_config()) { + // If not specified, use the quic crypto stream created by QUICHE. + crypto_stream_config.set_name("envoy.quic.crypto_stream.server.quiche"); + envoy::extensions::quic::crypto_stream::v3::CryptoServerStreamConfig empty_crypto_stream_config; + crypto_stream_config.mutable_typed_config()->PackFrom(empty_crypto_stream_config); + } else { + crypto_stream_config = config.crypto_stream_config(); + } + crypto_server_stream_factory_ = + Config::Utility::getAndCheckFactory( + crypto_stream_config); + + // Initialize proof source factory. + envoy::config::core::v3::TypedExtensionConfig proof_source_config; + if (!config.has_proof_source_config()) { + proof_source_config.set_name("envoy.quic.proof_source.filter_chain"); + envoy::extensions::quic::proof_source::v3::ProofSourceConfig empty_proof_source_config; + proof_source_config.mutable_typed_config()->PackFrom(empty_proof_source_config); + } else { + proof_source_config = config.proof_source_config(); + } + proof_source_factory_ = Config::Utility::getAndCheckFactory( + proof_source_config); } Network::ConnectionHandler::ActiveUdpListenerPtr ActiveQuicListenerFactory::createActiveUdpListener( @@ -315,11 +351,12 @@ Network::ConnectionHandler::ActiveUdpListenerPtr ActiveQuicListenerFactory::crea } #endif - return std::make_unique(worker_index, concurrency_, disptacher, parent, - config, quic_config_, std::move(options), - kernel_worker_routing, enabled_, quic_stat_names_, - packets_to_read_to_connection_count_ratio_); -} // namespace Quic + ASSERT(crypto_server_stream_factory_.has_value()); + return std::make_unique( + worker_index, concurrency_, disptacher, parent, config, quic_config_, std::move(options), + kernel_worker_routing, enabled_, quic_stat_names_, packets_to_read_to_connection_count_ratio_, + crypto_server_stream_factory_.value(), proof_source_factory_.value()); +} } // namespace Quic } // namespace Envoy diff --git a/source/common/quic/active_quic_listener.h b/source/common/quic/active_quic_listener.h index 44ec98bb7c93..39ff028a22fd 100644 --- a/source/common/quic/active_quic_listener.h +++ b/source/common/quic/active_quic_listener.h @@ -8,6 +8,7 @@ #include "source/common/protobuf/utility.h" #include "source/common/quic/envoy_quic_dispatcher.h" +#include "source/common/quic/envoy_quic_proof_source_factory_interface.h" #include "source/common/runtime/runtime_protos.h" #include "source/server/active_udp_listener.h" #include "source/server/connection_handler_impl.h" @@ -29,7 +30,9 @@ class ActiveQuicListener : public Envoy::Server::ActiveUdpListenerBase, Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing, const envoy::config::core::v3::RuntimeFeatureFlag& enabled, QuicStatNames& quic_stat_names, - uint32_t packets_to_read_to_connection_count_ratio); + uint32_t packets_to_read_to_connection_count_ratio, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory, + EnvoyQuicProofSourceFactoryInterface& proof_source_factory); ActiveQuicListener(uint32_t worker_index, uint32_t concurrency, Event::Dispatcher& dispatcher, Network::UdpConnectionHandler& parent, Network::SocketSharedPtr listen_socket, @@ -37,7 +40,9 @@ class ActiveQuicListener : public Envoy::Server::ActiveUdpListenerBase, Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing, const envoy::config::core::v3::RuntimeFeatureFlag& enabled, QuicStatNames& quic_stat_names, - uint32_t packets_to_read_to_connection_count_ratio); + uint32_t packets_to_read_to_connection_count_ratio, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory, + EnvoyQuicProofSourceFactoryInterface& proof_source_factory); ~ActiveQuicListener() override; @@ -77,8 +82,8 @@ class ActiveQuicListener : public Envoy::Server::ActiveUdpListenerBase, // The number of runs of the event loop in which at least one CHLO was buffered. // TODO(ggreenway): Consider making this a published stat, or some variation of this information. uint64_t event_loops_with_buffered_chlo_for_test_{0}; - uint32_t packets_to_read_to_connection_count_ratio_; + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory_; }; using ActiveQuicListenerPtr = std::unique_ptr; @@ -99,6 +104,10 @@ class ActiveQuicListenerFactory : public Network::ActiveUdpListenerFactory, private: friend class ActiveQuicListenerFactoryPeer; + absl::optional> + crypto_server_stream_factory_; + absl::optional> + proof_source_factory_; quic::QuicConfig quic_config_; const uint32_t concurrency_; absl::once_flag install_bpf_once_; diff --git a/source/common/quic/client_connection_factory_impl.cc b/source/common/quic/client_connection_factory_impl.cc index 8d3519b630ac..620081455fe0 100644 --- a/source/common/quic/client_connection_factory_impl.cc +++ b/source/common/quic/client_connection_factory_impl.cc @@ -74,7 +74,7 @@ createQuicNetworkConnection(Http::PersistentQuicInfo& info, Event::Dispatcher& d auto ret = std::make_unique( 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->buffer_limit_, info_impl->crypto_stream_factory_); return ret; } diff --git a/source/common/quic/client_connection_factory_impl.h b/source/common/quic/client_connection_factory_impl.h index ca66d7572556..8ec1038bf147 100644 --- a/source/common/quic/client_connection_factory_impl.h +++ b/source/common/quic/client_connection_factory_impl.h @@ -6,6 +6,7 @@ #include "source/common/quic/envoy_quic_connection_helper.h" #include "source/common/quic/envoy_quic_proof_verifier.h" #include "source/common/quic/envoy_quic_utils.h" +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h" #include "source/extensions/transport_sockets/tls/ssl_socket.h" #include "quiche/quic/core/http/quic_client_push_promise_index.h" @@ -47,6 +48,8 @@ struct PersistentQuicInfoImpl : public Http::PersistentQuicInfo { // This arguably should not be shared across connections but as Envoy doesn't // support push promise it's really moot point. quic::QuicClientPushPromiseIndex push_promise_index_; + // Hard code with the default crypto stream as there's no pluggable crypto for upstream Envoy. + EnvoyQuicCryptoClientStreamFactoryImpl crypto_stream_factory_; }; std::unique_ptr diff --git a/source/common/quic/envoy_quic_client_session.cc b/source/common/quic/envoy_quic_client_session.cc index 8910d62e8eb3..45557cafc5ca 100644 --- a/source/common/quic/envoy_quic_client_session.cc +++ b/source/common/quic/envoy_quic_client_session.cc @@ -10,12 +10,13 @@ EnvoyQuicClientSession::EnvoyQuicClientSession( std::unique_ptr connection, const quic::QuicServerId& server_id, std::shared_ptr crypto_config, quic::QuicClientPushPromiseIndex* push_promise_index, Event::Dispatcher& dispatcher, - uint32_t send_buffer_limit) + uint32_t send_buffer_limit, EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory) : QuicFilterManagerConnectionImpl(*connection, connection->connection_id(), dispatcher, send_buffer_limit), quic::QuicSpdyClientSession(config, supported_versions, connection.release(), server_id, crypto_config.get(), push_promise_index), - host_name_(server_id.host()), crypto_config_(crypto_config) {} + host_name_(server_id.host()), crypto_config_(crypto_config), + crypto_stream_factory_(crypto_stream_factory) {} EnvoyQuicClientSession::~EnvoyQuicClientSession() { ASSERT(!connection()->connected()); @@ -129,5 +130,11 @@ size_t EnvoyQuicClientSession::WriteHeadersOnHeadersStream( precedence, ack_listener); } +std::unique_ptr EnvoyQuicClientSession::CreateQuicCryptoStream() { + return crypto_stream_factory_.createEnvoyQuicCryptoClientStream( + server_id(), this, crypto_config()->proof_verifier()->CreateDefaultContext(), crypto_config(), + this, /*has_application_state = */ version().UsesHttp3()); +} + } // namespace Quic } // namespace Envoy diff --git a/source/common/quic/envoy_quic_client_session.h b/source/common/quic/envoy_quic_client_session.h index 29da91ad1a0b..39d4271d5adc 100644 --- a/source/common/quic/envoy_quic_client_session.h +++ b/source/common/quic/envoy_quic_client_session.h @@ -16,6 +16,7 @@ #include "source/common/quic/envoy_quic_client_stream.h" #include "source/common/quic/envoy_quic_client_connection.h" #include "source/common/quic/quic_filter_manager_connection_impl.h" +#include "source/common/quic/envoy_quic_crypto_stream_factory.h" namespace Envoy { namespace Quic { @@ -35,7 +36,8 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, const quic::QuicServerId& server_id, std::shared_ptr crypto_config, quic::QuicClientPushPromiseIndex* push_promise_index, - Event::Dispatcher& dispatcher, uint32_t send_buffer_limit); + Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, + EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory); ~EnvoyQuicClientSession() override; @@ -77,6 +79,7 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, // quic::QuicSpdySession quic::QuicSpdyStream* CreateIncomingStream(quic::QuicStreamId id) override; quic::QuicSpdyStream* CreateIncomingStream(quic::PendingStream* pending) override; + std::unique_ptr CreateQuicCryptoStream() override; // QuicFilterManagerConnectionImpl bool hasDataToWrite() override; @@ -90,6 +93,7 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl, Http::ConnectionCallbacks* http_connection_callbacks_{nullptr}; const absl::string_view host_name_; std::shared_ptr crypto_config_; + EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory_; }; } // namespace Quic diff --git a/source/common/quic/envoy_quic_crypto_stream_factory.h b/source/common/quic/envoy_quic_crypto_stream_factory.h new file mode 100644 index 000000000000..30ba1710751e --- /dev/null +++ b/source/common/quic/envoy_quic_crypto_stream_factory.h @@ -0,0 +1,50 @@ +#pragma once + +#include "envoy/config/typed_config.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + +#include "quiche/quic/core/quic_crypto_server_stream_base.h" +#include "quiche/quic/core/crypto/quic_crypto_server_config.h" +#include "quiche/quic/core/tls_server_handshaker.h" +#include "quiche/quic/core/quic_session.h" +#include "quiche/quic/core/quic_crypto_client_stream.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace Envoy { +namespace Quic { + +class EnvoyQuicCryptoServerStreamFactoryInterface : public Config::TypedFactory { +public: + std::string category() const override { return "envoy.quic.server.crypto_stream"; } + + // Return an Envoy specific quic crypto server stream object. + virtual std::unique_ptr + createEnvoyQuicCryptoServerStream(const quic::QuicCryptoServerConfig* crypto_config, + quic::QuicCompressedCertsCache* compressed_certs_cache, + quic::QuicSession* session, + quic::QuicCryptoServerStreamBase::Helper* helper) PURE; +}; + +class EnvoyQuicCryptoClientStreamFactoryInterface { +public: + virtual ~EnvoyQuicCryptoClientStreamFactoryInterface() = default; + + // Return an Envoy specific quic crypto client stream object. + virtual std::unique_ptr + createEnvoyQuicCryptoClientStream(const quic::QuicServerId& server_id, quic::QuicSession* session, + std::unique_ptr verify_context, + quic::QuicCryptoClientConfig* crypto_config, + quic::QuicCryptoClientStream::ProofHandler* proof_handler, + bool has_application_state) PURE; +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/common/quic/envoy_quic_dispatcher.cc b/source/common/quic/envoy_quic_dispatcher.cc index 040eb46028bd..b85e2e0d5844 100644 --- a/source/common/quic/envoy_quic_dispatcher.cc +++ b/source/common/quic/envoy_quic_dispatcher.cc @@ -1,5 +1,7 @@ #include "source/common/quic/envoy_quic_dispatcher.h" +#include + #include "source/common/common/safe_memcpy.h" #include "source/common/http/utility.h" #include "source/common/quic/envoy_quic_server_connection.h" @@ -17,13 +19,15 @@ EnvoyQuicDispatcher::EnvoyQuicDispatcher( uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler, Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats, Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher, - Network::Socket& listen_socket, QuicStatNames& quic_stat_names) + Network::Socket& listen_socket, QuicStatNames& quic_stat_names, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory) : quic::QuicDispatcher(&quic_config, crypto_config, version_manager, std::move(helper), std::make_unique(), std::move(alarm_factory), expected_server_connection_id_length), connection_handler_(connection_handler), listener_config_(listener_config), listener_stats_(listener_stats), per_worker_stats_(per_worker_stats), dispatcher_(dispatcher), - listen_socket_(listen_socket), quic_stat_names_(quic_stat_names) { + listen_socket_(listen_socket), quic_stat_names_(quic_stat_names), + crypto_server_stream_factory_(crypto_server_stream_factory) { // Set send buffer twice of max flow control window to ensure that stream send // buffer always takes all the data. // The max amount of data buffered is the per-stream high watermark + the max @@ -67,7 +71,7 @@ std::unique_ptr EnvoyQuicDispatcher::CreateQuicSession( quic_config, quic::ParsedQuicVersionVector{version}, std::move(quic_connection), this, session_helper(), crypto_config(), compressed_certs_cache(), dispatcher_, listener_config_.perConnectionBufferLimitBytes(), quic_stat_names_, - listener_config_.listenerScope()); + listener_config_.listenerScope(), crypto_server_stream_factory_); if (filter_chain != nullptr) { const bool has_filter_initialized = listener_config_.filterChainFactory().createNetworkFilterChain( diff --git a/source/common/quic/envoy_quic_dispatcher.h b/source/common/quic/envoy_quic_dispatcher.h index caa259329dc9..0864a909f42f 100644 --- a/source/common/quic/envoy_quic_dispatcher.h +++ b/source/common/quic/envoy_quic_dispatcher.h @@ -19,6 +19,7 @@ #include "envoy/network/listener.h" #include "source/server/connection_handler_impl.h" #include "source/server/active_listener_base.h" +#include "source/common/quic/envoy_quic_crypto_stream_factory.h" #include "source/common/quic/quic_stat_names.h" namespace Envoy { @@ -52,7 +53,8 @@ class EnvoyQuicDispatcher : public quic::QuicDispatcher { uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler, Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats, Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher, - Network::Socket& listen_socket, QuicStatNames& quic_stat_names); + Network::Socket& listen_socket, QuicStatNames& quic_stat_names, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory); void OnConnectionClosed(quic::QuicConnectionId connection_id, quic::QuicErrorCode error, const std::string& error_details, @@ -81,6 +83,7 @@ class EnvoyQuicDispatcher : public quic::QuicDispatcher { Event::Dispatcher& dispatcher_; Network::Socket& listen_socket_; QuicStatNames& quic_stat_names_; + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory_; }; } // namespace Quic diff --git a/source/common/quic/envoy_quic_proof_source_factory_interface.h b/source/common/quic/envoy_quic_proof_source_factory_interface.h new file mode 100644 index 000000000000..a6f69a176158 --- /dev/null +++ b/source/common/quic/envoy_quic_proof_source_factory_interface.h @@ -0,0 +1,38 @@ +#pragma once + +#include "envoy/config/typed_config.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + +#include "quiche/quic/core/crypto/proof_source.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#include "envoy/network/socket.h" +#include "envoy/network/filter.h" +#include "source/server/active_listener_base.h" + +namespace Envoy { +namespace Quic { + +// A factory interface to provide quic::ProofSource. +class EnvoyQuicProofSourceFactoryInterface : public Config::TypedFactory { +public: + ~EnvoyQuicProofSourceFactoryInterface() override = default; + + std::string category() const override { return "envoy.quic.proof_source"; } + + virtual std::unique_ptr + createQuicProofSource(Network::Socket& listen_socket, + Network::FilterChainManager& filter_chain_manager, + Server::ListenerStats& listener_stats) PURE; +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/common/quic/envoy_quic_server_session.cc b/source/common/quic/envoy_quic_server_session.cc index 330f969347cf..7fb668a639c7 100644 --- a/source/common/quic/envoy_quic_server_session.cc +++ b/source/common/quic/envoy_quic_server_session.cc @@ -14,13 +14,15 @@ EnvoyQuicServerSession::EnvoyQuicServerSession( std::unique_ptr connection, quic::QuicSession::Visitor* visitor, quic::QuicCryptoServerStream::Helper* helper, const quic::QuicCryptoServerConfig* crypto_config, quic::QuicCompressedCertsCache* compressed_certs_cache, Event::Dispatcher& dispatcher, - uint32_t send_buffer_limit, QuicStatNames& quic_stat_names, Stats::Scope& listener_scope) + uint32_t send_buffer_limit, QuicStatNames& quic_stat_names, Stats::Scope& listener_scope, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory) : quic::QuicServerSessionBase(config, supported_versions, connection.get(), visitor, helper, crypto_config, compressed_certs_cache), QuicFilterManagerConnectionImpl(*connection, connection->connection_id(), dispatcher, send_buffer_limit), quic_connection_(std::move(connection)), quic_stat_names_(quic_stat_names), - listener_scope_(listener_scope) {} + listener_scope_(listener_scope), crypto_server_stream_factory_(crypto_server_stream_factory) { +} EnvoyQuicServerSession::~EnvoyQuicServerSession() { ASSERT(!quic_connection_->connected()); @@ -35,7 +37,8 @@ std::unique_ptr EnvoyQuicServerSession::CreateQuicCryptoServerStream( const quic::QuicCryptoServerConfig* crypto_config, quic::QuicCompressedCertsCache* compressed_certs_cache) { - return CreateCryptoServerStream(crypto_config, compressed_certs_cache, this, stream_helper()); + return crypto_server_stream_factory_.createEnvoyQuicCryptoServerStream( + crypto_config, compressed_certs_cache, this, stream_helper()); } quic::QuicSpdyStream* EnvoyQuicServerSession::CreateIncomingStream(quic::QuicStreamId id) { diff --git a/source/common/quic/envoy_quic_server_session.h b/source/common/quic/envoy_quic_server_session.h index 6033a1a171cd..7bdb705ac764 100644 --- a/source/common/quic/envoy_quic_server_session.h +++ b/source/common/quic/envoy_quic_server_session.h @@ -23,6 +23,7 @@ #include "source/common/quic/quic_filter_manager_connection_impl.h" #include "source/common/quic/envoy_quic_server_connection.h" #include "source/common/quic/envoy_quic_server_stream.h" +#include "source/common/quic/envoy_quic_crypto_stream_factory.h" #include "source/common/quic/quic_stat_names.h" namespace Envoy { @@ -43,7 +44,8 @@ class EnvoyQuicServerSession : public quic::QuicServerSessionBase, const quic::QuicCryptoServerConfig* crypto_config, quic::QuicCompressedCertsCache* compressed_certs_cache, Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, - QuicStatNames& quic_stat_names, Stats::Scope& listener_scope); + QuicStatNames& quic_stat_names, Stats::Scope& listener_scope, + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory); ~EnvoyQuicServerSession() override; @@ -114,6 +116,8 @@ class EnvoyQuicServerSession : public quic::QuicServerSessionBase, QuicStatNames& quic_stat_names_; Stats::Scope& listener_scope_; + + EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory_; }; } // namespace Quic diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 867f1e5556b2..67c9d263f00c 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -280,6 +280,13 @@ EXTENSIONS = { "envoy.http.original_ip_detection.custom_header": "//source/extensions/http/original_ip_detection/custom_header:config", "envoy.http.original_ip_detection.xff": "//source/extensions/http/original_ip_detection/xff:config", + # + # Quic extensions + # + + "envoy.quic.crypto_stream.server.quiche": "//source/extensions/quic/crypto_stream:envoy_quic_default_crypto_server_stream", + "envoy.quic.proof_source.filter_chain": "//source/extensions/quic/proof_source:envoy_quic_default_proof_source", + } # These can be changed to ["//visibility:public"], for downstream builds which diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index 3d5ec5d6f30c..2500e09a957d 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -489,6 +489,16 @@ envoy.matching.input_matchers.consistent_hashing: - envoy.matching.input_matchers security_posture: robust_to_untrusted_downstream status: stable +envoy.quic.proof_source.filter_chain: + categories: + - envoy.quic.proof_source + security_posture: robust_to_untrusted_downstream + status: alpha +envoy.quic.crypto_stream.server.quiche: + categories: + - envoy.quic.server.crypto_stream + security_posture: robust_to_untrusted_downstream + status: alpha envoy.rate_limit_descriptors.expr: categories: - envoy.rate_limit_descriptors diff --git a/source/extensions/quic/crypto_stream/BUILD b/source/extensions/quic/crypto_stream/BUILD new file mode 100644 index 000000000000..8c919379f2c3 --- /dev/null +++ b/source/extensions/quic/crypto_stream/BUILD @@ -0,0 +1,59 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +# Extensions of QUIC crypto stream. + +envoy_extension_package() + +envoy_cc_library( + name = "envoy_quic_crypto_server_stream_lib", + srcs = ["envoy_quic_crypto_server_stream.cc"], + hdrs = ["envoy_quic_crypto_server_stream.h"], + tags = ["nofips"], + visibility = [ + "//source/common/quic:__subpackages__", + "//test:__subpackages__", + ], + deps = [ + "//source/common/quic:envoy_quic_crypto_stream_factory_lib", + "@envoy_api//envoy/extensions/quic/crypto_stream/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "envoy_quic_default_crypto_server_stream", + extra_visibility = [ + "//source/common/quic:__subpackages__", + "//test:__subpackages__", + ], + tags = ["nofips"], + deps = select( + { + "//bazel:boringssl_fips": [], + "//bazel:boringssl_disabled": [], + "//conditions:default": [ + ":envoy_quic_crypto_server_stream_lib", + ], + }, + ), +) + +envoy_cc_library( + name = "envoy_quic_crypto_client_stream_lib", + srcs = ["envoy_quic_crypto_client_stream.cc"], + hdrs = ["envoy_quic_crypto_client_stream.h"], + tags = ["nofips"], + visibility = [ + "//source/common/quic:__subpackages__", + "//test:__subpackages__", + ], + deps = [ + "//source/common/quic:envoy_quic_crypto_stream_factory_lib", + ], +) diff --git a/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.cc b/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.cc new file mode 100644 index 000000000000..da458db20eb2 --- /dev/null +++ b/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.cc @@ -0,0 +1,18 @@ +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h" + +namespace Envoy { +namespace Quic { + +std::unique_ptr +EnvoyQuicCryptoClientStreamFactoryImpl::createEnvoyQuicCryptoClientStream( + const quic::QuicServerId& server_id, quic::QuicSession* session, + std::unique_ptr verify_context, + quic::QuicCryptoClientConfig* crypto_config, + quic::QuicCryptoClientStream::ProofHandler* proof_handler, bool has_application_state) { + return std::make_unique(server_id, session, + std::move(verify_context), crypto_config, + proof_handler, has_application_state); +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h b/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h new file mode 100644 index 000000000000..7b8f12c09402 --- /dev/null +++ b/source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h @@ -0,0 +1,19 @@ +#pragma once + +#include "source/common/quic/envoy_quic_crypto_stream_factory.h" + +namespace Envoy { +namespace Quic { + +class EnvoyQuicCryptoClientStreamFactoryImpl : public EnvoyQuicCryptoClientStreamFactoryInterface { +public: + std::unique_ptr + createEnvoyQuicCryptoClientStream(const quic::QuicServerId& server_id, quic::QuicSession* session, + std::unique_ptr verify_context, + quic::QuicCryptoClientConfig* crypto_config, + quic::QuicCryptoClientStream::ProofHandler* proof_handler, + bool has_application_state) override; +}; + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.cc b/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.cc new file mode 100644 index 000000000000..282a5ad4d5bc --- /dev/null +++ b/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.cc @@ -0,0 +1,18 @@ +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h" + +namespace Envoy { +namespace Quic { + +std::unique_ptr +EnvoyQuicCryptoServerStreamFactoryImpl::createEnvoyQuicCryptoServerStream( + const quic::QuicCryptoServerConfig* crypto_config, + quic::QuicCompressedCertsCache* compressed_certs_cache, quic::QuicSession* session, + quic::QuicCryptoServerStreamBase::Helper* helper) { + return quic::CreateCryptoServerStream(crypto_config, compressed_certs_cache, session, helper); +} + +REGISTER_FACTORY(EnvoyQuicCryptoServerStreamFactoryImpl, + EnvoyQuicCryptoServerStreamFactoryInterface); + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h b/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h new file mode 100644 index 000000000000..1cf35b5c01c8 --- /dev/null +++ b/source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h @@ -0,0 +1,27 @@ +#pragma once + +#include "envoy/extensions/quic/crypto_stream/v3/crypto_stream.pb.h" +#include "envoy/registry/registry.h" + +#include "source/common/quic/envoy_quic_crypto_stream_factory.h" + +namespace Envoy { +namespace Quic { + +class EnvoyQuicCryptoServerStreamFactoryImpl : public EnvoyQuicCryptoServerStreamFactoryInterface { +public: + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() const override { return "envoy.quic.crypto_stream.server.quiche"; } + std::unique_ptr + createEnvoyQuicCryptoServerStream(const quic::QuicCryptoServerConfig* crypto_config, + quic::QuicCompressedCertsCache* compressed_certs_cache, + quic::QuicSession* session, + quic::QuicCryptoServerStreamBase::Helper* helper) override; +}; + +DECLARE_FACTORY(EnvoyQuicCryptoServerStreamFactoryImpl); + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic/proof_source/BUILD b/source/extensions/quic/proof_source/BUILD new file mode 100644 index 000000000000..87dfd8b6023b --- /dev/null +++ b/source/extensions/quic/proof_source/BUILD @@ -0,0 +1,46 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +# Extensions of QUIC proof source. + +envoy_extension_package() + +envoy_cc_library( + name = "envoy_quic_proof_source_factory_impl_lib", + srcs = ["envoy_quic_proof_source_factory_impl.cc"], + hdrs = ["envoy_quic_proof_source_factory_impl.h"], + tags = ["nofips"], + visibility = [ + "//source/common/quic:__subpackages__", + "//test:__subpackages__", + ], + deps = [ + "//source/common/quic:envoy_quic_proof_source_factory_interface", + "//source/common/quic:envoy_quic_proof_source_lib", + "@envoy_api//envoy/extensions/quic/proof_source/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "envoy_quic_default_proof_source", + extra_visibility = [ + "//source/common/quic:__subpackages__", + "//test:__subpackages__", + ], + tags = ["nofips"], + deps = select( + { + "//bazel:boringssl_fips": [], + "//bazel:boringssl_disabled": [], + "//conditions:default": [ + ":envoy_quic_proof_source_factory_impl_lib", + ], + }, + ), +) diff --git a/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.cc b/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.cc new file mode 100644 index 000000000000..3b459c4ca341 --- /dev/null +++ b/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.cc @@ -0,0 +1,16 @@ +#include "source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h" + +namespace Envoy { +namespace Quic { + +std::unique_ptr EnvoyQuicProofSourceFactoryImpl::createQuicProofSource( + Network::Socket& listen_socket, Network::FilterChainManager& filter_chain_manager, + Server::ListenerStats& listener_stats) { + return std::make_unique(listen_socket, filter_chain_manager, + listener_stats); +} + +REGISTER_FACTORY(EnvoyQuicProofSourceFactoryImpl, EnvoyQuicProofSourceFactoryInterface); + +} // namespace Quic +} // namespace Envoy diff --git a/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h b/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h new file mode 100644 index 000000000000..39384fcfbc8f --- /dev/null +++ b/source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h @@ -0,0 +1,28 @@ +#include "envoy/extensions/quic/proof_source/v3/proof_source.pb.h" +#include "envoy/registry/registry.h" + +#include "source/common/quic/envoy_quic_proof_source.h" +#include "source/common/quic/envoy_quic_proof_source_factory_interface.h" + +namespace Envoy { +namespace Quic { + +// Provides a ProofSource implementation which gets certs from filter chain. +class EnvoyQuicProofSourceFactoryImpl : public EnvoyQuicProofSourceFactoryInterface { +public: + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + + std::string name() const override { return "envoy.quic.proof_source.filter_chain"; } + + std::unique_ptr + createQuicProofSource(Network::Socket& listen_socket, + Network::FilterChainManager& filter_chain_manager, + Server::ListenerStats& listener_stats) override; +}; + +DECLARE_FACTORY(EnvoyQuicProofSourceFactoryImpl); + +} // namespace Quic +} // namespace Envoy diff --git a/test/common/quic/BUILD b/test/common/quic/BUILD index 03d1e625d5e1..943fd4b24147 100644 --- a/test/common/quic/BUILD +++ b/test/common/quic/BUILD @@ -175,6 +175,7 @@ envoy_cc_test( "//source/common/quic:envoy_quic_client_connection_lib", "//source/common/quic:envoy_quic_client_session_lib", "//source/common/quic:envoy_quic_connection_helper_lib", + "//source/extensions/quic/crypto_stream:envoy_quic_crypto_client_stream_lib", "//test/mocks/http:http_mocks", "//test/mocks/http:stream_decoder_mock", "//test/mocks/network:network_mocks", @@ -196,6 +197,8 @@ envoy_cc_test( "//source/common/quic:active_quic_listener_lib", "//source/common/quic:envoy_quic_utils_lib", "//source/common/quic:udp_gso_batch_writer_lib", + "//source/extensions/quic/crypto_stream:envoy_quic_crypto_server_stream_lib", + "//source/extensions/quic/proof_source:envoy_quic_proof_source_factory_impl_lib", "//source/server:configuration_lib", "//test/mocks/network:network_mocks", "//test/mocks/server:instance_mocks", @@ -220,6 +223,7 @@ envoy_cc_test( "//source/common/quic:envoy_quic_dispatcher_lib", "//source/common/quic:envoy_quic_proof_source_lib", "//source/common/quic:envoy_quic_server_session_lib", + "//source/extensions/quic/crypto_stream:envoy_quic_crypto_server_stream_lib", "//source/server:configuration_lib", "//test/mocks/event:event_mocks", "//test/mocks/http:http_mocks", diff --git a/test/common/quic/active_quic_listener_test.cc b/test/common/quic/active_quic_listener_test.cc index 4e356804160f..e495f07b78b6 100644 --- a/test/common/quic/active_quic_listener_test.cc +++ b/test/common/quic/active_quic_listener_test.cc @@ -43,6 +43,8 @@ #include "source/common/quic/platform/envoy_quic_clock.h" #include "source/common/quic/envoy_quic_utils.h" #include "source/common/quic/udp_gso_batch_writer.h" +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h" +#include "source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h" using testing::Return; using testing::ReturnRef; @@ -271,6 +273,14 @@ class ActiveQuicListenerTest : public QuicMultiVersionTest { default_value: true runtime_key: quic.enabled packets_to_read_to_connection_count_ratio: 50 + crypto_stream_config: + name: "envoy.quic.crypto_stream.server.quiche" + typed_config: + "@type": type.googleapis.com/envoy.extensions.quic.crypto_stream.v3.CryptoServerStreamConfig + proof_source_config: + name: "envoy.quic.proof_source.filter_chain" + typed_config: + "@type": type.googleapis.com/envoy.extensions.quic.proof_source.v3.ProofSourceConfig )EOF", connection_window_size_, stream_window_size_); } @@ -328,12 +338,14 @@ TEST_P(ActiveQuicListenerTest, FailSocketOptionUponCreation) { auto options = std::make_shared>(); options->emplace_back(std::move(option)); quic_listener_.reset(); + EnvoyQuicCryptoServerStreamFactoryImpl crypto_stream_factory; + EnvoyQuicProofSourceFactoryImpl proof_source_factory; EXPECT_THROW_WITH_REGEX((void)std::make_unique( 0, 1, *dispatcher_, connection_handler_, listen_socket_, listener_config_, quic_config_, options, false, ActiveQuicListenerFactoryPeer::runtimeEnabled( static_cast(listener_factory_.get())), - quic_stat_names_, 32u), + quic_stat_names_, 32u, crypto_stream_factory, proof_source_factory), Network::CreateListenerException, "Failed to apply socket options."); } diff --git a/test/common/quic/envoy_quic_client_session_test.cc b/test/common/quic/envoy_quic_client_session_test.cc index 1882a5bb0fb1..a9ac11d1077b 100644 --- a/test/common/quic/envoy_quic_client_session_test.cc +++ b/test/common/quic/envoy_quic_client_session_test.cc @@ -18,6 +18,8 @@ #include "source/common/quic/envoy_quic_connection_helper.h" #include "source/common/quic/envoy_quic_alarm_factory.h" #include "source/common/quic/envoy_quic_utils.h" +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_client_stream.h" + #include "test/common/quic/test_utils.h" #include "envoy/stats/stats_macros.h" @@ -74,22 +76,17 @@ class TestQuicCryptoClientStream : public quic::QuicCryptoClientStream { bool encryption_established() const override { return true; } }; -class TestEnvoyQuicClientSession : public EnvoyQuicClientSession { +class TestQuicCryptoClientStreamFactory : public EnvoyQuicCryptoClientStreamFactoryInterface { public: - TestEnvoyQuicClientSession(const quic::QuicConfig& config, - const quic::ParsedQuicVersionVector& supported_versions, - std::unique_ptr connection, - const quic::QuicServerId& server_id, - std::shared_ptr crypto_config, - quic::QuicClientPushPromiseIndex* push_promise_index, - Event::Dispatcher& dispatcher, uint32_t send_buffer_limit) - : EnvoyQuicClientSession(config, supported_versions, std::move(connection), server_id, - crypto_config, push_promise_index, dispatcher, send_buffer_limit) {} - - std::unique_ptr CreateQuicCryptoStream() override { - return std::make_unique( - server_id(), this, crypto_config()->proof_verifier()->CreateDefaultContext(), - crypto_config(), this, true); + std::unique_ptr + createEnvoyQuicCryptoClientStream(const quic::QuicServerId& server_id, quic::QuicSession* session, + std::unique_ptr verify_context, + quic::QuicCryptoClientConfig* crypto_config, + quic::QuicCryptoClientStream::ProofHandler* proof_handler, + bool has_application_state) override { + return std::make_unique(server_id, session, + std::move(verify_context), crypto_config, + proof_handler, has_application_state); } }; @@ -116,7 +113,7 @@ class EnvoyQuicClientSessionTest : public testing::TestWithParam { std::unique_ptr(quic_connection_), quic::QuicServerId("example.com", 443, false), crypto_config_, nullptr, *dispatcher_, - /*send_buffer_limit*/ 1024 * 1024), + /*send_buffer_limit*/ 1024 * 1024, crypto_stream_factory_), stats_({ALL_HTTP3_CODEC_STATS(POOL_COUNTER_PREFIX(scope_, "http3."), POOL_GAUGE_PREFIX(scope_, "http3."))}), http_connection_(envoy_quic_session_, http_connection_callbacks_, stats_, http3_options_, @@ -176,7 +173,8 @@ class EnvoyQuicClientSessionTest : public testing::TestWithParam { TestEnvoyQuicClientConnection* quic_connection_; quic::QuicConfig quic_config_; std::shared_ptr crypto_config_; - TestEnvoyQuicClientSession envoy_quic_session_; + TestQuicCryptoClientStreamFactory crypto_stream_factory_; + EnvoyQuicClientSession envoy_quic_session_; Network::MockConnectionCallbacks network_connection_callbacks_; Http::MockServerConnectionCallbacks http_connection_callbacks_; testing::StrictMock read_total_; diff --git a/test/common/quic/envoy_quic_dispatcher_test.cc b/test/common/quic/envoy_quic_dispatcher_test.cc index fe30f4cf3c32..92ef520ba44a 100644 --- a/test/common/quic/envoy_quic_dispatcher_test.cc +++ b/test/common/quic/envoy_quic_dispatcher_test.cc @@ -32,6 +32,7 @@ #include "test/common/quic/test_utils.h" #include "source/common/quic/envoy_quic_alarm_factory.h" #include "source/common/quic/envoy_quic_utils.h" +#include "source/extensions/quic/crypto_stream/envoy_quic_crypto_server_stream.h" #include "source/server/configuration_impl.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -83,7 +84,8 @@ class EnvoyQuicDispatcherTest : public QuicMultiVersionTest, std::make_unique(*dispatcher_), std::make_unique(*dispatcher_, *connection_helper_.GetClock()), quic::kQuicDefaultConnectionIdLength, connection_handler_, listener_config_, - listener_stats_, per_worker_stats_, *dispatcher_, *listen_socket_, quic_stat_names_), + listener_stats_, per_worker_stats_, *dispatcher_, *listen_socket_, quic_stat_names_, + crypto_stream_factory_), connection_id_(quic::test::TestConnectionId(1)) { auto writer = new testing::NiceMock(); envoy_quic_dispatcher_.InitializeWithWriter(writer); @@ -255,6 +257,7 @@ class EnvoyQuicDispatcherTest : public QuicMultiVersionTest, Server::PerHandlerListenerStats per_worker_stats_; QuicStatNames quic_stat_names_; Server::ConnectionHandlerImpl connection_handler_; + EnvoyQuicCryptoServerStreamFactoryImpl crypto_stream_factory_; EnvoyQuicDispatcher envoy_quic_dispatcher_; const quic::QuicConnectionId connection_id_; }; diff --git a/test/common/quic/envoy_quic_server_session_test.cc b/test/common/quic/envoy_quic_server_session_test.cc index ddcbf5641104..dd73908e3eef 100644 --- a/test/common/quic/envoy_quic_server_session_test.cc +++ b/test/common/quic/envoy_quic_server_session_test.cc @@ -122,6 +122,29 @@ class TestEnvoyQuicTlsServerHandshaker : public quic::TlsServerHandshaker, quic::QuicReferenceCountedPointer params_; }; +class EnvoyQuicTestCryptoServerStreamFactory : public EnvoyQuicCryptoServerStreamFactoryInterface { +public: + ProtobufTypes::MessagePtr createEmptyConfigProto() override { return nullptr; } + std::string name() const override { return "quic.test_crypto_server_stream"; } + + std::unique_ptr + createEnvoyQuicCryptoServerStream(const quic::QuicCryptoServerConfig* crypto_config, + quic::QuicCompressedCertsCache* compressed_certs_cache, + quic::QuicSession* session, + quic::QuicCryptoServerStreamBase::Helper* helper) override { + switch (session->connection()->version().handshake_protocol) { + case quic::PROTOCOL_QUIC_CRYPTO: + return std::make_unique(crypto_config, compressed_certs_cache, + session, helper); + case quic::PROTOCOL_TLS1_3: + return std::make_unique(session, *crypto_config); + case quic::PROTOCOL_UNSUPPORTED: + ASSERT(false, "Unknown handshake protocol"); + } + return nullptr; + } +}; + class EnvoyQuicServerSessionTest : public testing::TestWithParam { public: EnvoyQuicServerSessionTest() @@ -142,7 +165,8 @@ class EnvoyQuicServerSessionTest : public testing::TestWithParam { /*visitor=*/nullptr, &crypto_stream_helper_, &crypto_config_, &compressed_certs_cache_, *dispatcher_, /*send_buffer_limit*/ quic::kDefaultFlowControlSendWindow * 1.5, - quic_stat_names_, listener_config_.listenerScope()), + quic_stat_names_, listener_config_.listenerScope(), + crypto_stream_factory_), stats_({ALL_HTTP3_CODEC_STATS( POOL_COUNTER_PREFIX(listener_config_.listenerScope(), "http3."), POOL_GAUGE_PREFIX(listener_config_.listenerScope(), "http3."))}) { @@ -170,21 +194,6 @@ class EnvoyQuicServerSessionTest : public testing::TestWithParam { envoy_quic_session_.OnConfigNegotiated(); quic::test::QuicConfigPeer::SetNegotiated(envoy_quic_session_.config(), true); quic::test::QuicConnectionPeer::SetAddressValidated(quic_connection_); - // Switch to a encryption forward secure crypto stream. - quic::test::QuicServerSessionBasePeer::SetCryptoStream(&envoy_quic_session_, nullptr); - quic::QuicCryptoServerStreamBase* crypto_stream = nullptr; - if (quic_version_[0].handshake_protocol == quic::PROTOCOL_QUIC_CRYPTO) { - auto test_crypto_stream = new TestQuicCryptoServerStream( - &crypto_config_, &compressed_certs_cache_, &envoy_quic_session_, &crypto_stream_helper_); - crypto_stream = test_crypto_stream; - crypto_stream_ = test_crypto_stream; - } else { - auto test_crypto_stream = - new TestEnvoyQuicTlsServerHandshaker(&envoy_quic_session_, crypto_config_); - crypto_stream = test_crypto_stream; - crypto_stream_ = test_crypto_stream; - } - quic::test::QuicServerSessionBasePeer::SetCryptoStream(&envoy_quic_session_, crypto_stream); quic_connection_->SetEncrypter( quic::ENCRYPTION_FORWARD_SECURE, std::make_unique(quic::Perspective::IS_SERVER)); @@ -254,7 +263,7 @@ class EnvoyQuicServerSessionTest : public testing::TestWithParam { quic::QuicConfig quic_config_; quic::QuicCryptoServerConfig crypto_config_; testing::NiceMock crypto_stream_helper_; - ProofSourceDetailsSetter* crypto_stream_; + EnvoyQuicTestCryptoServerStreamFactory crypto_stream_factory_; TestEnvoyQuicServerSession envoy_quic_session_; quic::QuicCompressedCertsCache compressed_certs_cache_{100}; std::shared_ptr read_filter_; diff --git a/test/integration/BUILD b/test/integration/BUILD index dbea0c188ff0..5d4083e23c05 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -715,7 +715,7 @@ envoy_cc_test_library( "@envoy_api//envoy/config/listener/v3:pkg_cc_proto", ] + envoy_select_enable_http3([ "//source/common/quic:active_quic_listener_lib", - "//source/common/quic:codec_lib", + "//source/common/quic:quic_factory_lib", ]), ) @@ -1746,12 +1746,11 @@ envoy_cc_test( deps = envoy_select_enable_http3([ ":http_integration_lib", "//source/common/quic:client_connection_factory_lib", - "//source/common/quic:codec_lib", "//source/common/quic:envoy_quic_client_connection_lib", "//source/common/quic:envoy_quic_client_session_lib", "//source/common/quic:envoy_quic_connection_helper_lib", "//source/common/quic:envoy_quic_proof_verifier_lib", - "//source/common/quic:quic_transport_socket_factory_lib", + "//source/common/quic:quic_factory_lib", "//test/common/quic:quic_test_utils_for_envoy_lib", "//test/common/quic:test_utils_lib", "//test/integration/filters:encoder_decoder_buffer_filter_lib", diff --git a/test/integration/quic_http_integration_test.cc b/test/integration/quic_http_integration_test.cc index ece16e00e022..8d674f5d4849 100644 --- a/test/integration/quic_http_integration_test.cc +++ b/test/integration/quic_http_integration_test.cc @@ -110,7 +110,8 @@ class QuicHttpIntegrationTest : public HttpIntegrationTest, public QuicMultiVers *dispatcher_, // Use smaller window than the default one to have test coverage of client codec buffer // exceeding high watermark. - /*send_buffer_limit=*/2 * Http2::Utility::OptionsLimits::MIN_INITIAL_STREAM_WINDOW_SIZE); + /*send_buffer_limit=*/2 * Http2::Utility::OptionsLimits::MIN_INITIAL_STREAM_WINDOW_SIZE, + persistent_info.crypto_stream_factory_); return session; } diff --git a/tools/extensions/extensions_check.py b/tools/extensions/extensions_check.py index deae49b5b97e..fde5752799b2 100644 --- a/tools/extensions/extensions_check.py +++ b/tools/extensions/extensions_check.py @@ -49,11 +49,12 @@ "envoy.grpc_credentials", "envoy.guarddog_actions", "envoy.health_checkers", "envoy.http.stateful_header_formatters", "envoy.internal_redirect_predicates", "envoy.io_socket", "envoy.http.original_ip_detection", "envoy.matching.common_inputs", - "envoy.matching.input_matchers", "envoy.rate_limit_descriptors", "envoy.request_id", - "envoy.resource_monitors", "envoy.retry_host_predicates", "envoy.retry_priorities", - "envoy.stats_sinks", "envoy.thrift_proxy.filters", "envoy.tracers", - "envoy.transport_sockets.downstream", "envoy.transport_sockets.upstream", - "envoy.tls.cert_validator", "envoy.upstreams", "envoy.wasm.runtime") + "envoy.matching.input_matchers", "envoy.quic.proof_source", "envoy.quic.server.crypto_stream", + "envoy.rate_limit_descriptors", "envoy.request_id", "envoy.resource_monitors", + "envoy.retry_host_predicates", "envoy.retry_priorities", "envoy.stats_sinks", + "envoy.thrift_proxy.filters", "envoy.tracers", "envoy.transport_sockets.downstream", + "envoy.transport_sockets.upstream", "envoy.tls.cert_validator", "envoy.upstreams", + "envoy.wasm.runtime") EXTENSION_STATUS_VALUES = ( # This extension is stable and is expected to be production usable.