diff options
Diffstat (limited to 'src/ssl/test/runner/runner.go')
-rw-r--r-- | src/ssl/test/runner/runner.go | 700 |
1 files changed, 388 insertions, 312 deletions
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index ec2fede..bd03cb1 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "io/ioutil" + "math/big" "net" "os" "os/exec" @@ -160,6 +161,10 @@ type testCase struct { // resumeSession controls whether a second connection should be tested // which attempts to resume the first session. resumeSession bool + // expectResumeRejected, if true, specifies that the attempted + // resumption must be rejected by the client. This is only valid for a + // serverTest. + expectResumeRejected bool // resumeConfig, if not nil, points to a Config to be used on // resumption. Unless newSessionsOnResume is set, // SessionTicketKey, ServerSessionCache, and @@ -196,6 +201,9 @@ type testCase struct { // flags, if not empty, contains a list of command-line flags that will // be passed to the shim program. flags []string + // testTLSUnique, if true, causes the shim to send the tls-unique value + // which will be compared against the expected value. + testTLSUnique bool } var testCases = []testCase{ @@ -1085,6 +1093,49 @@ var testCases = []testCase{ }, expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, }, + { + protocol: dtls, + name: "SendSplitAlert-Sync", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + }, + { + protocol: dtls, + name: "SendSplitAlert-Async", + config: Config{ + Bugs: ProtocolBugs{ + SendSplitAlert: true, + }, + }, + flags: []string{"-async"}, + }, + { + protocol: dtls, + name: "PackDTLSHandshake", + config: Config{ + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: 2, + PackHandshakeFragments: 20, + PackHandshakeRecords: 200, + }, + }, + }, + { + testType: serverTest, + protocol: dtls, + name: "NoRC4-DTLS", + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Bugs: ProtocolBugs{ + EnableAllCiphersInDTLS: true, + }, + }, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", + }, } func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error { @@ -1144,16 +1195,20 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i if isResume && test.expectedResumeVersion != 0 { expectedVersion = test.expectedResumeVersion } - if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion { + connState := tlsConn.ConnectionState() + if vers := connState.Version; expectedVersion != 0 && vers != expectedVersion { return fmt.Errorf("got version %x, expected %x", vers, expectedVersion) } - if cipher := tlsConn.ConnectionState().CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher { + if cipher := connState.CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher { return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher) } + if didResume := connState.DidResume; isResume && didResume == test.expectResumeRejected { + return fmt.Errorf("didResume is %t, but we expected the opposite", didResume) + } if test.expectChannelID { - channelID := tlsConn.ConnectionState().ChannelID + channelID := connState.ChannelID if channelID == nil { return fmt.Errorf("no channel ID negotiated") } @@ -1165,18 +1220,18 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } if expected := test.expectedNextProto; expected != "" { - if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected { + if actual := connState.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 { + if (test.expectedNextProtoType == alpn) != connState.NegotiatedProtocolFromALPN { return fmt.Errorf("next proto type mismatch") } } - if p := tlsConn.ConnectionState().SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile { + if p := connState.SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile { return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile) } @@ -1194,6 +1249,17 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } } + if test.testTLSUnique { + var peersValue [12]byte + if _, err := io.ReadFull(tlsConn, peersValue[:]); err != nil { + return err + } + expected := tlsConn.ConnectionState().TLSUnique + if !bytes.Equal(peersValue[:], expected) { + return fmt.Errorf("tls-unique mismatch: peer sent %x, but %x was expected", peersValue[:], expected) + } + } + if test.shimWritesFirst { var buf [5]byte _, err := io.ReadFull(tlsConn, buf[:]) @@ -1321,6 +1387,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { panic("Error expected without shouldFail in " + test.name) } + if test.expectResumeRejected && !test.resumeSession { + panic("expectResumeRejected without resumeSession in " + test.name) + } + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}}) if err != nil { panic(err) @@ -1371,6 +1441,13 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error { flags = append(flags, "-use-export-context") } } + if test.expectResumeRejected { + flags = append(flags, "-expect-session-miss") + } + + if test.testTLSUnique { + flags = append(flags, "-tls-unique") + } flags = append(flags, test.flags...) @@ -1569,6 +1646,14 @@ func isDTLSCipher(suiteName string) bool { return !hasComponent(suiteName, "RC4") } +func bigFromHex(hex string) *big.Int { + ret, ok := new(big.Int).SetString(hex, 16) + if !ok { + panic("failed to parse hex number 0x" + hex) + } + return ret +} + func addCipherSuiteTests() { for _, suite := range testCipherSuites { const psk = "12345" @@ -1667,6 +1752,21 @@ func addCipherSuiteTests() { } } } + + testCases = append(testCases, testCase{ + name: "WeakDH", + config: Config{ + CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + // This is a 1023-bit prime number, generated + // with: + // openssl gendh 1023 | openssl asn1parse -i + DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"), + }, + }, + shouldFail: true, + expectedError: "BAD_DH_P_LENGTH", + }) } func addBadECDSASignatureTests() { @@ -1866,245 +1966,235 @@ func addExtendedMasterSecretTests() { } } - // When a session is resumed, it should still be aware that its master - // secret was generated via EMS and thus it's safe to use tls-unique. - testCases = append(testCases, testCase{ - name: "ExtendedMasterSecret-Resume", - config: Config{ - Bugs: ProtocolBugs{ - RequireExtendedMasterSecret: true, - }, - }, - flags: []string{expectEMSFlag}, - resumeSession: true, - }) + for _, isClient := range []bool{false, true} { + for _, supportedInFirstConnection := range []bool{false, true} { + for _, supportedInResumeConnection := range []bool{false, true} { + boolToWord := func(b bool) string { + if b { + return "Yes" + } + return "No" + } + suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-" + if isClient { + suffix += "Client" + } else { + suffix += "Server" + } + + supportedConfig := Config{ + Bugs: ProtocolBugs{ + RequireExtendedMasterSecret: true, + }, + } + + noSupportConfig := Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: true, + }, + } + + test := testCase{ + name: "ExtendedMasterSecret-" + suffix, + resumeSession: true, + } + + if !isClient { + test.testType = serverTest + } + + if supportedInFirstConnection { + test.config = supportedConfig + } else { + test.config = noSupportConfig + } + + if supportedInResumeConnection { + test.resumeConfig = &supportedConfig + } else { + test.resumeConfig = &noSupportConfig + } + + switch suffix { + case "YesToYes-Client", "YesToYes-Server": + // When a session is resumed, it should + // still be aware that its master + // secret was generated via EMS and + // thus it's safe to use tls-unique. + test.flags = []string{expectEMSFlag} + case "NoToYes-Server": + // If an original connection did not + // contain EMS, but a resumption + // handshake does, then a server should + // not resume the session. + test.expectResumeRejected = true + case "YesToNo-Server": + // Resuming an EMS session without the + // EMS extension should cause the + // server to abort the connection. + test.shouldFail = true + test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" + case "NoToYes-Client": + // A client should abort a connection + // where the server resumed a non-EMS + // session but echoed the EMS + // extension. + test.shouldFail = true + test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:" + case "YesToNo-Client": + // A client should abort a connection + // where the server didn't echo EMS + // when the session used it. + test.shouldFail = true + test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" + } + + testCases = append(testCases, test) + } + } + } } // Adds tests that try to cover the range of the handshake state machine, under // various conditions. Some of these are redundant with other tests, but they // only cover the synchronous case. func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) { - var suffix string - var flags []string - var maxHandshakeRecordLength int - if protocol == dtls { - suffix = "-DTLS" - } - if async { - suffix += "-Async" - flags = append(flags, "-async") - } else { - suffix += "-Sync" - } - if splitHandshake { - suffix += "-SplitHandshakeRecords" - maxHandshakeRecordLength = 1 - } + var tests []testCase // Basic handshake, with resumption. Client and server, // session ID and session ticket. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: flags, + tests = append(tests, testCase{ + name: "Basic-Client", resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-RenewTicket" + suffix, + tests = append(tests, testCase{ + name: "Basic-Client-RenewTicket", config: Config{ Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - RenewTicketOnResume: true, + RenewTicketOnResume: true, }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-NoTicket" + suffix, + tests = append(tests, testCase{ + name: "Basic-Client-NoTicket", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - name: "Basic-Client-Implicit" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-implicit-handshake"), + tests = append(tests, testCase{ + name: "Basic-Client-Implicit", + flags: []string{"-implicit-handshake"}, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: flags, + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server", resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "Basic-Server-NoTickets" + suffix, + name: "Basic-Server-NoTickets", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server-Implicit" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-implicit-handshake"), + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server-Implicit", + flags: []string{"-implicit-handshake"}, resumeSession: true, }) - testCases = append(testCases, testCase{ - protocol: protocol, - testType: serverTest, - name: "Basic-Server-EarlyCallback" + suffix, - config: Config{ - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, - }, - flags: append(flags, "-use-early-callback"), + tests = append(tests, testCase{ + testType: serverTest, + name: "Basic-Server-EarlyCallback", + flags: []string{"-use-early-callback"}, resumeSession: true, }) // TLS client auth. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: clientTest, - name: "ClientAuth-Client" + suffix, + name: "ClientAuth-Client", config: Config{ ClientAuth: RequireAnyClientCert, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-cert-file", rsaCertificateFile, - "-key-file", rsaKeyFile), + "-key-file", rsaKeyFile, + }, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "ClientAuth-Server" + suffix, + name: "ClientAuth-Server", config: Config{ Certificates: []Certificate{rsaCertificate}, }, - flags: append(flags, "-require-any-client-certificate"), + flags: []string{"-require-any-client-certificate"}, }) // No session ticket support; server doesn't send NewSessionTicket. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "SessionTicketsDisabled-Client" + suffix, + tests = append(tests, testCase{ + name: "SessionTicketsDisabled-Client", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "SessionTicketsDisabled-Server" + suffix, + name: "SessionTicketsDisabled-Server", config: Config{ SessionTicketsDisabled: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: flags, }) // Skip ServerKeyExchange in PSK key exchange if there's no // identity hint. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "EmptyPSKHint-Client" + suffix, + tests = append(tests, testCase{ + name: "EmptyPSKHint-Client", config: Config{ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, PreSharedKey: []byte("secret"), - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-psk", "secret"), + flags: []string{"-psk", "secret"}, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "EmptyPSKHint-Server" + suffix, + name: "EmptyPSKHint-Server", config: Config{ CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, PreSharedKey: []byte("secret"), - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-psk", "secret"), + flags: []string{"-psk", "secret"}, }) if protocol == tls { + tests = append(tests, testCase{ + name: "Renegotiate-Client", + renegotiate: true, + }) // NPN on client and server; results in post-handshake message. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "NPN-Client" + suffix, + tests = append(tests, testCase{ + name: "NPN-Client", config: Config{ NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, "-select-next-proto", "foo"), + flags: []string{"-select-next-proto", "foo"}, expectedNextProto: "foo", expectedNextProtoType: npn, }) - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "NPN-Server" + suffix, + name: "NPN-Server", config: Config{ NextProtos: []string{"bar"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-advertise-npn", "\x03foo\x03bar\x03baz", - "-expect-next-proto", "bar"), + "-expect-next-proto", "bar", + }, expectedNextProto: "bar", expectedNextProtoType: npn, }) @@ -2112,146 +2202,148 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) // TODO(davidben): Add tests for when False Start doesn't trigger. // Client does False Start and negotiates NPN. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart" + suffix, + tests = append(tests, testCase{ + name: "FalseStart", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", - "-select-next-proto", "foo"), + "-select-next-proto", "foo", + }, shimWritesFirst: true, resumeSession: true, }) // Client does False Start and negotiates ALPN. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart-ALPN" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-ALPN", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", - "-advertise-alpn", "\x03foo"), + "-advertise-alpn", "\x03foo", + }, shimWritesFirst: true, resumeSession: true, }) // Client does False Start but doesn't explicitly call // SSL_connect. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "FalseStart-Implicit" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-Implicit", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-implicit-handshake", "-false-start", - "-advertise-alpn", "\x03foo"), + "-advertise-alpn", "\x03foo", + }, }) // False Start without session tickets. - testCases = append(testCases, testCase{ - name: "FalseStart-SessionTicketsDisabled" + suffix, + tests = append(tests, testCase{ + name: "FalseStart-SessionTicketsDisabled", config: Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"foo"}, SessionTicketsDisabled: true, Bugs: ProtocolBugs{ - ExpectFalseStart: true, - MaxHandshakeRecordLength: maxHandshakeRecordLength, + ExpectFalseStart: true, }, }, - flags: append(flags, + flags: []string{ "-false-start", "-select-next-proto", "foo", - ), + }, shimWritesFirst: true, }) // Server parses a V2ClientHello. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "SendV2ClientHello" + suffix, + 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{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - SendV2ClientHello: true, + SendV2ClientHello: true, }, }, - flags: flags, }) // Client sends a Channel ID. - testCases = append(testCases, testCase{ - protocol: protocol, - name: "ChannelID-Client" + suffix, + tests = append(tests, testCase{ + name: "ChannelID-Client", config: Config{ RequestChannelID: true, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, - "-send-channel-id", channelIDKeyFile, - ), + flags: []string{"-send-channel-id", channelIDKeyFile}, resumeSession: true, expectChannelID: true, }) // Server accepts a Channel ID. - testCases = append(testCases, testCase{ - protocol: protocol, + tests = append(tests, testCase{ testType: serverTest, - name: "ChannelID-Server" + suffix, + name: "ChannelID-Server", config: Config{ ChannelID: channelIDKey, - Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - }, }, - flags: append(flags, + flags: []string{ "-expect-channel-id", base64.StdEncoding.EncodeToString(channelIDBytes), - ), + }, resumeSession: true, expectChannelID: true, }) } else { - testCases = append(testCases, testCase{ - protocol: protocol, - name: "SkipHelloVerifyRequest" + suffix, + tests = append(tests, testCase{ + name: "SkipHelloVerifyRequest", config: Config{ Bugs: ProtocolBugs{ - MaxHandshakeRecordLength: maxHandshakeRecordLength, - SkipHelloVerifyRequest: true, + SkipHelloVerifyRequest: true, }, }, - flags: flags, }) } + + var suffix string + var flags []string + var maxHandshakeRecordLength int + if protocol == dtls { + suffix = "-DTLS" + } + if async { + suffix += "-Async" + flags = append(flags, "-async") + } else { + suffix += "-Sync" + } + if splitHandshake { + suffix += "-SplitHandshakeRecords" + maxHandshakeRecordLength = 1 + } + for _, test := range tests { + test.protocol = protocol + test.name += suffix + test.config.Bugs.MaxHandshakeRecordLength = maxHandshakeRecordLength + test.flags = append(test.flags, flags...) + testCases = append(testCases, test) + } } func addDDoSCallbackTests() { @@ -2637,8 +2729,8 @@ func addExtensionTests() { CorruptTicket: true, }, }, - resumeSession: true, - flags: []string{"-expect-session-miss"}, + resumeSession: true, + expectResumeRejected: true, }) // Resume with an oversized session id. testCases = append(testCases, testCase{ @@ -2799,7 +2891,6 @@ func addResumptionVersionTests() { testCases = append(testCases, testCase{ protocol: protocol, name: "Resume-Client-NoResume" + suffix, - flags: []string{"-expect-session-miss"}, resumeSession: true, config: Config{ MaxVersion: sessionVers.version, @@ -2811,24 +2902,21 @@ func addResumptionVersionTests() { CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, newSessionsOnResume: true, + expectResumeRejected: true, expectedResumeVersion: resumeVers.version, }) - var flags []string - if sessionVers.version != resumeVers.version { - flags = append(flags, "-expect-session-miss") - } testCases = append(testCases, testCase{ protocol: protocol, testType: serverTest, name: "Resume-Server" + suffix, - flags: flags, resumeSession: true, config: Config{ MaxVersion: sessionVers.version, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, }, - expectedVersion: sessionVers.version, + expectedVersion: sessionVers.version, + expectResumeRejected: sessionVers.version != resumeVers.version, resumeConfig: &Config{ MaxVersion: resumeVers.version, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, @@ -2857,57 +2945,50 @@ func addResumptionVersionTests() { } func addRenegotiationTests() { + // Servers cannot renegotiate. testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server", - flags: []string{"-renegotiate"}, - shimWritesFirst: true, + testType: serverTest, + name: "Renegotiate-Server-Forbidden", + renegotiate: true, + flags: []string{"-reject-peer-renegotiations"}, + shouldFail: true, + expectedError: ":NO_RENEGOTIATION:", + expectedLocalError: "remote error: no renegotiation", }) + // TODO(agl): test the renegotiation info SCSV. testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-Full", + name: "Renegotiate-Client", config: Config{ Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, + FailIfResumeOnRenego: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, + renegotiate: true, }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-EmptyExt", + name: "Renegotiate-Client-EmptyExt", + renegotiate: true, config: Config{ Bugs: ProtocolBugs{ EmptyRenegotiationInfo: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-BadExt", + name: "Renegotiate-Client-BadExt", + renegotiate: true, config: Config{ Bugs: ProtocolBugs{ BadRenegotiationInfo: true, }, }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated", - renegotiate: true, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-NoExt", + name: "Renegotiate-Client-NoExt", renegotiate: true, config: Config{ Bugs: ProtocolBugs{ @@ -2916,75 +2997,16 @@ func addRenegotiationTests() { }, shouldFail: true, expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:", + flags: []string{"-no-legacy-server-connect"}, }) testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-NoExt-Allowed", + name: "Renegotiate-Client-NoExt-Allowed", renegotiate: true, config: Config{ Bugs: ProtocolBugs{ NoRenegotiationInfo: true, }, }, - flags: []string{"-allow-unsafe-legacy-renegotiation"}, - }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-ClientInitiated-Forbidden", - renegotiate: true, - flags: []string{"-reject-peer-renegotiations"}, - shouldFail: true, - expectedError: ":NO_RENEGOTIATION:", - expectedLocalError: "remote error: no renegotiation", - }) - // Regression test for CVE-2015-0291. - testCases = append(testCases, testCase{ - testType: serverTest, - name: "Renegotiate-Server-NoSignatureAlgorithms", - config: Config{ - Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, - NoSignatureAlgorithmsOnRenego: true, - }, - }, - flags: []string{"-renegotiate"}, - shimWritesFirst: true, - }) - // TODO(agl): test the renegotiation info SCSV. - testCases = append(testCases, testCase{ - name: "Renegotiate-Client", - renegotiate: true, - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-Full", - config: Config{ - Bugs: ProtocolBugs{ - NeverResumeOnRenego: true, - }, - }, - renegotiate: true, - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-EmptyExt", - renegotiate: true, - config: Config{ - Bugs: ProtocolBugs{ - EmptyRenegotiationInfo: true, - }, - }, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", - }) - testCases = append(testCases, testCase{ - name: "Renegotiate-Client-BadExt", - renegotiate: true, - config: Config{ - Bugs: ProtocolBugs{ - BadRenegotiationInfo: true, - }, - }, - shouldFail: true, - expectedError: ":RENEGOTIATION_MISMATCH:", }) testCases = append(testCases, testCase{ name: "Renegotiate-Client-SwitchCiphers", @@ -3365,6 +3387,59 @@ func addExportKeyingMaterialTests() { }) } +func addTLSUniqueTests() { + for _, isClient := range []bool{false, true} { + for _, isResumption := range []bool{false, true} { + for _, hasEMS := range []bool{false, true} { + var suffix string + if isResumption { + suffix = "Resume-" + } else { + suffix = "Full-" + } + + if hasEMS { + suffix += "EMS-" + } else { + suffix += "NoEMS-" + } + + if isClient { + suffix += "Client" + } else { + suffix += "Server" + } + + test := testCase{ + name: "TLSUnique-" + suffix, + testTLSUnique: true, + config: Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: !hasEMS, + }, + }, + } + + if isResumption { + test.resumeSession = true + test.resumeConfig = &Config{ + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: !hasEMS, + }, + } + } + + if isResumption && !hasEMS { + test.shouldFail = true + test.expectedError = "failed to get tls-unique" + } + + testCases = append(testCases, test) + } + } + } +} + func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { defer wg.Done() @@ -3463,6 +3538,7 @@ func main() { addFastRadioPaddingTests() addDTLSRetransmitTests() addExportKeyingMaterialTests() + addTLSUniqueTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { |