Protocol version selection and negotiation rewrite

The protocol selection code is now consolidated in a few consecutive
short functions in a single file and is table driven.  Protocol-specific
constraints that influence negotiation are moved into the flags
field of the method structure.  The same protocol version constraints
are now applied in all code paths.  It is now much easier to add
new protocol versions without reworking the protocol selection
logic.

In the presence of "holes" in the list of enabled client protocols
we no longer select client protocols below the hole based on a
subset of the constraints and then fail shortly after when it is
found that these don't meet the remaining constraints (suiteb, FIPS,
security level, ...).  Ideally, with the new min/max controls users
will be less likely to create "holes" in the first place.

Reviewed-by: Kurt Roeckx <kurt@openssl.org>
This commit is contained in:
Viktor Dukhovni 2015-12-29 03:24:17 -05:00
parent 57ce7b617c
commit 4fa52141b0
16 changed files with 543 additions and 479 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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"},

View file

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

View file

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

View file

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

View file

@ -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 (!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 (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_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 */

View file

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

View file

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

View file

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