]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
handshake: send missing extension alert
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 12 Oct 2018 15:08:15 +0000 (17:08 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Tue, 16 Oct 2018 12:53:49 +0000 (14:53 +0200)
When a key share extension is not seen under TLS1.3, send
the missing extension alert.

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
lib/alert.c
lib/errors.c
lib/ext/key_share.c
lib/gnutls_int.h
lib/handshake.c
lib/includes/gnutls/gnutls.h.in

index 9b101233452c83979d80bd59cc17c47279f4f7c3..b9aa7bd9bae99c63cdf148c224c211ddc961d05f 100644 (file)
@@ -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;
index fb6b54b4b0006889df56960fc4d894007a3661f2..e579f46852ca0cb77a4bc04c151747d876828a6d 100644 (file)
@@ -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."),
index c5b104f9ac0a1b608293ef4d3313aba3d74433b2..6a9e6513a9051ca33de87d5a509004c736c9566a 100644 (file)
@@ -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))
index 4a514ccc717a137a36933d6161d6c5823a76aa3c..3a830e214f27fc9ed1e5dccad9d1c8e668c3021f 100644 (file)
@@ -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.
                                         */
index 7db134a6385d29c91686b91d6f77e35fe4aec51b..841c88385d0783a479d737d1a4c830e7b5d83b99 100644 (file)
@@ -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;
index 01cf9a880ed3d82cd15c3d5cfa581807110c039b..b4903bb97c7f22019c3702d8b47b18f2b71d7850 100644 (file)
@@ -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