Opened 7 years ago
Closed 4 years ago
#844 closed enhancement (wontfix)
Allow support for different protocols on different hosts (same machine)
|Reported by:||Owned by:|
|uname -a:||Linux mydomain.com 3.2... x86_64 GNU/Linux|
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
So I have multiple hosts set up on one nginx installation:
- mydomain.com (default_server)
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 , 7 years ago
|Status:||new → closed|
comment:2 by , 7 years ago
Duplicate of #676.
comment:3 by , 5 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 , 5 years ago
|Status:||closed → reopened|
comment:5 by , 5 years ago
|Priority:||major → minor|
|Type:||defect → enhancement|
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 , 5 years ago
See also #1470.
comment:7 by , 5 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.
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 , 4 years ago
See also #1714.
comment:9 by , 4 years ago
|Status:||reopened → closed|
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.
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.