Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions patch/1.21.4/nginx-sni_restriction.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
From 823e886851263a8ce84fd22aeead4c3aa819bce1 Mon Sep 17 00:00:00 2001
From: Sergey Kandaurov <[email protected]>
Date: Wed, 22 Jan 2025 18:55:44 +0400
Subject: [PATCH] SNI: added restriction for TLSv1.3 cross-SNI session
resumption.

In OpenSSL, session resumption always happens in the default SSL context,
prior to invoking the SNI callback. Further, unlike in TLSv1.2 and older
protocols, SSL_get_servername() returns values received in the resumption
handshake, which may be different from the value in the initial handshake.
Notably, this makes the restriction added in b720f650b insufficient for
sessions resumed with different SNI server name.

Considering the example from b720f650b, previously, a client was able to
request example.org by presenting a certificate for example.org, then to
resume and request example.com.

The fix is to reject handshakes resumed with a different server name, if
verification of client certificates is enabled in a corresponding server
configuration.
---
src/http/ngx_http_request.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 013b7158e..d5ac3d415 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -909,6 +909,31 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
goto done;
}

+ sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_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
+
hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t));
if (hc->ssl_servername == NULL) {
goto error;
@@ -922,8 +947,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)

ngx_set_connection_log(c, clcf->error_log);

- sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
-
c->ssl->buffer_size = sscf->buffer_size;

if (sscf->ssl.ctx) {
--
2.43.0