[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Fri Mar 24 14:11:03 UTC 2017


The branch master has been updated
       via  643a3580423c8774c08aed7e377495800b7e7266 (commit)
       via  b9647e34ff67f0f7af19a7775fc3f8846a30ac2e (commit)
       via  3556b83ea2a00d0dd3e4f1ec38adb6837553e451 (commit)
       via  c3043dcd55d81617408025b1cdb8241ef753b805 (commit)
       via  f7f2a01d6364f10f353652e29555e6c66aec9b6d (commit)
      from  a41815f05e71009d2a5148bd30b70f47186ed66b (commit)


- Log -----------------------------------------------------------------
commit 643a3580423c8774c08aed7e377495800b7e7266
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Mar 24 09:57:21 2017 +0000

    Move the downgrade sentinel declarations to a header file
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3022)

commit b9647e34ff67f0f7af19a7775fc3f8846a30ac2e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Mar 23 16:33:57 2017 +0000

    Add a test for the TLSv1.3 downgrade mechanism
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3022)

commit 3556b83ea2a00d0dd3e4f1ec38adb6837553e451
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 22 11:52:45 2017 +0000

    Make the TLSv1.3 downgrade mechanism a configurable option
    
    Make it disabled by default. When TLSv1.3 is out of draft we can remove
    this option and have it enabled all the time.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3022)

commit c3043dcd55d81617408025b1cdb8241ef753b805
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 22 11:50:32 2017 +0000

    Add client side support for TLSv1.3 downgrade mechanism
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3022)

commit f7f2a01d6364f10f353652e29555e6c66aec9b6d
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 22 08:52:54 2017 +0000

    Add server side support for TLSv1.3 downgrade mechanism
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3022)

-----------------------------------------------------------------------

Summary of changes:
 Configure                             |  2 +
 INSTALL                               | 10 ++++
 ssl/s3_lib.c                          | 33 +++++++++++--
 ssl/ssl_locl.h                        | 17 +++++--
 ssl/statem/statem_clnt.c              | 30 +++++------
 ssl/statem/statem_lib.c               | 86 ++++++++++++++++++++++++++++----
 ssl/statem/statem_srvr.c              |  7 +--
 test/recipes/70-test_sslextension.t   |  9 ++++
 test/recipes/70-test_sslversions.t    | 11 +++++
 test/recipes/70-test_tls13downgrade.t | 93 +++++++++++++++++++++++++++++++++++
 10 files changed, 263 insertions(+), 35 deletions(-)
 create mode 100644 test/recipes/70-test_tls13downgrade.t

diff --git a/Configure b/Configure
index b7d669c..191fe73 100755
--- a/Configure
+++ b/Configure
@@ -407,6 +407,7 @@ my @disablables = (
     "tests",
     "threads",
     "tls",
+    "tls13downgrade",
     "ts",
     "ubsan",
     "ui",
@@ -451,6 +452,7 @@ our %disabled = ( # "what"         => "comment"
                   "ubsan"		=> "default",
           #TODO(TLS1.3): Temporarily disabled while this is a WIP
 		  "tls1_3"              => "default",
+		  "tls13downgrade"      => "default",
 		  "unit-test"           => "default",
 		  "weak-ssl-ciphers"    => "default",
 		  "zlib"                => "default",
diff --git a/INSTALL b/INSTALL
index d741b9f..59486ef 100644
--- a/INSTALL
+++ b/INSTALL
@@ -427,6 +427,16 @@
                    require additional system-dependent options! See "Note on
                    multi-threading" below.
 
+  enable-tls13downgrade
+                   TODO(TLS1.3): Make this enabled by default and remove the
+                   option when TLSv1.3 is out of draft
+                   TLSv1.3 offers a downgrade protection mechanism. This is
+                   implemented but disabled by default. It should not typically
+                   be enabled except for testing purposes. Otherwise this could
+                   cause problems if a pre-RFC version of OpenSSL talks to an
+                   RFC implementation (it will erroneously be detected as a
+                   downgrade).
+
   no-ts
                    Don't build Time Stamping Authority support.
 
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 1669652..d8cce5e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -48,6 +48,7 @@
  */
 
 #include <stdio.h>
+#include <assert.h>
 #include <openssl/objects.h>
 #include "ssl_locl.h"
 #include <openssl/md5.h>
@@ -57,6 +58,14 @@
 #define SSL3_NUM_CIPHERS        OSSL_NELEM(ssl3_ciphers)
 #define SSL3_NUM_SCSVS          OSSL_NELEM(ssl3_scsvs)
 
+/* TLSv1.3 downgrade protection sentinel values */
+const unsigned char tls11downgrade[] = {
+    0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
+};
+const unsigned char tls12downgrade[] = {
+    0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
+};
+
 /*
  * The list of available ciphers, mostly organized into the following
  * groups:
@@ -4007,9 +4016,10 @@ long ssl_get_algorithm2(SSL *s)
  * Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 on
  * failure, 1 on success.
  */
-int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len)
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len,
+                          DOWNGRADE dgrd)
 {
-    int send_time = 0;
+    int send_time = 0, ret;
 
     if (len < 4)
         return 0;
@@ -4022,9 +4032,22 @@ int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len)
         unsigned char *p = result;
         l2n(Time, p);
         /* TODO(size_t): Convert this */
