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.
# 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
# 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
/* 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
# 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
# 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
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;
}
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;
/*
* 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;
}
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)
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)
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)
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,
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,
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,
}
#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;
}
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:
/* 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
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
*/
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);
}
/*
*/
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)
{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"},
{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"},
"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"},
{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"},
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));
}
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));
}
}
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;
}
* 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)
/* 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);
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, \
{ \
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, \
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, \
__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,
* 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;
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) {
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);
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
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) ||
/*
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 */
{
int al;
long remain;
-
+
remain = PACKET_remaining(pkt);
/*
* 'Change Cipher Spec' is just a single byte, which should already have
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;
+}
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;
}
}
- /* 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
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;
* 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;
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