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>
This commit is contained in:
Matt Braithwaite 2016-05-25 12:06:05 -07:00 committed by Adam Langley
parent d09175ffe3
commit 053931e74e
13 changed files with 317 additions and 74 deletions

View File

@ -1098,6 +1098,9 @@ OPENSSL_EXPORT int SSL_CIPHER_is_ECDSA(const SSL_CIPHER *cipher);
/* 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 @@ OPENSSL_EXPORT const char *SSL_alert_desc_string(int value);
#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"

View File

@ -441,6 +441,12 @@ extern "C" {
#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 @@ extern "C" {
#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

View File

@ -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

View File

@ -1132,7 +1132,8 @@ int ssl3_get_server_key_exchange(SSL *ssl) {
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 @@ int ssl3_get_server_key_exchange(SSL *ssl) {
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 @@ int ssl3_get_server_key_exchange(SSL *ssl) {
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 @@ int ssl3_send_client_key_exchange(SSL *ssl) {
!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)) {

View File

@ -1209,7 +1209,7 @@ int ssl3_send_server_key_exchange(SSL *ssl) {
!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 @@ int ssl3_send_server_key_exchange(SSL *ssl) {
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 @@ int ssl3_get_client_key_exchange(SSL *ssl) {
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,

View File

@ -375,6 +375,52 @@ static const SSL_CIPHER kCiphers[] = {
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 @@ static const SSL_CIPHER kCiphers[] = {
SSL_AEAD,
SSL_HANDSHAKE_MAC_SHA256,
},
};
static const size_t kCiphersLen = sizeof(kCiphers) / sizeof(kCiphers[0]);
@ -651,8 +698,9 @@ typedef struct cipher_alias_st {
} 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 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{"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 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{"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 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
/* 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 @@ int SSL_CIPHER_is_ECDHE(const SSL_CIPHER *cipher) {
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 @@ const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) {
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 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf,
kx = "ECDH";
break;
case SSL_kCECPQ1:
kx = "CECPQ1";
break;
case SSL_kPSK:
kx = "PSK";
break;
@ -1963,7 +2032,9 @@ int ssl_cipher_uses_certificate_auth(const SSL_CIPHER *cipher) {
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;
}

View File

@ -1725,6 +1725,9 @@ void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
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;

View File

@ -254,6 +254,31 @@ static const char *kMustNotIncludeNull[] = {
"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 @@ static bool TestRuleDoesNotIncludeNull(const char *rule) {
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 @@ static bool TestCipherRules() {
}
}
for (const char *rule : kMustNotIncludeCECPQ1) {
if (!TestRuleDoesNotIncludeCECPQ1(rule)) {
return false;
}
}
return true;
}

View File

@ -1313,7 +1313,7 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
}
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]))) {

View File

@ -43,6 +43,9 @@ const (
// 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 @@ var cipherSuites = []*cipherSuite{
{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 ecdheECDSAKA(version uint16) keyAgreement {
}
}
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 ecdheRSAKA(version uint16) keyAgreement {
}
}
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 (
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
)

View File

@ -103,7 +103,6 @@ const (
CurveP384 CurveID = 24
CurveP521 CurveID = 25
CurveX25519 CurveID = 29
CurveCECPQ1 CurveID = 65165
)
// TLS Elliptic Curve Point Formats

View File

@ -421,8 +421,6 @@ func curveForCurveID(id CurveID) (ecdhCurve, bool) {
return &ellipticECDHCurve{curve: elliptic.P521()}, true
case CurveX25519:
return &x25519ECDHCurve{}, true
case CurveCECPQ1:
return &cecpq1Curve{}, true
default:
return nil, false
}
@ -647,19 +645,15 @@ NextCandidate:
}
// 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 @@ NextCandidate:
}
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 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
}
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 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel
}
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

View File

@ -915,6 +915,10 @@ var testCipherSuites = []struct {
{"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 @@ func addCipherSuiteTests() {
// 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 @@ var testCurves = []struct {
{"P-384", CurveP384},
{"P-521", CurveP521},
{"X25519", CurveX25519},
{"CECPQ1", CurveCECPQ1},
}
func addCurveTests() {