Opened 8 years ago

Closed 5 years ago

#844 closed enhancement (wontfix)

Allow support for different protocols on different hosts (same machine)

Reported by: Commenter123@… Owned by:
Priority: minor Milestone:
Component: other Version: 1.9.x
Keywords: Cc:
uname -a: Linux mydomain.com 3.2... x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.9.7
built by gcc 4...
built with LibreSSL 2.3.2
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-file-aio --with-http_v2_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security' --with-ld-opt=-Wl,-z,relro --with-ipv6 --with-openssl=submodules/libressl --with-pcre=submodules/pcre --with-pcre-jit

Description

So I have multiple hosts set up on one nginx installation:

  • mydomain.com (default_server)
  • www.mydomain.com
  • aaa.mydomain.com
  • bbb.mydomain.com

mydomain.com and www.mydomain.com both support TLS1.0, TLS1.1 and TLS1.2: ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
aaa.mydomain.com and bbb.mydomain.com however should only use TLS1.2

This is currently not possible. As soon as one host supports a protocol, all the other hosts support that protocol too (even if disabled)

Change History (9)

comment:1 by Maxim Dounin, 8 years ago

Resolution: wontfix
Status: newclosed

This is not something nginx can fix: OpenSSL selects the protocol to use before it calls SNI callback, so it's not possible for nginx to impose different protocol preferences for SNI-based virtual servers. Moreover, nginx already provides all relevant preferences to OpenSSL in the SNI callback - though they are ignored due to the above.

Note well that in some cases it's not at all possible to have different protocols on different SNI-based virtual servers. E.g., you can't enable SSL3 in a SNI-based virtual server, because there is no SNI in SSL3.

Trivial solution to such problems is to use IP-based servers instead of SNI-based virtual ones. It requires an additional IP address though. Another solution would be to check $ssl_protocol on HTTP level, and return an HTTP error if it's not high enough.

comment:2 by Maxim Dounin, 7 years ago

Duplicate of #676.

comment:3 by gfrankliu@…, 6 years ago

Looks like OpenSSL 1.1.1 finally fixed this (https://github.com/openssl/openssl/issues/4301) and added early callback (new in OpenSSL 1.1.1), which allows the application to switch SSL_CTXes before TLS version negotiation.
Hopefully nginx 1.15 milestone will be able to take advantage of this.

comment:4 by gfrankliu@…, 6 years ago

Resolution: wontfix
Status: closedreopened

comment:5 by Maxim Dounin, 6 years ago

Priority: majorminor
Type: defectenhancement

No, certainly they haven't fixed this, see my response at http://mailman.nginx.org/pipermail/nginx/2018-April/056036.html. The other issue linked there suggests that the new clienthello callback they added in the upcoming OpenSSL 1.1.1 can be used to implement this in some cases (note that in some cases it is simply not possible, see above), yet this is something to look into and will certainly involve more work than using dedicated servername callback as we do now.

comment:6 by Maxim Dounin, 6 years ago

See also #1470.

comment:7 by gfrankliu@…, 6 years ago

In case someone wants to try this before nginx officially supports it, Piotr Sikora has provided patches to use the early ClientHello callback from OpenSSL 1.1.1 or BoringSSL to allow configuration of available TLS protocol versions on a per server basis.

Patch 1:
https://nginx.googlesource.com/nginx/+/efeb94462a1720740b35efe3859f3128f1537a6e%5E%21/#F0

Patch 2:
https://nginx.googlesource.com/nginx/+/64e8587513d4b6b1a0d6f4d68b1ac61b94029e12%5E%21/#F0

Patch 3:
https://nginx.googlesource.com/nginx/+/43e7b101936289ce985f4f201f9856947a02a5ea%5E%21/#F0

Patch 4:
https://nginx-review.googlesource.com/changes/3420/revisions/8/patch?zip

Patches 1 and 2 are already in nginx 1.15.2, so you will only need to apply them if you are running nginx versions < 1.15.2.

comment:8 by Maxim Dounin, 5 years ago

See also #1714.

comment:9 by Maxim Dounin, 5 years ago

Resolution: wontfix
Status: reopenedclosed

For the record, patch from Piotr has several drawbacks, including:

  • It implies manual parsing of the server_name TLS extensions by nginx. Such parsing is not something normal software usually do, and two versions of the code - one for BoringSSL, and another one for OpenSSL - is an immediate result of the problem. Amount of the code added is comparable to the ngx_stream_ssl_preread_module.c, which implements all SSL parsing.
  • This approach can produce incorrect results if we consider any protocols not using the server_name extension. E.g., it will produce incorrect results if using SSLv3 either in the default or in the target server.
  • This approach is not compatible with upcoming encrypted SNI (actually, this is just another example of a protocol not using the server_name extension).

Given the above, I don't think that using the SSL_CTX_set_client_hello_cb() callback is going to work. While it allows manually inspecting ClientHello contents, it doesn't look like a replacement for SSL_CTX_set_tlsext_servername_callback(). And it is going to become completely useless for SNI once encrypted SNI will be finally supported.

Note: See TracTickets for help on using tickets.