Add a test for SSL_OP_TLS_D5_BUG.

If this is part of SSL_OP_ALL, we should have a test for it.

Change-Id: Ia72422beb2da6434726e78e174f3416f90f7c897
Reviewed-on: https://boringssl-review.googlesource.com/1695
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 8955324..0459afc 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -316,6 +316,9 @@
   if (config->cookie_exchange) {
     SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
   }
+  if (config->tls_d5_bug) {
+    SSL_set_options(ssl, SSL_OP_TLS_D5_BUG);
+  }
   if (!config->expected_channel_id.empty()) {
     SSL_enable_tls_channel_id(ssl);
   }
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 78e484f..fa0e6d8 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -440,6 +440,11 @@
 	// isn't sent until we receive an application data record
 	// from the peer.
 	ExpectFalseStart bool
+
+	// SSL3RSAKeyExchange causes the client to always send an RSA
+	// ClientKeyExchange message without the two-byte length
+	// prefix, as if it were SSL3.
+	SSL3RSAKeyExchange bool
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index 2e2eff4..f8ba1f8 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -87,7 +87,7 @@
 		return nil, nil, err
 	}
 	ckx := new(clientKeyExchangeMsg)
-	if clientHello.vers != VersionSSL30 {
+	if clientHello.vers != VersionSSL30 && !config.Bugs.SSL3RSAKeyExchange {
 		ckx.ciphertext = make([]byte, len(encrypted)+2)
 		ckx.ciphertext[0] = byte(len(encrypted) >> 8)
 		ckx.ciphertext[1] = byte(len(encrypted))
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 79bf99c..d238e8a 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -1311,6 +1311,40 @@
 	}
 }
 
+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 worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -1363,6 +1397,7 @@
 	addCBCSplittingTests()
 	addClientAuthTests()
 	addVersionNegotiationTests()
+	addD5BugTests()
 	for _, async := range []bool{false, true} {
 		for _, splitHandshake := range []bool{false, true} {
 			for _, protocol := range []protocol{tls, dtls} {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 9d1ffc9..41188af 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -54,6 +54,7 @@
   { "-no-ssl3", &TestConfig::no_ssl3 },
   { "-cookie-exchange", &TestConfig::cookie_exchange },
   { "-shim-writes-first", &TestConfig::shim_writes_first },
+  { "-tls-d5-bug", &TestConfig::tls_d5_bug },
 };
 
 const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
@@ -95,7 +96,8 @@
       no_tls1(false),
       no_ssl3(false),
       cookie_exchange(false),
-      shim_writes_first(false) {
+      shim_writes_first(false),
+      tls_d5_bug(false) {
 }
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index d79b7f4..208f19b 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -46,6 +46,7 @@
   std::string expected_channel_id;
   std::string send_channel_id;
   bool shim_writes_first;
+  bool tls_d5_bug;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);