Test that client cipher preferences are enforced.

Change-Id: I6e760cfd785c0c5688da6f7d3d3092a8add40409
Reviewed-on: https://boringssl-review.googlesource.com/4070
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 047a475..125cef4 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -615,6 +615,10 @@
   if (config->install_ddos_callback) {
     SSL_CTX_set_dos_protection_cb(ssl_ctx, DDoSCallback);
   }
+  if (!config->cipher.empty() &&
+      !SSL_set_cipher_list(ssl.get(), config->cipher.c_str())) {
+    return false;
+  }
 
   int sock = Connect(config->port);
   if (sock == -1) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 5cad289..a9c5083 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -671,6 +671,10 @@
 	// NoSignatureAlgorithmsOnRenego, if true, causes renegotiations to omit
 	// the signature_algorithms extension.
 	NoSignatureAlgorithmsOnRenego bool
+
+	// IgnorePeerCipherPreferences, if true, causes the peer's cipher
+	// preferences to be ignored.
+	IgnorePeerCipherPreferences bool
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 3caf81b..00ee44b 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -340,6 +340,9 @@
 		return false, errors.New("tls: fallback SCSV found when not expected")
 	}
 
+	if config.Bugs.IgnorePeerCipherPreferences {
+		hs.clientHello.cipherSuites = c.config.cipherSuites()
+	}
 	var preferenceList, supportedList []uint16
 	if c.config.PreferServerCipherSuites {
 		preferenceList = c.config.cipherSuites()
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index c936214..d72ac43 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -892,6 +892,18 @@
 			},
 		},
 	},
+	{
+		name: "UnsupportedCipherSuite",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+			Bugs: ProtocolBugs{
+				IgnorePeerCipherPreferences: true,
+			},
+		},
+		flags:         []string{"-cipher", "DEFAULT:!RC4"},
+		shouldFail:    true,
+		expectedError: ":WRONG_CIPHER_RETURNED:",
+	},
 }
 
 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index cbfc10f..1f7bd5b 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -96,6 +96,7 @@
   { "-psk", &TestConfig::psk },
   { "-psk-identity", &TestConfig::psk_identity },
   { "-srtp-profiles", &TestConfig::srtp_profiles },
+  { "-cipher", &TestConfig::cipher },
 };
 
 const Flag<std::string> kBase64Flags[] = {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 380e845..eef22e5 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -73,6 +73,7 @@
   bool install_ddos_callback;
   bool fail_ddos_callback;
   bool fail_second_ddos_callback;
+  std::string cipher;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);