diff options
Diffstat (limited to 'ssl/test/runner/runner.go')
-rw-r--r-- | ssl/test/runner/runner.go | 587 |
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} { |