diff options
author | David Benjamin <davidben@chromium.org> | 2014-09-06 13:21:53 -0400 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2014-09-15 21:10:59 +0000 |
commit | fc7b0863057cdbbcdf7af4d82c4d8d3ac688766b (patch) | |
tree | 6f2644fa8c95d130e424b52fade6249160097361 | |
parent | ae2888fbdc21ac70652034b5bfc24953a56dbe57 (diff) | |
download | src-fc7b0863057cdbbcdf7af4d82c4d8d3ac688766b.tar.gz |
Test that ALPN is preferred over NPN.
Change-Id: Ia9d10f672c8a83f507b46f75869b7c00fe1a4fda
Reviewed-on: https://boringssl-review.googlesource.com/1755
Reviewed-by: Adam Langley <agl@google.com>
-rw-r--r-- | ssl/test/runner/common.go | 6 | ||||
-rw-r--r-- | ssl/test/runner/conn.go | 2 | ||||
-rw-r--r-- | ssl/test/runner/handshake_client.go | 2 | ||||
-rw-r--r-- | ssl/test/runner/handshake_messages.go | 12 | ||||
-rw-r--r-- | ssl/test/runner/handshake_server.go | 1 | ||||
-rw-r--r-- | ssl/test/runner/runner.go | 66 |
6 files changed, 80 insertions, 9 deletions
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index acaa89c..7dbc1f0 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -167,6 +167,7 @@ type ConnectionState struct { CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server + NegotiatedProtocolFromALPN bool // protocol negotiated with ALPN ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates @@ -454,6 +455,11 @@ type ProtocolBugs struct { // ExpectServerName, if not empty, is the hostname the client // must specify in the server_name extension. ExpectServerName string + + // SwapNPNAndALPN switches the relative order between NPN and + // ALPN on the server. This is to test that server preference + // of ALPN works regardless of their relative order. + SwapNPNAndALPN bool } func (c *Config) serverInit() { diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 47b6e61..9f0c328 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go @@ -47,6 +47,7 @@ type Conn struct { clientProtocol string clientProtocolFallback bool + usedALPN bool channelID *ecdsa.PublicKey @@ -1105,6 +1106,7 @@ func (c *Conn) ConnectionState() ConnectionState { state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback + state.NegotiatedProtocolFromALPN = c.usedALPN state.CipherSuite = c.cipherSuite state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index d61c6d2..d78e767 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -69,6 +69,7 @@ func (c *Conn) clientHandshake() error { alpnProtocols: c.config.NextProtos, duplicateExtension: c.config.Bugs.DuplicateExtension, channelIDSupported: c.config.ChannelID != nil, + npnLast: c.config.Bugs.SwapNPNAndALPN, } if c.config.Bugs.SendClientVersion != 0 { @@ -601,6 +602,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { if serverHasALPN { c.clientProtocol = hs.serverHello.alpnProtocol c.clientProtocolFallback = false + c.usedALPN = true } if !hs.hello.channelIDSupported && hs.serverHello.channelIDRequested { diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index f0a1493..136360d 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go @@ -27,6 +27,7 @@ type clientHelloMsg struct { alpnProtocols []string duplicateExtension bool channelIDSupported bool + npnLast bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -54,7 +55,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.secureRenegotiation == m1.secureRenegotiation && eqStrings(m.alpnProtocols, m1.alpnProtocols) && m.duplicateExtension == m1.duplicateExtension && - m.channelIDSupported == m1.channelIDSupported + m.channelIDSupported == m1.channelIDSupported && + m.npnLast == m1.npnLast } func (m *clientHelloMsg) marshal() []byte { @@ -160,7 +162,7 @@ func (m *clientHelloMsg) marshal() []byte { z[1] = 0xff z = z[4:] } - if m.nextProtoNeg { + if m.nextProtoNeg && !m.npnLast { z[0] = byte(extensionNextProtoNeg >> 8) z[1] = byte(extensionNextProtoNeg & 0xff) // The length is always 0 @@ -305,6 +307,12 @@ func (m *clientHelloMsg) marshal() []byte { z[1] = byte(extensionChannelID & 0xff) z = z[4:] } + if m.nextProtoNeg && m.npnLast { + z[0] = byte(extensionNextProtoNeg >> 8) + z[1] = byte(extensionNextProtoNeg & 0xff) + // The length is always 0 + z = z[4:] + } if m.duplicateExtension { // Add a duplicate bogus extension at the beginning and end. z[0] = 0xff diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 7f6b521..45e300d 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -225,6 +225,7 @@ Curves: if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback { hs.hello.alpnProtocol = selectedProto c.clientProtocol = selectedProto + c.usedALPN = true } } else { // Although sending an empty NPN extension is reasonable, Firefox has diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 25e7626..7a87b91 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -97,6 +97,11 @@ const ( dtls ) +const ( + alpn = 1 + npn = 2 +) + type testCase struct { testType testType protocol protocol @@ -116,6 +121,9 @@ type testCase struct { // expectedNextProto controls whether the connection should // negotiate a next protocol via NPN or ALPN. expectedNextProto string + // expectedNextProtoType, if non-zero, is the expected next + // protocol negotiation mechanism. + expectedNextProtoType int // messageLen is the length, in bytes, of the test message that will be // sent. messageLen int @@ -523,6 +531,12 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e } } + if test.expectedNextProtoType != 0 { + if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN { + return fmt.Errorf("next proto type mismatch") + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -1143,8 +1157,9 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) MaxHandshakeRecordLength: maxHandshakeRecordLength, }, }, - flags: append(flags, "-select-next-proto", "foo"), - expectedNextProto: "foo", + flags: append(flags, "-select-next-proto", "foo"), + expectedNextProto: "foo", + expectedNextProtoType: npn, }) testCases = append(testCases, testCase{ protocol: protocol, @@ -1159,7 +1174,8 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: append(flags, "-advertise-npn", "\x03foo\x03bar\x03baz", "-expect-next-proto", "bar"), - expectedNextProto: "bar", + expectedNextProto: "bar", + expectedNextProtoType: npn, }) // Client does False Start and negotiates NPN. @@ -1446,8 +1462,9 @@ func addExtensionTests() { "-advertise-alpn", "\x03foo\x03bar\x03baz", "-expect-alpn", "foo", }, - expectedNextProto: "foo", - resumeSession: true, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, }) testCases = append(testCases, testCase{ testType: serverTest, @@ -1459,8 +1476,43 @@ func addExtensionTests() { "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", "-select-alpn", "foo", }, - expectedNextProto: "foo", - resumeSession: true, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) + // Test that the server prefers ALPN over NPN. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer-Preferred", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ALPNServer-Preferred-Swapped", + config: Config{ + NextProtos: []string{"foo", "bar", "baz"}, + Bugs: ProtocolBugs{ + SwapNPNAndALPN: true, + }, + }, + flags: []string{ + "-expect-advertised-alpn", "\x03foo\x03bar\x03baz", + "-select-alpn", "foo", + "-advertise-npn", "\x03foo\x03bar\x03baz", + }, + expectedNextProto: "foo", + expectedNextProtoType: alpn, + resumeSession: true, }) } |