Skip to content

Commit

Permalink
Fix invalid SNI handling
Browse files Browse the repository at this point in the history
SNIExtension was previously marshalling both ip addresses and empty
strings, which are not allowed. See RFC 6066, Section 3.

All of the utls specific testdata replays needed to be rebuilt to
properly accomodate this change since they had previously been including
empty server name extension values

Addresses refraction-networking#96
  • Loading branch information
max-b committed Feb 2, 2022
1 parent c498a9e commit 5c64f88
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 9 deletions.
33 changes: 33 additions & 0 deletions u_conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,38 @@ func TestUTLSRemoveSNIExtension(t *testing.T) {
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}

func TestUTLSServerNameIP(t *testing.T) {
hello := &helloID{HelloChrome_70}

config := getUTLSTestConfig()
config.ServerName = "1.1.1.1"

opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-ServerNameIP",
args: []string{"-cipher", opensslCipherName},
config: config,
}

runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}

func TestUTLSEmptyServerName(t *testing.T) {
hello := &helloID{HelloChrome_70}

config := getUTLSTestConfig()
config.ServerName = ""

opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-EmptyServerName",
args: []string{"-cipher", opensslCipherName},
config: config,
}

runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}

/*
*
HELPER FUNCTIONS BELOW
Expand All @@ -212,6 +244,7 @@ func getUTLSTestConfig() *Config {
MinVersion: VersionSSL30,
MaxVersion: VersionTLS13,
CipherSuites: allCipherSuites(),
ServerName: "foobar.com",
}
return testUTLSConfig
}
Expand Down
32 changes: 23 additions & 9 deletions u_tls_extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,43 @@ type SNIExtension struct {

func (e *SNIExtension) writeToUConn(uc *UConn) error {
uc.config.ServerName = e.ServerName
uc.HandshakeState.Hello.ServerName = e.ServerName
hostName := hostnameInSNI(e.ServerName)
uc.HandshakeState.Hello.ServerName = hostName

return nil
}

func (e *SNIExtension) Len() int {
return 4 + 2 + 1 + 2 + len(e.ServerName)
// Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
// See RFC 6066, Section 3.
hostName := hostnameInSNI(e.ServerName)
if len(hostName) == 0 {
return 0
}
return 4 + 2 + 1 + 2 + len(hostName)
}

func (e *SNIExtension) Read(b []byte) (int, error) {
// Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
// See RFC 6066, Section 3.
hostName := hostnameInSNI(e.ServerName)
if len(hostName) == 0 {
return 0, io.EOF
}
if len(b) < e.Len() {
return 0, io.ErrShortBuffer
}
// RFC 3546, section 3.1
b[0] = byte(extensionServerName >> 8)
b[1] = byte(extensionServerName)
b[2] = byte((len(e.ServerName) + 5) >> 8)
b[3] = byte((len(e.ServerName) + 5))
b[4] = byte((len(e.ServerName) + 3) >> 8)
b[5] = byte(len(e.ServerName) + 3)
b[2] = byte((len(hostName) + 5) >> 8)
b[3] = byte((len(hostName) + 5))
b[4] = byte((len(hostName) + 3) >> 8)
b[5] = byte(len(hostName) + 3)
// b[6] Server Name Type: host_name (0)
b[7] = byte(len(e.ServerName) >> 8)
b[8] = byte(len(e.ServerName))
copy(b[9:], []byte(e.ServerName))
b[7] = byte(len(hostName) >> 8)
b[8] = byte(len(hostName))
copy(b[9:], []byte(hostName))
return e.Len(), io.EOF
}

Expand Down

0 comments on commit 5c64f88

Please sign in to comment.