From 2970779684c6f164a0e261e96a3d59f331123320 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Fri, 20 Jun 2014 12:00:00 -0700 Subject: [PATCH] Fallback SCSV. This patch adds server-side support for TLS_FALLBACK_SCSV (see http://tools.ietf.org/html/draft-bmoeller-tls-downgrade-scsv-01). --- ssl/s3_enc.c | 1 + ssl/ssl.h | 2 ++ ssl/ssl3.h | 4 ++++ ssl/ssl_error.c | 1 + ssl/ssl_lib.c | 32 ++++++++++++++++++++++++++++++++ ssl/ssl_locl.h | 1 + ssl/t1_enc.c | 1 + 7 files changed, 42 insertions(+) diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index c275a9a5..b35af844 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -878,6 +878,7 @@ int ssl3_alert_code(int code) case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_INAPPROPRIATE_FALLBACK:return(SSL3_AD_INAPPROPRIATE_FALLBACK); default: return(-1); } } diff --git a/ssl/ssl.h b/ssl/ssl.h index fd049127..13bf5cbe 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1774,6 +1774,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE #define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE #define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ +#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK /* fatal */ #define SSL_ERROR_NONE 0 #define SSL_ERROR_SSL 1 @@ -3057,5 +3058,6 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNEXPECTED_GROUP_CLOSE 433 #define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 434 #define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 435 +#define SSL_R_INAPPROPRIATE_FALLBACK 436 #endif diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 77e7c5d8..a7535b31 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -127,6 +127,9 @@ extern "C" { /* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */ #define SSL3_CK_SCSV 0x030000FF +/* Fallback signalling cipher suite value: not IANA assigned. + * See https://tools.ietf.org/html/draft-bmoeller-tls-downgrade-scsv-01 */ +#define SSL3_CK_FALLBACK_SCSV 0x03005600 #define SSL3_CK_RSA_NULL_MD5 0x03000001 #define SSL3_CK_RSA_NULL_SHA 0x03000002 @@ -351,6 +354,7 @@ extern "C" { #define SSL3_AD_CERTIFICATE_EXPIRED 45 #define SSL3_AD_CERTIFICATE_UNKNOWN 46 #define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ +#define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */ #define TLS1_HB_REQUEST 1 #define TLS1_HB_RESPONSE 2 diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c index 42715243..57a45cb6 100644 --- a/ssl/ssl_error.c +++ b/ssl/ssl_error.c @@ -300,6 +300,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "HTTP_REQUEST"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_PADDING), "ILLEGAL_PADDING"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_SUITEB_DIGEST), "ILLEGAL_SUITEB_DIGEST"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INAPPROPRIATE_FALLBACK), "INAPPROPRIATE_FALLBACK"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION), "INCONSISTENT_COMPRESSION"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUDIT_PROOF), "INVALID_AUDIT_PROOF"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_AUTHZ_DATA), "INVALID_AUTHZ_DATA"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 46b3953c..c753e509 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1636,6 +1636,17 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num, continue; } + /* Check for FALLBACK_SCSV */ + if (s->s3 && n == 2 && + (p[0] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) && + (p[1] == (SSL3_CK_FALLBACK_SCSV & 0xff)) && + s->version < ssl_get_max_version(s)) + { + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL3_AD_INAPPROPRIATE_FALLBACK); + goto err; + } + c=ssl_get_cipher_by_char(s,p); p+=n; if (c != NULL) @@ -3479,6 +3490,27 @@ int ssl3_can_cutthrough(const SSL *s) return 1; } +/* ssl_get_max_version returns the maximum SSL/TLS version number supported by + * |s|, or zero if all versions are disabled. */ +int ssl_get_max_version(const SSL *s) + { + /* Only one version supported for DTLS. */ + if (s->version == DTLS1_VERSION) + return DTLS1_VERSION; + + if (!(s->options & SSL_OP_NO_TLSv1_2)) + return TLS1_2_VERSION; + if (!(s->options & SSL_OP_NO_TLSv1_1)) + return TLS1_1_VERSION; + if (!(s->options & SSL_OP_NO_TLSv1)) + return TLS1_VERSION; + if (!(s->options & SSL_OP_NO_SSLv3)) + return SSL3_VERSION; + if (!(s->options & SSL_OP_NO_SSLv2)) + return SSL2_VERSION; + return 0; + } + /* Allocates new EVP_MD_CTX and sets pointer to it into given pointer * vairable, freeing EVP_MD_CTX previously stored in that variable, if * any. If EVP_MD pointer is passed, initializes ctx with this md diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 0084613f..ad938b64 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1343,6 +1343,7 @@ void tls1_set_cert_validity(SSL *s); #endif int ssl3_can_cutthrough(const SSL *s); +int ssl_get_max_version(const SSL *s); EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; void ssl_clear_hash_ctx(EVP_MD_CTX **hash); int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 7c73e35b..72dbee35 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -1497,6 +1497,7 @@ int tls1_alert_code(int code) case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_INAPPROPRIATE_FALLBACK:return(SSL3_AD_INAPPROPRIATE_FALLBACK); #if 0 /* not appropriate for TLS, not used for DTLS */ case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);