This is an automated email from the ASF dual-hosted git repository. zwoop pushed a commit to branch CleanupWS9.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 7e0ba0658481151fd3e5cb045b3f3d35583ac83c Author: xinli1 <xin...@linkedin.com> AuthorDate: Tue Oct 22 10:04:52 2019 -0700 set host name in TLS extension for SNI Host check in service side with sni policy verify_with_name_source. fix build error in autest update document fix wrong comment (cherry picked from commit 48771056f71f85a3ac6b01f1fa10a7172c4bdc04) --- doc/admin-guide/files/records.config.en.rst | 16 +++++++++++++++- iocore/net/I_NetVConnection.h | 23 +++++++++++++++++++++++ iocore/net/P_UnixNetVConnection.h | 1 + iocore/net/SSLNetVConnection.cc | 9 +++++---- iocore/net/quic/QUICTLS_openssl.cc | 3 ++- proxy/http/HttpSM.cc | 11 +++++++++++ 6 files changed, 57 insertions(+), 6 deletions(-) diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index d9999df..56a5645 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -3473,7 +3473,21 @@ Client-Related Configuration Indicate how the SNI value for the TLS connection to the origin is selected. By default it is `host` which means the host header field value is used for the SNI. If `remap` is specified, the - remapped origin name is used for the SNI value. + remapped origin name is used for the SNI value. If `verify_with_name_source` is specified, the + SNI will be the host header value and the name to check in the server certificate will be the + remap header value. + We have two names that could be used in the transaction host header and the SNI value to the + origin. These could be the host header from the client or the remap host name. Unless you have + pristine host header enabled, these are likely the same values. + If sni_policy = host, both the sni and the host header to origin will be the same. + If sni_policy = remap, the sni value with be the remap host name and the host header will be the + host header from the client. + In addition, We may want to set the SNI and host headers the same (makes some common web servers + happy), but the certificate served by the origin may have a name that corresponds to the remap + name. So instead of using the SNI name for the name check, we may want to use the remap name. + So if sni_policy = verify_with_name_source, the sni will be the host header value and the name to + check in the server certificate will be the remap header value. + .. ts:cv:: CONFIG proxy.config.ssl.client.TLSv1 INT 0 diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h index df0667f..bfe1137 100644 --- a/iocore/net/I_NetVConnection.h +++ b/iocore/net/I_NetVConnection.h @@ -192,6 +192,10 @@ struct NetVCOptions { */ ats_scoped_str ssl_servername; + /** Server host name from client's request to use for SNI data on an outbound connection. + */ + ats_scoped_str sni_hostname; + /** * Client certificate to use in response to OS's certificate request */ @@ -259,6 +263,20 @@ struct NetVCOptions { } self & + set_sni_hostname(const char *name, size_t len) + { + IpEndpoint ip; + + // Literal IPv4 and IPv6 addresses are not permitted in "HostName".(rfc6066#section-3) + if (name && len && ats_ip_pton(std::string_view(name, len), &ip) != 0) { + sni_hostname = ats_strndup(name, len); + } else { + sni_hostname = nullptr; + } + return *this; + } + + self & operator=(self const &that) { if (&that != this) { @@ -274,6 +292,7 @@ struct NetVCOptions { */ sni_servername = nullptr; // release any current name. ssl_servername = nullptr; + sni_hostname = nullptr; memcpy(static_cast<void *>(this), &that, sizeof(self)); if (that.sni_servername) { sni_servername.release(); // otherwise we'll free the source string. @@ -283,6 +302,10 @@ struct NetVCOptions { ssl_servername.release(); // otherwise we'll free the source string. this->ssl_servername = ats_strdup(that.ssl_servername); } + if (that.sni_hostname) { + sni_hostname.release(); // otherwise we'll free the source string. + this->sni_hostname = ats_strdup(that.sni_hostname); + } } return *this; } diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h index 128f572..26d573d 100644 --- a/iocore/net/P_UnixNetVConnection.h +++ b/iocore/net/P_UnixNetVConnection.h @@ -68,6 +68,7 @@ NetVCOptions::reset() sni_servername = nullptr; ssl_servername = nullptr; + sni_hostname = nullptr; ssl_client_cert_name = nullptr; ssl_client_private_key_name = nullptr; ssl_client_ca_cert_name = nullptr; diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc index d5771f5..051c97a 100644 --- a/iocore/net/SSLNetVConnection.cc +++ b/iocore/net/SSLNetVConnection.cc @@ -1078,11 +1078,12 @@ SSLNetVConnection::sslStartHandShake(int event, int &err) SSL_set_verify(this->ssl, SSL_VERIFY_PEER, verify_callback); - if (this->options.sni_servername) { - if (SSL_set_tlsext_host_name(this->ssl, this->options.sni_servername)) { - Debug("ssl", "using SNI name '%s' for client handshake", this->options.sni_servername.get()); + ats_scoped_str &tlsext_host_name = this->options.sni_hostname ? this->options.sni_hostname : this->options.sni_servername; + if (tlsext_host_name) { + if (SSL_set_tlsext_host_name(this->ssl, tlsext_host_name)) { + Debug("ssl", "using SNI name '%s' for client handshake", tlsext_host_name.get()); } else { - Debug("ssl.error", "failed to set SNI name '%s' for client handshake", this->options.sni_servername.get()); + Debug("ssl.error", "failed to set SNI name '%s' for client handshake", tlsext_host_name.get()); SSL_INCREMENT_DYN_STAT(ssl_sni_name_set_failure); } } diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 0eabec1..75e9842 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -405,7 +405,8 @@ QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, Net SSL_set_alpn_protos(this->_ssl, reinterpret_cast<const unsigned char *>(netvc_options.alpn_protos.data()), netvc_options.alpn_protos.size()); - SSL_set_tlsext_host_name(this->_ssl, netvc_options.sni_servername.get()); + const ats_scoped_str &tlsext_host_name = netvc_options.sni_hostname ? netvc_options.sni_hostname : netvc_options.sni_servername; + SSL_set_tlsext_host_name(this->_ssl, tlsext_host_name.get()); } else { SSL_set_accept_state(this->_ssl); } diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 45d3e5b..2450d2b 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -5007,6 +5007,17 @@ HttpSM::do_http_server_open(bool raw) if (t_state.txn_conf->ssl_client_sni_policy != nullptr && !strcmp(t_state.txn_conf->ssl_client_sni_policy, "remap")) { len = strlen(t_state.server_info.name); opt.set_sni_servername(t_state.server_info.name, len); + } else if (t_state.txn_conf->ssl_client_sni_policy != nullptr && + !strcmp(t_state.txn_conf->ssl_client_sni_policy, "verify_with_name_source")) { + // the same with "remap" policy to set sni_servername + len = strlen(t_state.server_info.name); + opt.set_sni_servername(t_state.server_info.name, len); + + // also set sni_hostname with host header from server request in this policy + const char *host = t_state.hdr_info.server_request.host_get(&len); + if (host && len > 0) { + opt.set_sni_hostname(host, len); + } } else { // Do the default of host header for SNI const char *host = t_state.hdr_info.server_request.host_get(&len); if (host && len > 0) {