diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-10-12 17:08:15 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-10-16 14:53:49 +0200 |
commit | 50d5f65d0ba312fb304108ee4fa6b37c41008bb4 (patch) | |
tree | 042e1e501181fcfff0997cbf5b3d71e4187036c7 | |
parent | b2be78193354e67b0fb6db3d789a375cf3032eae (diff) | |
download | gnutls-50d5f65d0ba312fb304108ee4fa6b37c41008bb4.tar.gz |
handshake: send missing extension alert
When a key share extension is not seen under TLS1.3, send
the missing extension alert.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/alert.c | 6 | ||||
-rw-r--r-- | lib/errors.c | 2 | ||||
-rw-r--r-- | lib/ext/key_share.c | 1 | ||||
-rw-r--r-- | lib/gnutls_int.h | 7 | ||||
-rw-r--r-- | lib/handshake.c | 29 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 9 |
6 files changed, 43 insertions, 11 deletions
diff --git a/lib/alert.c b/lib/alert.c index 9b10123345..b9aa7bd9ba 100644 --- a/lib/alert.c +++ b/lib/alert.c @@ -79,6 +79,8 @@ static const gnutls_alert_entry sup_alerts[] = { N_("The server name sent was not recognized")), ALERT_ENTRY(GNUTLS_A_UNKNOWN_PSK_IDENTITY, N_("The SRP/PSK username is missing or not known")), + ALERT_ENTRY(GNUTLS_A_MISSING_EXTENSION, + N_("An extension was expected but was not seen")), ALERT_ENTRY(GNUTLS_A_NO_APPLICATION_PROTOCOL, N_ ("No supported application protocol could be negotiated")), @@ -262,6 +264,10 @@ int gnutls_error_to_alert(int err, int *level) ret = GNUTLS_A_UNSUPPORTED_EXTENSION; _level = GNUTLS_AL_FATAL; break; + case GNUTLS_E_MISSING_EXTENSION: + ret = GNUTLS_A_MISSING_EXTENSION; + _level = GNUTLS_AL_FATAL; + break; case GNUTLS_E_USER_ERROR: ret = GNUTLS_A_USER_CANCELED; _level = GNUTLS_AL_FATAL; diff --git a/lib/errors.c b/lib/errors.c index fb6b54b4b0..e579f46852 100644 --- a/lib/errors.c +++ b/lib/errors.c @@ -81,6 +81,8 @@ static const gnutls_error_entry error_entries[] = { GNUTLS_E_INAPPROPRIATE_FALLBACK), ERROR_ENTRY(N_("An illegal TLS extension was received."), GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION), + ERROR_ENTRY(N_("An required TLS extension was received."), + GNUTLS_E_MISSING_EXTENSION), ERROR_ENTRY(N_("A TLS fatal alert has been received."), GNUTLS_E_FATAL_ALERT_RECEIVED), ERROR_ENTRY(N_("An unexpected TLS packet was received."), diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c index c5b104f9ac..6a9e6513a9 100644 --- a/lib/ext/key_share.c +++ b/lib/ext/key_share.c @@ -575,6 +575,7 @@ key_share_recv_params(gnutls_session_t session, return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE); } + session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED; } else { /* Client */ ver = get_version(session); if (unlikely(ver == NULL || ver->key_shares == 0)) diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 4a514ccc71..3a830e214f 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1332,9 +1332,12 @@ typedef struct { #define HSK_PSK_KE_MODE_DHE_PSK (1<<14) /* server: whether PSK with DH is selected * client: whether PSK with DH is allowed */ -#define HSK_PSK_SELECTED (1<<15) +#define HSK_PSK_SELECTED (1<<15) /* server: whether PSK was selected, either for resumption or not; + * on resumption session->internals.resumed will be set as well. + * client: the same */ #define HSK_KEY_SHARE_SENT (1<<16) /* server: key share was sent to client */ -#define HSK_KEY_SHARE_RECEIVED (1<<17) /* client: key share was received */ +#define HSK_KEY_SHARE_RECEIVED (1<<17) /* client: key share was received + * server: key share was received and accepted */ #define HSK_TLS13_TICKET_SENT (1<<18) /* client: sent a ticket under TLS1.3; * server: a ticket was sent to client. */ diff --git a/lib/handshake.c b/lib/handshake.c index 7db134a638..841c88385d 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -539,23 +539,40 @@ _gnutls_user_hello_func(gnutls_session_t session, return sret; } +/* Associates the right credential types for the session, and + * performs sanity checks. */ static int set_auth_types(gnutls_session_t session) { const version_entry_st *ver = get_version(session); gnutls_kx_algorithm_t kx; - kx = session->security_parameters.cs->kx_algorithm; - if (kx == 0 && ver->tls13_sem) { - /* if we are resuming then the KX seen doesn't match the original */ + /* sanity check: + * we see TLS1.3 negotiated but no key share was sent */ + if (ver->tls13_sem) { + if (unlikely(!(session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) && + !(session->internals.hsk_flags & HSK_KEY_SHARE_RECEIVED))) { + return gnutls_assert_val(GNUTLS_E_MISSING_EXTENSION); + } + + /* Under TLS1.3 this returns a KX which matches the negotiated + * groups from the key shares; if we are resuming then the KX seen + * here doesn't match the original session. */ if (session->internals.resumed == RESUME_FALSE) kx = gnutls_kx_get(session); + else + kx = GNUTLS_KX_UNKNOWN; + } else { + /* TLS1.2 or earlier, kx is associated with ciphersuite */ + kx = session->security_parameters.cs->kx_algorithm; } - if (kx) { + if (kx != GNUTLS_KX_UNKNOWN) { session->security_parameters.server_auth_type = _gnutls_map_kx_get_cred(kx, 1); session->security_parameters.client_auth_type = _gnutls_map_kx_get_cred(kx, 0); - } else if (session->internals.resumed == RESUME_FALSE) { - return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + } else if (unlikely(session->internals.resumed == RESUME_FALSE)) { + /* Here we can only arrive if something we received + * prevented the session from completing. */ + return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); } return 0; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 01cf9a880e..b4903bb97c 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -498,14 +498,15 @@ typedef enum { * @GNUTLS_A_EXPORT_RESTRICTION: Export restriction. * @GNUTLS_A_PROTOCOL_VERSION: Error in protocol version. * @GNUTLS_A_INSUFFICIENT_SECURITY: Insufficient security. - * @GNUTLS_A_USER_CANCELED: User canceled. * @GNUTLS_A_INTERNAL_ERROR: Internal error. * @GNUTLS_A_INAPPROPRIATE_FALLBACK: Inappropriate fallback, + * @GNUTLS_A_USER_CANCELED: User canceled. * @GNUTLS_A_NO_RENEGOTIATION: No renegotiation is allowed. - * @GNUTLS_A_CERTIFICATE_UNOBTAINABLE: Could not retrieve the - * specified certificate. + * @GNUTLS_A_MISSING_EXTENSION: An extension was expected but was not seen * @GNUTLS_A_UNSUPPORTED_EXTENSION: An unsupported extension was * sent. + * @GNUTLS_A_CERTIFICATE_UNOBTAINABLE: Could not retrieve the + * specified certificate. * @GNUTLS_A_UNRECOGNIZED_NAME: The server name sent was not * recognized. * @GNUTLS_A_UNKNOWN_PSK_IDENTITY: The SRP/PSK username is missing @@ -541,6 +542,7 @@ typedef enum { GNUTLS_A_INAPPROPRIATE_FALLBACK = 86, GNUTLS_A_USER_CANCELED = 90, GNUTLS_A_NO_RENEGOTIATION = 100, + GNUTLS_A_MISSING_EXTENSION = 109, GNUTLS_A_UNSUPPORTED_EXTENSION = 110, GNUTLS_A_CERTIFICATE_UNOBTAINABLE = 111, GNUTLS_A_UNRECOGNIZED_NAME = 112, @@ -3230,6 +3232,7 @@ void gnutls_fips140_set_mode(gnutls_fips_mode_t mode, unsigned flags); #define GNUTLS_E_REAUTH_REQUEST -424 #define GNUTLS_E_TOO_MANY_MATCHES -425 #define GNUTLS_E_CRL_VERIFICATION_ERROR -426 +#define GNUTLS_E_MISSING_EXTENSION -427 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 |