diff --git a/mobile/.bazelproject b/mobile/.bazelproject new file mode 100644 index 000000000000..abae58ffe896 --- /dev/null +++ b/mobile/.bazelproject @@ -0,0 +1,7 @@ +# Uncomment the examples you'd like to use! +import examples/kotlin/hello_world/.bazelproject +import examples/java/hello_world/.bazelproject +import test/kotlin/apps/baseline/.bazelproject +import test/kotlin/apps/experimental/.bazelproject + +android_sdk_platform: android-31 diff --git a/mobile/.bazelrc b/mobile/.bazelrc index c1581d320d11..242fa4760b0b 100644 --- a/mobile/.bazelrc +++ b/mobile/.bazelrc @@ -101,7 +101,7 @@ build:tsan-dev --test_env="TSAN_OPTIONS=report_atomic_races=0" build:release-common --define=no_debug_info=1 # Compile releases optimizing for size (eg -Os, etc). -build:release-common --config=sizeopt +build:release-common --config=sizeopt --define=admin_functionality=disabled # Set default symbols visibility to hidden to reduce .dynstr and the symbol table size build:release-common --copt=-fvisibility=hidden diff --git a/mobile/dist/envoy-pom.xml b/mobile/dist/envoy-pom.xml deleted file mode 100755 index e98f5e184aa5..000000000000 --- a/mobile/dist/envoy-pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - 4.0.0 - - io.envoyproxy.envoymobile - envoy - LOCAL-SNAPSHOT - aar - - - - - Envoy Mobile - Client networking libraries based on the Envoy project. - https://github.com/envoyproxy/envoy-mobile - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - buildbreaker - Alan Chiu - awlchiu@gmail.com - - - rebello95 - Michael Rebello - me@michaelrebello.com - - - junr03 - Jose Ulises Nino Rivera - jnino@lyft.com - - - goaway - Mike Schore - mike.schore@gmail.com - - - - https://github.com/envoyproxy/envoy-mobile - scm:git:git@github.com:envoyproxy/envoy-mobile.git - scm:git:git@github.com:envoyproxy/envoy-mobile.git - HEAD - - - diff --git a/mobile/dist/envoy.aar b/mobile/dist/envoy.aar deleted file mode 100755 index be7f3ff691fa..000000000000 Binary files a/mobile/dist/envoy.aar and /dev/null differ diff --git a/mobile/docs/root/intro/version_history.rst b/mobile/docs/root/intro/version_history.rst index e732e84f4453..bfb3119212f4 100644 --- a/mobile/docs/root/intro/version_history.rst +++ b/mobile/docs/root/intro/version_history.rst @@ -10,6 +10,7 @@ Breaking changes: - build: building on macOS now requires Xcode 14.1. (:issue:`#2664 <2664>`) - iOS: remove experimental option to force all connections to use IPv6. - kotlin: always use ``getaddrinfo`` DNS resolver. Remove ``addDNSFallbackNameservers``, ``enableDNSFilterUnroutableFamilies``, and ``enableDNSUseSystemResolver`` methods from the Kotlin engine builder. (:issue:`#2618 <2618>`) +- Envoy Mobile's release builds compile without admin support by default. (``--define=admin_functionality=disabled``) (:issue`#2693 <2693>`) Bugfixes: diff --git a/mobile/experimental/swift/QUICStreamTest.swift b/mobile/experimental/swift/QUICStreamTest.swift new file mode 100644 index 000000000000..f4e941c87b0a --- /dev/null +++ b/mobile/experimental/swift/QUICStreamTest.swift @@ -0,0 +1,189 @@ +import Envoy +import EnvoyEngine +import Foundation +import XCTest + +final class QUICStreamTests: XCTestCase { + func testQUICStream() throws { + // swiftlint:disable:next line_length + let hcmType = "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager" + // swiftlint:disable:next line_length + let quicDownstreamType = "type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport" + // swiftlint:disable:next line_length + let quicUpstreamType = "type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport" + let config = + """ + static_resources: + listeners: + - name: h3_remote_listener + address: + socket_address: { protocol: UDP, address: 127.0.0.1, port_value: 10101 } + reuse_port: true + udp_listener_config: + quic_options: {} + downstream_socket_config: + prefer_gro: true + filter_chains: + transport_socket: + name: envoy.transport_sockets.quic + typed_config: + "@type": \(quicDownstreamType) + downstream_tls_context: + common_tls_context: + alpn_protocols: h3 + tls_certificates: + certificate_chain: + inline_string: | + -----BEGIN CERTIFICATE----- + MIIEbDCCA1SgAwIBAgIUJuVBh0FKfFgIcO++ljWm7D47eYUwDQYJKoZIhvcNAQEL + BQAwdjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM + DVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsMEEx5ZnQgRW5n + aW5lZXJpbmcxEDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMjAwODA1MTkxNjAxWhcNMjIw + ODA1MTkxNjAxWjCBpjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx + FjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBEx5ZnQxGTAXBgNVBAsM + EEx5ZnQgRW5naW5lZXJpbmcxGjAYBgNVBAMMEVRlc3QgQmFja2VuZCBUZWFtMSQw + IgYJKoZIhvcNAQkBFhViYWNrZW5kLXRlYW1AbHlmdC5jb20wggEiMA0GCSqGSIb3 + DQEBAQUAA4IBDwAwggEKAoIBAQC9JgaI7hxjPM0tsUna/QmivBdKbCrLnLW9Teak + RH/Ebg68ovyvrRIlybDT6XhKi+iVpzVY9kqxhGHgrFDgGLBakVMiYJ5EjIgHfoo4 + UUAHwIYbunJluYCgANzpprBsvTC/yFYDVMqUrjvwHsoYYVm36io994k9+t813b70 + o0l7/PraBsKkz8NcY2V2mrd/yHn/0HAhv3hl6iiJme9yURuDYQrae2ACSrQtsbel + KwdZ/Re71Z1awz0OQmAjMa2HuCop+Q/1QLnqBekT5+DH1qKUzJ3Jkq6NRkERXOpi + 87j04rtCBteCogrO67qnuBZ2lH3jYEMb+lQdLkyNMLltBSdLAgMBAAGjgcAwgb0w + DAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIG + CCsGAQUFBwMBMEEGA1UdEQQ6MDiGHnNwaWZmZTovL2x5ZnQuY29tL2JhY2tlbmQt + dGVhbYIIbHlmdC5jb22CDHd3dy5seWZ0LmNvbTAdBgNVHQ4EFgQU2XcTZbc0xKZf + gNVKSvAbMZJCBoYwHwYDVR0jBBgwFoAUlkvaLFO0vpXGk3Pip6SfLg1yGIcwDQYJ + KoZIhvcNAQELBQADggEBAFW05aca3hSiEz/g593GAV3XP4lI5kYUjGjbPSy/HmLr + rdv/u3bGfacywAPo7yld+arMzd35tIYEqnhoq0+/OxPeyhwZXVVUatg5Oknut5Zv + 2+8l+mVW+8oFCXRqr2gwc8Xt4ByYN+HaNUYfoucnjDplOPukkfSuRhbxqnkhA14v + Lri2EbISX14sXf2VQ9I0dkm1hXUxiO0LlA1Z7tvJac9zPSoa6Oljke4D1iH2jzwF + Yn7S/gGvVQgkTmWrs3S3TGyBDi4GTDhCF1R+ESvXz8z4UW1MrCSdYUXbRtsT7sbE + CjlFYuUyxCi1oe3IHCeXVDo/bmzwGQPDuF3WaDNSYWU= + -----END CERTIFICATE----- + private_key: + inline_string: | + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAvSYGiO4cYzzNLbFJ2v0JorwXSmwqy5y1vU3mpER/xG4OvKL8 + r60SJcmw0+l4Sovolac1WPZKsYRh4KxQ4BiwWpFTImCeRIyIB36KOFFAB8CGG7py + ZbmAoADc6aawbL0wv8hWA1TKlK478B7KGGFZt+oqPfeJPfrfNd2+9KNJe/z62gbC + pM/DXGNldpq3f8h5/9BwIb94ZeooiZnvclEbg2EK2ntgAkq0LbG3pSsHWf0Xu9Wd + WsM9DkJgIzGth7gqKfkP9UC56gXpE+fgx9ailMydyZKujUZBEVzqYvO49OK7QgbX + gqIKzuu6p7gWdpR942BDG/pUHS5MjTC5bQUnSwIDAQABAoIBADEMwlcSAFSPuNln + hzJ9udj0k8md4T8p5Usw/2WLyeJDdBjg30wjQniAJBXgDmyueWMNmFz4iYgdP1CG + /vYOEPV7iCZ7Da/TDZd77hYKo+MevuhD4lSU1VEoyCDjNA8OxKyHJB77BwmlYS+0 + nE3UOPLji47EOVfUTbvnRBSmn3DCSHkQiRIUP1xMivoiZgKJn+D+FxSMwwiq2pQR + 5tdo7nh2A8RxlYUbaD6i4poUB26HVm8vthXahNEkLpXQOz8MWRzs6xOdDHRzi9kT + ItRLa4A/3LIATqviQ2EpwcALHXcULcNUMTHORC1EHPvheWR5nLuRllYzN4ReoeHC + 3+A5KEkCgYEA52rlh/22/rLckCWugjyJic17vkg46feSOGhjuP2LelrIxNlg491y + o28n8lQPSVnEp3/sT7Y3quVvdboq4DC9LTzq52f6/mCYh9UQRpljuSmFqC2MPG46 + Zl5KLEVLzhjC8aTWkhVINSpz9vauXderOpFYlPW32lnRTjJWE276kj8CgYEA0T2t + ULnn7TBvRSpmeWzEBA5FFo2QYkYvwrcVe0pfUltV6pf05xUmMXYFjpezSTEmPhh6 + +dZdhwxDk+6j8Oo61rTWucDsIqMj5ZT1hPNph8yQtb5LRlRbLGVrirU9Tp7xTgMq + 3uRA2Eka1d98dDBsEbMIVFSZ2MX3iezSGRL6j/UCgYEAxZQ82HjEDn2DVwb1EXjC + LQdliTZ8cTXQf5yQ19aRiSuNkpPN536ga+1xe7JNQuEDx8auafg3Ww98tFT4WmUC + f2ctX9klMJ4kXISK2twHioVq+gW5X7b04YXLajTX3eTCPDHyiNLmzY2raMWAZdrG + 9MA3kyafjCt3Sn4rg3gTM10CgYEAtJ8WRpJEd8aQttcUIItYZdvfnclUMtE9l0su + GwCnalN3xguol/X0w0uLHn0rgeoQhhfhyFtY3yQiDcg58tRvODphBXZZIMlNSnic + vEjW9ygKXyjGmA5nqdpezB0JsB2aVep8Dm5g35Ozu52xNCc8ksbGUO265Jp3xbMN + 5iEw9CUCgYBmfoPnJwzA5S1zMIqESUdVH6p3UwHU/+XTY6JHAnEVsE+BuLe3ioi7 + 6dU4rFd845MCkunBlASLV8MmMbod9xU0vTVHPtmANaUCPxwUIxXQket09t19Dzg7 + A23sE+5myXtcfz6YrPhbLkijV4Nd7fmecodwDckvpBaWTMrv52/Www== + -----END RSA PRIVATE KEY----- + filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": \(hcmType) + codec_type: HTTP3 + stat_prefix: remote_hcm + route_config: + name: remote_route + virtual_hosts: + - name: remote_service + domains: ["*"] + routes: + - match: { prefix: "/" } + direct_response: { status: 200 } + http3_protocol_options: + http_filters: + - name: envoy.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + - name: base_api_listener + address: + socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 } + api_listener: + api_listener: + "@type": \(hcmType) + stat_prefix: api_hcm + route_config: + name: api_router + virtual_hosts: + - name: api + domains: ["*"] + routes: + - match: { prefix: "/" } + route: { host_rewrite_literal: lyft.com, cluster: h3_remote } + http_filters: + - name: envoy.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + clusters: + - name: h3_remote + connect_timeout: 10s + type: STATIC + dns_lookup_family: V4_ONLY + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: h3_remote + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: { address: 127.0.0.1, port_value: 10101 } + typed_extension_protocol_options: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicit_http_config: + http3_protocol_options: {} + common_http_protocol_options: + idle_timeout: 1s + transport_socket: + name: envoy.transport_sockets.quic + typed_config: + "@type": \(quicUpstreamType) + upstream_tls_context: + sni: lyft.com + """ + let expectation = self.expectation(description: "Complete response received.") + + let client = EngineBuilder(yaml: config) + .addLogLevel(.trace) + .build() + .streamClient() + + let requestHeaders = RequestHeadersBuilder(method: .get, scheme: "https", + authority: "lyft.com", path: "/test") + .build() + + client + .newStreamPrototype() + .setOnResponseHeaders { responseHeaders, endStream, _ in + XCTAssertEqual(200, responseHeaders.httpStatus) + if endStream { + expectation.fulfill() + } + } + .setOnResponseData { _, endStream, _ in + if endStream { + expectation.fulfill() + } + } + .setOnError { _, _ in + XCTFail("Unexpected error") + } + .start() + .sendHeaders(requestHeaders, endStream: true) + + XCTAssertEqual(XCTWaiter.wait(for: [expectation], timeout: 1), .completed) + } +} diff --git a/mobile/library/cc/engine_builder.cc b/mobile/library/cc/engine_builder.cc index 7133c398104e..35fcda4fc669 100644 --- a/mobile/library/cc/engine_builder.cc +++ b/mobile/library/cc/engine_builder.cc @@ -70,8 +70,7 @@ EngineBuilder& EngineBuilder::addDnsQueryTimeoutSeconds(int dns_query_timeout_se return *this; } -EngineBuilder& -EngineBuilder::addDnsPreresolveHostnames(std::string dns_preresolve_hostnames) { +EngineBuilder& EngineBuilder::addDnsPreresolveHostnames(std::string dns_preresolve_hostnames) { this->dns_preresolve_hostnames_ = std::move(dns_preresolve_hostnames); return *this; } @@ -207,8 +206,7 @@ EngineBuilder& EngineBuilder::addStringAccessor(std::string name, return *this; } -EngineBuilder& EngineBuilder::addNativeFilter(std::string name, - std::string typed_config) { +EngineBuilder& EngineBuilder::addNativeFilter(std::string name, std::string typed_config) { native_filter_chain_.emplace_back(std::move(name), std::move(typed_config)); return *this; } diff --git a/mobile/library/cc/headers_builder.cc b/mobile/library/cc/headers_builder.cc index a28cc69731af..12a30442e91a 100644 --- a/mobile/library/cc/headers_builder.cc +++ b/mobile/library/cc/headers_builder.cc @@ -11,12 +11,11 @@ HeadersBuilder& HeadersBuilder::add(std::string name, std::string value) { return *this; } -HeadersBuilder& HeadersBuilder::set(std::string name, - std::vector values) { +HeadersBuilder& HeadersBuilder::set(std::string name, std::vector values) { if (this->isRestrictedHeader(name)) { return *this; } - this->headers_[std::move(name)] = values; + this->headers_[std::move(name)] = std::move(values); return *this; } @@ -30,8 +29,7 @@ HeadersBuilder& HeadersBuilder::remove(const std::string& name) { HeadersBuilder::HeadersBuilder() {} -HeadersBuilder& HeadersBuilder::internalSet(std::string name, - std::vector values) { +HeadersBuilder& HeadersBuilder::internalSet(std::string name, std::vector values) { this->headers_[std::move(name)] = std::move(values); return *this; } diff --git a/mobile/library/cc/request_headers_builder.cc b/mobile/library/cc/request_headers_builder.cc index 595e66f891b0..7302dd579098 100644 --- a/mobile/library/cc/request_headers_builder.cc +++ b/mobile/library/cc/request_headers_builder.cc @@ -3,10 +3,8 @@ namespace Envoy { namespace Platform { -RequestHeadersBuilder::RequestHeadersBuilder(RequestMethod request_method, - std::string scheme, - std::string authority, - std::string path) { +RequestHeadersBuilder::RequestHeadersBuilder(RequestMethod request_method, std::string scheme, + std::string authority, std::string path) { this->internalSet(":method", {requestMethodToString(request_method)}); this->internalSet(":scheme", {std::move(scheme)}); this->internalSet(":authority", {std::move(authority)}); diff --git a/mobile/library/cc/request_headers_builder.h b/mobile/library/cc/request_headers_builder.h index 6fe0f44c96f3..c5bc245b1ad3 100644 --- a/mobile/library/cc/request_headers_builder.h +++ b/mobile/library/cc/request_headers_builder.h @@ -16,8 +16,8 @@ struct RetryPolicy; class RequestHeadersBuilder : public HeadersBuilder { public: - RequestHeadersBuilder(RequestMethod request_method, std::string scheme, - std::string authority, std::string path); + RequestHeadersBuilder(RequestMethod request_method, std::string scheme, std::string authority, + std::string path); RequestHeadersBuilder& addRetryPolicy(const RetryPolicy& retry_policy); RequestHeadersBuilder& addUpstreamHttpProtocol(UpstreamHttpProtocol upstream_http_protocol); diff --git a/mobile/library/common/extensions/cert_validator/platform_bridge/c_types.h b/mobile/library/common/extensions/cert_validator/platform_bridge/c_types.h index 3925ebe13bfb..cfaf4c036c9b 100644 --- a/mobile/library/common/extensions/cert_validator/platform_bridge/c_types.h +++ b/mobile/library/common/extensions/cert_validator/platform_bridge/c_types.h @@ -25,9 +25,9 @@ typedef envoy_cert_validation_result (*envoy_validate_cert_f)(const envoy_data* const char* host_name); /** - * Function signature for calling into platform APIs to clean up after validation completion. + * Function signature for calling into platform APIs to clean up after validation is complete. */ -typedef void (*envoy_release_validator_f)(); +typedef void (*envoy_validation_cleanup_f)(); #ifdef __cplusplus } // function pointers @@ -38,5 +38,5 @@ typedef void (*envoy_release_validator_f)(); */ typedef struct { envoy_validate_cert_f validate_cert; - envoy_release_validator_f release_validator; + envoy_validation_cleanup_f validation_cleanup; } envoy_cert_validator; diff --git a/mobile/library/common/extensions/cert_validator/platform_bridge/config.h b/mobile/library/common/extensions/cert_validator/platform_bridge/config.h index 435f5bc949a6..46ae690785c1 100644 --- a/mobile/library/common/extensions/cert_validator/platform_bridge/config.h +++ b/mobile/library/common/extensions/cert_validator/platform_bridge/config.h @@ -2,6 +2,7 @@ #include "source/extensions/transport_sockets/tls/cert_validator/factory.h" +#include "library/common/extensions/cert_validator/platform_bridge/platform_bridge.pb.h" #include "library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.h" #include "library/common/extensions/cert_validator/platform_bridge/platform_bridge.pb.h" @@ -10,7 +11,9 @@ namespace Extensions { namespace TransportSockets { namespace Tls { + class PlatformBridgeCertValidatorFactory : public CertValidatorFactory, public Config::TypedFactory { + public: CertValidatorPtr createCertValidator(const Envoy::Ssl::CertificateValidationContextConfig* config, SslStats& stats, TimeSource& time_source) override; @@ -19,6 +22,7 @@ class PlatformBridgeCertValidatorFactory : public CertValidatorFactory, public C return "envoy_mobile.cert_validator.platform_bridge_cert_validator"; } ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); } std::string category() const override { return "envoy.tls.cert_validator"; } diff --git a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge.proto b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge.proto index c56bcbe72364..e44e0131512a 100644 --- a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge.proto +++ b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge.proto @@ -2,4 +2,5 @@ syntax = "proto3"; package envoy_mobile.extensions.cert_validator.platform_bridge; -message PlatformBridgeCertValidator {} +message PlatformBridgeCertValidator { +} diff --git a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.cc b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.cc index b4e025445af1..4f1d366d0e46 100644 --- a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.cc +++ b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.cc @@ -14,15 +14,14 @@ namespace Tls { PlatformBridgeCertValidator::PlatformBridgeCertValidator( const Envoy::Ssl::CertificateValidationContextConfig* config, SslStats& stats, const envoy_cert_validator* platform_validator) - : config_(config), stats_(stats), platform_validator_(platform_validator) { + : allow_untrusted_certificate_(config != nullptr && + config->trustChainVerification() == + envoy::extensions::transport_sockets::tls::v3:: + CertificateValidationContext::ACCEPT_UNTRUSTED), + platform_validator_(platform_validator), stats_(stats) { ENVOY_BUG(config != nullptr && config->caCert().empty() && config->certificateRevocationList().empty(), "Invalid certificate validation context config."); - if (config_ != nullptr) { - allow_untrusted_certificate_ = config_->trustChainVerification() == - envoy::extensions::transport_sockets::tls::v3:: - CertificateValidationContext::ACCEPT_UNTRUSTED; - } } PlatformBridgeCertValidator::~PlatformBridgeCertValidator() { @@ -34,17 +33,12 @@ PlatformBridgeCertValidator::~PlatformBridgeCertValidator() { } } -int PlatformBridgeCertValidator::initializeSslContexts(std::vector /*contexts*/, - bool /*handshaker_provides_certificates*/) { - return SSL_VERIFY_PEER; -} - ValidationResults PlatformBridgeCertValidator::doVerifyCertChain( STACK_OF(X509) & cert_chain, Ssl::ValidateResultCallbackPtr callback, Ssl::SslExtendedSocketInfo* ssl_extended_info, const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options, SSL_CTX& /*ssl_ctx*/, const CertValidator::ExtraValidationContext& /*validation_context*/, - bool is_server, absl::string_view host_name) { + bool is_server, absl::string_view hostname) { ASSERT(!is_server); if (sk_X509_num(&cert_chain) == 0) { if (ssl_extended_info) { @@ -78,30 +72,37 @@ ValidationResults PlatformBridgeCertValidator::doVerifyCertChain( !transport_socket_options->verifySubjectAltNameListOverride().empty()) { host = transport_socket_options->verifySubjectAltNameListOverride()[0]; } else { - host = host_name; + host = hostname; + } + + std::vector subject_alt_names; + if (transport_socket_options != nullptr) { + subject_alt_names = transport_socket_options->verifySubjectAltNameListOverride(); + } else { + subject_alt_names = {std::string(hostname)}; } - PendingValidation validation(*this, std::move(certs), host, std::move(transport_socket_options), - std::move(callback)); - auto insert_result = validations_.insert(std::move(validation)); - ASSERT(insert_result.second); - PendingValidation& ref = const_cast(*insert_result.first); - std::thread verification_thread(&PendingValidation::verifyCertsByPlatform, &ref); + + auto validation = std::make_unique( + *this, std::move(certs), host, std::move(subject_alt_names), std::move(callback)); + PendingValidation* validation_ptr = validation.get(); + validations_.insert(std::move(validation)); + std::thread verification_thread(&PendingValidation::verifyCertsByPlatform, validation_ptr); std::thread::id thread_id = verification_thread.get_id(); validation_threads_[thread_id] = std::move(verification_thread); return {ValidationResults::ValidationStatus::Pending, absl::nullopt, absl::nullopt}; } void PlatformBridgeCertValidator::verifyCertChainByPlatform( - std::vector& cert_chain, const std::string& host_name, + const std::vector& cert_chain, const std::string& hostname, const std::vector& subject_alt_names, PendingValidation& pending_validation) { ASSERT(!cert_chain.empty()); - ENVOY_LOG(trace, "Start verifyCertChainByPlatform for host {}", host_name); + ENVOY_LOG(trace, "Start verifyCertChainByPlatform for host {}", hostname); // This is running in a stand alone thread other than the engine thread. envoy_data leaf_cert_der = cert_chain[0]; bssl::UniquePtr leaf_cert(d2i_X509( nullptr, const_cast(&leaf_cert_der.bytes), leaf_cert_der.length)); envoy_cert_validation_result result = - platform_validator_->validate_cert(cert_chain.data(), cert_chain.size(), host_name.c_str()); + platform_validator_->validate_cert(cert_chain.data(), cert_chain.size(), hostname.c_str()); bool success = result.result == ENVOY_SUCCESS; if (!success) { ENVOY_LOG(debug, result.error_details); @@ -127,40 +128,37 @@ void PlatformBridgeCertValidator::verifyCertChainByPlatform( } void PlatformBridgeCertValidator::PendingValidation::verifyCertsByPlatform() { - parent_.verifyCertChainByPlatform( - certs_, host_name_, - (transport_socket_options_ != nullptr - ? transport_socket_options_->verifySubjectAltNameListOverride() - : std::vector{host_name_}), - *this); + parent_.verifyCertChainByPlatform(certs_, hostname_, subject_alt_names_, *this); } void PlatformBridgeCertValidator::PendingValidation::postVerifyResultAndCleanUp( bool success, absl::string_view error_details, uint8_t tls_alert, OptRef error_counter) { + ENVOY_LOG(trace, + "Finished platform cert validation for {}, post result callback to network thread", + hostname_); + + if (parent_.platform_validator_->validation_cleanup) { + parent_.platform_validator_->validation_cleanup(); + } std::weak_ptr weak_alive_indicator(parent_.alive_indicator_); + + // Once this task runs, `this` will be deleted so this must be the last statement in the file. result_callback_->dispatcher().post([this, weak_alive_indicator, success, error = std::string(error_details), tls_alert, error_counter, thread_id = std::this_thread::get_id()]() { if (weak_alive_indicator.expired()) { return; } - ENVOY_LOG(trace, "Got validation result for {} from platform", host_name_); + ENVOY_LOG(trace, "Got validation result for {} from platform", hostname_); parent_.validation_threads_[thread_id].join(); parent_.validation_threads_.erase(thread_id); if (error_counter.has_value()) { const_cast(error_counter.ref()).inc(); } result_callback_->onCertValidationResult(success, error, tls_alert); - parent_.validations_.erase(*this); + parent_.validations_.erase(this); }); - ENVOY_LOG(trace, - "Finished platform cert validation for {}, post result callback to network thread", - host_name_); - - if (parent_.platform_validator_->release_validator) { - parent_.platform_validator_->release_validator(); - } } } // namespace Tls diff --git a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.h b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.h index ffa0c23fd90b..dc31d2dfeaed 100644 --- a/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.h +++ b/mobile/library/common/extensions/cert_validator/platform_bridge/platform_bridge_cert_validator.h @@ -56,63 +56,53 @@ class PlatformBridgeCertValidator : public CertValidator, Logger::Loggable contexts, - bool handshaker_provides_certificates) override; + absl::string_view hostname) override; + // Returns SSL_VERIFY_PEER so that doVerifyCertChain() will be called from the TLS stack. + int initializeSslContexts(std::vector /*contexts*/, + bool /*handshaker_provides_certificates*/) override { + return SSL_VERIFY_PEER; + } private: class PendingValidation { public: PendingValidation(PlatformBridgeCertValidator& parent, std::vector certs, - absl::string_view host_name, - const Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + absl::string_view hostname, std::vector subject_alt_names, Ssl::ValidateResultCallbackPtr result_callback) - : parent_(parent), certs_(std::move(certs)), host_name_(host_name), - result_callback_(std::move(result_callback)), - transport_socket_options_(std::move(transport_socket_options)) {} + : parent_(parent), certs_(std::move(certs)), hostname_(hostname), + subject_alt_names_(std::move(subject_alt_names)), + result_callback_(std::move(result_callback)) {} + + // Ensure that this class is never moved or copied to guarantee pointer stability. + PendingValidation(const PendingValidation&) = delete; + PendingValidation(PendingValidation&&) = delete; + // Calls into platform APIs in a stand-alone thread to verify the given certs. + // Once the validation is done, the result will be posted back to the current + // thread to trigger callback and update verify stats. void verifyCertsByPlatform(); void postVerifyResultAndCleanUp(bool success, absl::string_view error_details, uint8_t tls_alert, OptRef error_counter); - struct Hash { - size_t operator()(const PendingValidation& p) const { - return reinterpret_cast(p.result_callback_.get()); - } - }; - struct Eq { - bool operator()(const PendingValidation& a, const PendingValidation& b) const { - return a.result_callback_.get() == b.result_callback_.get(); - } - }; - private: - Event::SchedulableCallbackPtr next_iteration_callback_; PlatformBridgeCertValidator& parent_; - std::vector certs_; - std::string host_name_; + const std::vector certs_; + const std::string hostname_; + const std::vector subject_alt_names_; Ssl::ValidateResultCallbackPtr result_callback_; - const Network::TransportSocketOptionsConstSharedPtr transport_socket_options_; }; - // Calls into platform APIs in a stand-alone thread to verify the given certs. - // Once the validation is done, the result will be posted back to the current - // thread to trigger callback and update verify stats. - void verifyCertChainByPlatform(std::vector& cert_chain, const std::string& host_name, + void verifyCertChainByPlatform(const std::vector& cert_chain, + const std::string& hostname, const std::vector& subject_alt_names, PendingValidation& pending_validation); - const Envoy::Ssl::CertificateValidationContextConfig* config_; - SslStats& stats_; - bool allow_untrusted_certificate_ = false; - // latches the platform extension API. + const bool allow_untrusted_certificate_; const envoy_cert_validator* platform_validator_; + SslStats& stats_; absl::flat_hash_map validation_threads_; - absl::flat_hash_set - validations_; + absl::flat_hash_set> validations_; std::shared_ptr alive_indicator_{new size_t(1)}; }; diff --git a/mobile/library/common/jni/android_network_utility.cc b/mobile/library/common/jni/android_network_utility.cc index 8711728646fc..7842835048a5 100644 --- a/mobile/library/common/jni/android_network_utility.cc +++ b/mobile/library/common/jni/android_network_utility.cc @@ -144,6 +144,6 @@ static envoy_cert_validation_result verify_x509_cert_chain(const envoy_data* cer envoy_cert_validator* get_android_cert_validator_api() { envoy_cert_validator* api = (envoy_cert_validator*)safe_malloc(sizeof(envoy_cert_validator)); api->validate_cert = verify_x509_cert_chain; - api->release_validator = jvm_detach_thread; + api->validation_cleanup = jvm_detach_thread; return api; } diff --git a/mobile/library/common/network/apple_platform_cert_verifier.cc b/mobile/library/common/network/apple_platform_cert_verifier.cc index 26fcb50e2ac8..e77b693cca86 100644 --- a/mobile/library/common/network/apple_platform_cert_verifier.cc +++ b/mobile/library/common/network/apple_platform_cert_verifier.cc @@ -111,7 +111,7 @@ extern "C" { void register_apple_platform_cert_verifier() { envoy_cert_validator* api = (envoy_cert_validator*)safe_malloc(sizeof(envoy_cert_validator)); api->validate_cert = verify_cert; - api->release_validator = NULL; + api->validation_cleanup = NULL; register_platform_api("platform_cert_validator", api); } diff --git a/mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt b/mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt index b1121f166516..e1e2ef0a1bf1 100644 --- a/mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt +++ b/mobile/library/kotlin/io/envoyproxy/envoymobile/EngineBuilder.kt @@ -560,6 +560,9 @@ open class EngineBuilder( * used for development/debugging purposes only. Enabling it in production may open * your app to security vulnerabilities. * + * Note this will not work with the default production build, as it builds with admin + * functionality disabled via --define=admin_functionality=disabled + * * @return this builder. */ fun enableAdminInterface(): EngineBuilder { diff --git a/mobile/library/proguard.txt b/mobile/library/proguard.txt index fa5602b64dcd..bf717065f448 100644 --- a/mobile/library/proguard.txt +++ b/mobile/library/proguard.txt @@ -15,6 +15,10 @@ ; } +-keep, includedescriptorclasses class org.chromium.net.AndroidCertVerifyResult { + ; +} + -keep, includedescriptorclasses class io.envoyproxy.envoymobile.engine.types.EnvoyEventTracker { ; } diff --git a/mobile/library/swift/EngineBuilder.swift b/mobile/library/swift/EngineBuilder.swift index 450b756a3aa9..98248dd9863b 100644 --- a/mobile/library/swift/EngineBuilder.swift +++ b/mobile/library/swift/EngineBuilder.swift @@ -487,6 +487,9 @@ open class EngineBuilder: NSObject { /// used for development/debugging purposes only. Enabling it in production may open /// your app to security vulnerabilities. /// + /// Note this will not work with the default production build, as it builds with admin + /// functionality disabled via --define=admin_functionality=disabled + /// /// - returns: This builder. @discardableResult public func enableAdminInterface() -> Self { diff --git a/mobile/test/common/integration/base_client_integration_test.cc b/mobile/test/common/integration/base_client_integration_test.cc index d7665187ac9d..7ac8701454d2 100644 --- a/mobile/test/common/integration/base_client_integration_test.cc +++ b/mobile/test/common/integration/base_client_integration_test.cc @@ -6,8 +6,10 @@ #include "gtest/gtest.h" #include "library/cc/bridge_utility.h" +#include "library/cc/log_level.h" #include "library/common/config/internal.h" #include "library/common/http/header_utility.h" +#include "spdlog/spdlog.h" namespace Envoy { namespace { @@ -52,6 +54,31 @@ std::string defaultConfig() { return config_str; } +// Gets the spdlog level from the test options and converts it to the Platform::LogLevel used by +// the Envoy Mobile engine. +Platform::LogLevel getPlatformLogLevelFromOptions() { + switch (TestEnvironment::getOptions().logLevel()) { + case spdlog::level::level_enum::trace: + return Platform::LogLevel::trace; + case spdlog::level::level_enum::debug: + return Platform::LogLevel::debug; + case spdlog::level::level_enum::info: + return Platform::LogLevel::info; + case spdlog::level::level_enum::warn: + return Platform::LogLevel::warn; + case spdlog::level::level_enum::err: + return Platform::LogLevel::error; + case spdlog::level::level_enum::critical: + return Platform::LogLevel::critical; + case spdlog::level::level_enum::off: + return Platform::LogLevel::off; + default: + ENVOY_LOG_MISC(warn, "Couldn't map spdlog level {}. Using `info` level.", + TestEnvironment::getOptions().logLevel()); + return Platform::LogLevel::info; + } +} + } // namespace BaseClientIntegrationTest::BaseClientIntegrationTest(Network::Address::IpVersion ip_version) @@ -61,6 +88,8 @@ BaseClientIntegrationTest::BaseClientIntegrationTest(Network::Address::IpVersion use_lds_ = false; autonomous_upstream_ = true; defer_listener_finalization_ = true; + + addLogLevel(getPlatformLogLevelFromOptions()); } void BaseClientIntegrationTest::initialize() { diff --git a/mobile/test/common/integration/rtds_integration_test.cc b/mobile/test/common/integration/rtds_integration_test.cc index 720e4843e3dd..67f39cf31944 100644 --- a/mobile/test/common/integration/rtds_integration_test.cc +++ b/mobile/test/common/integration/rtds_integration_test.cc @@ -20,8 +20,6 @@ envoy::config::bootstrap::v3::LayeredRuntime layeredRuntimeConfig(const std::str rtds_layer: name: some_rtds_layer rtds_config: - # TODO(abeyad): Remove the initial_fetch_timeout when - # https://github.com/envoyproxy/envoy-mobile/issues/2678 is fixed. initial_fetch_timeout: seconds: 1 resource_api_version: V3 @@ -96,6 +94,8 @@ TEST_P(RtdsIntegrationTest, RtdsReload) { )EOF"); sendDiscoveryResponse( Config::TypeUrl::get().Runtime, {some_rtds_layer}, {some_rtds_layer}, {}, "1"); + // Wait until the RTDS updates from the DiscoveryResponse have been applied. + ASSERT_TRUE(waitForCounterGe("runtime.load_success", 1)); // Verify that the Runtime config values are from the RTDS response. EXPECT_EQ("bar", getRuntimeKey("foo")); diff --git a/mobile/test/common/integration/sds_integration_test.cc b/mobile/test/common/integration/sds_integration_test.cc index 69fe4ab1e2ee..a689e76c4d40 100644 --- a/mobile/test/common/integration/sds_integration_test.cc +++ b/mobile/test/common/integration/sds_integration_test.cc @@ -63,8 +63,6 @@ class SdsIntegrationTest : public XdsIntegrationTest { api_config_source->set_transport_api_version(envoy::config::core::v3::V3); auto* grpc_service = api_config_source->add_grpc_services(); setGrpcService(*grpc_service, std::string(XDS_CLUSTER), fake_upstreams_.back()->localAddress()); - // TODO(abeyad): Remove the initial_fetch_timeout when - // https://github.com/envoyproxy/envoy-mobile/issues/2678 is fixed. config_source->mutable_initial_fetch_timeout()->set_seconds(1); } diff --git a/mobile/test/java/org/chromium/net/testing/data/content_length_mismatch.html b/mobile/test/java/org/chromium/net/testing/data/content_length_mismatch.html index c0e81b12bd01..8b117afa936e 100644 --- a/mobile/test/java/org/chromium/net/testing/data/content_length_mismatch.html +++ b/mobile/test/java/org/chromium/net/testing/data/content_length_mismatch.html @@ -1,3 +1,2 @@ Response that lies about content length. -