summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2018-10-12 17:08:15 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-10-16 14:53:49 +0200
commit50d5f65d0ba312fb304108ee4fa6b37c41008bb4 (patch)
tree042e1e501181fcfff0997cbf5b3d71e4187036c7
parentb2be78193354e67b0fb6db3d789a375cf3032eae (diff)
downloadgnutls-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.c6
-rw-r--r--lib/errors.c2
-rw-r--r--lib/ext/key_share.c1
-rw-r--r--lib/gnutls_int.h7
-rw-r--r--lib/handshake.c29
-rw-r--r--lib/includes/gnutls/gnutls.h.in9
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