CECPQ1: change from named curve to ciphersuite.

This is easier to deploy, and more obvious.  This commit reverts a few
pieces of e25775bc, but keeps most of it.

Change-Id: If8d657a4221c665349c06041bb12fffca1527a2c
Reviewed-on: https://boringssl-review.googlesource.com/8061
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1648922..3770c6e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1098,6 +1098,9 @@
 /* SSL_CIPHER_is_ECDHE returns one if |cipher| uses ECDHE. */
 OPENSSL_EXPORT int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher);
 
+/* SSL_CIPHER_is_CECPQ1 returns one if |cipher| uses CECPQ1. */
+OPENSSL_EXPORT int SSL_CIPHER_is_CECPQ1(const SSL_CIPHER *cipher);
+
 /* SSL_CIPHER_get_min_version returns the minimum protocol version required
  * for |cipher|. */
 OPENSSL_EXPORT uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher);
@@ -3358,6 +3361,7 @@
 #define SSL_TXT_kDHE "kDHE"
 #define SSL_TXT_kEDH "kEDH"
 #define SSL_TXT_kECDHE "kECDHE"
+#define SSL_TXT_kCECPQ1 "kCECPQ1"
 #define SSL_TXT_kEECDH "kEECDH"
 #define SSL_TXT_kPSK "kPSK"
 #define SSL_TXT_aRSA "aRSA"
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index df17375..6ed9fa9 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -441,6 +441,12 @@
 #define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 \
   TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
 
+/* CECPQ1 ciphersuites.  These are specific to BoringSSL and not standard. */
+#define TLS1_CK_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 0x030016B7
+#define TLS1_CK_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x030016B8
+#define TLS1_CK_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 0x030016B9
+#define TLS1_CK_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 0x030016BA
+
 /* XXX
  * Inconsistency alert:
  * The OpenSSL names of ciphers with ephemeral DH here include the string
@@ -621,6 +627,17 @@
 #define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 \
   TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
 
+/* CECPQ1 ciphersuites.  These are specific to BoringSSL and not standard. */
+#define TLS1_TXT_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 \
+  "CECPQ1-RSA-CHACHA20-POLY1305-SHA256"
+#define TLS1_TXT_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 \
+  "CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256"
+#define TLS1_TXT_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 \
+  "CECPQ1-RSA-AES256-GCM-SHA384"
+#define TLS1_TXT_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 \
+  "CECPQ1-ECDSA-AES256-GCM-SHA384"
+
+
 #define TLS_CT_RSA_SIGN 1
 #define TLS_CT_DSS_SIGN 2
 #define TLS_CT_RSA_FIXED_DH 3
diff --git a/ssl/internal.h b/ssl/internal.h
index 5d003f9..3b56e78 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -167,6 +167,7 @@
 #define SSL_kECDHE 0x00000004L
 /* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */
 #define SSL_kPSK 0x00000008L
+#define SSL_kCECPQ1 0x00000010L
 
 /* Bits for |algorithm_auth| (server authentication). */
 #define SSL_aRSA 0x00000001L
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index bfd948a..82e4e35 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -1132,7 +1132,8 @@
     if (!CBS_stow(&dh_Ys, &ssl->s3->tmp.peer_key, &peer_key_len)) {
       goto err;
     }
-    /* |dh_Ys| has a u16 length prefix, so this fits in a |uint16_t|. */
+    /* |dh_Ys| was initialized with CBS_get_u16_length_prefixed, so peer_key_len
+     * fits in a uint16_t. */
     assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
     ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
   } else if (alg_k & SSL_kECDHE) {
@@ -1142,7 +1143,8 @@
     CBS point;
     if (!CBS_get_u8(&server_key_exchange, &group_type) ||
         group_type != NAMED_CURVE_TYPE ||
-        !CBS_get_u16(&server_key_exchange, &group_id)) {
+        !CBS_get_u16(&server_key_exchange, &group_id) ||
+        !CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
       al = SSL_AD_DECODE_ERROR;
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       goto f_err;
@@ -1156,22 +1158,33 @@
       goto f_err;
     }
 
-    if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, group_id)) {
+    /* Initialize ECDH and save the peer public key for later. */
+    size_t peer_key_len;
+    if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, group_id) ||
+        !CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) {
       goto err;
     }
-    if (!SSL_ECDH_CTX_get_key(&ssl->s3->tmp.ecdh_ctx, &server_key_exchange,
-                              &point)) {
+    /* |point| was initialized with CBS_get_u8_length_prefixed, so peer_key_len
+     * fits in a uint16_t. */
+    assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
+    ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
+  } else if (alg_k & SSL_kCECPQ1) {
+    if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, SSL_GROUP_CECPQ1)) {
+      goto err;
+    }
+    CBS key;
+    if (!CBS_get_u16_length_prefixed(&server_key_exchange, &key)) {
       al = SSL_AD_DECODE_ERROR;
       OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
       goto f_err;
     }
 
-    /* Initialize ECDH and save the peer public key for later. */
     size_t peer_key_len;
-    if (!CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) {
+    if (!CBS_stow(&key, &ssl->s3->tmp.peer_key, &peer_key_len)) {
       goto err;
     }
-    /* |point| has a u8 or u16 length prefix, so this fits in a |uint16_t|. */
+    /* |key| was initialized with CBS_get_u16_length_prefixed, so peer_key_len
+     * fits in a uint16_t. */
     assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
     ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
   } else if (!(alg_k & SSL_kPSK)) {
@@ -1623,7 +1636,7 @@
         !CBB_flush(&cbb)) {
       goto err;
     }
-  } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
+  } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) {
     /* Generate a keypair and serialize the public half. */
     CBB child;
     if (!SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child)) {
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 9ac1e40..eef1544 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -1209,7 +1209,7 @@
           !BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) ||
           !CBB_add_u16_length_prefixed(&cbb, &child) ||
           !BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) ||
-          !SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child) ||
+          !CBB_add_u16_length_prefixed(&cbb, &child) ||
           !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
         goto err;
       }
@@ -1227,7 +1227,13 @@
       if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, group_id) ||
           !CBB_add_u8(&cbb, NAMED_CURVE_TYPE) ||
           !CBB_add_u16(&cbb, group_id) ||
-          !SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child) ||
+          !CBB_add_u8_length_prefixed(&cbb, &child) ||
+          !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
+        goto err;
+      }
+    } else if (alg_k & SSL_kCECPQ1) {
+      if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, SSL_GROUP_CECPQ1) ||
+          !CBB_add_u16_length_prefixed(&cbb, &child) ||
           !SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
         goto err;
       }
@@ -1590,7 +1596,7 @@
 
     OPENSSL_free(decrypt_buf);
     decrypt_buf = NULL;
-  } else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
+  } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) {
     /* Parse the ClientKeyExchange. */
     CBS peer_key;
     if (!SSL_ECDH_CTX_get_key(&ssl->s3->tmp.ecdh_ctx, &client_key_exchange,
diff --git a/ssl/ssl_cipher.c b/ssl/ssl_cipher.c
index 7fb8809..dcee293 100644
--- a/ssl/ssl_cipher.c
+++ b/ssl/ssl_cipher.c
@@ -375,6 +375,52 @@
      SSL_HANDSHAKE_MAC_SHA384,
     },
 
+    /* CECPQ1 (combined elliptic curve + post-quantum) suites. */
+
+    /* Cipher 16B7 */
+    {
+     TLS1_TXT_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256,
+     TLS1_CK_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256,
+     SSL_kCECPQ1,
+     SSL_aRSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     SSL_HANDSHAKE_MAC_SHA256,
+    },
+
+    /* Cipher 16B8 */
+    {
+     TLS1_TXT_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+     TLS1_CK_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+     SSL_kCECPQ1,
+     SSL_aECDSA,
+     SSL_CHACHA20POLY1305,
+     SSL_AEAD,
+     SSL_HANDSHAKE_MAC_SHA256,
+    },
+
+    /* Cipher 16B9 */
+    {
+     TLS1_TXT_CECPQ1_RSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_CECPQ1_RSA_WITH_AES_256_GCM_SHA384,
+     SSL_kCECPQ1,
+     SSL_aRSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     SSL_HANDSHAKE_MAC_SHA384,
+    },
+
+    /* Cipher 16BA */
+    {
+     TLS1_TXT_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384,
+     TLS1_CK_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384,
+     SSL_kCECPQ1,
+     SSL_aECDSA,
+     SSL_AES256GCM,
+     SSL_AEAD,
+     SSL_HANDSHAKE_MAC_SHA384,
+    },
+
     /* Cipher C007 */
     {
      TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA,
@@ -615,6 +661,7 @@
      SSL_AEAD,
      SSL_HANDSHAKE_MAC_SHA256,
     },
+
 };
 
 static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]);
@@ -651,8 +698,9 @@
 } CIPHER_ALIAS;
 
 static const CIPHER_ALIAS kCipherAliases[] = {
-    /* "ALL" doesn't include eNULL (must be specifically enabled) */
-    {"ALL", ~0u, ~0u, ~SSL_eNULL, ~0u, 0},
+    /* "ALL" doesn't include eNULL nor kCECPQ1. These must be explicitly
+     * enabled. */
+    {"ALL", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
 
     /* The "COMPLEMENTOFDEFAULT" rule is omitted. It matches nothing. */
 
@@ -667,15 +715,16 @@
     {"DH", SSL_kDHE, ~0u, ~0u, ~0u, 0},
 
     {"kECDHE", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
+    {"kCECPQ1", SSL_kCECPQ1, ~0u, ~0u, ~0u, 0},
     {"kEECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
     {"ECDH", SSL_kECDHE, ~0u, ~0u, ~0u, 0},
 
     {"kPSK", SSL_kPSK, ~0u, ~0u, ~0u, 0},
 
     /* server authentication aliases */
-    {"aRSA", ~0u, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
-    {"aECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
-    {"ECDSA", ~0u, SSL_aECDSA, ~0u, ~0u, 0},
+    {"aRSA", ~SSL_kCECPQ1, SSL_aRSA, ~SSL_eNULL, ~0u, 0},
+    {"aECDSA", ~SSL_kCECPQ1, SSL_aECDSA, ~0u, ~0u, 0},
+    {"ECDSA", ~SSL_kCECPQ1, SSL_aECDSA, ~0u, ~0u, 0},
     {"aPSK", ~0u, SSL_aPSK, ~0u, ~0u, 0},
 
     /* aliases combining key exchange and server authentication */
@@ -690,29 +739,29 @@
     {"3DES", ~0u, ~0u, SSL_3DES, ~0u, 0},
     {"RC4", ~0u, ~0u, SSL_RC4, ~0u, 0},
     {"AES128", ~0u, ~0u, SSL_AES128 | SSL_AES128GCM, ~0u, 0},
-    {"AES256", ~0u, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0},
-    {"AES", ~0u, ~0u, SSL_AES, ~0u, 0},
-    {"AESGCM", ~0u, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0},
-    {"CHACHA20", ~0u, ~0u, SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD, ~0u,
+    {"AES256", ~SSL_kCECPQ1, ~0u, SSL_AES256 | SSL_AES256GCM, ~0u, 0},
+    {"AES", ~SSL_kCECPQ1, ~0u, SSL_AES, ~0u, 0},
+    {"AESGCM", ~SSL_kCECPQ1, ~0u, SSL_AES128GCM | SSL_AES256GCM, ~0u, 0},
+    {"CHACHA20", ~SSL_kCECPQ1, ~0u, SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_OLD, ~0u,
      0},
 
     /* MAC aliases */
     {"MD5", ~0u, ~0u, ~0u, SSL_MD5, 0},
     {"SHA1", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
     {"SHA", ~0u, ~0u, ~SSL_eNULL, SSL_SHA1, 0},
-    {"SHA256", ~0u, ~0u, ~0u, SSL_SHA256, 0},
-    {"SHA384", ~0u, ~0u, ~0u, SSL_SHA384, 0},
+    {"SHA256", ~SSL_kCECPQ1, ~0u, ~0u, SSL_SHA256, 0},
+    {"SHA384", ~SSL_kCECPQ1, ~0u, ~0u, SSL_SHA384, 0},
 
     /* Legacy protocol minimum version aliases. "TLSv1" is intentionally the
      * same as "SSLv3". */
-    {"SSLv3", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
-    {"TLSv1", ~0u, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
-    {"TLSv1.2", ~0u, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
+    {"SSLv3", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+    {"TLSv1", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
+    {"TLSv1.2", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
 
     /* Legacy strength classes. */
     {"MEDIUM", ~0u, ~0u, SSL_RC4, ~0u, 0},
-    {"HIGH", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
-    {"FIPS", ~0u, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
+    {"HIGH", ~SSL_kCECPQ1, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
+    {"FIPS", ~SSL_kCECPQ1, ~0u, ~(SSL_eNULL|SSL_RC4), ~0u, 0},
 };
 
 static const size_t kCipherAliasesLen =
@@ -1404,6 +1453,7 @@
 
   /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other
    * key exchange mechanisms */
+
   ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
                         0, &head, &tail);
   ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
@@ -1623,6 +1673,10 @@
   return (cipher->algorithm_mkey & SSL_kECDHE) != 0;
 }
 
+int SSL_CIPHER_is_CECPQ1(const SSL_CIPHER *cipher) {
+  return (cipher->algorithm_mkey & SSL_kCECPQ1) != 0;
+}
+
 uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) {
   if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) {
     /* Cipher suites before TLS 1.2 use the default PRF, while all those added
@@ -1672,6 +1726,17 @@
           return "UNKNOWN";
       }
 
+    case SSL_kCECPQ1:
+      switch (cipher->algorithm_auth) {
+        case SSL_aECDSA:
+          return "CECPQ1_ECDSA";
+        case SSL_aRSA:
+          return "CECPQ1_RSA";
+        default:
+          assert(0);
+          return "UNKNOWN";
+      }
+
     case SSL_kPSK:
       assert(cipher->algorithm_auth == SSL_aPSK);
       return "PSK";
@@ -1826,6 +1891,10 @@
       kx = "ECDH";
       break;
 
+    case SSL_kCECPQ1:
+      kx = "CECPQ1";
+      break;
+
     case SSL_kPSK:
       kx = "PSK";
       break;
@@ -1963,7 +2032,9 @@
 
 int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher) {
   /* Ephemeral Diffie-Hellman key exchanges require a ServerKeyExchange. */
-  if (cipher->algorithm_mkey & SSL_kDHE || cipher->algorithm_mkey & SSL_kECDHE) {
+  if (cipher->algorithm_mkey & SSL_kDHE ||
+      cipher->algorithm_mkey & SSL_kECDHE ||
+      cipher->algorithm_mkey & SSL_kCECPQ1) {
     return 1;
   }
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a27d430..3b8cff7 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1725,6 +1725,9 @@
     mask_k |= SSL_kECDHE;
   }
 
+  /* CECPQ1 ciphers are always acceptable if supported by both sides. */
+  mask_k |= SSL_kCECPQ1;
+
   /* PSK requires a server callback. */
   if (ssl->psk_server_callback != NULL) {
     mask_k |= SSL_kPSK;
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index bbac051..aadc4f0 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -254,6 +254,31 @@
   "TLSv1.2",
 };
 
+static const char *kMustNotIncludeCECPQ1[] = {
+  "ALL",
+  "DEFAULT",
+  "MEDIUM",
+  "HIGH",
+  "FIPS",
+  "SHA",
+  "SHA1",
+  "SHA256",
+  "SHA384",
+  "RSA",
+  "SSLv3",
+  "TLSv1",
+  "TLSv1.2",
+  "aRSA",
+  "RSA",
+  "aECDSA",
+  "ECDSA",
+  "AES",
+  "AES128",
+  "AES256",
+  "AESGCM",
+  "CHACHA20",
+};
+
 static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) {
   bool in_group = false;
   for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
@@ -324,6 +349,24 @@
   return true;
 }
 
+static bool TestRuleDoesNotIncludeCECPQ1(const char *rule) {
+  ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+  if (!ctx) {
+    return false;
+  }
+  if (!SSL_CTX_set_cipher_list(ctx.get(), rule)) {
+    fprintf(stderr, "Error: cipher rule '%s' failed\n", rule);
+    return false;
+  }
+  for (size_t i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+    if (SSL_CIPHER_is_CECPQ1(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) {
+      fprintf(stderr, "Error: cipher rule '%s' includes CECPQ1\n",rule);
+      return false;
+    }
+  }
+  return true;
+}
+
 static bool TestCipherRules() {
   for (const CipherTest &test : kCipherTests) {
     if (!TestCipherRule(test)) {
@@ -349,6 +392,12 @@
     }
   }
 
+  for (const char *rule : kMustNotIncludeCECPQ1) {
+    if (!TestRuleDoesNotIncludeCECPQ1(rule)) {
+      return false;
+    }
+  }
+
   return true;
 }
 
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 8982459..519736d 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1313,7 +1313,7 @@
   }
   if (config->enable_all_curves) {
     static const int kAllCurves[] = {
-      NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519, NID_cecpq1
+      NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
     };
     if (!SSL_set1_curves(ssl.get(), kAllCurves,
                          sizeof(kAllCurves) / sizeof(kAllCurves[0]))) {
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index bfd31a5..799f2d5 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -43,6 +43,9 @@
 	// client indicates that it supports ECC with a curve and point format
 	// that we're happy with.
 	suiteECDHE = 1 << iota
+	// suiteCECPQ1 indicates that the cipher suite uses the
+	// experimental, temporary, and non-standard CECPQ1 key agreement.
+	suiteCECPQ1
 	// suiteECDSA indicates that the cipher suite involves an ECDSA
 	// signature and therefore may only be selected when the server's
 	// certificate is ECDSA. If this is not set then the cipher suite is
@@ -104,6 +107,10 @@
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, cecpq1RSAKA, suiteCECPQ1 | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+	{TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, cecpq1ECDSAKA, suiteCECPQ1 | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+	{TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, cecpq1RSAKA, suiteCECPQ1 | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, cecpq1ECDSAKA, suiteCECPQ1 | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
@@ -373,6 +380,15 @@
 	}
 }
 
+func cecpq1ECDSAKA(version uint16) keyAgreement {
+	return &cecpq1KeyAgreement{
+		auth: &signedKeyAgreement{
+			sigType: signatureECDSA,
+			version: version,
+		},
+	}
+}
+
 func ecdheRSAKA(version uint16) keyAgreement {
 	return &ecdheKeyAgreement{
 		auth: &signedKeyAgreement{
@@ -382,6 +398,15 @@
 	}
 }
 
+func cecpq1RSAKA(version uint16) keyAgreement {
+	return &cecpq1KeyAgreement{
+		auth: &signedKeyAgreement{
+			sigType: signatureRSA,
+			version: version,
+		},
+	}
+}
+
 func dheRSAKA(version uint16) keyAgreement {
 	return &dheKeyAgreement{
 		auth: &signedKeyAgreement{
@@ -472,4 +497,8 @@
 const (
 	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD   uint16 = 0xcc13
 	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc14
+	TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256      uint16 = 0x16b7
+	TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256    uint16 = 0x16b8
+	TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384            uint16 = 0x16b9
+	TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384          uint16 = 0x16ba
 )
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 3b085d3..57b7b29 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -103,7 +103,6 @@
 	CurveP384   CurveID = 24
 	CurveP521   CurveID = 25
 	CurveX25519 CurveID = 29
-	CurveCECPQ1 CurveID = 65165
 )
 
 // TLS Elliptic Curve Point Formats
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index 75998b4..9a9962b 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -421,8 +421,6 @@
 		return &ellipticECDHCurve{curve: elliptic.P521()}, true
 	case CurveX25519:
 		return &x25519ECDHCurve{}, true
-	case CurveCECPQ1:
-		return &cecpq1Curve{}, true
 	default:
 		return nil, false
 	}
@@ -647,19 +645,15 @@
 	}
 
 	// http://tools.ietf.org/html/rfc4492#section-5.4
-	var serverECDHParams []byte
-	serverECDHParams = append(serverECDHParams, byte(3)) // named curve
-	serverECDHParams = append(serverECDHParams, byte(curveid>>8))
-	serverECDHParams = append(serverECDHParams, byte(curveid))
+	serverECDHParams := make([]byte, 1+2+1+len(publicKey))
+	serverECDHParams[0] = 3 // named curve
+	serverECDHParams[1] = byte(curveid >> 8)
+	serverECDHParams[2] = byte(curveid)
 	if config.Bugs.InvalidSKXCurve {
 		serverECDHParams[2] ^= 0xff
 	}
-	if curveid == CurveCECPQ1 {
-		// The larger key size requires an extra length byte.
-		serverECDHParams = append(serverECDHParams, byte(len(publicKey)>>8))
-	}
-	serverECDHParams = append(serverECDHParams, byte(len(publicKey)&0xff))
-	serverECDHParams = append(serverECDHParams, publicKey[:]...)
+	serverECDHParams[3] = byte(len(publicKey))
+	copy(serverECDHParams[4:], publicKey)
 	if config.Bugs.InvalidECDHPoint {
 		serverECDHParams[4] ^= 0xff
 	}
@@ -668,21 +662,10 @@
 }
 
 func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
-	if len(ckx.ciphertext) == 0 {
+	if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
 		return nil, errClientKeyExchange
 	}
-	peerKeyLen := int(ckx.ciphertext[0])
-	offset := 1
-	if _, postQuantum := ka.curve.(*cecpq1Curve); postQuantum {
-		// The larger key size requires an extra length byte.
-		peerKeyLen = int(ckx.ciphertext[0])<<8 + int(ckx.ciphertext[1])
-		offset = 2
-	}
-	peerKey := ckx.ciphertext[offset:]
-	if peerKeyLen != len(peerKey) {
-		return nil, errClientKeyExchange
-	}
-	return ka.curve.finish(peerKey)
+	return ka.curve.finish(ckx.ciphertext[1:])
 }
 
 func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
@@ -700,22 +683,15 @@
 	}
 
 	publicLen := int(skx.key[3])
-	publicOffset := 4
-	if curveid == CurveCECPQ1 {
-		// The larger key size requires an extra length byte.
-		publicLen = int(skx.key[3])<<8 + int(skx.key[4])
-		publicOffset += 1
-	}
-
-	if publicLen+publicOffset > len(skx.key) {
+	if publicLen+4 > len(skx.key) {
 		return errServerKeyExchange
 	}
 	// Save the peer key for later.
-	ka.peerKey = skx.key[publicOffset : publicOffset+publicLen]
+	ka.peerKey = skx.key[4 : 4+publicLen]
 
 	// Check the signature.
-	serverECDHParams := skx.key[:publicOffset+publicLen]
-	sig := skx.key[publicOffset+publicLen:]
+	serverECDHParams := skx.key[:4+publicLen]
+	sig := skx.key[4+publicLen:]
 	return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
 }
 
@@ -730,14 +706,82 @@
 	}
 
 	ckx := new(clientKeyExchangeMsg)
-	if _, postQuantum := ka.curve.(*cecpq1Curve); postQuantum {
-		// The larger key size requires an extra length byte.
-		ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)>>8))
-	}
-	ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)&0xff))
+	ckx.ciphertext = make([]byte, 1+len(publicKey))
+	ckx.ciphertext[0] = byte(len(publicKey))
+	copy(ckx.ciphertext[1:], publicKey)
 	if config.Bugs.InvalidECDHPoint {
-		publicKey[0] ^= 0xff
+		ckx.ciphertext[1] ^= 0xff
 	}
+
+	return preMasterSecret, ckx, nil
+}
+
+// cecpq1RSAKeyAgreement is like an ecdheKeyAgreement, but using the cecpq1Curve
+// pseudo-curve, and without any parameters (e.g. curve name) other than the
+// keys being exchanged. The signature may either be ECDSA or RSA.
+type cecpq1KeyAgreement struct {
+	auth    keyAgreementAuthentication
+	curve   ecdhCurve
+	peerKey []byte
+}
+
+func (ka *cecpq1KeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	ka.curve = &cecpq1Curve{}
+	publicKey, err := ka.curve.offer(config.rand())
+	if err != nil {
+		return nil, err
+	}
+
+	var params []byte
+	params = append(params, byte(len(publicKey)>>8))
+	params = append(params, byte(len(publicKey)&0xff))
+	params = append(params, publicKey[:]...)
+
+	return ka.auth.signParameters(config, cert, clientHello, hello, params)
+}
+
+func (ka *cecpq1KeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+	peerKeyLen := int(ckx.ciphertext[0])<<8 + int(ckx.ciphertext[1])
+	peerKey := ckx.ciphertext[2:]
+	if peerKeyLen != len(peerKey) {
+		return nil, errClientKeyExchange
+	}
+	return ka.curve.finish(peerKey)
+}
+
+func (ka *cecpq1KeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	if len(skx.key) < 2 {
+		return errServerKeyExchange
+	}
+	peerKeyLen := int(skx.key[0])<<8 + int(skx.key[1])
+	// Save the peer key for later.
+	if len(skx.key) < 2+peerKeyLen {
+		return errServerKeyExchange
+	}
+	ka.peerKey = skx.key[2 : 2+peerKeyLen]
+	if peerKeyLen != len(ka.peerKey) {
+		return errServerKeyExchange
+	}
+
+	// Check the signature.
+	params := skx.key[:2+peerKeyLen]
+	sig := skx.key[2+peerKeyLen:]
+	return ka.auth.verifyParameters(config, clientHello, serverHello, cert, params, sig)
+}
+
+func (ka *cecpq1KeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	curve := &cecpq1Curve{}
+	publicKey, preMasterSecret, err := curve.accept(config.rand(), ka.peerKey)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)>>8))
+	ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)&0xff))
 	ckx.ciphertext = append(ckx.ciphertext, publicKey[:]...)
 
 	return preMasterSecret, ckx, nil
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 806d2fe..c10987e 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -915,6 +915,10 @@
 	{"ECDHE-RSA-CHACHA20-POLY1305", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
 	{"ECDHE-RSA-CHACHA20-POLY1305-OLD", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD},
 	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+	{"CECPQ1-RSA-CHACHA20-POLY1305-SHA256", TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256},
+	{"CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256", TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
+	{"CECPQ1-RSA-AES256-GCM-SHA384", TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384},
+	{"CECPQ1-ECDSA-AES256-GCM-SHA384", TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384},
 	{"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
 	{"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
 	{"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
@@ -2295,6 +2299,10 @@
 			// NULL ciphers must be explicitly enabled.
 			flags = append(flags, "-cipher", "DEFAULT:NULL-SHA")
 		}
+		if hasComponent(suite.name, "CECPQ1") {
+			// CECPQ1 ciphers must be explicitly enabled.
+			flags = append(flags, "-cipher", "DEFAULT:kCECPQ1")
+		}
 
 		for _, ver := range tlsVersions {
 			if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
@@ -5020,7 +5028,6 @@
 	{"P-384", CurveP384},
 	{"P-521", CurveP521},
 	{"X25519", CurveX25519},
-	{"CECPQ1", CurveCECPQ1},
 }
 
 func addCurveTests() {