-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cert validation: use Android cert validation APIs #2525
Changes from 41 commits
f0a846a
464f365
7edc2ef
d8e9c6d
c9894a1
b1f9a04
79443ee
b40b230
93ab2ed
1e4f295
e13b72e
c8fdf91
ffa0c1b
0a8a474
9012dbb
c6cea9d
27129eb
8384259
3de8d89
658a340
403eca1
3a02268
2154876
2f1e156
e5a6bcc
47ea600
0e3d5ef
76bd20e
26b754f
c680e44
5fc2770
d9c4c0f
d485003
853667f
b76a1ad
09433c4
a481c44
406c24f
00ecfa4
66580a3
1a2cc8b
cebcea3
82f87c4
ed215f0
c4b6198
7fd388b
61ab5c8
3e9418e
34526b3
e815550
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
#include <sstream> | ||
|
||
#include "source/common/common/assert.h" | ||
|
||
#include "absl/strings/str_replace.h" | ||
#include "fmt/core.h" | ||
#include "library/common/main_interface.h" | ||
|
@@ -124,6 +126,15 @@ EngineBuilder& EngineBuilder::enableSocketTagging(bool socket_tagging_on) { | |
return *this; | ||
} | ||
|
||
EngineBuilder& | ||
EngineBuilder::enablePlatformCertificatesValidation(bool platform_certificates_validation_on) { | ||
#if defined(__APPLE__) | ||
PANIC("Certificates validation using platform provided APIs is not supported in IOS."); | ||
#endif | ||
this->platform_certificates_validation_on_ = platform_certificates_validation_on; | ||
return *this; | ||
} | ||
|
||
std::string EngineBuilder::generateConfigStr() { | ||
#if defined(__APPLE__) | ||
std::string dns_resolver_name = "envoy.network.dns_resolver.apple"; | ||
|
@@ -180,6 +191,12 @@ std::string EngineBuilder::generateConfigStr() { | |
for (const auto& [key, value] : replacements) { | ||
config_builder << "- &" << key << " " << value << std::endl; | ||
} | ||
|
||
const std::string& cert_validation_template = | ||
(this->platform_certificates_validation_on_ ? platform_cert_validation_context_template | ||
: default_cert_validation_context_template); | ||
config_builder << "- &validation_context" << cert_validation_template << std::endl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! I personally think that it is much simpler now - thank you for working on this! |
||
|
||
if (this->gzip_filter_) { | ||
absl::StrReplaceAll( | ||
{{"#{custom_filters}", absl::StrCat("#{custom_filters}\n", gzip_config_insert)}}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,20 @@ const char* brotli_config_insert = R"( | |
ignore_no_transform_header: true | ||
)"; | ||
|
||
const char* default_cert_validation_context_template = R"( | ||
- &validation_context | ||
trusted_ca: | ||
inline_string: *tls_root_certs | ||
trust_chain_verification: *trust_chain_verification | ||
)"; | ||
|
||
const char* platform_cert_validation_context_template = R"( | ||
- &validation_context | ||
custom_validator_config: | ||
name: "envoy_mobile.cert_validator.platform_bridge_cert_validator" | ||
trust_chain_verification: *trust_chain_verification | ||
)"; | ||
|
||
const char* socket_tag_config_insert = R"( | ||
- name: envoy.filters.http.socket_tag | ||
typed_config: | ||
|
@@ -142,21 +156,11 @@ R"(- &enable_drain_post_dns_refresh false | |
#include "certificates.inc" | ||
R"( | ||
|
||
!ignore tls_socket_defs: | ||
Augustyniak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- &base_tls_socket | ||
name: envoy.transport_sockets.http_11_proxy | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport | ||
transport_socket: | ||
name: envoy.transport_sockets.tls | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext | ||
common_tls_context: | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: | ||
trusted_ca: | ||
inline_string: *tls_root_certs | ||
!ignore validation_context_defs: | ||
- &validation_context | ||
trusted_ca: | ||
inline_string: *tls_root_certs | ||
trust_chain_verification: *trust_chain_verification | ||
)"; | ||
|
||
const char* config_template = R"( | ||
|
@@ -271,6 +275,42 @@ const char* config_template = R"( | |
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router | ||
|
||
!ignore tls_socket_defs: | ||
- &base_tls_socket | ||
name: envoy.transport_sockets.http_11_proxy | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport | ||
transport_socket: | ||
name: envoy.transport_sockets.tls | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext | ||
common_tls_context: | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: *validation_context | ||
- &base_h2_socket | ||
name: envoy.transport_sockets.http_11_proxy | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport | ||
transport_socket: | ||
name: envoy.transport_sockets.tls | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext | ||
common_tls_context: | ||
alpn_protocols: [h2] | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: *validation_context | ||
- &base_h3_socket | ||
name: envoy.transport_sockets.quic | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport | ||
upstream_tls_context: | ||
common_tls_context: | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: *validation_context | ||
|
||
!ignore custom_cluster_defs: | ||
stats_cluster: &stats_cluster | ||
name: stats | ||
|
@@ -408,41 +448,15 @@ R"( | |
connect_timeout: *connect_timeout | ||
lb_policy: CLUSTER_PROVIDED | ||
cluster_type: *base_cluster_type | ||
transport_socket: | ||
name: envoy.transport_sockets.http_11_proxy | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport | ||
transport_socket: | ||
name: envoy.transport_sockets.tls | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext | ||
common_tls_context: | ||
alpn_protocols: [h2] | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: | ||
trusted_ca: | ||
inline_string: *tls_root_certs | ||
trust_chain_verification: *trust_chain_verification | ||
transport_socket: *base_h2_socket | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice clean up 👍 |
||
upstream_connection_options: *upstream_opts | ||
circuit_breakers: *circuit_breakers_settings | ||
typed_extension_protocol_options: *h2_protocol_options | ||
- name: base_h3 | ||
connect_timeout: *connect_timeout | ||
lb_policy: CLUSTER_PROVIDED | ||
cluster_type: *base_cluster_type | ||
transport_socket: | ||
name: envoy.transport_sockets.quic | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport | ||
upstream_tls_context: | ||
common_tls_context: | ||
tls_params: | ||
tls_maximum_protocol_version: TLSv1_3 | ||
validation_context: | ||
trusted_ca: | ||
inline_string: *tls_root_certs | ||
trust_chain_verification: *trust_chain_verification | ||
transport_socket: *base_h3_socket | ||
upstream_connection_options: *upstream_opts | ||
circuit_breakers: *circuit_breakers_settings | ||
typed_extension_protocol_options: *h3_protocol_options | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,3 +85,15 @@ extern const char* socket_tag_config_insert; | |
* direct responses to mutate headers which are then later used for routing. | ||
*/ | ||
extern const char* route_cache_reset_filter_insert; | ||
|
||
/** | ||
* Config template which uses Envoy's built-in certificates validator to verify | ||
* certificate chain. | ||
*/ | ||
extern const char* default_cert_validation_context_template; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: comments, please There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
/** | ||
* Config template which uses platform's certificates APIs to verify certificate | ||
* chain. | ||
*/ | ||
extern const char* platform_cert_validation_context_template; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
load( | ||
"@envoy//bazel:envoy_build_system.bzl", | ||
"envoy_cc_extension", | ||
"envoy_cc_library", | ||
"envoy_extension_package", | ||
) | ||
|
||
licenses(["notice"]) # Apache 2 | ||
|
||
envoy_extension_package() | ||
|
||
envoy_cc_library( | ||
name = "c_types_lib", | ||
hdrs = ["c_types.h"], | ||
repository = "@envoy", | ||
deps = [ | ||
"//library/common/data:utility_lib", | ||
], | ||
) | ||
|
||
envoy_cc_library( | ||
name = "platform_bridge_cert_validator_lib", | ||
srcs = ["platform_bridge_cert_validator.cc"], | ||
hdrs = [ | ||
"platform_bridge_cert_validator.h", | ||
], | ||
repository = "@envoy", | ||
deps = [ | ||
":c_types_lib", | ||
"@envoy//source/extensions/transport_sockets/tls/cert_validator:cert_validator_lib", | ||
], | ||
) | ||
|
||
envoy_cc_extension( | ||
name = "config", | ||
srcs = ["config.cc"], | ||
hdrs = [ | ||
"c_types.h", | ||
"config.h", | ||
], | ||
repository = "@envoy", | ||
deps = [ | ||
":platform_bridge_cert_validator_lib", | ||
"//library/common/api:external_api_lib", | ||
"//library/common/data:utility_lib", | ||
"@envoy//envoy/registry", | ||
], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include "library/common/types/c_types.h" | ||
|
||
// NOLINT(namespace-envoy) | ||
|
||
/** | ||
* Certification validation binary result with corresponding boring SSL alert | ||
* and error details if the result indicates failure. | ||
*/ | ||
typedef struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments on all the structs/functions, please There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
envoy_status_t result; | ||
uint8_t tls_alert; | ||
const char* error_details; | ||
} envoy_cert_validation_result; | ||
|
||
#ifdef __cplusplus | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when would we expect this to be false? Asking mostly so that I understand why it's needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually don't know, but I saw this has been used in all c_types.h to wrap the C interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's necessary because the public headers are both valid C++ and pure C headers. When called publicly (e.g. from the built-in iOS and Android platform layers), they're bound as C functions. When the core layer is compiled though, everything is C++. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you @goaway 👍 |
||
extern "C" { // function pointers | ||
#endif | ||
|
||
/** | ||
* Function signature for calling into platform APIs to validate certificates. | ||
*/ | ||
typedef envoy_cert_validation_result (*envoy_validate_cert_f)(const envoy_data* certs, uint8_t size, | ||
const char* host_name); | ||
|
||
/** | ||
* Function signature for calling into platform APIs to clean up after validation completion. | ||
*/ | ||
typedef void (*envoy_release_validator_f)(); | ||
|
||
#ifdef __cplusplus | ||
} // function pointers | ||
#endif | ||
|
||
/** | ||
* A bag of function pointers to be registered in the platform registry. | ||
*/ | ||
typedef struct { | ||
envoy_validate_cert_f validate_cert; | ||
envoy_release_validator_f release_validator; | ||
} envoy_cert_validator; |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,23 @@ | ||||
#include "library/common/extensions/cert_validator/platform_bridge/config.h" | ||||
|
||||
#include "library/common/api/external.h" | ||||
|
||||
namespace Envoy { | ||||
namespace Extensions { | ||||
namespace TransportSockets { | ||||
namespace Tls { | ||||
|
||||
CertValidatorPtr PlatformBridgeCertValidatorFactory::createCertValidator( | ||||
const Envoy::Ssl::CertificateValidationContextConfig* config, SslStats& stats, | ||||
TimeSource& /*time_source*/) { | ||||
platform_validator_ = | ||||
static_cast<envoy_cert_validator*>(Api::External::retrieveApi("platform_cert_validator")); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be the bad config case. Would it make sense to throw or PANIC as this is still during start up? |
||||
return std::make_unique<PlatformBridgeCertValidator>(config, stats, platform_validator_); | ||||
} | ||||
|
||||
REGISTER_FACTORY(PlatformBridgeCertValidatorFactory, CertValidatorFactory); | ||||
|
||||
} // namespace Tls | ||||
} // namespace TransportSockets | ||||
} // namespace Extensions | ||||
} // namespace Envoy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will happen if we enable this feature on iOS? Will Envoy work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note that I did not suggest the use of
if defined(__ANDROID_API__)
even thought that would be probably more correct technically speaking. That's because it would make testing of this code harder than necessary (see #2450).If you agree with a proposed change, we can make it and drop a TODO (you can assign to me) for changing
#if defined(__APPLE__)
todefined(__ANDROID_API__)
once is addressed #2450There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize that I didn't even register the platform API in this engine. Adding it right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I moved the API registration from JniLibrary interface to JNI_OnLoad() which is also called when using C++ engine.