Description
Please answer these questions before submitting your issue. Thanks!
- What version of Go are you using (
go version
)?
go version go1.6.2 darwin/amd64
- What operating system and processor architecture are you using (
go env
)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/frschroeder/gopath"
GORACE=""
GOROOT="/Users/frschroeder/go1.6.2"
GOTOOLDIR="/Users/frschroeder/go1.6.2/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"
- What did you do?
Sample app: https://play.golang.org/p/Tk9CR4BUyU
a) Save certPEM
from the sample app into a file, e.g. cert.pem
b) Start WireShark and capture traffic on lo
or lo0
c) Set a filter tcp.port == 4433
d) Goto Preferences -> Protocols -> SSL
and add the cert.pem
to the RSA key list for 127.0.0.1:4433
protocol tcp
Run the sample program from as follows:
1st terminal: go run main.go -server
2nd terminal: go run main.go
This will start a server in the first terminal and a client in the second terminal which executes a SNI handshake.
WireShark will capture and decrypt the traffic
- What did you expect to see?
A Server Hello with an empty server_name
extension, e.g.
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 53
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 49
Version: TLS 1.2 (0x0303)
Random
Session ID Length: 0
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Compression Method: null (0)
Extensions Length: 9
Extension: server_name
Type: server_name (0x0000)
Length: 0
Extension: renegotiation_info
Type: renegotiation_info (0xff01)
Length: 1
Renegotiation Info extension
Renegotiation info extension length: 0
- What did you see instead?
Secure Sockets Layer
TLSv1.2 Record Layer: Handshake Protocol: Server Hello
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 49
Handshake Protocol: Server Hello
Handshake Type: Server Hello (2)
Length: 45
Version: TLS 1.2 (0x0303)
Random
Session ID Length: 0
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Compression Method: null (0)
Extensions Length: 5
Extension: renegotiation_info
Type: renegotiation_info (0xff01)
Length: 1
Renegotiation Info extension
Renegotiation info extension length: 0
The extension section of the ServerHello does not contain a server_name
extension.
When you make a request with an SNI header the client sends a client hello with a server name extension. RFC 6606 Section 3 states:
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.
We found this when debugging a TLS connection from the AWS API GW to a go server instance.
I am not sure whether this is a real issue or something that can be ignored. In any case it seems to be mentioned in the RFC and I couldn't find any mention in the issues. So even if it doesn't get addressed people can still find out why.
I realize that you prefer discussion first over code but the following patch added the server_name
extension:
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 111ce53..34f8eaa 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -490,6 +490,7 @@ type serverHelloMsg struct {
cipherSuite uint16
compressionMethod uint8
nextProtoNeg bool
+ serverName bool
nextProtos []string
ocspStapling bool
scts [][]byte
@@ -545,6 +546,9 @@ func (m *serverHelloMsg) marshal() []byte {
nextProtoLen += len(m.nextProtos)
extensionsLength += nextProtoLen
}
+ if m.serverName {
+ numExtensions++
+ }
if m.ocspStapling {
numExtensions++
}
@@ -614,6 +618,11 @@ func (m *serverHelloMsg) marshal() []byte {
z = z[1+l:]
}
}
+ if m.serverName {
+ z[0] = byte(extensionServerName >> 8)
+ z[1] = byte(extensionServerName & 0xff)
+ z = z[4:]
+ }
if m.ocspStapling {
z[0] = byte(extensionStatusRequest >> 8)
z[1] = byte(extensionStatusRequest)
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index e16cddc..66a9c02 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -122,6 +122,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
c.haveVers = true
hs.hello = new(serverHelloMsg)
+ hs.hello.serverName = len(hs.clientHello.serverName) > 0
supportedCurve := false
preferredCurves := config.curvePreferences()