summaryrefslogtreecommitdiff
path: root/ssl/test/runner/runner.go
diff options
context:
space:
mode:
Diffstat (limited to 'ssl/test/runner/runner.go')
-rw-r--r--ssl/test/runner/runner.go587
1 files changed, 490 insertions, 97 deletions
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4a5b762..323f43f 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2,7 +2,11 @@ package main
import (
"bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
"crypto/x509"
+ "encoding/base64"
+ "encoding/pem"
"flag"
"fmt"
"io"
@@ -25,11 +29,14 @@ const (
)
const (
- rsaKeyFile = "key.pem"
- ecdsaKeyFile = "ecdsa_key.pem"
+ rsaKeyFile = "key.pem"
+ ecdsaKeyFile = "ecdsa_key.pem"
+ channelIDKeyFile = "channel_id_key.pem"
)
var rsaCertificate, ecdsaCertificate Certificate
+var channelIDKey *ecdsa.PrivateKey
+var channelIDBytes []byte
func initCertificates() {
var err error
@@ -42,6 +49,26 @@ func initCertificates() {
if err != nil {
panic(err)
}
+
+ channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
+ if err != nil {
+ panic(err)
+ }
+ channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
+ if channelIDDERBlock.Type != "EC PRIVATE KEY" {
+ panic("bad key type")
+ }
+ channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
+ if err != nil {
+ panic(err)
+ }
+ if channelIDKey.Curve != elliptic.P256() {
+ panic("bad curve")
+ }
+
+ channelIDBytes = make([]byte, 64)
+ writeIntPadded(channelIDBytes[:32], channelIDKey.X)
+ writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
}
var certificateOnce sync.Once
@@ -70,6 +97,11 @@ const (
dtls
)
+const (
+ alpn = 1
+ npn = 2
+)
+
type testCase struct {
testType testType
protocol protocol
@@ -83,6 +115,18 @@ type testCase struct {
// expectedVersion, if non-zero, specifies the TLS version that must be
// negotiated.
expectedVersion uint16
+ // expectedResumeVersion, if non-zero, specifies the TLS version that
+ // must be negotiated on resumption. If zero, expectedVersion is used.
+ expectedResumeVersion uint16
+ // expectChannelID controls whether the connection should have
+ // negotiated a Channel ID with channelIDKey.
+ expectChannelID bool
+ // 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
@@ -91,11 +135,19 @@ type testCase struct {
// keyFile is the path to the private key to use for the server.
keyFile string
// resumeSession controls whether a second connection should be tested
- // which resumes the first session.
+ // which attempts to resume the first session.
resumeSession bool
+ // resumeConfig, if not nil, points to a Config to be used on
+ // resumption. SessionTicketKey and ClientSessionCache are copied from
+ // the initial connection's config. If nil, the initial connection's
+ // config is used.
+ resumeConfig *Config
// sendPrefix sends a prefix on the socket before actually performing a
// handshake.
sendPrefix string
+ // shimWritesFirst controls whether the shim sends an initial "hello"
+ // message before doing a roundtrip with the runner.
+ shimWritesFirst bool
// flags, if not empty, contains a list of command-line flags that will
// be passed to the shim program.
flags []string
@@ -160,7 +212,7 @@ var testCases = []testCase{
expectedLocalError: "no fallback SCSV found",
},
{
- name: "FallbackSCSV",
+ name: "SendFallbackSCSV",
config: Config{
Bugs: ProtocolBugs{
FailIfNotFallbackSCSV: true,
@@ -169,36 +221,6 @@ var testCases = []testCase{
flags: []string{"-fallback-scsv"},
},
{
- testType: serverTest,
- name: "ServerNameExtension",
- config: Config{
- ServerName: "example.com",
- },
- flags: []string{"-expect-server-name", "example.com"},
- },
- {
- testType: clientTest,
- name: "DuplicateExtensionClient",
- config: Config{
- Bugs: ProtocolBugs{
- DuplicateExtension: true,
- },
- },
- shouldFail: true,
- expectedLocalError: "remote error: error decoding message",
- },
- {
- testType: serverTest,
- name: "DuplicateExtensionServer",
- config: Config{
- Bugs: ProtocolBugs{
- DuplicateExtension: true,
- },
- },
- shouldFail: true,
- expectedLocalError: "remote error: error decoding message",
- },
- {
name: "ClientCertificateTypes",
config: Config{
ClientAuth: RequestClientCert,
@@ -208,11 +230,14 @@ var testCases = []testCase{
CertTypeECDSASign,
},
},
- flags: []string{"-expect-certificate-types", string([]byte{
- CertTypeDSSSign,
- CertTypeRSASign,
- CertTypeECDSASign,
- })},
+ flags: []string{
+ "-expect-certificate-types",
+ base64.StdEncoding.EncodeToString([]byte{
+ CertTypeDSSSign,
+ CertTypeRSASign,
+ CertTypeECDSASign,
+ }),
+ },
},
{
name: "NoClientCertificate",
@@ -447,9 +472,21 @@ var testCases = []testCase{
shouldFail: true,
expectedError: ":HTTPS_PROXY_REQUEST:",
},
+ {
+ name: "SkipCipherVersionCheck",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ MaxVersion: VersionTLS11,
+ Bugs: ProtocolBugs{
+ SkipCipherVersionCheck: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CIPHER_RETURNED:",
+ },
}
-func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
+func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
if test.protocol == dtls {
conn = newPacketAdaptor(conn)
}
@@ -480,8 +517,50 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e
return err
}
- if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion {
- return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion)
+ // TODO(davidben): move all per-connection expectations into a dedicated
+ // expectations struct that can be specified separately for the two
+ // legs.
+ expectedVersion := test.expectedVersion
+ if isResume && test.expectedResumeVersion != 0 {
+ expectedVersion = test.expectedResumeVersion
+ }
+ if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
+ return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
+ }
+
+ if test.expectChannelID {
+ channelID := tlsConn.ConnectionState().ChannelID
+ if channelID == nil {
+ return fmt.Errorf("no channel ID negotiated")
+ }
+ if channelID.Curve != channelIDKey.Curve ||
+ channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
+ channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
+ return fmt.Errorf("incorrect channel ID")
+ }
+ }
+
+ if expected := test.expectedNextProto; expected != "" {
+ if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
+ return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
+ }
+ }
+
+ 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[:])
+ if err != nil {
+ return err
+ }
+ if string(buf[:]) != "hello" {
+ return fmt.Errorf("bad initial message")
+ }
}
if messageLen < 0 {
@@ -601,6 +680,10 @@ func runTest(test *testCase, buildDir string) error {
flags = append(flags, "-resume")
}
+ if test.shimWritesFirst {
+ flags = append(flags, "-shim-writes-first")
+ }
+
flags = append(flags, test.flags...)
var shim *exec.Cmd
@@ -630,12 +713,25 @@ func runTest(test *testCase, buildDir string) error {
}
}
- err := doExchange(test, &config, conn, test.messageLen)
+ err := doExchange(test, &config, conn, test.messageLen,
+ false /* not a resumption */)
conn.Close()
if err == nil && test.resumeSession {
- err = doExchange(test, &config, connResume, test.messageLen)
- connResume.Close()
+ var resumeConfig Config
+ if test.resumeConfig != nil {
+ resumeConfig = *test.resumeConfig
+ if len(resumeConfig.Certificates) == 0 {
+ resumeConfig.Certificates = []Certificate{getRSACertificate()}
+ }
+ resumeConfig.SessionTicketKey = config.SessionTicketKey
+ resumeConfig.ClientSessionCache = config.ClientSessionCache
+ } else {
+ resumeConfig = config
+ }
+ err = doExchange(test, &resumeConfig, connResume, test.messageLen,
+ true /* resumption */)
}
+ connResume.Close()
childErr := shim.Wait()
@@ -697,25 +793,40 @@ var testCipherSuites = []struct {
{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
{"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+ {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
{"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+ {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
{"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
{"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+ {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
{"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
{"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
+ {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
}
+func isTLS12Only(suiteName string) bool {
+ return strings.HasSuffix(suiteName, "-GCM") ||
+ strings.HasSuffix(suiteName, "-SHA256") ||
+ strings.HasSuffix(suiteName, "-SHA384")
+}
+
func addCipherSuiteTests() {
for _, suite := range testCipherSuites {
var cert Certificate
@@ -732,7 +843,7 @@ func addCipherSuiteTests() {
}
for _, ver := range tlsVersions {
- if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
+ if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
continue
}
@@ -902,29 +1013,14 @@ func addClientAuthTests() {
certPool.AddCert(cert)
for _, ver := range tlsVersions {
- if ver.version == VersionSSL30 {
- // TODO(davidben): The Go implementation does not
- // correctly compute CertificateVerify hashes for SSLv3.
- continue
- }
-
- var cipherSuites []uint16
- if ver.version >= VersionTLS12 {
- // Pick a SHA-256 cipher suite. The Go implementation
- // does not correctly handle client auth with a SHA-384
- // cipher suite.
- cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
- }
-
testCases = append(testCases, testCase{
testType: clientTest,
name: ver.name + "-Client-ClientAuth-RSA",
config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: cipherSuites,
- ClientAuth: RequireAnyClientCert,
- ClientCAs: certPool,
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
},
flags: []string{
"-cert-file", rsaCertificateFile,
@@ -932,36 +1028,41 @@ func addClientAuthTests() {
},
})
testCases = append(testCases, testCase{
- testType: clientTest,
- name: ver.name + "-Client-ClientAuth-ECDSA",
- config: Config{
- MinVersion: ver.version,
- MaxVersion: ver.version,
- CipherSuites: cipherSuites,
- ClientAuth: RequireAnyClientCert,
- ClientCAs: certPool,
- },
- flags: []string{
- "-cert-file", ecdsaCertificateFile,
- "-key-file", ecdsaKeyFile,
- },
- })
- testCases = append(testCases, testCase{
testType: serverTest,
name: ver.name + "-Server-ClientAuth-RSA",
config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
Certificates: []Certificate{rsaCertificate},
},
flags: []string{"-require-any-client-certificate"},
})
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: ver.name + "-Server-ClientAuth-ECDSA",
- config: Config{
- Certificates: []Certificate{ecdsaCertificate},
- },
- flags: []string{"-require-any-client-certificate"},
- })
+ if ver.version != VersionSSL30 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-Server-ClientAuth-ECDSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{ecdsaCertificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-Client-ClientAuth-ECDSA",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ClientAuth: RequireAnyClientCert,
+ ClientCAs: certPool,
+ },
+ flags: []string{
+ "-cert-file", ecdsaCertificateFile,
+ "-key-file", ecdsaKeyFile,
+ },
+ })
+ }
}
}
@@ -1029,8 +1130,7 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
testType: clientTest,
name: "ClientAuth-Client" + suffix,
config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- ClientAuth: RequireAnyClientCert,
+ ClientAuth: RequireAnyClientCert,
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
@@ -1080,13 +1180,14 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
protocol: protocol,
name: "NPN-Client" + suffix,
config: Config{
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
- NextProtos: []string{"foo"},
+ NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
- flags: append(flags, "-select-next-proto", "foo"),
+ flags: append(flags, "-select-next-proto", "foo"),
+ expectedNextProto: "foo",
+ expectedNextProtoType: npn,
})
testCases = append(testCases, testCase{
protocol: protocol,
@@ -1101,6 +1202,8 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
flags: append(flags,
"-advertise-npn", "\x03foo\x03bar\x03baz",
"-expect-next-proto", "bar"),
+ expectedNextProto: "bar",
+ expectedNextProtoType: npn,
})
// Client does False Start and negotiates NPN.
@@ -1111,13 +1214,34 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
flags: append(flags,
"-false-start",
"-select-next-proto", "foo"),
- resumeSession: true,
+ shimWritesFirst: true,
+ resumeSession: true,
+ })
+
+ // Client does False Start and negotiates ALPN.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "FalseStart-ALPN" + suffix,
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
+ },
+ flags: append(flags,
+ "-false-start",
+ "-advertise-alpn", "\x03foo"),
+ shimWritesFirst: true,
+ resumeSession: true,
})
// False Start without session tickets.
@@ -1127,14 +1251,19 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
SessionTicketsDisabled: true,
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
},
- flags: []string{
+ flags: append(flags,
"-false-start",
"-select-next-proto", "foo",
- },
+ ),
+ shimWritesFirst: true,
})
- // Client sends a V2ClientHello.
+ // Server parses a V2ClientHello.
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
@@ -1151,6 +1280,42 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
},
flags: flags,
})
+
+ // Client sends a Channel ID.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: "ChannelID-Client" + suffix,
+ config: Config{
+ RequestChannelID: true,
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
+ },
+ flags: append(flags,
+ "-send-channel-id", channelIDKeyFile,
+ ),
+ resumeSession: true,
+ expectChannelID: true,
+ })
+
+ // Server accepts a Channel ID.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "ChannelID-Server" + suffix,
+ config: Config{
+ ChannelID: channelIDKey,
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ },
+ },
+ flags: append(flags,
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ ),
+ resumeSession: true,
+ expectChannelID: true,
+ })
} else {
testCases = append(testCases, testCase{
protocol: protocol,
@@ -1216,6 +1381,231 @@ func addVersionNegotiationTests() {
}
}
+func addD5BugTests() {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "D5Bug-NoQuirk-Reject",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SSL3RSAKeyExchange: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "D5Bug-Quirk-Normal",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ flags: []string{"-tls-d5-bug"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "D5Bug-Quirk-Bug",
+ config: Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SSL3RSAKeyExchange: true,
+ },
+ },
+ flags: []string{"-tls-d5-bug"},
+ })
+}
+
+func addExtensionTests() {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "DuplicateExtensionClient",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DuplicateExtension: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DuplicateExtensionServer",
+ config: Config{
+ Bugs: ProtocolBugs{
+ DuplicateExtension: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClient",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectServerName: "example.com",
+ },
+ },
+ flags: []string{"-host-name", "example.com"},
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClient",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectServerName: "mismatch.com",
+ },
+ },
+ flags: []string{"-host-name", "example.com"},
+ shouldFail: true,
+ expectedLocalError: "tls: unexpected server name",
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ServerNameExtensionClient",
+ config: Config{
+ Bugs: ProtocolBugs{
+ ExpectServerName: "missing.com",
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "tls: unexpected server name",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerNameExtensionServer",
+ config: Config{
+ ServerName: "example.com",
+ },
+ flags: []string{"-expect-server-name", "example.com"},
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ALPNClient",
+ config: Config{
+ NextProtos: []string{"foo"},
+ },
+ flags: []string{
+ "-advertise-alpn", "\x03foo\x03bar\x03baz",
+ "-expect-alpn", "foo",
+ },
+ expectedNextProto: "foo",
+ expectedNextProtoType: alpn,
+ resumeSession: true,
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ALPNServer",
+ config: Config{
+ NextProtos: []string{"foo", "bar", "baz"},
+ },
+ flags: []string{
+ "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+ "-select-alpn", "foo",
+ },
+ 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,
+ })
+}
+
+func addResumptionVersionTests() {
+ // TODO(davidben): Once DTLS 1.2 is working, test that as well.
+ for _, sessionVers := range tlsVersions {
+ // TODO(davidben): SSLv3 is omitted here because runner does not
+ // support resumption with session IDs.
+ if sessionVers.version == VersionSSL30 {
+ continue
+ }
+ for _, resumeVers := range tlsVersions {
+ if resumeVers.version == VersionSSL30 {
+ continue
+ }
+ suffix := "-" + sessionVers.name + "-" + resumeVers.name
+
+ // TODO(davidben): Write equivalent tests for the server
+ // and clean up the server's logic. This requires being
+ // able to give the shim a different set of SSL_OP_NO_*
+ // flags between the initial connection and the
+ // resume. Perhaps resumption should be tested by
+ // serializing the SSL_SESSION and starting a second
+ // shim.
+ testCases = append(testCases, testCase{
+ name: "Resume-Client" + suffix,
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ AllowSessionVersionMismatch: true,
+ },
+ },
+ expectedVersion: sessionVers.version,
+ resumeConfig: &Config{
+ MaxVersion: resumeVers.version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ AllowSessionVersionMismatch: true,
+ },
+ },
+ expectedResumeVersion: resumeVers.version,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "Resume-Client-NoResume" + suffix,
+ flags: []string{"-expect-session-miss"},
+ resumeSession: true,
+ config: Config{
+ MaxVersion: sessionVers.version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ },
+ expectedVersion: sessionVers.version,
+ resumeConfig: &Config{
+ MaxVersion: resumeVers.version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ SessionTicketsDisabled: true,
+ },
+ expectedResumeVersion: resumeVers.version,
+ })
+ }
+ }
+}
+
func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
defer wg.Done()
@@ -1268,6 +1658,9 @@ func main() {
addCBCSplittingTests()
addClientAuthTests()
addVersionNegotiationTests()
+ addD5BugTests()
+ addExtensionTests()
+ addResumptionVersionTests()
for _, async := range []bool{false, true} {
for _, splitHandshake := range []bool{false, true} {
for _, protocol := range []protocol{tls, dtls} {