Add support for TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256

This TLS 1.2 cipher is substantially inferior to AES-GCM and should
never be used; it was previously removed in 2018. We add it back for
backwards-compatibility with devices that cannot be updated. It is added
as a deprecated cipher and is not available unless configured explicitly
by name.

Change-Id: Idc85ab4f1eb38768edba6562345d77616a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/86687
Reviewed-by: David Benjamin <davidben@google.com>
Auto-Submit: Lily Chen <chlily@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 0e99279..bc66010 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1472,6 +1472,7 @@
 #define SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xc014
 #define SSL_CIPHER_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xc035
 #define SSL_CIPHER_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xc036
+#define SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xc023
 #define SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xc027
 #define SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 0x009c
 #define SSL_CIPHER_RSA_WITH_AES_256_GCM_SHA384 0x009d
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index ea55e2a..696ccfd 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -187,6 +187,7 @@
 #define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A
 #define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013
 #define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0x0300C023
 #define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0x0300C027
 #define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B
 #define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C
@@ -220,6 +221,7 @@
 #define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA"
 #define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA"
 #define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA"
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 "ECDHE-ECDSA-AES128-SHA256"
 #define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA256 "ECDHE-RSA-AES128-SHA256"
 #define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \
   "ECDHE-ECDSA-AES128-GCM-SHA256"
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc
index 108681c..1cda428 100644
--- a/ssl/ssl_cipher.cc
+++ b/ssl/ssl_cipher.cc
@@ -213,7 +213,21 @@
         SSL_HANDSHAKE_MAC_DEFAULT,
     },
 
-    // Cipher C027
+    // HMAC based TLS v1.2 ciphersuites from RFC5289
+
+    // Cipher C023 (deprecated)
+    {
+        TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+        SSL_kECDHE,
+        SSL_aECDSA,
+        SSL_AES128,
+        SSL_SHA256,
+        SSL_HANDSHAKE_MAC_SHA256,
+    },
+
+    // Cipher C027 (deprecated)
     {
         TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
         "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
@@ -642,7 +656,9 @@
 }
 
 bool ssl_cipher_is_deprecated(const SSL_CIPHER *cipher) {
-  return cipher->protocol_id == SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ||
+  return cipher->protocol_id ==
+             SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 ||
+         cipher->protocol_id == SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ||
          cipher->algorithm_enc == SSL_3DES;
 }
 
@@ -1007,8 +1023,7 @@
   }
 
   // We prefer ECDHE ciphers over non-PFS ciphers. Then we prefer AEAD over
-  // non-AEAD. The constants are masked by 0xffff to remove the vestigial 0x03
-  // byte from SSL 2.0.
+  // non-AEAD.
   static const uint16_t kAESCiphers[] = {
       SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
       SSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
@@ -1027,6 +1042,7 @@
       SSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
       SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA,
       SSL_CIPHER_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+      SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
       SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
       SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256,
       SSL_CIPHER_RSA_WITH_AES_256_GCM_SHA384,
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 05f95e0..9b75ef0 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -480,9 +480,17 @@
     "SHA1", "RSA",     "SSLv3", "TLSv1", "TLSv1.2",
 };
 
-static const char *kShouldIncludeCBCSHA256[] = {
-    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
-    "ALL:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+static const struct {
+  const char *rule;
+  int expected_included_deprecated_count;
+} kDeprecatedCBCSHA256Rules[] = {
+    {"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 1},
+    {"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 1},
+    {"ALL:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 1},
+    {"ALL:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 1},
+    {"ALL:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:TLS_ECDHE_RSA_WITH_AES_128_"
+     "CBC_SHA256",
+     2},
 };
 
 static const CurveTest kCurveTests[] = {
@@ -624,23 +632,22 @@
       EXPECT_FALSE(ssl_cipher_is_deprecated(cipher));
     }
   }
+}
 
-  {
-    for (const char *rule : kShouldIncludeCBCSHA256) {
-      bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
-      ASSERT_TRUE(ctx);
-      ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(ctx.get(), rule));
+TEST(SSLTest, CipherRulesDeprecated) {
+  for (const auto& test : kDeprecatedCBCSHA256Rules) {
+    SCOPED_TRACE(test.rule);
+    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+    ASSERT_TRUE(ctx);
+    ASSERT_TRUE(SSL_CTX_set_strict_cipher_list(ctx.get(), test.rule));
 
-      bool found = false;
-      for (const SSL_CIPHER *cipher : SSL_CTX_get_ciphers(ctx.get())) {
-        if (SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ==
-            SSL_CIPHER_get_protocol_id(cipher)) {
-          found = true;
-          break;
-        }
+    int found = 0;
+    for (const SSL_CIPHER *cipher : SSL_CTX_get_ciphers(ctx.get())) {
+      if (ssl_cipher_is_deprecated(cipher)) {
+        ++found;
       }
-      EXPECT_TRUE(found);
     }
+    EXPECT_EQ(found, test.expected_included_deprecated_count);
   }
 }
 
diff --git a/ssl/test/runner/cipher_suite_tests.go b/ssl/test/runner/cipher_suite_tests.go
index 26b7114..01a0ecb 100644
--- a/ssl/test/runner/cipher_suite_tests.go
+++ b/ssl/test/runner/cipher_suite_tests.go
@@ -38,6 +38,7 @@
 	{"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
 	{"ECDHE_RSA_WITH_AES_128_GCM_SHA256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 	{"ECDHE_RSA_WITH_AES_128_CBC_SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
 	{"ECDHE_RSA_WITH_AES_128_CBC_SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
 	{"ECDHE_RSA_WITH_AES_256_GCM_SHA384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
 	{"ECDHE_RSA_WITH_AES_256_CBC_SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 01dbea0..dbf5ab8 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -2006,7 +2006,10 @@
 
   SSL_CTX_set0_buffer_pool(ssl_ctx.get(), BufferPool());
 
-  std::string cipher_list = "ALL:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+  std::string cipher_list = "ALL";
+  // Explicitly add deprecated ciphers that are otherwise not included.
+  cipher_list += ":TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
+  cipher_list += ":TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
   if (!cipher.empty()) {
     cipher_list = cipher;
     SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE);