summaryrefslogtreecommitdiffhomepage
path: root/src/stream
diff options
context:
space:
mode:
authorSergey Kandaurov <pluknet@nginx.com>2025-01-28 00:53:15 +0400
committerpluknet <pluknet@nginx.com>2025-09-25 19:25:08 +0400
commit0373fe5d98c1515640e74fa6f4d32fac1f1d3ab2 (patch)
tree10090027a69f6e84e65c079e53094558b446b377 /src/stream
parentbc71625dcca1f1cbd0db7450af853feb90ebba85 (diff)
downloadnginx-0373fe5d98c1515640e74fa6f4d32fac1f1d3ab2.tar.gz
nginx-0373fe5d98c1515640e74fa6f4d32fac1f1d3ab2.tar.bz2
SNI: using the ClientHello callback.
The change introduces an SNI based virtual server selection during early ClientHello processing. The callback is available since OpenSSL 1.1.1; for older OpenSSL versions, the previous behaviour is kept. Using the ClientHello callback sets a reasonable processing order for the "server_name" TLS extension. Notably, session resumption decision now happens after applying server configuration chosen by SNI, useful with enabled verification of client certificates, which brings consistency with BoringSSL behaviour. The change supersedes and reverts a fix made in 46b9f5d38 for TLSv1.3 resumed sessions. In addition, since the callback is invoked prior to the protocol version negotiation, this makes it possible to set "ssl_protocols" on a per-virtual server basis. To keep the $ssl_server_name variable working with TLSv1.2 resumed sessions, as previously fixed in fd97b2a80, a limited server name callback is preserved in order to acknowledge the extension. Note that to allow third-party modules to properly chain the call to ngx_ssl_client_hello_callback(), the servername callback function is passed through exdata.
Diffstat (limited to 'src/stream')
-rw-r--r--src/stream/ngx_stream_ssl_module.c68
1 files changed, 33 insertions, 35 deletions
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 7ce1175f1..7bf6304e4 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -555,27 +555,41 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
+ if (c->ssl->sni_accepted) {
+ return SSL_TLSEXT_ERR_OK;
+ }
+
s = c->data;
- servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
+ if (arg) {
+ host = *(ngx_str_t *) arg;
- if (servername == NULL) {
- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
- "SSL server name: null");
- goto done;
+ if (host.data == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL server name: null");
+ goto done;
+ }
+
+ } else {
+ servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
+
+ if (servername == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL server name: null");
+ goto done;
+ }
+
+ host.len = ngx_strlen(servername);
+ host.data = (u_char *) servername;
}
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
- "SSL server name: \"%s\"", servername);
-
- host.len = ngx_strlen(servername);
+ "SSL server name: \"%V\"", &host);
if (host.len == 0) {
goto done;
}
- host.data = (u_char *) servername;
-
rc = ngx_stream_validate_host(&host, c->pool, 1);
if (rc == NGX_ERROR) {
@@ -596,35 +610,12 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
goto done;
}
- sscf = ngx_stream_get_module_srv_conf(cscf->ctx, ngx_stream_ssl_module);
-
-#if (defined TLS1_3_VERSION \
- && !defined LIBRESSL_VERSION_NUMBER && !defined OPENSSL_IS_BORINGSSL)
-
- /*
- * SSL_SESSION_get0_hostname() is only available in OpenSSL 1.1.1+,
- * but servername being negotiated in every TLSv1.3 handshake
- * is only returned in OpenSSL 1.1.1+ as well
- */
-
- if (sscf->verify) {
- const char *hostname;
-
- hostname = SSL_SESSION_get0_hostname(SSL_get0_session(ssl_conn));
-
- if (hostname != NULL && ngx_strcmp(hostname, servername) != 0) {
- c->ssl->handshake_rejected = 1;
- *ad = SSL_AD_ACCESS_DENIED;
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- }
- }
-
-#endif
-
s->srv_conf = cscf->ctx->srv_conf;
ngx_set_connection_log(c, cscf->error_log);
+ sscf = ngx_stream_get_module_srv_conf(cscf->ctx, ngx_stream_ssl_module);
+
if (sscf->ssl.ctx) {
if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) {
goto error;
@@ -663,6 +654,7 @@ done:
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
+ c->ssl->sni_accepted = 1;
return SSL_TLSEXT_ERR_OK;
error:
@@ -1002,8 +994,14 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
cln->data = &conf->ssl;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ {
+ static ngx_ssl_client_hello_arg cb = { ngx_stream_ssl_servername };
+
+ ngx_ssl_set_client_hello_callback(conf->ssl.ctx, &cb);
+
SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,
ngx_stream_ssl_servername);
+ }
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation