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() {