diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 4de2b47455cff..c59aa847e4a2e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2229,7 +2229,7 @@ STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s) ssl_set_client_disabled(s); for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i); - if (!ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED)) { + if (!ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0)) { if (!sk) sk = sk_SSL_CIPHER_new_null(); if (!sk) diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 5ca7237fc56f6..8eb6ff52c9b5f 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -2394,7 +2394,7 @@ __owur int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey); __owur size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs); __owur int tls12_check_peer_sigalg(SSL *s, uint16_t, EVP_PKEY *pkey); void ssl_set_client_disabled(SSL *s); -__owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op); +__owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op, int echde); __owur int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen, size_t *hashlen); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index a8bb5663f099f..0452729c44ec0 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -1259,7 +1259,7 @@ static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars) * If it is a disabled cipher we either didn't send it in client hello, * or it's not allowed for the selected protocol. So we return an error. */ - if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) { + if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK, 1)) { SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED); return 0; } @@ -3552,7 +3552,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, WPACKET *pkt) c = sk_SSL_CIPHER_value(sk, i); /* Skip disabled ciphers */ - if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED)) + if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED, 0)) continue; if (!s->method->put_cipher_by_char(c, pkt, &len)) { diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 698c25b46fc03..5007f7ebb37a6 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1034,19 +1034,31 @@ void ssl_set_client_disabled(SSL *s) * @s: SSL connection that you want to use the cipher on * @c: cipher to check * @op: Security check that you want to do + * @ecdhe: If set to 1 then TLSv1 ECDHE ciphers are also allowed in SSLv3 * * Returns 1 when it's disabled, 0 when enabled. */ -int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op) +int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op, int ecdhe) { if (c->algorithm_mkey & s->s3->tmp.mask_k || c->algorithm_auth & s->s3->tmp.mask_a) return 1; if (s->s3->tmp.max_ver == 0) return 1; - if (!SSL_IS_DTLS(s) && ((c->min_tls > s->s3->tmp.max_ver) - || (c->max_tls < s->s3->tmp.min_ver))) - return 1; + if (!SSL_IS_DTLS(s)) { + int min_tls = c->min_tls; + + /* + * For historical reasons we will allow ECHDE to be selected by a server + * in SSLv3 if we are a client + */ + if (min_tls == TLS1_VERSION && ecdhe + && (c->algorithm_mkey & (SSL_kECDHE | SSL_kECDHEPSK)) != 0) + min_tls = SSL3_VERSION; + + if ((min_tls > s->s3->tmp.max_ver) || (c->max_tls < s->s3->tmp.min_ver)) + return 1; + } if (SSL_IS_DTLS(s) && (DTLS_VERSION_GT(c->min_dtls, s->s3->tmp.max_ver) || DTLS_VERSION_LT(c->max_dtls, s->s3->tmp.min_ver))) return 1;