diff --git a/CHANGES b/CHANGES index b0331b25941254f970577c822f7da2fcd8b86b06..b4cc2d4c93e1c8db7cacda042d07b7d9f7f3adcd 100644 --- a/CHANGES +++ b/CHANGES @@ -9,7 +9,9 @@ SSL_set_max_proto_version(), or via the SSL_CONF's MinProtocol and MaxProtcol. It's recommended to use the new APIs to disable protocols instead of disabling individual protocols using - SSL_set_options() or SSL_CONF's Protocol. + SSL_set_options() or SSL_CONF's Protocol. This change also + removes support for disabling TLS 1.2 in the OpenSSL TLS + client at compile time by defining OPENSSL_NO_TLS1_2_CLIENT. [Kurt Roeckx] *) Support for ChaCha20 and Poly1305 added to libcrypto and libssl. diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index a0d66fa0c44a72dc722461c8e07dc8c7a4ba986a..0d22ab7716355b28d644464e20f3aae9fc91bcd3 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1217,7 +1217,6 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) # define SSL_CTRL_SELECT_CURRENT_CERT 116 # define SSL_CTRL_SET_CURRENT_CERT 117 # define SSL_CTRL_SET_DH_AUTO 118 -# define SSL_CTRL_CHECK_PROTO_VERSION 119 # define DTLS_CTRL_SET_LINK_MTU 120 # define DTLS_CTRL_GET_LINK_MIN_MTU 121 # define SSL_CTRL_GET_EXTMS_SUPPORT 122 @@ -2099,7 +2098,6 @@ void ERR_load_SSL_strings(void); # define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 # define SSL_F_SSL_SET_SESSION_TICKET_EXT 294 # define SSL_F_SSL_SET_TRUST 228 -# define SSL_F_SSL_SET_VERSION 347 # define SSL_F_SSL_SET_WFD 196 # define SSL_F_SSL_SHUTDOWN 224 # define SSL_F_SSL_SRP_CTX_INIT 313 @@ -2170,6 +2168,8 @@ void ERR_load_SSL_strings(void); /* Reason codes. */ # define SSL_R_APP_DATA_IN_HANDSHAKE 100 # define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 +# define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE 143 +# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE 158 # define SSL_R_BAD_ALERT_RECORD 101 # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 # define SSL_R_BAD_DATA 390 @@ -2323,9 +2323,6 @@ void ERR_load_SSL_strings(void); # define SSL_R_NULL_SSL_METHOD_PASSED 196 # define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 # define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344 -# define SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE 387 -# define SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE 379 -# define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 # define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327 # define SSL_R_PACKET_LENGTH_TOO_LONG 198 # define SSL_R_PARSE_TLSEXT 227 @@ -2443,6 +2440,7 @@ void ERR_load_SSL_strings(void); # define SSL_R_UNSUPPORTED_SSL_VERSION 259 # define SSL_R_UNSUPPORTED_STATUS_TYPE 329 # define SSL_R_USE_SRTP_NOT_NEGOTIATED 369 +# define SSL_R_VERSION_TOO_HIGH 166 # define SSL_R_VERSION_TOO_LOW 396 # define SSL_R_WRONG_CERTIFICATE_TYPE 383 # define SSL_R_WRONG_CIPHER_RETURNED 261 diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index a510b5bebe6e234f7e079d81b35ab16436e38a88..3cd4b786e45e1951c475bf324abf4613bd343a0d 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -235,7 +235,7 @@ void dtls1_clear(SSL *s) if (s->options & SSL_OP_CISCO_ANYCONNECT) s->client_version = s->version = DTLS1_BAD_VER; else if (s->method->version == DTLS_ANY_VERSION) - s->version = DTLS1_2_VERSION; + s->version = DTLS_MAX_VERSION; else s->version = s->method->version; } @@ -256,38 +256,6 @@ long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) case DTLS_CTRL_LISTEN: ret = dtls1_listen(s, parg); break; - case SSL_CTRL_CHECK_PROTO_VERSION: - /* - * For library-internal use; checks that the current protocol is the - * is the highest enabled version. - */ - if (s->max_proto_version == 0 && s->version == DTLS_MAX_VERSION) - return 1; - if (s->max_proto_version != 0 && s->version == s->max_proto_version) - return 1; - /* We're not limited by the max_proto_version but might still have - * other reasons why we use an older version like not using a - * version-flexible SSL_METHOD. Check s->ctx->method as version - * negotiation may have changed s->method. - * This check can be removed when we only have version-flexible - * SSL_METHODs - */ - if (s->version == s->ctx->method->version) - return 1; - /* - * Apparently we're using a version-flexible SSL_METHOD (not at its - * highest protocol version, not limited by max_proto_version). - */ - if (s->ctx->method->version == DTLS_method()->version) { -#if DTLS_MAX_VERSION != DTLS1_2_VERSION -# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION. -#endif - if (!(s->options & SSL_OP_NO_DTLSv1_2)) - return s->version == DTLS1_2_VERSION; - if (!(s->options & SSL_OP_NO_DTLSv1)) - return s->version == DTLS1_VERSION; - } - return 0; /* Unexpected state; fail closed. */ case DTLS_CTRL_SET_LINK_MTU: if (larg < (long)dtls1_link_min_mtu()) return 0; @@ -708,8 +676,8 @@ int dtls1_listen(SSL *s, struct sockaddr *client) /* * Verify client version is supported */ - if ((clientvers > (unsigned int)s->method->version && - s->method->version != DTLS_ANY_VERSION)) { + if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) && + s->method->version != DTLS_ANY_VERSION) { SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_WRONG_VERSION_NUMBER); goto end; } diff --git a/ssl/methods.c b/ssl/methods.c index ef20c9ca3e021f962db248d3acf0d230e8f2656d..7a8bb11b7772588eca70e961c6ef6e0bb0b8cc7c 100644 --- a/ssl/methods.c +++ b/ssl/methods.c @@ -135,19 +135,23 @@ static const SSL_METHOD *tls1_get_method(int ver) return NULL; } -IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method, +IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0, + TLS_method, ossl_statem_accept, ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method, +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2, + TLSv1_2_method, ossl_statem_accept, ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1, + TLSv1_1_method, ossl_statem_accept, ossl_statem_connect, tls1_get_method, TLSv1_1_enc_data) -IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method, +IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1, + TLSv1_method, ossl_statem_accept, ossl_statem_connect, tls1_get_method, TLSv1_enc_data) @@ -178,22 +182,26 @@ static const SSL_METHOD *tls1_get_server_method(int ver) return NULL; } -IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method, +IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0, + TLS_server_method, ossl_statem_accept, ssl_undefined_function, tls1_get_server_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method, +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2, + TLSv1_2_server_method, ossl_statem_accept, ssl_undefined_function, tls1_get_server_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1, + TLSv1_1_server_method, ossl_statem_accept, ssl_undefined_function, tls1_get_server_method, TLSv1_1_enc_data) -IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method, +IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1, + TLSv1_server_method, ossl_statem_accept, ssl_undefined_function, tls1_get_server_method, TLSv1_enc_data) @@ -226,22 +234,26 @@ static const SSL_METHOD *tls1_get_client_method(int ver) return NULL; } -IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method, +IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0, + TLS_client_method, ssl_undefined_function, ossl_statem_connect, tls1_get_client_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method, +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2, + TLSv1_2_client_method, ssl_undefined_function, ossl_statem_connect, tls1_get_client_method, TLSv1_2_enc_data) -IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1, + TLSv1_1_client_method, ssl_undefined_function, ossl_statem_connect, tls1_get_client_method, TLSv1_1_enc_data) -IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method, +IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1, + TLSv1_client_method, ssl_undefined_function, ossl_statem_connect, tls1_get_client_method, TLSv1_enc_data) @@ -268,19 +280,19 @@ static const SSL_METHOD *dtls1_get_method(int ver) return NULL; } -IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1, DTLSv1_method, ossl_statem_accept, ossl_statem_connect, dtls1_get_method, DTLSv1_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2, DTLSv1_2_method, ossl_statem_accept, ossl_statem_connect, dtls1_get_method, DTLSv1_2_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0, DTLS_method, ossl_statem_accept, ossl_statem_connect, @@ -303,19 +315,19 @@ static const SSL_METHOD *dtls1_get_server_method(int ver) return NULL; } -IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1, DTLSv1_server_method, ossl_statem_accept, ssl_undefined_function, dtls1_get_server_method, DTLSv1_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2, DTLSv1_2_server_method, ossl_statem_accept, ssl_undefined_function, dtls1_get_server_method, DTLSv1_2_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0, DTLS_server_method, ossl_statem_accept, ssl_undefined_function, @@ -338,19 +350,19 @@ static const SSL_METHOD *dtls1_get_client_method(int ver) return NULL; } -IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1, DTLSv1_client_method, ssl_undefined_function, ossl_statem_connect, dtls1_get_client_method, DTLSv1_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2, DTLSv1_2_client_method, ssl_undefined_function, ossl_statem_connect, dtls1_get_client_method, DTLSv1_2_enc_data) -IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0, DTLS_client_method, ssl_undefined_function, ossl_statem_connect, diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index e3e4fd34f8b3dbc5176bed6e2500d3e7feb207a8..d307ec05d6c4e3941d3b153e11ffc3d9d2a42417 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3777,33 +3777,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) } #endif - case SSL_CTRL_CHECK_PROTO_VERSION: - /* - * For library-internal use; checks that the current protocol is the - * highest enabled version (according to s->ctx->method, as version - * negotiation may have changed s->method). - */ - if (s->version == s->ctx->method->version) - return 1; - /* - * Apparently we're using a version-flexible SSL_METHOD (not at its - * highest protocol version). - */ - if (s->ctx->method->version == TLS_method()->version) { -#if TLS_MAX_VERSION != TLS1_2_VERSION -# error Code needs update for TLS_method() support beyond TLS1_2_VERSION. -#endif - if (!(s->options & SSL_OP_NO_TLSv1_2)) - return s->version == TLS1_2_VERSION; - if (!(s->options & SSL_OP_NO_TLSv1_1)) - return s->version == TLS1_1_VERSION; - if (!(s->options & SSL_OP_NO_TLSv1)) - return s->version == TLS1_VERSION; - if (!(s->options & SSL_OP_NO_SSLv3)) - return s->version == SSL3_VERSION; - } - return 0; /* Unexpected state; fail closed. */ - default: break; } diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index f01d3a783505d6a71e728d8253f797caed795e20..597de0ad6c08592a7e9f2d4c68d6e9f719275770 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -1084,15 +1084,21 @@ static int ssl_security_default_callback(SSL *s, SSL_CTX *ctx, int op, break; } case SSL_SECOP_VERSION: - /* SSLv3 not allowed on level 2 */ - if (nid <= SSL3_VERSION && level >= 2) - return 0; - /* TLS v1.1 and above only for level 3 */ - if (nid <= TLS1_VERSION && level >= 3) - return 0; - /* TLS v1.2 only for level 4 and above */ - if (nid <= TLS1_1_VERSION && level >= 4) - return 0; + if (!SSL_IS_DTLS(s)) { + /* SSLv3 not allowed at level 2 */ + if (nid <= SSL3_VERSION && level >= 2) + return 0; + /* TLS v1.1 and above only for level 3 */ + if (nid <= TLS1_VERSION && level >= 3) + return 0; + /* TLS v1.2 only for level 4 and above */ + if (nid <= TLS1_1_VERSION && level >= 4) + return 0; + } else { + /* DTLS v1.2 only for level 4 and above */ + if (DTLS_VERSION_LT(nid, DTLS1_2_VERSION) && level >= 4) + return 0; + } break; case SSL_SECOP_COMPRESSION: diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 65a5bb6c968cbb886adfed9e59a2c9b97652e4b8..a15248d41bdc19841203d5a3816469fd81801055 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -1349,12 +1349,8 @@ static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c, /* Check version: if TLS 1.2 ciphers allowed we can use Suite B */ if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)) { - if (meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) - SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, - SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); - else - SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, - SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE); + SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, + SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE); return 0; } # ifndef OPENSSL_NO_EC diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index 1e14a4497e89d10b129002c18833c28465bd6a12..9529d30842cc10b60b7d3e09fd91b4e841433b25 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -347,6 +347,22 @@ static int protocol_from_string(const char *value) return -1; } +static int min_max_proto(SSL_CONF_CTX *cctx, const char *value, int *bound) +{ + int method_version; + int new_version; + + if (cctx->ctx != NULL) + method_version = cctx->ctx->method->version; + else if (cctx->ssl != NULL) + method_version = cctx->ssl->ctx->method->version; + else + return 0; + if ((new_version = protocol_from_string(value)) < 0) + return 0; + return ssl_set_version_bound(method_version, new_version, bound); +} + /* * cmd_MinProtocol - Set min protocol version * @cctx: config structure to save settings in @@ -356,13 +372,7 @@ static int protocol_from_string(const char *value) */ static int cmd_MinProtocol(SSL_CONF_CTX *cctx, const char *value) { - int version = protocol_from_string(value); - - if (version < 0) - return 0; - - *(cctx->min_version) = version; - return 1; + return min_max_proto(cctx, value, cctx->min_version); } /* @@ -374,13 +384,7 @@ static int cmd_MinProtocol(SSL_CONF_CTX *cctx, const char *value) */ static int cmd_MaxProtocol(SSL_CONF_CTX *cctx, const char *value) { - int version = protocol_from_string(value); - - if (version < 0) - return 0; - - *(cctx->max_version) = version; - return 1; + return min_max_proto(cctx, value, cctx->max_version); } static int cmd_Options(SSL_CONF_CTX *cctx, const char *value) diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 0c40b7b3ec08d1ef0a46fdea2223ca0644e29457..d9dbf99391ba4ba9846220a7bad5b9fbeedf9319 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -314,7 +314,6 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"}, {ERR_FUNC(SSL_F_SSL_SET_TRUST), "SSL_set_trust"}, - {ERR_FUNC(SSL_F_SSL_SET_VERSION), "SSL_SET_VERSION"}, {ERR_FUNC(SSL_F_SSL_SET_WFD), "SSL_set_wfd"}, {ERR_FUNC(SSL_F_SSL_SHUTDOWN), "SSL_shutdown"}, {ERR_FUNC(SSL_F_SSL_SRP_CTX_INIT), "SSL_SRP_CTX_init"}, @@ -416,6 +415,10 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE), "app data in handshake"}, {ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT), "attempt to reuse session in different context"}, + {ERR_REASON(SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE), + "at least TLS 1.0 needed in FIPS mode"}, + {ERR_REASON(SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE), + "at least (D)TLS 1.2 needed in Suite B mode"}, {ERR_REASON(SSL_R_BAD_ALERT_RECORD), "bad alert record"}, {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"}, {ERR_REASON(SSL_R_BAD_DATA), "bad data"}, @@ -603,14 +606,6 @@ static ERR_STRING_DATA SSL_str_reasons[] = { "old session cipher not returned"}, {ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED), "old session compression algorithm not returned"}, - {ERR_REASON(SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE), - "only DTLS 1.2 allowed in Suite B mode"}, - {ERR_REASON(SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE), - "only TLS 1.2 allowed in Suite B mode"}, - {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE), - "only tls allowed in fips mode"}, - {ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG), - "opaque PRF input too long"}, {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG), "packet length too long"}, {ERR_REASON(SSL_R_PARSE_TLSEXT), "parse tlsext"}, {ERR_REASON(SSL_R_PATH_TOO_LONG), "path too long"}, @@ -794,6 +789,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION), "unsupported ssl version"}, {ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE), "unsupported status type"}, {ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED), "use srtp not negotiated"}, + {ERR_REASON(SSL_R_VERSION_TOO_HIGH), "version too high"}, {ERR_REASON(SSL_R_VERSION_TOO_LOW), "version too low"}, {ERR_REASON(SSL_R_WRONG_CERTIFICATE_TYPE), "wrong certificate type"}, {ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED), "wrong cipher returned"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index cfc73de9cab84c3f84c841e66a835fcdd41c2762..760014d739eed93f874160e68832205d451919a5 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1201,11 +1201,11 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) else return 0; case SSL_CTRL_SET_MIN_PROTO_VERSION: - s->min_proto_version = larg; - return 1; + return ssl_set_version_bound(s->ctx->method->version, (int)larg, + &s->min_proto_version); case SSL_CTRL_SET_MAX_PROTO_VERSION: - s->max_proto_version = larg; - return 1; + return ssl_set_version_bound(s->ctx->method->version, (int)larg, + &s->max_proto_version); default: return (s->method->ssl_ctrl(s, cmd, larg, parg)); } @@ -1323,11 +1323,11 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) case SSL_CTRL_CLEAR_CERT_FLAGS: return (ctx->cert->cert_flags &= ~larg); case SSL_CTRL_SET_MIN_PROTO_VERSION: - ctx->min_proto_version = larg; - return 1; + return ssl_set_version_bound(ctx->method->version, (int)larg, + &ctx->min_proto_version); case SSL_CTRL_SET_MAX_PROTO_VERSION: - ctx->max_proto_version = larg; - return 1; + return ssl_set_version_bound(ctx->method->version, (int)larg, + &ctx->max_proto_version); default: return (ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg)); } @@ -1795,7 +1795,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) } if (FIPS_mode() && (meth->version < TLS1_VERSION)) { - SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE); return NULL; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9482fc91add5d59a25621445ff03a8bee4576447..7e07297f2f5146b14983b575cbe65fce9c5dfa60 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -471,8 +471,8 @@ * flags because it may not be set to correct version yet. */ # define SSL_CLIENT_USE_TLS1_2_CIPHERS(s) \ - ((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \ - (!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION)) + ((!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION) || \ + (SSL_IS_DTLS(s) && DTLS_VERSION_GE(s->client_version, DTLS1_2_VERSION))) # ifdef TLSEXT_TYPE_encrypt_then_mac # define SSL_USE_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) @@ -535,6 +535,8 @@ struct ssl_cipher_st { /* Used to hold SSL/TLS functions */ struct ssl_method_st { int version; + unsigned flags; + unsigned long mask; int (*ssl_new) (SSL *s); void (*ssl_clear) (SSL *s); void (*ssl_free) (SSL *s); @@ -1685,12 +1687,20 @@ extern const SSL3_ENC_METHOD SSLv3_enc_data; extern const SSL3_ENC_METHOD DTLSv1_enc_data; extern const SSL3_ENC_METHOD DTLSv1_2_enc_data; -# define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \ - s_get_meth, enc_data) \ +/* + * Flags for SSL methods + */ +#define SSL_METHOD_NO_FIPS (1U<<0) +#define SSL_METHOD_NO_SUITEB (1U<<1) + +# define IMPLEMENT_tls_meth_func(version, flags, mask, func_name, s_accept, \ + s_connect, s_get_meth, enc_data) \ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ version, \ + flags, \ + mask, \ tls1_new, \ tls1_clear, \ tls1_free, \ @@ -1727,6 +1737,8 @@ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ SSL3_VERSION, \ + SSL_METHOD_NO_FIPS | SSL_METHOD_NO_SUITEB, \ + SSL_OP_NO_SSLv3, \ ssl3_new, \ ssl3_clear, \ ssl3_free, \ @@ -1758,12 +1770,14 @@ const SSL_METHOD *func_name(void) \ return &func_name##_data; \ } -# define IMPLEMENT_dtls1_meth_func(version, func_name, s_accept, s_connect, \ - s_get_meth, enc_data) \ +# define IMPLEMENT_dtls1_meth_func(version, flags, mask, func_name, s_accept, \ + s_connect, s_get_meth, enc_data) \ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ version, \ + flags, \ + mask, \ dtls1_new, \ dtls1_clear, \ dtls1_free, \ @@ -1911,6 +1925,12 @@ __owur int ssl3_handshake_write(SSL *s); __owur int ssl_allow_compression(SSL *s); +__owur int ssl_set_client_hello_version(SSL *s); +__owur int ssl_check_version_downgrade(SSL *s); +__owur int ssl_set_version_bound(int method_version, int version, int *bound); +__owur int ssl_choose_server_version(SSL *s); +__owur int ssl_choose_client_version(SSL *s, int version); + __owur long tls1_default_timeout(void); __owur int dtls1_do_write(SSL *s, int type); void dtls1_set_message_header(SSL *s, diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index bc3fc54fabf3b86ec115ff779e131f722db7236e..a03fe32083205b2e84867f3b5b2c362821389c3d 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -261,7 +261,8 @@ static void (*get_callback(SSL *s))(const SSL *, int, int) * 1: Success * <=0: NBIO or error */ -static int state_machine(SSL *s, int server) { +static int state_machine(SSL *s, int server) +{ BUF_MEM *buf = NULL; unsigned long Time = (unsigned long)time(NULL); void (*cb) (const SSL *ssl, int type, int val) = NULL; @@ -336,19 +337,15 @@ static int state_machine(SSL *s, int server) { goto end; } } else { - if ((s->version >> 8) != SSL3_VERSION_MAJOR - && s->version != TLS_ANY_VERSION) { + if ((s->version >> 8) != SSL3_VERSION_MAJOR) { SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR); goto end; } } - if (!SSL_IS_DTLS(s)) { - if (s->version != TLS_ANY_VERSION && - !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) { - SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW); - goto end; - } + if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) { + SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW); + goto end; } if (s->init_buf == NULL) { diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 26acdc548827a1f3829470f19102807f0d3d94c3..cfbfa5f8c3d33d67ef01f437f1a23297963880cd 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -166,7 +166,6 @@ static ossl_inline int cert_req_allowed(SSL *s); static int key_exchange_expected(SSL *s); -static int ssl_set_version(SSL *s); static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b); static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p); @@ -800,128 +799,12 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst) return WORK_ERROR; } -/* - * Work out what version we should be using for the initial ClientHello if - * the version is currently set to (D)TLS_ANY_VERSION. - * Returns 1 on success - * Returns 0 on error - */ -static int ssl_set_version(SSL *s) -{ - unsigned long mask, options = s->options; - - if (s->method->version == TLS_ANY_VERSION) { - /* - * SSL_OP_NO_X disables all protocols above X *if* there are - * some protocols below X enabled. This is required in order - * to maintain "version capability" vector contiguous. So - * that if application wants to disable TLS1.0 in favour of - * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the - * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3. - */ - mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 -#if !defined(OPENSSL_NO_SSL3) - | SSL_OP_NO_SSLv3 -#endif - ; -#if !defined(OPENSSL_NO_TLS1_2_CLIENT) - if (options & SSL_OP_NO_TLSv1_2) { - if ((options & mask) != mask) { - s->version = TLS1_1_VERSION; - } else { - SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE); - return 0; - } - } else { - s->version = TLS1_2_VERSION; - } -#else - if ((options & mask) == mask) { - SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE); - return 0; - } - s->version = TLS1_1_VERSION; -#endif - - mask &= ~SSL_OP_NO_TLSv1_1; - if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) - s->version = TLS1_VERSION; - mask &= ~SSL_OP_NO_TLSv1; -#if !defined(OPENSSL_NO_SSL3) - if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) - s->version = SSL3_VERSION; -#endif - - if (s->max_proto_version != 0 && (s->version > s->max_proto_version)) - s->version = s->max_proto_version; - if (s->version < s->min_proto_version) - { - SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE); - return 0; - } - - if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) { - SSLerr(SSL_F_SSL_SET_VERSION, - SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE); - return 0; - } - - if (s->version == SSL3_VERSION && FIPS_mode()) { - SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); - return 0; - } - - } else if (s->method->version == DTLS_ANY_VERSION) { - int max_version = DTLS_MAX_VERSION; - int min_version = DTLS_MIN_VERSION; - - if (s->max_proto_version != 0) - max_version = s->max_proto_version; - if (s->min_proto_version != 0) - min_version = s->min_proto_version; - - /* If DTLS 1.2 disabled correct the version number */ - if (options & SSL_OP_NO_DTLSv1_2 - || DTLS_VERSION_GT(DTLS1_2_VERSION, max_version)) { - if (tls1_suiteb(s)) { - SSLerr(SSL_F_SSL_SET_VERSION, - SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); - return 0; - } - /* - * Disabling all versions is silly: return an error. - */ - if (options & SSL_OP_NO_DTLSv1 - || DTLS_VERSION_GT(min_version, DTLS1_VERSION)) { - SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION); - return 0; - } - /* - * Update method so we don't use any DTLS 1.2 features. - */ - s->method = DTLSv1_client_method(); - s->version = DTLS1_VERSION; - } else { - /* - * We only support one version: update method - */ - if (options & SSL_OP_NO_DTLSv1 - || DTLS_VERSION_GE(min_version, DTLS1_2_VERSION)) - s->method = DTLSv1_2_client_method(); - s->version = DTLS1_2_VERSION; - } - } - - s->client_version = s->version; - - return 1; -} - int tls_construct_client_hello(SSL *s) { unsigned char *buf; unsigned char *p, *d; int i; + int protverr; unsigned long l; int al = 0; #ifndef OPENSSL_NO_COMP @@ -933,8 +816,11 @@ int tls_construct_client_hello(SSL *s) buf = (unsigned char *)s->init_buf->data; /* Work out what SSL/TLS/DTLS version to use */ - if (ssl_set_version(s) == 0) + protverr = ssl_set_client_hello_version(s); + if (protverr != 0) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, protverr); goto err; + } if ((sess == NULL) || (sess->ssl_version != s->version) || /* @@ -1141,121 +1027,23 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) unsigned char *cipherchars; int i, al = SSL_AD_INTERNAL_ERROR; unsigned int compression; + unsigned int sversion; + int protverr; #ifndef OPENSSL_NO_COMP SSL_COMP *comp; #endif - if (s->method->version == TLS_ANY_VERSION) { - unsigned int sversion; - int max_version = TLS_MAX_VERSION; - - if (s->max_proto_version != 0) - max_version = s->max_proto_version; - - if (!PACKET_get_net_2(pkt, &sversion)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); - goto f_err; - } - -#if TLS_MAX_VERSION != TLS1_2_VERSION -#error Code needs updating for new TLS version -#endif -#ifndef OPENSSL_NO_SSL3 - if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3) && - (s->min_proto_version <= SSL3_VERSION) && - (max_version >= SSL3_VERSION)) { - if (FIPS_mode()) { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - s->method = SSLv3_client_method(); - } else -#endif - if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1) && - (s->min_proto_version <= TLS1_VERSION) && - (max_version >= TLS1_VERSION)) { - s->method = TLSv1_client_method(); - } else if ((sversion == TLS1_1_VERSION) && - !(s->options & SSL_OP_NO_TLSv1_1) && - (s->min_proto_version <= TLS1_1_VERSION) && - (max_version >= TLS1_1_VERSION)) { - s->method = TLSv1_1_client_method(); - } else if ((sversion == TLS1_2_VERSION) && - !(s->options & SSL_OP_NO_TLSv1_2) && - (s->min_proto_version <= TLS1_2_VERSION) && - (max_version >= TLS1_2_VERSION)) { - s->method = TLSv1_2_client_method(); - } else { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - s->session->ssl_version = s->version = s->method->version; - - if ((s->version < s->min_proto_version) - || !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - } else if (s->method->version == DTLS_ANY_VERSION) { - /* Work out correct protocol version to use */ - unsigned int hversion; - int options; - int max_version = DTLS_MAX_VERSION; - int min_version = DTLS_MIN_VERSION; - - if (s->max_proto_version != 0) - max_version = s->max_proto_version; - if (s->min_proto_version != 0) - min_version = s->min_proto_version; - - if (!PACKET_get_net_2(pkt, &hversion)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - options = s->options; - if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2) && - DTLS_VERSION_LE(min_version, DTLS1_2_VERSION) && - DTLS_VERSION_GE(max_version, DTLS1_2_VERSION)) - s->method = DTLSv1_2_client_method(); - else if (tls1_suiteb(s)) { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, - SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); - s->version = hversion; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1) && - DTLS_VERSION_LE(min_version, DTLS1_VERSION) && - DTLS_VERSION_GE(max_version, DTLS1_VERSION)) - s->method = DTLSv1_client_method(); - else { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); - s->version = hversion; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - s->session->ssl_version = s->version = s->method->version; - } else { - unsigned char *vers; + if (!PACKET_get_net_2(pkt, &sversion)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } - if (!PACKET_get_bytes(pkt, &vers, 2)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH); - goto f_err; - } - if ((vers[0] != (s->version >> 8)) - || (vers[1] != (s->version & 0xff))) { - SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); - s->version = (s->version & 0xff00) | vers[1]; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } + protverr = ssl_choose_client_version(s, sversion); + if (protverr != 0) { + al = SSL_AD_PROTOCOL_VERSION; + SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr); + goto f_err; } /* load the server hello data */ diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 86d200f0b2d11b37dcfb488567da6a2454795b9c..bf59eb3925733b19914df4eeba6d5c2013d11b44 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -229,7 +229,7 @@ MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt) { int al; long remain; - + remain = PACKET_remaining(pkt); /* * 'Change Cipher Spec' is just a single byte, which should already have @@ -704,3 +704,386 @@ int ssl_allow_compression(SSL *s) return 0; return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL); } + +static int version_cmp(SSL *s, int a, int b) +{ + int dtls = SSL_IS_DTLS(s); + + if (a == b) + return 0; + if (!dtls) + return a < b ? -1 : 1; + return DTLS_VERSION_LT(a, b) ? -1 : 1; +} + +typedef struct { + int version; + const SSL_METHOD *(*cmeth)(void); + const SSL_METHOD *(*smeth)(void); +} version_info; + +#if TLS_MAX_VERSION != TLS1_2_VERSION +# error Code needs update for TLS_method() support beyond TLS1_2_VERSION. +#endif + +static const version_info tls_version_table[] = { + { TLS1_2_VERSION, TLSv1_2_client_method, TLSv1_2_server_method }, + { TLS1_1_VERSION, TLSv1_1_client_method, TLSv1_1_server_method }, + { TLS1_VERSION, TLSv1_client_method, TLSv1_server_method }, +#ifndef OPENSSL_NO_SSL3 + { SSL3_VERSION, SSLv3_client_method, SSLv3_server_method }, +#endif + { 0, NULL, NULL }, +}; + +#if DTLS_MAX_VERSION != DTLS1_2_VERSION +# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION. +#endif + +static const version_info dtls_version_table[] = { + { DTLS1_2_VERSION, DTLSv1_2_client_method, DTLSv1_2_server_method }, + { DTLS1_VERSION, DTLSv1_client_method, DTLSv1_server_method }, + { 0, NULL, NULL }, +}; + +/* + * ssl_method_error - Check whether an SSL_METHOD is enabled. + * + * @s: The SSL handle for the candidate method + * @method: the intended method. + * + * Returns 0 on success, or an SSL error reason on failure. + */ +static int ssl_method_error(SSL *s, const SSL_METHOD *method) +{ + int version = method->version; + + if ((s->min_proto_version != 0 && + version_cmp(s, version, s->min_proto_version) < 0) || + ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0) + return SSL_R_VERSION_TOO_LOW; + + if (s->max_proto_version != 0 && + version_cmp(s, version, s->max_proto_version) > 0) + return SSL_R_VERSION_TOO_HIGH; + + if ((s->options & method->mask) != 0) + return SSL_R_UNSUPPORTED_PROTOCOL; + if ((method->flags & SSL_METHOD_NO_SUITEB) != 0 && tls1_suiteb(s)) + return SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE; + else if ((method->flags & SSL_METHOD_NO_FIPS) != 0 && FIPS_mode()) + return SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE; + + return 0; +} + +/* + * ssl_check_version_downgrade - In response to RFC7507 SCSV version + * fallback indication from a client check whether we're using the highest + * supported protocol version. + * + * @s server SSL handle. + * + * Returns 1 when using the highest enabled version, 0 otherwise. + */ +int ssl_check_version_downgrade(SSL *s) +{ + const version_info *vent; + const version_info *table; + + /* + * Check that the current protocol is the highest enabled version + * (according to s->ctx->method, as version negotiation may have changed + * s->method). + */ + if (s->version == s->ctx->method->version) + return 1; + + /* + * Apparently we're using a version-flexible SSL_METHOD (not at its + * highest protocol version). + */ + if (s->ctx->method->version == TLS_method()->version) + table = tls_version_table; + else if (s->ctx->method->version == DTLS_method()->version) + table = dtls_version_table; + else { + /* Unexpected state; fail closed. */ + return 0; + } + + for (vent = table; vent->version != 0; ++vent) { + if (vent->smeth != NULL && + ssl_method_error(s, vent->smeth()) == 0) + return s->version == vent->version; + } + return 0; +} + +/* + * ssl_set_version_bound - set an upper or lower bound on the supported (D)TLS + * protocols, provided the initial (D)TLS method is version-flexible. This + * function sanity-checks the proposed value and makes sure the method is + * version-flexible, then sets the limit if all is well. + * + * @method_version: The version of the current SSL_METHOD. + * @version: the intended limit. + * @bound: pointer to limit to be updated. + * + * Returns 1 on success, 0 on failure. + */ +int ssl_set_version_bound(int method_version, int version, int *bound) +{ + /*- + * Restrict TLS methods to TLS protocol versions. + * Restrict DTLS methods to DTLS protocol versions. + * Note, DTLS version numbers are decreasing, use comparison macros. + * + * Note that for both lower-bounds we use explicit versions, not + * (D)TLS_MIN_VERSION. This is because we don't want to break user + * configurations. If the MIN (supported) version ever rises, the user's + * "floor" remains valid even if no longer available. We don't expect the + * MAX ceiling to ever get lower, so making that variable makes sense. + */ + switch (method_version) { + default: + /* + * XXX For fixed version methods, should we always fail and not set any + * bounds, always succeed and not set any bounds, or set the bounds and + * arrange to fail later if they are not met? At present fixed-version + * methods are not subject to controls that disable individual protocol + * versions. + */ + return 0; + + case TLS_ANY_VERSION: + if (version < SSL3_VERSION || version > TLS_MAX_VERSION) + return 0; + break; + + case DTLS_ANY_VERSION: + if (DTLS_VERSION_GT(version, DTLS_MAX_VERSION) || + DTLS_VERSION_LT(version, DTLS1_VERSION)) + return 0; + break; + } + + *bound = version; + return 1; +} + +/* + * ssl_choose_server_version - Choose server (D)TLS version. Called when the + * client HELLO is received to select the final server protocol version and + * the version specific method. + * + * @s: server SSL handle. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_choose_server_version(SSL *s) +{ + /*- + * With version-flexible methods we have an initial state with: + * + * s->method->version == (D)TLS_ANY_VERSION, + * s->version == (D)TLS_MAX_VERSION. + * + * So we detect version-flexible methods via the method version, not the + * handle version. + */ + int server_version = s->method->version; + int client_version = s->client_version; + const version_info *vent; + const version_info *table; + int disabled = 0; + + switch (server_version) { + default: + if (version_cmp(s, client_version, s->version) < 0) + return SSL_R_WRONG_SSL_VERSION; + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + for (vent = table; vent->version != 0; ++vent) { + const SSL_METHOD *method; + + if (vent->smeth == NULL || + version_cmp(s, client_version, vent->version) < 0) + continue; + method = vent->smeth(); + if (ssl_method_error(s, method) == 0) { + s->version = vent->version; + s->method = method; + return 0; + } + disabled = 1; + } + return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW; +} + +/* + * ssl_choose_client_version - Choose client (D)TLS version. Called when the + * server HELLO is received to select the final client protocol version and + * the version specific method. + * + * @s: client SSL handle. + * @version: The proposed version from the server's HELLO. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_choose_client_version(SSL *s, int version) +{ + const version_info *vent; + const version_info *table; + + switch (s->method->version) { + default: + if (version != s->version) + return SSL_R_WRONG_SSL_VERSION; + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max, FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + s->session->ssl_version = s->version; + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + for (vent = table; vent->version != 0; ++vent) { + const SSL_METHOD *method; + int err; + + if (version != vent->version) + continue; + if (vent->cmeth == NULL) + break; + method = vent->cmeth(); + err = ssl_method_error(s, method); + if (err != 0) + return err; + s->method = method; + s->session->ssl_version = s->version = version; + return 0; + } + + return SSL_R_UNSUPPORTED_PROTOCOL; +} + +/*- + * ssl_set_client_hello_version - Work out what version we should be using for + * the initial ClientHello if the version is initially (D)TLS_ANY_VERSION. We + * apply any explicit SSL_OP_NO_xxx options, the MinProtocol and MaxProtocol + * configuration commands, any Suite B or FIPS_mode() constraints and any floor + * imposed by the security level here, so we don't advertise the wrong protocol + * version to only reject the outcome later. + * + * Computing the right floor matters. If, e.g., TLS 1.0 and 1.2 are enabled, + * TLS 1.1 is disabled, but the security level, Suite-B and/or MinProtocol + * only allow TLS 1.2, we want to advertise TLS1.2, *not* TLS1. + * + * @s: client SSL handle. + * + * Returns 0 on success or an SSL error reason number on failure. + */ +int ssl_set_client_hello_version(SSL *s) +{ + int version; + int hole; + const SSL_METHOD *single = NULL; + const SSL_METHOD *method; + const version_info *table; + const version_info *vent; + + switch (s->method->version) { + default: + /* + * If this SSL handle is not from a version flexible method we don't + * (and never did) check min/max FIPS or Suite B constraints. Hope + * that's OK. It is up to the caller to not choose fixed protocol + * versions they don't want. If not, then easy to fix, just return + * ssl_method_error(s, s->method) + */ + s->client_version = s->version; + return 0; + case TLS_ANY_VERSION: + table = tls_version_table; + break; + case DTLS_ANY_VERSION: + table = dtls_version_table; + break; + } + + /* + * SSL_OP_NO_X disables all protocols above X *if* there are some protocols + * below X enabled. This is required in order to maintain the "version + * capability" vector contiguous. Any versions with a NULL client method + * (protocol version client is disabled at compile-time) is also a "hole". + * + * Our initial state is hole == 1, version == 0. That is, versions above + * the first version in the method table are disabled (a "hole" above + * the valid protocol entries) and we don't have a selected version yet. + * + * Whenever "hole == 1", and we hit an enabled method, its version becomes + * the selected version, and the method becomes a candidate "single" + * method. We're no longer in a hole, so "hole" becomes 0. + * + * If "hole == 0" and we hit an enabled method, then "single" is cleared, + * as we support a contiguous range of at least two methods. If we hit + * a disabled method, then hole becomes true again, but nothing else + * changes yet, because all the remaining methods may be disabled too. + * If we again hit an enabled method after the new hole, it becomes + * selected, as we start from scratch. + */ + version = 0; + hole = 1; + for (vent = table; vent->version != 0; ++vent) { + /* + * A table entry with a NULL client method is still a hole in the + * "version capability" vector. + */ + if (vent->cmeth == NULL) { + hole = 1; + continue; + } + method = vent->cmeth(); + if (ssl_method_error(s, method) != 0) { + hole = 1; + } else if (!hole) { + single = NULL; + } else { + version = (single = method)->version; + hole = 0; + } + } + + /* Fail if everything is disabled */ + if (version == 0) + return SSL_R_NO_PROTOCOLS_AVAILABLE; + + if (single != NULL) + s->method = single; + s->client_version = s->version = version; + return 0; +} diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index a1163ed98608e4d9f1fc2d719423d0d2d4591ba4..604b36565be3fad28c1f11a9b243183c266511d1 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -970,7 +970,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) SSL_COMP *comp = NULL; #endif STACK_OF(SSL_CIPHER) *ciphers = NULL; - int protverr = 1; + int protverr; /* |cookie| will only be initialized for DTLS. */ PACKET session_id, cipher_suites, compression, extensions, cookie; int is_v2_record; @@ -1037,76 +1037,21 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) } } - /* Do SSL/TLS version negotiation if applicable */ + /* + * Do SSL/TLS version negotiation if applicable. For DTLS we just check + * versions are potentially compatible. Version negotiation comes later. + */ if (!SSL_IS_DTLS(s)) { - if (s->version != TLS_ANY_VERSION) { - if (s->client_version >= s->version) { - protverr = 0; - } - } else if (s->client_version >= SSL3_VERSION) { - int max_version = TLS_MAX_VERSION; - - if (s->max_proto_version != 0) - max_version = s->max_proto_version; - - switch(s->client_version) { - default: - case TLS1_2_VERSION: - if(!(s->options & SSL_OP_NO_TLSv1_2) && - (max_version >= TLS1_2_VERSION) && - (s->min_proto_version <= TLS1_2_VERSION)) { - s->version = TLS1_2_VERSION; - s->method = TLSv1_2_server_method(); - protverr = 0; - break; - } - /* Deliberately fall through */ - case TLS1_1_VERSION: - if(!(s->options & SSL_OP_NO_TLSv1_1) && - (max_version >= TLS1_1_VERSION) && - (s->min_proto_version <= TLS1_1_VERSION)) { - s->version = TLS1_1_VERSION; - s->method = TLSv1_1_server_method(); - protverr = 0; - break; - } - /* Deliberately fall through */ - case TLS1_VERSION: - if(!(s->options & SSL_OP_NO_TLSv1) && - (max_version >= TLS1_VERSION) && - (s->min_proto_version <= TLS1_VERSION)) { - s->version = TLS1_VERSION; - s->method = TLSv1_server_method(); - protverr = 0; - break; - } - /* Deliberately fall through */ - case SSL3_VERSION: -#ifndef OPENSSL_NO_SSL3 - if(!(s->options & SSL_OP_NO_SSLv3) && - (max_version >= SSL3_VERSION) && - (s->min_proto_version <= SSL3_VERSION)) { - s->version = SSL3_VERSION; - s->method = SSLv3_server_method(); - protverr = 0; - break; - } -#else - break; -#endif - } - } - } else if (s->client_version <= s->version - || s->method->version == DTLS_ANY_VERSION) { - /* - * For DTLS we just check versions are potentially compatible. Version - * negotiation comes later. - */ + protverr = ssl_choose_server_version(s); + } else if (s->method->version != DTLS_ANY_VERSION && + DTLS_VERSION_LT(s->client_version, s->version)) { + protverr = SSL_R_VERSION_TOO_LOW; + } else { protverr = 0; } if (protverr) { - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); if ((!s->enc_write_ctx && !s->write_hash)) { /* * similar to ssl3_get_record, send alert using remote version @@ -1266,36 +1211,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) s->d1->cookie_verified = 1; } if (s->method->version == DTLS_ANY_VERSION) { - /* Select version to use */ - int max_version = DTLS_MAX_VERSION; - int min_version = DTLS_MIN_VERSION; - - if (s->max_proto_version != 0) - max_version = s->max_proto_version; - if (s->min_proto_version != 0) - min_version = s->min_proto_version; - - if (DTLS_VERSION_GE(s->client_version, DTLS1_2_VERSION) && - !(s->options & SSL_OP_NO_DTLSv1_2) && - DTLS_VERSION_GE(max_version, DTLS1_2_VERSION) && - DTLS_VERSION_LE(min_version, DTLS1_2_VERSION)) { - s->version = DTLS1_2_VERSION; - s->method = DTLSv1_2_server_method(); - } else if (tls1_suiteb(s)) { - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, - SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); - s->version = s->client_version; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } else if (DTLS_VERSION_GE(s->client_version, DTLS1_VERSION) && - !(s->options & SSL_OP_NO_DTLSv1) && - DTLS_VERSION_GE(max_version, DTLS1_VERSION) && - DTLS_VERSION_LE(min_version, DTLS1_VERSION)) { - s->version = DTLS1_VERSION; - s->method = DTLSv1_server_method(); - } else { - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, - SSL_R_WRONG_VERSION_NUMBER); + protverr = ssl_choose_server_version(s); + if (protverr != 0) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); s->version = s->client_version; al = SSL_AD_PROTOCOL_VERSION; goto f_err; @@ -3303,7 +3221,7 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, * version. Fail if the current version is an unexpected * downgrade. */ - if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) { + if (!ssl_check_version_downgrade(s)) { SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_INAPPROPRIATE_FALLBACK); *al = SSL_AD_INAPPROPRIATE_FALLBACK; diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index a2a68af6c92c6e17ae8008c3ae55eccbf43ed7f2..980f2f5d0bbba6867c747a956cd4b425187d6367 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -208,7 +208,10 @@ void tls1_free(SSL *s) void tls1_clear(SSL *s) { ssl3_clear(s); - s->version = s->method->version; + if (s->method->version == TLS_ANY_VERSION) + s->version = TLS_MAX_VERSION; + else + s->version = s->method->version; } #ifndef OPENSSL_NO_EC