diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-06-19 13:30:46 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-02-19 15:29:33 +0100 |
commit | 0ea16543448885d18a3841c2a25d06a38b11f4ba (patch) | |
tree | 0dda669334085433945ca54a2c5a2a11c9044ebf | |
parent | 23e48151eba05142b15ddd2cea6fa42fbc626abf (diff) | |
download | gnutls-0ea16543448885d18a3841c2a25d06a38b11f4ba.tar.gz |
handshake: legacy version negotiation is not used for TLS 1.3
That is, ensure that the functions used for TLS 1.2 and earlier
negotiation cannot be used with TLS 1.3. That is because TLS 1.3
is negotiated using a TLS extension.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/algorithms.h | 2 | ||||
-rw-r--r-- | lib/algorithms/protocols.c | 70 | ||||
-rw-r--r-- | lib/gnutls_int.h | 1 | ||||
-rw-r--r-- | lib/handshake.c | 20 | ||||
-rw-r--r-- | lib/handshake.h | 2 | ||||
-rw-r--r-- | lib/priority.c | 5 | ||||
-rw-r--r-- | lib/sslv2_compat.c | 2 |
7 files changed, 75 insertions, 27 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h index ebdef8880f..bb1d4a5a6c 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -40,7 +40,7 @@ /* Functions for version handling. */ const version_entry_st *version_to_entry(gnutls_protocol_t version); const version_entry_st *_gnutls_version_lowest(gnutls_session_t session); -gnutls_protocol_t _gnutls_version_max(gnutls_session_t session); +gnutls_protocol_t _gnutls_legacy_version_max(gnutls_session_t session); int _gnutls_version_priority(gnutls_session_t session, gnutls_protocol_t version); int _gnutls_version_is_supported(gnutls_session_t session, diff --git a/lib/algorithms/protocols.c b/lib/algorithms/protocols.c index a70c3e5815..0b035adddf 100644 --- a/lib/algorithms/protocols.c +++ b/lib/algorithms/protocols.c @@ -27,7 +27,7 @@ /* TLS Versions */ static const version_entry_st sup_versions[] = { - {.name = "SSL3.0", + {.name = "SSL3.0", .id = GNUTLS_SSL3, .age = 0, .major = 3, @@ -39,9 +39,10 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 0, .selectable_prf = 0, .obsolete = 1, + .only_extension = 0, .false_start = 0 }, - {.name = "TLS1.0", + {.name = "TLS1.0", .id = GNUTLS_TLS1, .age = 1, .major = 3, @@ -53,9 +54,10 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 0, .selectable_prf = 0, .obsolete = 0, + .only_extension = 0, .false_start = 0 }, - {.name = "TLS1.1", + {.name = "TLS1.1", .id = GNUTLS_TLS1_1, .age = 2, .major = 3, @@ -67,9 +69,10 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 0, .selectable_prf = 0, .obsolete = 0, + .only_extension = 0, .false_start = 0 }, - {.name = "TLS1.2", + {.name = "TLS1.2", .id = GNUTLS_TLS1_2, .age = 3, .major = 3, @@ -81,8 +84,24 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 1, .selectable_prf = 1, .obsolete = 0, + .only_extension = 0, .false_start = 1 }, + {.name = "TLS1.3", + .id = GNUTLS_TLS1_3, + .age = 4, + .major = 3, + .minor = 4, + .transport = GNUTLS_STREAM, + .supported = 1, + .explicit_iv = 1, + .extensions = 1, + .selectable_sighash = 1, + .selectable_prf = 1, + .obsolete = 0, + .only_extension = 1, + .false_start = 0 /* doesn't make sense */ + }, {.name = "DTLS0.9", /* Cisco AnyConnect (based on about OpenSSL 0.9.8e) */ .id = GNUTLS_DTLS0_9, .age = 200, @@ -95,9 +114,10 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 0, .selectable_prf = 0, .obsolete = 0, + .only_extension = 0, .false_start = 0 }, - {.name = "DTLS1.0", + {.name = "DTLS1.0", .id = GNUTLS_DTLS1_0, .age = 201, .major = 254, @@ -109,9 +129,10 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 0, .selectable_prf = 0, .obsolete = 0, + .only_extension = 0, .false_start = 0 }, - {.name = "DTLS1.2", + {.name = "DTLS1.2", .id = GNUTLS_DTLS1_2, .age = 202, .major = 254, @@ -123,6 +144,7 @@ static const version_entry_st sup_versions[] = { .selectable_sighash = 1, .selectable_prf = 1, .obsolete = 0, + .only_extension = 0, .false_start = 1 }, {0, 0, 0, 0, 0} @@ -198,9 +220,9 @@ const version_entry_st *_gnutls_version_lowest(gnutls_session_t session) /* Returns the maximum version in the priorities */ -static const version_entry_st *version_max(gnutls_session_t session) +static const version_entry_st *legacy_version_max(gnutls_session_t session) { - int max_proto = _gnutls_version_max(session); + int max_proto = _gnutls_legacy_version_max(session); if (max_proto < 0) return NULL; @@ -208,19 +230,41 @@ static const version_entry_st *version_max(gnutls_session_t session) return version_to_entry(max_proto); } -gnutls_protocol_t _gnutls_version_max(gnutls_session_t session) +gnutls_protocol_t _gnutls_legacy_version_max(gnutls_session_t session) { unsigned int i, max = 0x00; gnutls_protocol_t cur_prot; + const version_entry_st *p; for (i = 0; i < session->internals.priorities->protocol.algorithms; i++) { cur_prot = session->internals.priorities->protocol.priority[i]; - if (cur_prot > max - && _gnutls_version_is_supported(session, cur_prot)) - max = cur_prot; + for (p = sup_versions; p->name != NULL; p++) + if(p->id == cur_prot) { +#ifndef ENABLE_SSL3 + if (p->obsolete != 0) + break; +#endif + if (!p->supported || p->transport != session->internals.transport) + break; + + if (p->only_extension != 0) { + /* TLS 1.3 or later found */ + if (p->transport == GNUTLS_STREAM) { + return GNUTLS_TLS1_2; + } else { + return GNUTLS_DTLS1_2; + } + } + + if (!p->only_extension && cur_prot > max) { + max = cur_prot; + } + break; + } + } } if (max == 0x00) @@ -235,7 +279,7 @@ unsigned _gnutls_version_is_too_high(gnutls_session_t session, uint8_t major, ui { const version_entry_st *e; - e = version_max(session); + e = legacy_version_max(session); if (e == NULL) /* we don't know; but that means something is unconfigured */ return 1; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 17c0486999..8cc8e8c0bc 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -519,6 +519,7 @@ typedef struct { * otherwise it prevents this protocol from being set as record version */ bool obsolete; bool false_start; /* That version can be used with false start */ + bool only_extension; /* negotiated only with an extension */ } version_entry_st; diff --git a/lib/handshake.c b/lib/handshake.c index 254bf75d48..1804bf5b81 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -181,10 +181,9 @@ int _gnutls_set_client_random(gnutls_session_t session, uint8_t * rnd) resumed_security_parameters.client_random, GNUTLS_RANDOM_SIZE); } else { - ret = - gnutls_rnd(GNUTLS_RND_NONCE, - session->security_parameters.client_random, - GNUTLS_RANDOM_SIZE); + ret = gnutls_rnd(GNUTLS_RND_NONCE, + session->security_parameters.client_random, + GNUTLS_RANDOM_SIZE); if (ret < 0) return gnutls_assert_val(ret); } @@ -361,12 +360,11 @@ _gnutls_finished(gnutls_session_t session, int type, void *ret, /* returns the 0 on success or a negative error code. */ int -_gnutls_negotiate_version(gnutls_session_t session, +_gnutls_negotiate_legacy_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor) { int ret; - /* if we do not support that version */ if (adv_version == GNUTLS_VERSION_UNKNOWN || _gnutls_version_is_supported(session, adv_version) == 0) { /* if we get an unknown/unsupported version, then fail if the version we @@ -377,7 +375,7 @@ _gnutls_negotiate_version(gnutls_session_t session, /* If he requested something we do not support * then we send him the highest we support. */ - ret = _gnutls_version_max(session); + ret = _gnutls_legacy_version_max(session); if (ret == GNUTLS_VERSION_UNKNOWN) { /* this check is not really needed. */ @@ -419,7 +417,7 @@ _gnutls_user_hello_func(gnutls_session_t session, /* Here we need to renegotiate the version since the callee might * have disabled some TLS versions. */ - ret = _gnutls_negotiate_version(session, adv_version, major, minor); + ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); if (ret < 0) { gnutls_assert(); return ret; @@ -457,7 +455,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, minor = data[pos+1]; set_adv_version(session, major, minor); - neg_version = _gnutls_negotiate_version(session, adv_version, major, minor); + neg_version = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); if (neg_version < 0) { gnutls_assert(); return neg_version; @@ -875,7 +873,7 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data, /* TLS_FALLBACK_SCSV */ if (data[i] == GNUTLS_FALLBACK_SCSV_MAJOR && data[i + 1] == GNUTLS_FALLBACK_SCSV_MINOR) { - unsigned max = _gnutls_version_max(session); + unsigned max = _gnutls_legacy_version_max(session); _gnutls_handshake_log ("HSK[%p]: Received fallback CS\n", session); @@ -1644,7 +1642,7 @@ static int send_client_hello(gnutls_session_t session, int again) hver = get_version(session); else /* new handshake. just get the max */ hver = - version_to_entry(_gnutls_version_max + version_to_entry(_gnutls_legacy_version_max (session)); } else { /* we are resuming a session */ diff --git a/lib/handshake.h b/lib/handshake.h index c6b393a205..3f9b55faa0 100644 --- a/lib/handshake.h +++ b/lib/handshake.h @@ -40,7 +40,7 @@ int _gnutls_find_pk_algos_in_ciphersuites(uint8_t * data, int datalen); int _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data, unsigned int datalen, unsigned int scsv_only); -int _gnutls_negotiate_version(gnutls_session_t session, +int _gnutls_negotiate_legacy_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); int _gnutls_user_hello_func(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); diff --git a/lib/priority.c b/lib/priority.c index ff49875e7b..5a00c3aa7d 100644 --- a/lib/priority.c +++ b/lib/priority.c @@ -161,13 +161,18 @@ static const int protocol_priority[] = { 0 }; +/* contains all the supported TLS protocols, intended to be used for eliminating them + */ static const int stream_protocol_priority[] = { + GNUTLS_TLS1_3, GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1_0, 0 }; +/* contains all the supported DTLS protocols, intended to be used for eliminating them + */ static const int dgram_protocol_priority[] = { GNUTLS_DTLS1_2, GNUTLS_DTLS1_0, diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c index c66ad77439..5ec5a0ad34 100644 --- a/lib/sslv2_compat.c +++ b/lib/sslv2_compat.c @@ -112,7 +112,7 @@ _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, adv_version = _gnutls_version_get(major, minor); - ret = _gnutls_negotiate_version(session, adv_version, major, minor); + ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); if (ret < 0) { gnutls_assert(); return ret; |