-
Notifications
You must be signed in to change notification settings - Fork 7.6k
SNI: using ClientHello callback. #562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Would it be possible to support SSL_CTX_set_select_certificate_cb in BoringSSL, as this PR currently uses SSL_CTX_set_client_hello_cb for OpenSSL? |
|
A history of the topic: https://trac.nginx.org/nginx/ticket/844 In a nutshell, a previous attempt was made by Piotr Sikora 7 years ago. That effort was rejected by Maxim Dounin. Apart from the style/tradition issue and the implementation issue, the biggest concern was that ESNI may not be compatible with this approach. Now that ESNI is no longer around, we need to make sure this approach is compatible with ECH. Seems like there should be less issues here. I would expect a separate call for the inner ClientHello, but this needs to be verified. |
|
Apart from the session resume issue, one of the major reasons for this change is enabling per-server |
|
SSL_CTX_set_select_certificate_cb and per-server This change aims to solve the specific deficiency of the servername callback in OpenSSL which is called too late wrt SSL session resumption. So far, I don't think we need to touch BoringSSL API bits, as it doesn't suffer from this problem. Considering ESNI and now ECH, OpenSSL doesn't support it, so I don't see anything to discuss so far. |
|
ECH is not going to be an issue. Now, I'm not quite happy with how this forces us to apply ECH configs to a listener scope instead of a server scope, because the default server must be able to unwrap the ECH extension before we are able switch to another Going back to the current patch:
|
I agree it is not the goal of this change. But since the callback is now called before OpenSSL negotiates the protocol version, the change does this as well. My point is, the behavior needs to be consistent across libraries.
It may be too late to reconsider. |
Note it's just WiP. Considering how much is happening in openssl/openssl@86da814 while merging OpenSSL client-side support into a feature-branch (not even mainstream), I wouldn't rely on that. |
|
The use of SSL_CTX_set_client_hello_cb will break ssl_client_hello_by_lua_block, which to be sure, is a separate project but many people use it. |
|
[ .. strip unrelated .. ]
Note that 46b9f5d is the result of an (awkward) processing order in OpenSSL.
This follows the OpenSSL behaviour as documented in the SSL_get_servername manual page.
46b9f5d is largely a kludge, this will make me happy when it goes away.
These two are now addressed in the updated change, specifically c393026. |
|
While perusing this pull-request I stumbled upon this change in +#ifdef SSL_CLIENT_HELLO_SUCCESS
+ {
+ ngx_ssl_client_hello_arg *arg;
+
+ arg = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_client_hello_arg));
+ arg->servername = ngx_stream_ssl_servername;
+
+ SSL_CTX_set_client_hello_cb(conf->ssl.ctx, ngx_ssl_client_hello_callback,
+ arg);
+ }
+#endif
+I like the use of a new block (always a fan of reducing variable scope), |
The referenced code is used to pass the function pointer in the callback Such declaration is generally used in nginx to avoid messing with ifdefs On a related note, I pondered how to make this code snippet look less awkward. Here, cycle pool allocation is not actually needed and can be removed. |
c393026 to
237f7f2
Compare
|
changes:
|
237f7f2 to
59109ec
Compare
|
The commit message mentions AWS-LC; I'm aware of 4 modules that register
I don't want to block the current PR, but I'd like to discuss if we can provide an API for using SSL callbacks from a third-party module before the next release. |
59109ec to
a55f4e9
Compare
It's hard to say how this callback is used in these modules without deeply |
|
(GH interface doesn't allow to properly reference or respond to this comment, ref'ing it manually)
@bavshin-f5 wrote:
Err, not API, just compatibility. Passing it as ngx_str_t is more solid, but this would require even more changes in ngx_http_ssl_servername() I'd like to avoid to keep it readable. |
a55f4e9 to
d2d3231
Compare
|
Changes to evaluate:
|
d2d3231 to
faf67b3
Compare
|
Changes:
|
bavshin-f5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good with a few nits.
Will do additional testing later.
faf67b3 to
ea32af4
Compare
|
Changes:
|
|
I want to proxy TLS connections with an ALPN of acme-tls/1 to an "upstream" ALPN terminator like ualpn/uacme. The aim is to share ACME challenges to a single IP address between Nginx which controls port 443, and other services on that IP. Linux at least doesn't have a way to do this in the kernel since ClientHello can span multiple TCP segments. Considering nginx-acme module, it should likely be configured per-SNI-virtual-host, so this internal ACME responder can take some ACME challenges, while letting others (perhaps any that don't match) go to the "upstream". At present I'm peeling off where http module peeks at the ALPN and detects "h2". It works but it seems like there is soon to be an SNI callback way of doing this (maybe h2 detection would use it also?) and I don't want to get in the way. If someone could point to where things are likely to land considering this PR and nginx-acme, I would appreciate it. |
|
ualpn will want to receive and handle a pristine TLS handshake. It is no longer possible to achieve that once we started feeding the data to the OpenSSL routines, so the changes here are irrelevant for your goal. A possible configuration with an external tls-alpn-01 responder could be based on http {
server {
listen 8443 ssl;
...
}
}
stream {
map $ssl_preread_alpn_protocols $next_server {
~\bacme-tls/1\b 127.0.0.1:8444; # ualpn proxy
default 127.0.0.1:8443; # https listener
}
server {
listen 443;
ssl_preread on;
# preread_buffer_size ...; # adjust as necessary
pass $next_server;
}
server {
listen 127.0.0.1:8444;
proxy_pass ualpn;
}
}And if you want to mix internal and external tls-alpn-01 responders, you will have to separate them in the same place, stream preread. |
|
I see 3 options:
|
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 46b9f5d 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 fd97b2a, 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.
This brings feature parity with OpenSSL after the previous change, making it possible to set SSL protocols per virtual server.
ea32af4 to
e5de81a
Compare
|
Changes: merged simplified setting of callbacks; function sorting & minor cleanup. As for me, the code has become noticeably cleaner. |
bavshin-f5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
- Session resumption behavior on SNI change is consistent with BoringSSL, which we consider the correct behavior.
ssl_protocolsare now applied on non-default servers.tls-perfshows negligible changes.- The changes necessary for third-party modules are small and straightforward.
|
Thanks for testing. |
The change introduces a SNI based virtual server selection with the ClientHello callback used for early server-side ClientHello processing. It reverts 46b9f5d.
The ClientHello callback is available in OpenSSL version 1.1.1+, where the TLSv1.3 protocol support was introduced. For other versions, the servername callback is preserved.
Notably, this follows BoringSSL behaviour to process server name before SSL session resumption.