-        return RAND_bytes(p, (int)(len - 4));
-    } else
-        return RAND_bytes(result, (int)len);
+        ret = RAND_bytes(p, (int)(len - 4));
+    } else {
+        ret = RAND_bytes(result, (int)len);
+    }
+#ifndef OPENSSL_NO_TLS13DOWNGRADE
+    if (ret) {
+        assert(sizeof(tls11downgrade) < len && sizeof(tls12downgrade) < len);
+        if (dgrd == DOWNGRADE_TO_1_2)
+            memcpy(result + len - sizeof(tls12downgrade), tls12downgrade,
+                   sizeof(tls12downgrade));
+        else if (dgrd == DOWNGRADE_TO_1_1)
+            memcpy(result + len - sizeof(tls11downgrade), tls11downgrade,
+                   sizeof(tls11downgrade));
+    }
+#endif
+    return ret;
 }
 
 int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index f6eb03f..4378b71 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1783,6 +1783,12 @@ typedef struct ssl3_comp_st {
 } SSL3_COMP;
 # endif
 
+typedef enum downgrade_en {
+    DOWNGRADE_NONE,
+    DOWNGRADE_TO_1_2,
+    DOWNGRADE_TO_1_1
+} DOWNGRADE;
+
 /*
  * Extension index values NOTE: Any updates to these defines should be mirrored
  * with equivalent updates to ext_defs in extensions.c
@@ -1859,6 +1865,9 @@ typedef enum tlsext_index_en {
 /* A dummy signature value not valid for TLSv1.2 signature algs */
 #define TLSEXT_signature_rsa_pss                                0x0101
 
+/* TLSv1.3 downgrade protection sentinel values */
+extern const unsigned char tls11downgrade[8];
+extern const unsigned char tls12downgrade[8];
 
 extern SSL3_ENC_METHOD ssl3_undef_enc_method;
 
@@ -2101,7 +2110,7 @@ __owur int ssl_verify_alarm_type(long type);
 void ssl_sort_cipher_list(void);
 void ssl_load_ciphers(void);
 __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
-                                 size_t len);
+                                 size_t len, DOWNGRADE dgrd);
 __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
                                       int free_pms);
 __owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
@@ -2167,8 +2176,10 @@ __owur int ssl_version_supported(const SSL *s, int version);
 __owur int ssl_set_client_hello_version(SSL *s);
 __owur int ssl_check_version_downgrade(SSL *s);
 __owur int ssl_set_version_bound(int method_version, int version, int *bound);
-__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello);
-__owur int ssl_choose_client_version(SSL *s, int version);
+__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello,
+                                     DOWNGRADE *dgrd);
+__owur int ssl_choose_client_version(SSL *s, int version, int checkdgrd,
+                                     int *al);
 int ssl_get_client_min_max_version(const SSL *s, int *min_version,
                                    int *max_version);
 
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index d584bd7..1342272 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1094,7 +1094,8 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     } else
         i = 1;
 
-    if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)) <= 0)
+    if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random),
+                                   DOWNGRADE_NONE) <= 0)
         return 0;
 
     /*-
@@ -1316,10 +1317,20 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    /* We do this immediately so we know what format the ServerHello is in */
-    protverr = ssl_choose_client_version(s, sversion);
+    /* load the server random */
+    if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    /*
+     * We do this immediately so we know what format the ServerHello is in.
+     * Must be done after reading the random data so we can check for the
+     * TLSv1.3 downgrade sentinels
+     */
+    protverr = ssl_choose_client_version(s, sversion, 1, &al);
     if (protverr != 0) {
-        al = SSL_AD_PROTOCOL_VERSION;
         SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr);
         goto f_err;
     }
