Add a test to assert parsing V2ClientHellos works.
Should have test coverage there as long as we care about supporting it.
Change-Id: Ic67539228b550f2ebd0b543d5a58640913b0474b
Reviewed-on: https://boringssl-review.googlesource.com/1371
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 7b8d964..1cfdda9 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -383,6 +383,10 @@
// SkipNewSessionTicket causes the server to skip sending the
// NewSessionTicket message despite promising to in ServerHello.
SkipNewSessionTicket bool
+
+ // SendV2ClientHello causes the client to send a V2ClientHello
+ // instead of a normal ClientHello.
+ SendV2ClientHello bool
}
func (c *Config) serverInit() {
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 49224a2..02ed8f0 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -700,6 +700,15 @@
return c.sendAlertLocked(err)
}
+// writeV2Record writes a record for a V2ClientHello.
+func (c *Conn) writeV2Record(data []byte) (n int, err error) {
+ record := make([]byte, 2+len(data))
+ record[0] = uint8(len(data)>>8) | 0x80
+ record[1] = uint8(len(data))
+ copy(record[2:], data)
+ return c.conn.Write(record)
+}
+
// writeRecord writes a TLS record with the given type and payload
// to the connection and updates the record layer state.
// c.out.Mutex <= L.
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 80208dd..0b9d772 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -126,7 +126,21 @@
}
}
- c.writeRecord(recordTypeHandshake, hello.marshal())
+ var helloBytes []byte
+ if c.config.Bugs.SendV2ClientHello {
+ v2Hello := &v2ClientHelloMsg{
+ vers: hello.vers,
+ cipherSuites: hello.cipherSuites,
+ // No session resumption for V2ClientHello.
+ sessionId: nil,
+ challenge: hello.random,
+ }
+ helloBytes = v2Hello.marshal()
+ c.writeV2Record(helloBytes)
+ } else {
+ helloBytes = hello.marshal()
+ c.writeRecord(recordTypeHandshake, helloBytes)
+ }
msg, err := c.readHandshake()
if err != nil {
@@ -162,7 +176,7 @@
session: session,
}
- hs.finishedHash.Write(hs.hello.marshal())
+ hs.finishedHash.Write(helloBytes)
hs.finishedHash.Write(hs.serverHello.marshal())
if c.config.Bugs.EarlyChangeCipherSpec > 0 {
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index edb45d8..1c633bb 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -1314,6 +1314,60 @@
return true
}
+type v2ClientHelloMsg struct {
+ raw []byte
+ vers uint16
+ cipherSuites []uint16
+ sessionId []byte
+ challenge []byte
+}
+
+func (m *v2ClientHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*v2ClientHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.vers == m1.vers &&
+ eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ bytes.Equal(m.challenge, m1.challenge)
+}
+
+func (m *v2ClientHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 1 + 2 + 2 + 2 + 2 + len(m.cipherSuites)*3 + len(m.sessionId) + len(m.challenge)
+
+ x := make([]byte, length)
+ x[0] = 1
+ x[1] = uint8(m.vers >> 8)
+ x[2] = uint8(m.vers)
+ x[3] = uint8((len(m.cipherSuites) * 3) >> 8)
+ x[4] = uint8(len(m.cipherSuites) * 3)
+ x[5] = uint8(len(m.sessionId) >> 8)
+ x[6] = uint8(len(m.sessionId))
+ x[7] = uint8(len(m.challenge) >> 8)
+ x[8] = uint8(len(m.challenge))
+ y := x[9:]
+ for i, spec := range m.cipherSuites {
+ y[i*3] = 0
+ y[i*3+1] = uint8(spec >> 8)
+ y[i*3+2] = uint8(spec)
+ }
+ y = y[len(m.cipherSuites)*3:]
+ copy(y, m.sessionId)
+ y = y[len(m.sessionId):]
+ copy(y, m.challenge)
+
+ m.raw = x
+
+ return x
+}
+
func eqUint16s(x, y []uint16) bool {
if len(x) != len(y) {
return false
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index eedb2f1..bec89b1 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -347,7 +347,7 @@
name: "FalseStart",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
+ NextProtos: []string{"foo"},
},
flags: []string{
"-false-start",
@@ -358,8 +358,8 @@
{
name: "FalseStart-SessionTicketsDisabled",
config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
SessionTicketsDisabled: true,
},
flags: []string{
@@ -367,6 +367,19 @@
"-select-next-proto", "foo",
},
},
+ {
+ testType: serverTest,
+ name: "SendV2ClientHello",
+ config: Config{
+ // Choose a cipher suite that does not involve
+ // elliptic curves, so no extensions are
+ // involved.
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ SendV2ClientHello: true,
+ },
+ },
+ },
}
func doExchange(testType testType, config *Config, conn net.Conn, messageLen int) error {