Line data Source code
1 : #pragma once 2 : 3 : #include <openssl/safestack.h> 4 : 5 : #include <array> 6 : #include <deque> 7 : #include <functional> 8 : #include <memory> 9 : #include <string> 10 : #include <vector> 11 : 12 : #include "envoy/network/transport_socket.h" 13 : #include "envoy/ssl/context.h" 14 : #include "envoy/ssl/context_config.h" 15 : #include "envoy/ssl/private_key/private_key.h" 16 : #include "envoy/ssl/ssl_socket_extended_info.h" 17 : #include "envoy/stats/scope.h" 18 : #include "envoy/stats/stats_macros.h" 19 : 20 : #include "source/common/common/matchers.h" 21 : #include "source/common/stats/symbol_table.h" 22 : #include "source/extensions/transport_sockets/tls/cert_validator/cert_validator.h" 23 : #include "source/extensions/transport_sockets/tls/context_manager_impl.h" 24 : #include "source/extensions/transport_sockets/tls/ocsp/ocsp.h" 25 : #include "source/extensions/transport_sockets/tls/stats.h" 26 : 27 : #include "absl/synchronization/mutex.h" 28 : #include "openssl/ssl.h" 29 : #include "openssl/x509v3.h" 30 : 31 : namespace Envoy { 32 : #ifndef OPENSSL_IS_BORINGSSL 33 : #error Envoy requires BoringSSL 34 : #endif 35 : 36 : namespace Extensions { 37 : namespace TransportSockets { 38 : namespace Tls { 39 : 40 : struct TlsContext { 41 : // Each certificate specified for the context has its own SSL_CTX. `SSL_CTXs` 42 : // are identical with the exception of certificate material, and can be 43 : // safely substituted via SSL_set_SSL_CTX() during the 44 : // SSL_CTX_set_select_certificate_cb() callback following ClientHello. 45 : bssl::UniquePtr<SSL_CTX> ssl_ctx_; 46 : bssl::UniquePtr<X509> cert_chain_; 47 : std::string cert_chain_file_path_; 48 : Ocsp::OcspResponseWrapperPtr ocsp_response_; 49 : bool is_ecdsa_{}; 50 : bool is_must_staple_{}; 51 : Ssl::PrivateKeyMethodProviderSharedPtr private_key_method_provider_{}; 52 : 53 0 : std::string getCertChainFileName() const { return cert_chain_file_path_; }; 54 : bool isCipherEnabled(uint16_t cipher_id, uint16_t client_version); 55 0 : Envoy::Ssl::PrivateKeyMethodProviderSharedPtr getPrivateKeyMethodProvider() { 56 0 : return private_key_method_provider_; 57 0 : } 58 : void loadCertificateChain(const std::string& data, const std::string& data_path); 59 : void loadPrivateKey(const std::string& data, const std::string& data_path, 60 : const std::string& password); 61 : void loadPkcs12(const std::string& data, const std::string& data_path, 62 : const std::string& password); 63 : void checkPrivateKey(const bssl::UniquePtr<EVP_PKEY>& pkey, const std::string& key_path); 64 : }; 65 : 66 : class ContextImpl : public virtual Envoy::Ssl::Context, 67 : protected Logger::Loggable<Logger::Id::config> { 68 : public: 69 : virtual bssl::UniquePtr<SSL> newSsl(const Network::TransportSocketOptionsConstSharedPtr& options); 70 : 71 : /** 72 : * Logs successful TLS handshake and updates stats. 73 : * @param ssl the connection to log 74 : */ 75 : void logHandshake(SSL* ssl) const; 76 : 77 0 : SslStats& stats() { return stats_; } 78 : 79 : /** 80 : * The global SSL-library index used for storing a pointer to the SslExtendedSocketInfo 81 : * class in the SSL instance, for retrieval in callbacks. 82 : */ 83 : static int sslExtendedSocketInfoIndex(); 84 : 85 : static int sslSocketIndex(); 86 : // Ssl::Context 87 : absl::optional<uint32_t> daysUntilFirstCertExpires() const override; 88 : Envoy::Ssl::CertificateDetailsPtr getCaCertInformation() const override; 89 : std::vector<Envoy::Ssl::CertificateDetailsPtr> getCertChainInformation() const override; 90 : absl::optional<uint64_t> secondsUntilFirstOcspResponseExpires() const override; 91 : 92 : std::vector<Ssl::PrivateKeyMethodProviderSharedPtr> getPrivateKeyMethodProviders(); 93 : 94 : // Validate cert asynchronously for a QUIC connection. 95 : ValidationResults customVerifyCertChainForQuic( 96 : STACK_OF(X509)& cert_chain, Ssl::ValidateResultCallbackPtr callback, bool is_server, 97 : const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options, 98 : const CertValidator::ExtraValidationContext& validation_context, 99 : const std::string& host_name); 100 : 101 : static void keylogCallback(const SSL* ssl, const char* line); 102 : 103 : protected: 104 : friend class ContextImplPeer; 105 : 106 : ContextImpl(Stats::Scope& scope, const Envoy::Ssl::ContextConfig& config, 107 : TimeSource& time_source); 108 : 109 : /** 110 : * The global SSL-library index used for storing a pointer to the context 111 : * in the SSL instance, for retrieval in callbacks. 112 : */ 113 : static int sslContextIndex(); 114 : 115 : // A SSL_CTX_set_custom_verify callback for asynchronous cert validation. 116 : static enum ssl_verify_result_t customVerifyCallback(SSL* ssl, uint8_t* out_alert); 117 : 118 : bool parseAndSetAlpn(const std::vector<std::string>& alpn, SSL& ssl); 119 : std::vector<uint8_t> parseAlpnProtocols(const std::string& alpn_protocols); 120 : 121 : void incCounter(const Stats::StatName name, absl::string_view value, 122 : const Stats::StatName fallback) const; 123 : 124 : // Helper function to validate cert for TCP connections asynchronously. 125 : ValidationResults customVerifyCertChain( 126 : Envoy::Ssl::SslExtendedSocketInfo* extended_socket_info, 127 : const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options, SSL* ssl); 128 : 129 : void populateServerNamesMap(TlsContext& ctx, const int pkey_id); 130 : 131 : // This is always non-empty, with the first context used for all new SSL 132 : // objects. For server contexts, once we have ClientHello, we 133 : // potentially switch to a different CertificateContext based on certificate 134 : // selection. 135 : std::vector<TlsContext> tls_contexts_; 136 : CertValidatorPtr cert_validator_; 137 : Stats::Scope& scope_; 138 : SslStats stats_; 139 : std::vector<uint8_t> parsed_alpn_protocols_; 140 : bssl::UniquePtr<X509> cert_chain_; 141 : std::string cert_chain_file_path_; 142 : TimeSource& time_source_; 143 : const unsigned tls_max_version_; 144 : mutable Stats::StatNameSetPtr stat_name_set_; 145 : const Stats::StatName unknown_ssl_cipher_; 146 : const Stats::StatName unknown_ssl_curve_; 147 : const Stats::StatName unknown_ssl_algorithm_; 148 : const Stats::StatName unknown_ssl_version_; 149 : const Stats::StatName ssl_ciphers_; 150 : const Stats::StatName ssl_versions_; 151 : const Stats::StatName ssl_curves_; 152 : const Stats::StatName ssl_sigalgs_; 153 : const Ssl::HandshakerCapabilities capabilities_; 154 : const Network::Address::IpList tls_keylog_local_; 155 : const Network::Address::IpList tls_keylog_remote_; 156 : AccessLog::AccessLogFileSharedPtr tls_keylog_file_; 157 : }; 158 : 159 : using ContextImplSharedPtr = std::shared_ptr<ContextImpl>; 160 : 161 : class ClientContextImpl : public ContextImpl, public Envoy::Ssl::ClientContext { 162 : public: 163 : ClientContextImpl(Stats::Scope& scope, const Envoy::Ssl::ClientContextConfig& config, 164 : TimeSource& time_source); 165 : 166 : bssl::UniquePtr<SSL> 167 : newSsl(const Network::TransportSocketOptionsConstSharedPtr& options) override; 168 : 169 : private: 170 : int newSessionKey(SSL_SESSION* session); 171 : 172 : const std::string server_name_indication_; 173 : const bool allow_renegotiation_; 174 : const bool enforce_rsa_key_usage_; 175 : const size_t max_session_keys_; 176 : absl::Mutex session_keys_mu_; 177 : std::deque<bssl::UniquePtr<SSL_SESSION>> session_keys_ ABSL_GUARDED_BY(session_keys_mu_); 178 : bool session_keys_single_use_{false}; 179 : }; 180 : 181 : enum class OcspStapleAction { Staple, NoStaple, Fail, ClientNotCapable }; 182 : 183 : class ServerContextImpl : public ContextImpl, public Envoy::Ssl::ServerContext { 184 : public: 185 : ServerContextImpl(Stats::Scope& scope, const Envoy::Ssl::ServerContextConfig& config, 186 : const std::vector<std::string>& server_names, TimeSource& time_source); 187 : 188 : // Select the TLS certificate context in SSL_CTX_set_select_certificate_cb() callback with 189 : // ClientHello details. This is made public for use by custom TLS extensions who want to 190 : // manually create and use this as a client hello callback. 191 : enum ssl_select_cert_result_t selectTlsContext(const SSL_CLIENT_HELLO* ssl_client_hello); 192 : 193 : private: 194 : // Currently, at most one certificate of a given key type may be specified for each exact 195 : // server name or wildcard domain name. 196 : using PkeyTypesMap = absl::flat_hash_map<int, std::reference_wrapper<TlsContext>>; 197 : // Both exact server names and wildcard domains are part of the same map, in which wildcard 198 : // domains are prefixed with "." (i.e. ".example.com" for "*.example.com") to differentiate 199 : // between exact and wildcard entries. 200 : using ServerNamesMap = absl::flat_hash_map<std::string, PkeyTypesMap>; 201 : 202 : void populateServerNamesMap(TlsContext& ctx, const int pkey_id); 203 : 204 : using SessionContextID = std::array<uint8_t, SSL_MAX_SSL_SESSION_ID_LENGTH>; 205 : 206 : int alpnSelectCallback(const unsigned char** out, unsigned char* outlen, const unsigned char* in, 207 : unsigned int inlen); 208 : int sessionTicketProcess(SSL* ssl, uint8_t* key_name, uint8_t* iv, EVP_CIPHER_CTX* ctx, 209 : HMAC_CTX* hmac_ctx, int encrypt); 210 : bool isClientEcdsaCapable(const SSL_CLIENT_HELLO* ssl_client_hello); 211 : bool isClientOcspCapable(const SSL_CLIENT_HELLO* ssl_client_hello); 212 : OcspStapleAction ocspStapleAction(const TlsContext& ctx, bool client_ocsp_capable); 213 : 214 : SessionContextID generateHashForSessionContextId(const std::vector<std::string>& server_names); 215 : 216 : const std::vector<Envoy::Ssl::ServerContextConfig::SessionTicketKey> session_ticket_keys_; 217 : const Ssl::ServerContextConfig::OcspStaplePolicy ocsp_staple_policy_; 218 : ServerNamesMap server_names_map_; 219 : bool has_rsa_{false}; 220 : bool full_scan_certs_on_sni_mismatch_; 221 : }; 222 : 223 : } // namespace Tls 224 : } // namespace TransportSockets 225 : } // namespace Extensions 226 : } // namespace Envoy