diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 21497fd6..dccf0c98 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -1883,6 +1883,22 @@ static bool DoExchange(bssl::UniquePtr *out_session, return false; } + if (config->handshake_twice) { + do { + ret = SSL_do_handshake(ssl.get()); + } while (config->async && RetryAsync(ssl.get(), ret)); + if (ret != 1) { + return false; + } + } + + // Skip the |config->async| logic as this should be a no-op. + if (config->no_op_extra_handshake && + SSL_do_handshake(ssl.get()) != 1) { + fprintf(stderr, "Extra SSL_do_handshake was not a no-op.\n"); + return false; + } + // Reset the state to assert later that the callback isn't called in // renegotations. GetTestState(ssl.get())->got_new_session = false; diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 3aa2c464..3bdb8656 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -10740,6 +10740,109 @@ func addECDSAKeyUsageTests() { } } +func addExtraHandshakeTests() { + // An extra SSL_do_handshake is normally a no-op. These tests use -async + // to ensure there is no transport I/O. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ExtraHandshake-Client-TLS12", + config: Config{ + MinVersion: VersionTLS12, + MaxVersion: VersionTLS12, + }, + flags: []string{ + "-async", + "-no-op-extra-handshake", + }, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ExtraHandshake-Server-TLS12", + config: Config{ + MinVersion: VersionTLS12, + MaxVersion: VersionTLS12, + }, + flags: []string{ + "-async", + "-no-op-extra-handshake", + }, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ExtraHandshake-Client-TLS13", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + }, + flags: []string{ + "-async", + "-no-op-extra-handshake", + }, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ExtraHandshake-Server-TLS13", + config: Config{ + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + }, + flags: []string{ + "-async", + "-no-op-extra-handshake", + }, + }) + + // An extra SSL_do_handshake is a no-op in server 0-RTT. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ExtraHandshake-Server-EarlyData-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyData: [][]byte{{1, 2, 3, 4}}, + ExpectEarlyDataAccepted: true, + ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, + }, + }, + messageCount: 2, + resumeSession: true, + flags: []string{ + "-async", + "-enable-early-data", + "-expect-accept-early-data", + "-no-op-extra-handshake", + }, + }) + + // An extra SSL_do_handshake drives the handshake to completion in False + // Start. We test this by handshaking twice and asserting the False + // Start does not appear to happen. See AlertBeforeFalseStartTest for + // how the test works. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ExtraHandshake-FalseStart", + config: Config{ + MaxVersion: VersionTLS12, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + NextProtos: []string{"foo"}, + Bugs: ProtocolBugs{ + ExpectFalseStart: true, + AlertBeforeFalseStartTest: alertAccessDenied, + }, + }, + flags: []string{ + "-handshake-twice", + "-false-start", + "-advertise-alpn", "\x03foo", + }, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", + expectedLocalError: "tls: peer did not false start: EOF", + }) +} + func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) { defer wg.Done() @@ -10866,6 +10969,7 @@ func main() { addCertificateTests() addRetainOnlySHA256ClientCertTests() addECDSAKeyUsageTests() + addExtraHandshakeTests() var wg sync.WaitGroup diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 7e57543e..a8cf755c 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -128,6 +128,8 @@ const Flag kBoolFlags[] = { { "-expect-reject-early-data", &TestConfig::expect_reject_early_data }, { "-expect-no-alpn", &TestConfig::expect_no_alpn }, { "-expect-no-resume-alpn", &TestConfig::expect_no_resume_alpn }, + { "-no-op-extra-handshake", &TestConfig::no_op_extra_handshake }, + { "-handshake-twice", &TestConfig::handshake_twice }, }; const Flag kStringFlags[] = { diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index fadd05eb..ef14f152 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -141,6 +141,8 @@ struct TestConfig { bool expect_session_id = false; bool expect_no_session_id = false; int expect_ticket_age_skew = 0; + bool no_op_extra_handshake = false; + bool handshake_twice = false; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config);