@@ -1334,14 +1345,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    /* load the server hello data */
-    /* load the server random */
-    if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
     /* Get the session-id. */
     if (!SSL_IS_TLS13(s)) {
         if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
@@ -1608,9 +1611,8 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
     s->hello_retry_request = 1;
 
     /* This will fail if it doesn't choose TLSv1.3+ */
-    errorcode = ssl_choose_client_version(s, sversion);
+    errorcode = ssl_choose_client_version(s, sversion, 0, &al);
     if (errorcode != 0) {
-        al = SSL_AD_PROTOCOL_VERSION;
         SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, errorcode);
         goto f_err;
     }
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 849310e..bf1a5b2 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -1295,6 +1295,7 @@ typedef struct {
 # error Code needs update for TLS_method() support beyond TLS1_3_VERSION.
 #endif
 
+/* Must be in order high to low */
 static const version_info tls_version_table[] = {
 #ifndef OPENSSL_NO_TLS1_3
     {TLS1_3_VERSION, tlsv1_3_client_method, tlsv1_3_server_method},
@@ -1328,6 +1329,7 @@ static const version_info tls_version_table[] = {
 # error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
 #endif
 
+/* Must be in order high to low */
 static const version_info dtls_version_table[] = {
 #ifndef OPENSSL_NO_DTLS1_2
     {DTLS1_2_VERSION, dtlsv1_2_client_method, dtlsv1_2_server_method},
@@ -1510,6 +1512,20 @@ int ssl_set_version_bound(int method_version, int version, int *bound)
     return 1;
 }
 
+static void check_for_downgrade(SSL *s, int vers, DOWNGRADE *dgrd)
+{
+    if (vers == TLS1_2_VERSION
+            && ssl_version_supported(s, TLS1_3_VERSION)) {
+        *dgrd = DOWNGRADE_TO_1_2;
+    } else if (!SSL_IS_DTLS(s) && vers < TLS1_2_VERSION
+            && (ssl_version_supported(s, TLS1_2_VERSION)
+                || ssl_version_supported(s, TLS1_3_VERSION))) {
+        *dgrd = DOWNGRADE_TO_1_1;
+    } else {
+        *dgrd = DOWNGRADE_NONE;
+    }
+}
+
 /*
  * ssl_choose_server_version - Choose server (D)TLS version.  Called when the
  * client HELLO is received to select the final server protocol version and
@@ -1519,7 +1535,7 @@ int ssl_set_version_bound(int method_version, int version, int *bound)
  *
  * Returns 0 on success or an SSL error reason number on failure.
  */
-int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
+int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd)
 {
     /*-
      * With version-flexible methods we have an initial state with:
@@ -1544,6 +1560,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
         if (!SSL_IS_TLS13(s)) {
             if (version_cmp(s, client_version, s->version) < 0)
                 return SSL_R_WRONG_SSL_VERSION;
+            *dgrd = DOWNGRADE_NONE;
             /*
              * If this SSL handle is not from a version flexible method we don't
              * (and never did) check min/max FIPS or Suite B constraints.  Hope
@@ -1620,6 +1637,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
                     return SSL_R_UNSUPPORTED_PROTOCOL;
                 return 0;
             }
+            check_for_downgrade(s, best_vers, dgrd);
             s->version = best_vers;
             s->method = best_method;
             return 0;
@@ -1646,6 +1664,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
             continue;
         method = vent->smeth();
         if (ssl_method_error(s, method) == 0) {
+            check_for_downgrade(s, vent->version, dgrd);
             s->version = vent->version;
             s->method = method;
             return 0;
@@ -1662,22 +1681,32 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
  *
  * @s: client SSL handle.
  * @version: The proposed version from the server's HELLO.
+ * @checkdgrd: Whether to check the downgrade sentinels in the server_random
+ * @al: Where to store any alert value that may be generated
  *
  * Returns 0 on success or an SSL error reason number on failure.
  */
-int ssl_choose_client_version(SSL *s, int version)
+int ssl_choose_client_version(SSL *s, int version, int checkdgrd, int *al)
 {
     const version_info *vent;
     const version_info *table;
+    int highver = 0;
 
     /* TODO(TLS1.3): Remove this before release */
     if (version == TLS1_3_VERSION_DRAFT)
         version = TLS1_3_VERSION;
 
+    if (s->hello_retry_request && version != TLS1_3_VERSION) {
+        *al = SSL_AD_PROTOCOL_VERSION;
+        return SSL_R_WRONG_SSL_VERSION;
+    }
+
     switch (s->method->version) {
     default:
-        if (version != s->version)
+        if (version != s->version) {
+            *al = SSL_AD_PROTOCOL_VERSION;
             return SSL_R_WRONG_SSL_VERSION;
+        }
         /*
          * If this SSL handle is not from a version flexible method we don't
          * (and never did) check min/max, FIPS or Suite B constraints.  Hope
@@ -1698,22 +1727,59 @@ int ssl_choose_client_version(SSL *s, int version)
         const SSL_METHOD *method;
         int err;
 
-        if (version != vent->version)
-            continue;
         if (vent->cmeth == NULL)
-            break;
-        if (s->hello_retry_request && version != TLS1_3_VERSION)
-            return SSL_R_WRONG_SSL_VERSION;
+            continue;
+
+        if (highver != 0 && version != vent->version)
+            continue;
 
         method = vent->cmeth();
         err = ssl_method_error(s, method);
-        if (err != 0)
-            return err;
+        if (err != 0) {
+            if (version == vent->version) {
+                *al = SSL_AD_PROTOCOL_VERSION;
+                return err;
+            }
+
+            continue;
+        }
+        if (highver == 0)
+            highver = vent->version;
+
+        if (version != vent->version)
+            continue;
+
+#ifndef OPENSSL_NO_TLS13DOWNGRADE
+        /* Check for downgrades */
+        if (checkdgrd) {
+            if (version == TLS1_2_VERSION && highver > version) {
+                if (memcmp(tls12downgrade,
+                           s->s3->server_random + SSL3_RANDOM_SIZE
+                                                - sizeof(tls12downgrade),
+                           sizeof(tls12downgrade)) == 0) {
+                    *al = SSL_AD_ILLEGAL_PARAMETER;
+                    return SSL_R_INAPPROPRIATE_FALLBACK;
+                }
+            } else if (!SSL_IS_DTLS(s)
+                       && version < TLS1_2_VERSION
+                       && highver > version) {
+                if (memcmp(tls11downgrade,
+                           s->s3->server_random + SSL3_RANDOM_SIZE
+                                                - sizeof(tls11downgrade),
+                           sizeof(tls11downgrade)) == 0) {
+                    *al = SSL_AD_ILLEGAL_PARAMETER;
+                    return SSL_R_INAPPROPRIATE_FALLBACK;
+                }
+            }
+        }
+#endif
+
         s->method = method;
         s->version = version;
         return 0;
     }
 
+    *al = SSL_AD_PROTOCOL_VERSION;
     return SSL_R_UNSUPPORTED_PROTOCOL;
 }
 
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index ffb0685..e2c4799 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1476,6 +1476,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
     STACK_OF(SSL_CIPHER) *ciphers = NULL;
     STACK_OF(SSL_CIPHER) *scsvs = NULL;
     CLIENTHELLO_MSG *clienthello = s->clienthello;
+    DOWNGRADE dgrd = DOWNGRADE_NONE;
 
     *al = SSL_AD_INTERNAL_ERROR;
     /* Finished parsing the ClientHello, now we can start processing it */
@@ -1516,7 +1517,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
      * versions are potentially compatible. Version negotiation comes later.
      */
     if (!SSL_IS_DTLS(s)) {
-        protverr = ssl_choose_server_version(s, clienthello);
+        protverr = ssl_choose_server_version(s, clienthello, &dgrd);
     } else if (s->method->version != DTLS_ANY_VERSION &&
                DTLS_VERSION_LT((int)clienthello->legacy_version, s->version)) {
         protverr = SSL_R_VERSION_TOO_LOW;
@@ -1565,7 +1566,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
             s->d1->cookie_verified = 1;
         }
         if (s->method->version == DTLS_ANY_VERSION) {
-            protverr = ssl_choose_server_version(s, clienthello);
+            protverr = ssl_choose_server_version(s, clienthello, &dgrd);
             if (protverr != 0) {
                 SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, protverr);
                 s->version = s->client_version;
@@ -1722,7 +1723,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
     {
         unsigned char *pos;
         pos = s->s3->server_random;
-        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
+        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE, dgrd) <= 0) {
             goto err;
         }
     }
diff --git a/test/recipes/70-test_sslextension.t b/test/recipes/70-test_sslextension.t
index 7f69f64..1c0e96e 100644
--- a/test/recipes/70-test_sslextension.t
+++ b/test/recipes/70-test_sslextension.t
@@ -43,6 +43,15 @@ sub extension_filter
 {
     my $proxy = shift;
 
+    if ($proxy->flight == 1) {
+        # Change the ServerRandom so that the downgrade sentinel doesn't cause
+        # the connection to fail
+        my $message = ${$proxy->message_list}[1];
+        $message->random("\0"x32);
+        $message->repack();
+        return;
+    }
+
     # We're only interested in the initial ClientHello
     if ($proxy->flight != 0) {
         return;
diff --git a/test/recipes/70-test_sslversions.t b/test/recipes/70-test_sslversions.t
index ff4eac8..1f3db22 100644
--- a/test/recipes/70-test_sslversions.t
+++ b/test/recipes/70-test_sslversions.t
@@ -115,6 +115,17 @@ sub modify_supported_versions_filter
 {
     my $proxy = shift;
 
+    if ($proxy->flight == 1) {
+        # Change the ServerRandom so that the downgrade sentinel doesn't cause
+        # the connection to fail
+        my $message = ${$proxy->message_list}[1];
+        return if (!defined $message);
+
+        $message->random("\0"x32);
+        $message->repack();
+        return;
+    }
+
     # We're only interested in the initial ClientHello
     if ($proxy->flight != 0) {
         return;
diff --git a/test/recipes/70-test_tls13downgrade.t b/test/recipes/70-test_tls13downgrade.t
new file mode 100644
index 0000000..6719d18
--- /dev/null
+++ b/test/recipes/70-test_tls13downgrade.t
@@ -0,0 +1,93 @@
+#! /usr/bin/env perl
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+
+my $test_name = "test_tls13downgrade";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+    if $^O =~ /^(VMS|MSWin32)$/;
+
+plan skip_all => "$test_name needs the dynamic engine feature enabled"
+    if disabled("engine") || disabled("dynamic-engine");
+
+plan skip_all => "$test_name needs the sock feature enabled"
+    if disabled("sock");
+
+plan skip_all => "$test_name needs TLS1.3 and TLS1.2 enabled"
+    if disabled("tls1_3") || disabled("tls1_2");
+
+# TODO(TLS1.3): Enable this when TLSv1.3 comes out of draft
+plan skip_all => "$test_name not run in pre TLSv1.3 RFC implementation"
+    if disabled("tls13downgrade");
+
+$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+
+my $proxy = TLSProxy::Proxy->new(
+    undef,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+use constant {
+    DOWNGRADE_TO_TLS_1_2 => 0,
+    DOWNGRADE_TO_TLS_1_1 => 1
+};
+
+#Test 1: Downgrade from TLSv1.3 to TLSv1.2
+$proxy->filter(\&downgrade_filter);
+my $testtype = DOWNGRADE_TO_TLS_1_2;
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 3;
+ok(TLSProxy::Message->fail(), "Downgrade TLSv1.3 to TLSv1.2");
+
+#Test 2: Downgrade from TLSv1.3 to TLSv1.1
+$proxy->clear();
+$testtype = DOWNGRADE_TO_TLS_1_1;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Downgrade TLSv1.3 to TLSv1.1");
+
+#Test 3: Downgrade from TLSv1.2 to TLSv1.1
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->serverflags("-no_tls1_3");
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Downgrade TLSv1.2 to TLSv1.1");
+
+sub downgrade_filter
+{
+    my $proxy = shift;
+
+    # We're only interested in the initial ClientHello
+    if ($proxy->flight != 0) {
+        return;
+    }
+
+    my $message = ${$proxy->message_list}[0];
+
+    my $ext;
+    if ($testtype == DOWNGRADE_TO_TLS_1_2) {
+        $ext = pack "C3",
+            0x02, # Length
+            0x03, 0x03; #TLSv1.2
+    } else {
+        $ext = pack "C3",
+            0x02, # Length
+            0x03, 0x02; #TLSv1.1
+    }
+
+    $message->set_extension(TLSProxy::Message::EXT_SUPPORTED_VERSIONS, $ext);
+
+    $message->repack();
+}
+


More information about the openssl-commits mailing list