]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
handshake: check for TLS_FALLBACK_SCSV
authorAlessandro Ghedini <alessandro@ghedini.me>
Fri, 31 Jul 2015 22:04:16 +0000 (00:04 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 1 Aug 2015 12:21:14 +0000 (12:21 +0000)
If TLS_FALLBACK_SCSV was sent by the client during the handshake, and
the advertised protocol version is lower than GNUTLS_TLS_VERSION_MAX,
send the "Inappropriate fallback" fatal alert and abort the handshake.

This mechanism was defined in RFC7507.

lib/algorithms.h
lib/gnutls_alert.c
lib/gnutls_errors.c
lib/gnutls_handshake.c
lib/includes/gnutls/gnutls.h.in

index b628d630bc8ffc4e8a840d22f2846c5c4774b03b..f9f0be19ce68ac7fedf157c4522349665833a52b 100644 (file)
@@ -28,6 +28,9 @@
 #define GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR 0x00
 #define GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR 0xFF
 
+#define GNUTLS_FALLBACK_SCSV_MAJOR 0x56
+#define GNUTLS_FALLBACK_SCSV_MINOR 0x00
+
 /* would allow for 256 ciphersuites */
 #define MAX_CIPHERSUITE_SIZE 512
 
index 2744bf8f921424bceb1ff15c6c0d767094b93a14..fb3a9d624bac5448cda6c3d21ed5520f80dfef1c 100644 (file)
@@ -67,6 +67,8 @@ static const gnutls_alert_entry sup_alerts[] = {
        ALERT_ENTRY(GNUTLS_A_SSL3_NO_CERTIFICATE,
                    N_("No certificate (SSL 3.0)")),
        ALERT_ENTRY(GNUTLS_A_INTERNAL_ERROR, N_("Internal error")),
+       ALERT_ENTRY(GNUTLS_A_INAPPROPRIATE_FALLBACK,
+                   N_("Inappropriate fallback")),
        ALERT_ENTRY(GNUTLS_A_NO_RENEGOTIATION,
                    N_("No renegotiation is allowed")),
        ALERT_ENTRY(GNUTLS_A_CERTIFICATE_UNOBTAINABLE,
@@ -275,6 +277,10 @@ int gnutls_error_to_alert(int err, int *level)
                ret = GNUTLS_A_INTERNAL_ERROR;
                _level = GNUTLS_AL_FATAL;
                break;
+       case GNUTLS_E_INAPPROPRIATE_FALLBACK:
+               ret = GNUTLS_A_INAPPROPRIATE_FALLBACK;
+               _level = GNUTLS_AL_FATAL;
+               break;
        case GNUTLS_E_OPENPGP_GETKEY_FAILED:
                ret = GNUTLS_A_CERTIFICATE_UNOBTAINABLE;
                _level = GNUTLS_AL_FATAL;
index 9838b758ad4e9f24c0cf0ee4a3c88be4e220809c..885427b98084291234ce73a464ba48f7cf09cc91 100644 (file)
@@ -73,6 +73,9 @@ static const gnutls_error_entry error_entries[] = {
                    GNUTLS_E_INVALID_SESSION),
 
        ERROR_ENTRY(N_("GnuTLS internal error."), GNUTLS_E_INTERNAL_ERROR),
+       ERROR_ENTRY(N_(
+                   "A connection with inappropriate fallback was attempted."),
+                   GNUTLS_E_INAPPROPRIATE_FALLBACK),
        ERROR_ENTRY(N_("An illegal TLS extension was received."),
                    GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION),
        ERROR_ENTRY(N_("A TLS fatal alert has been received."),
index 2566bceb353a9011e1b5040bb2fd1bfdbcf8bbb6..9b92c1356b34891f525c4276e2e3e59a70545f56 100644 (file)
@@ -909,28 +909,32 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
                                                         * supported by the peer.
                                                         */
 
-       /* First, check for safe renegotiation SCSV.
-        */
-       if (session->internals.priorities.sr != SR_DISABLED) {
-               unsigned int offset;
-
-               for (offset = 0; offset < datalen; offset += 2) {
-                       /* TLS_RENEGO_PROTECTION_REQUEST = { 0x00, 0xff } */
-                       if (data[offset] ==
-                           GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR
-                           && data[offset + 1] ==
-                           GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR) {
-                               _gnutls_handshake_log
-                                   ("HSK[%p]: Received safe renegotiation CS\n",
-                                    session);
-                               retval = _gnutls_ext_sr_recv_cs(session);
-                               if (retval < 0) {
-                                       gnutls_assert();
-                                       return retval;
-                               }
-                               break;
+       for (i = 0; i < datalen; i += 2) {
+               /* TLS_RENEGO_PROTECTION_REQUEST = { 0x00, 0xff } */
+               if (session->internals.priorities.sr != SR_DISABLED &&
+                   data[i] == GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR &&
+                   data[i + 1] == GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR) {
+                       _gnutls_handshake_log
+                           ("HSK[%p]: Received safe renegotiation CS\n",
+                            session);
+                       retval = _gnutls_ext_sr_recv_cs(session);
+                       if (retval < 0) {
+                               gnutls_assert();
+                               return retval;
                        }
                }
+
+               /* TLS_FALLBACK_SCSV */
+               if (data[i] == GNUTLS_FALLBACK_SCSV_MAJOR &&
+                   data[i + 1] == GNUTLS_FALLBACK_SCSV_MINOR) {
+                       _gnutls_handshake_log
+                           ("HSK[%p]: Received fallback CS\n",
+                            session);
+
+                       if (gnutls_protocol_get_version(session) !=
+                           GNUTLS_TLS_VERSION_MAX)
+                               return GNUTLS_E_INAPPROPRIATE_FALLBACK;
+               }
        }
 
        pk_algos_size = MAX_ALGOS;
index 58da371f574a1e9c2d3946a7fd3de86f7522e87e..36173cabe8ee967cba8ba92366beafad3069df35 100644 (file)
@@ -372,6 +372,7 @@ typedef enum {
  * @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_NO_RENEGOTIATION: No renegotiation is allowed.
  * @GNUTLS_A_CERTIFICATE_UNOBTAINABLE: Could not retrieve the
  *   specified certificate.
@@ -409,6 +410,7 @@ typedef enum {
        GNUTLS_A_PROTOCOL_VERSION = 70,
        GNUTLS_A_INSUFFICIENT_SECURITY,
        GNUTLS_A_INTERNAL_ERROR = 80,
+       GNUTLS_A_INAPPROPRIATE_FALLBACK = 86,
        GNUTLS_A_USER_CANCELED = 90,
        GNUTLS_A_NO_RENEGOTIATION = 100,
        GNUTLS_A_UNSUPPORTED_EXTENSION = 110,
@@ -2389,6 +2391,7 @@ int gnutls_fips140_mode_enabled(void);
 #define GNUTLS_E_PKCS1_WRONG_PAD -57
 #define GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION -58
 #define GNUTLS_E_INTERNAL_ERROR -59
+#define GNUTLS_E_INAPPROPRIATE_FALLBACK -60 /*GNUTLS_A_INAPPROPRIATE_FALLBACK*/
 #define GNUTLS_E_DH_PRIME_UNACCEPTABLE -63
 #define GNUTLS_E_FILE_ERROR -64
 #define GNUTLS_E_TOO_MANY_EMPTY_PACKETS -78