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

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