Go version
Any
Output of go env
in your module/workspace:
GOARCH="amd64"
What did you do?
Set up a HTTPS server using crypto/tls and intiate a TLS handshake with it where the TLS Client Hello contains the extension "server_name". A complete example for this has already been provided in #16072. This issue is therefore a duplicate of #16072 because we believe that the decision taken there should be revisited for the reasons given below.
What did you see happen?
The TLS Server Hello response of the HTTPS server does not contain a server_name extension.
What did you expect to see?
RFC 6066 section 3 mandates that a server MAY use the information from the server_name extension in the Client Hello. However if it does so, then the server MUST in turn include the extension in the response with an empty value:
A server that receives a client hello containing the "server_name" extension MAY use the information contained in the extension to guide its selection of an appropriate certificate to return to the client, and/or other aspects of security policy. In this event, the server SHALL include an extension of type "server_name" in the (extended) server hello. The "extension_data" field of this extension SHALL be empty. (the word SHALL in RFCs is a synonym for MUST, see RFC 2119)
Currently software using GOs crypto/tls stack does never sent a server_name extension. This is not just a theoretical issue, but creates actual compatibility problems: If you turn the statement from RFC 6066 around, it means that a server which receives a server_name extension from the client but does not include the extension in its response, does not use the server_name information from the client, ie it does not use SNI. Some software from eg IBM, Citrix or AWS will then omit the server_name extension from following requests to the same server, because it knows that the server doesn't need it. However if the GO server is actually using SNI (without telling it), those requests will fail.
To fix this, crypto/tls should always include an empty server_name extension if the client sent this extension. I cannot think of a scenario where this causes a problem. Even if the server does not use SNI no harm is done if the client believes otherwise and continues to supply a superfluous server_name extension.
Comment From: gabyhelp
Related Issues
- crypto/tls: server should send empty server_name extension when using SNI #16072 (closed)
- crypto/tls: Go HTTP server - when receiving Client Hello with SNI - is not including Server Name extension in Server Hello #54691 (closed)
- proposal: crypto/tls: make server name extension optional #28754 (closed)
- crypto/tls: Conn.ConnectionState should set state.ServerName from c.serverName unconditionally - handshakeComplete is not necessary for SNI #15571 (closed)
- crypto/tls: GetCertificate should have a way to signal `unrecognized_name` #19300 (closed)
- crypto/tls: abort handshake if unrequested extensions are sent #51090
- crypto/tls: Allow sending unrecognized_name alert from GetCertificate #18377 (closed)
Related Discussions
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: seankhliao
note the RFC only says SHALL, not MUST. I think we need to see real examples of failures.
Comment From: AGWA
@seankhliao SHALL means the same thing as MUST, see RFC 2119
Comment From: gnugnug
Yes, the RFC in question declares the following conventions at the beginning:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC2119
And RFC2119 says:
[...] the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification
Regarding real world examples: I can provide packet captures of Contour which uses crypto/tls and relies heavely on SNI but does not include a server_name extension in its responses. This causes issues as soon as a reverse proxy like IBM Webseal or Citrix Netscaler are placed in front of it, which take the RFC verbatim and only send the server_name in their initial request and leave it out from all subsequent requests.
Comment From: seankhliao
cc @golang/security
Comment From: davidben
Some software from eg IBM, Citrix or AWS will then omit the server_name extension from following requests to the same server, because it knows that the server doesn't need it.
Separate from whether Go should send this boolean, this behavior is also just broken. Just because today the server doesn't use SNI, the server might use it tomorrow. The client can't assume that the server configuration remains unchanged across connections.
(I have never seen a legitimate use for this TLS feature. Of course, legitimate or not, it exists and servers have to deal with it, but clients that do broken things in response to its presence, or lack thereof, should also be fixed.)
Comment From: gopherbot
Change https://go.dev/cl/684795 mentions this issue: crypto/tls: empty server_name conf. ext. from server