libtls: Add downgrade protection for TLS 1.3 and TLS 1.2
authorPascal Knecht <pascal.knecht@hsr.ch>
Sun, 17 Jan 2021 15:33:02 +0000 (16:33 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 12 Feb 2021 13:35:23 +0000 (14:35 +0100)
Section 4.1.3 in RFC 8446 defines a new downgrade protection mechanism
that also affects TLS 1.2.

src/libtls/tls.c
src/libtls/tls.h
src/libtls/tls_peer.c
src/libtls/tls_server.c

index 8b9911a..da45f4b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2021 Tobias Brunner
- * Copyright (C) 2020 Pascal Knecht
+ * Copyright (C) 2020-2021 Pascal Knecht
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2010 Martin Willi
@@ -153,6 +153,13 @@ chunk_t tls_hello_retry_request_magic = chunk_from_chars(
        0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
 );
 
+chunk_t tls_downgrade_protection_tls11 = chunk_from_chars(
+       0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00,
+);
+chunk_t tls_downgrade_protection_tls12 = chunk_from_chars(
+       0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01,
+);
+
 /**
  * TLS record
  */
index 5a11f70..9de042b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2021 Tobias Brunner
- * Copyright (C) 2020 Pascal Knecht
+ * Copyright (C) 2020-2021 Pascal Knecht
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2010 Martin Willi
@@ -214,6 +214,12 @@ extern enum_name_t *tls_extension_names;
 extern chunk_t tls_hello_retry_request_magic;
 
 /**
+ * Magic values for downgrade protection (see RFC 8446, section 4.1.3)
+ */
+extern chunk_t tls_downgrade_protection_tls11;
+extern chunk_t tls_downgrade_protection_tls12;
+
+/**
  * A bottom-up driven TLS stack, suitable for EAP implementations.
  */
 struct tls_t {
index 9d797f3..dac3aca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2020 Tobias Brunner
- * Copyright (C) 2020 Pascal Knecht
+ * Copyright (C) 2020-2021 Pascal Knecht
  * Copyright (C) 2020 Méline Sieber
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -208,6 +208,7 @@ static status_t process_server_hello(private_tls_peer_t *this,
        chunk_t msg, random, session, ext = chunk_empty, key_share = chunk_empty;
        chunk_t cookie = chunk_empty;
        tls_cipher_suite_t suite = 0;
+       tls_version_t version_max;
        bool is_retry_request;
 
        msg = reader->peek(reader);
@@ -286,6 +287,23 @@ static status_t process_server_hello(private_tls_peer_t *this,
        }
        extensions->destroy(extensions);
 
+       /* downgrade protection (see RFC 8446, section 4.1.3) */
+       version_max = this->tls->get_version_max(this->tls);
+       if ((version_max == TLS_1_3 && version < TLS_1_3) ||
+               (version_max == TLS_1_2 && version < TLS_1_2))
+       {
+               chunk_t server_random_end = chunk_create(&this->server_random[24], 8);
+
+               if (chunk_equals(server_random_end, tls_downgrade_protection_tls11) ||
+                       chunk_equals(server_random_end, tls_downgrade_protection_tls12))
+               {
+                       DBG1(DBG_TLS, "server random indicates downgrade attack to %N",
+                                tls_version_names, version);
+                       this->alert->add(this->alert, TLS_FATAL, TLS_ILLEGAL_PARAMETER);
+                       return NEED_MORE;
+               }
+       }
+
        if (!this->tls->set_version(this->tls, version, version))
        {
                DBG1(DBG_TLS, "negotiated version %N not supported",
index eb3edf8..2753231 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 Pascal Knecht
+ * Copyright (C) 2020-2021 Pascal Knecht
  * HSR Hochschule fuer Technik Rapperswil
  *
  * Copyright (C) 2010 Martin Willi
@@ -338,6 +338,7 @@ static status_t process_client_hello(private_tls_server_t *this,
        chunk_t extension_data = chunk_empty;
        bio_reader_t *extensions, *extension;
        tls_cipher_suite_t *suites;
+       tls_version_t original_version_max;
        int count, i;
        rng_t *rng;
 
@@ -456,6 +457,8 @@ static status_t process_client_hello(private_tls_server_t *this,
        }
        rng->destroy(rng);
 
+       original_version_max = this->tls->get_version_max(this->tls);
+
        if (versions.len)
        {
                bio_reader_t *client_versions;
@@ -482,6 +485,21 @@ static status_t process_client_hello(private_tls_server_t *this,
                        this->client_version = version;
                }
        }
+
+       /* downgrade protection (see RFC 8446, section 4.1.3) */
+       if ((original_version_max == TLS_1_3 && version < TLS_1_3) ||
+               (original_version_max == TLS_1_2 && version < TLS_1_2))
+       {
+               chunk_t downgrade_protection = tls_downgrade_protection_tls11;
+
+               if (version == TLS_1_2)
+               {
+                       downgrade_protection = tls_downgrade_protection_tls12;
+               }
+               memcpy(&this->server_random[24], downgrade_protection.ptr,
+                          downgrade_protection.len);
+       }
+
        if (!this->client_version)
        {
                DBG1(DBG_TLS, "proposed version %N not supported", tls_version_names,