[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Nov 9 16:10:32 UTC 2016


The branch master has been updated
       via  f2342b7ac3c3fe5914235a692c22db1dae316af4 (commit)
       via  60e3b3c5506997084352710cd78c4723642936c4 (commit)
       via  b97667ce679d439a5620c326e0e9fefea3186bdc (commit)
       via  54682aa3574b9830362a51c919b6aa1d5429074b (commit)
       via  d2f42576c46ce84662134a68ccbf76bd1cf639ba (commit)
       via  17d01b420151d05edd347b584fa1942f5b914fc5 (commit)
       via  bf0ba5e7040d59b0c8e2c5cf6922fdd0ccc11d1a (commit)
       via  7b21c00e1c8841a1efe654e0488d4fc9af47db4c (commit)
       via  bf85ef1b60d03c76e85ec06be3999ead4533f092 (commit)
       via  16bce0e08b16b28a1953795bde3f913957b08ef2 (commit)
       via  203b1cdf73be98b2abfe00cc2c0347cf246ad80d (commit)
       via  619d8336d00fe19bc694e61e772b5838d7e422e5 (commit)
       via  cd99883755f428ac47e8e2ccb21333b675ec22d9 (commit)
       via  5506e835a87f3ab8be77c96d3ccea8566bd42335 (commit)
       via  b5b253b1bfe55d0d1be4c45dafed8d789ab97c17 (commit)
      from  7bb37cb5938a0cf76c12c8421950e72634d5f61c (commit)


- Log -----------------------------------------------------------------
commit f2342b7ac3c3fe5914235a692c22db1dae316af4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 9 14:43:05 2016 +0000

    Address some supported_versions review comments
    
    Added some TODOs, refactored a couple of things and added a SSL_IS_TLS13()
    macro.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 60e3b3c5506997084352710cd78c4723642936c4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 9 09:52:37 2016 +0000

    Remove some redundant trace code
    
    No need to have a supported versions table and a versions table. They
    should be the same.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b97667ce679d439a5620c326e0e9fefea3186bdc
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 7 13:48:07 2016 +0000

    Fix some missing checks for TLS1_3_VERSION_DRAFT
    
    There were a few places where we weren't checking to see if we were using
    the draft TLS1.3 version or not.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 54682aa3574b9830362a51c919b6aa1d5429074b
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 7 15:36:00 2016 +0000

    Give the test with only TLS1.1 and TLS1.0 a better name
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d2f42576c46ce84662134a68ccbf76bd1cf639ba
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 2 11:33:20 2016 +0000

    Add a TODO(TLS1.3) about renegotation
    
    Renegotiation does not exist in TLS1.3, so we need to disable it at some
    point.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 17d01b420151d05edd347b584fa1942f5b914fc5
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 2 09:09:02 2016 +0000

    Add some more version tests
    
    Send a TLS1.4 ClientHello with supported_versions and get TLS1.3
    Send a TLS1.3 ClientHello without supported_versions and get TLS1.2
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit bf0ba5e7040d59b0c8e2c5cf6922fdd0ccc11d1a
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 1 00:37:23 2016 +0000

    A style tweak based on feedback received
    
    Replace a bare ";" with "continue;" for the body of a for loop.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 7b21c00e1c8841a1efe654e0488d4fc9af47db4c
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 31 18:12:33 2016 +0000

    Look at the supported_versions extension even if the server <TLS1.3
    
    If supported_versions is present it takes precedence.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit bf85ef1b60d03c76e85ec06be3999ead4533f092
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 2 11:15:08 2016 +0000

    Ensure that vent->smeth != NULL before we call vent->smeth()
    
    We can end up with a NULL SSL_METHOD function if a method has been
    disabled. If that happens then we shouldn't call vent->smeth().
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 16bce0e08b16b28a1953795bde3f913957b08ef2
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 31 17:05:20 2016 +0000

    Address some review feedback comments for supported_versions
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 203b1cdf73be98b2abfe00cc2c0347cf246ad80d
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 27 18:32:19 2016 +0100

    Add a test for the supported_versions extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 619d8336d00fe19bc694e61e772b5838d7e422e5
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Oct 27 16:30:36 2016 +0100

    Update TLS1.3 draft version numbers for latest draft
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit cd99883755f428ac47e8e2ccb21333b675ec22d9
Author: Matt Caswell <matt at openssl.org>
Date:   Sun Oct 23 00:41:11 2016 +0100

    Add server side support for supported_versions extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 5506e835a87f3ab8be77c96d3ccea8566bd42335
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 23:41:18 2016 +0100

    Ensure that the -trace option can interpret the supported_versions extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b5b253b1bfe55d0d1be4c45dafed8d789ab97c17
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 21 23:40:52 2016 +0100

    Add the ability to send the supported_versions extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 include/openssl/tls1.h                |   7 ++
 ssl/ssl_locl.h                        |   7 ++
 ssl/statem/statem_clnt.c              |   7 +-
 ssl/statem/statem_lib.c               |  76 ++++++++++++++++
 ssl/statem/statem_srvr.c              |   5 +-
 ssl/t1_lib.c                          |  52 +++++++++--
 ssl/t1_trce.c                         |  12 +++
 test/recipes/70-test_sslversions.t    | 164 ++++++++++++++++++++++++++++++++++
 test/recipes/70-test_sslvertol.t      |  26 ++++--
 test/ssl-tests/17-renegotiate.conf    |   4 +
 test/ssl-tests/17-renegotiate.conf.in |  14 ++-
 test/ssl-tests/protocol_version.pm    |   7 +-
 util/TLSProxy/Message.pm              |   1 +
 util/TLSProxy/Record.pm               |   1 +
 14 files changed, 362 insertions(+), 21 deletions(-)
 create mode 100755 test/recipes/70-test_sslversions.t

diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index ba3c413..d0cce09 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -68,6 +68,10 @@ extern "C" {
 # define TLS1_3_VERSION                  0x0304
 # define TLS_MAX_VERSION                 TLS1_3_VERSION
 
+/* TODO(TLS1.3) REMOVE ME: Version indicator for draft -18 */
+# define TLS1_3_VERSION_DRAFT            0x7f12
+# define TLS1_3_VERSION_DRAFT_TXT        "TLS 1.3 (draft 18)"
+
 /* Special value for method supporting multiple versions */
 # define TLS_ANY_VERSION                 0x10000
 
@@ -163,6 +167,9 @@ extern "C" {
 /* ExtensionType value from RFC4507 */
 # define TLSEXT_TYPE_session_ticket              35
 
+/* As defined for TLS1.3 */
+# define TLSEXT_TYPE_supported_versions          43
+
 /* Temporary extension type */
 # define TLSEXT_TYPE_renegotiate                 0xff01
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 0c7aeed..63b001f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -349,6 +349,10 @@
 
 /* Check if an SSL structure is using DTLS */
 # define SSL_IS_DTLS(s)  (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
+
+/* Check if we are using TLSv1.3 */
+# define SSL_IS_TLS13(s) (!SSL_IS_DTLS(s) && (s)->version >= TLS1_3_VERSION)
+
 /* See if we need explicit IV */
 # define SSL_USE_EXPLICIT_IV(s)  \
                 (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
@@ -2077,6 +2081,9 @@ __owur int dtls1_process_heartbeat(SSL *s, unsigned char *p,
                                    size_t length);
 #  endif
 
+__owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts,
+                                                size_t numexts,
+                                                unsigned int type);
 __owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
                                       SSL_SESSION **ret);
 __owur int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 6a05b9d..e0d53fe 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -703,6 +703,7 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     SSL_COMP *comp;
 #endif
     SSL_SESSION *sess = s->session;
+    int client_version;
 
     if (!WPACKET_set_max_size(pkt, SSL3_RT_MAX_PLAIN_LENGTH)) {
         /* Should not happen */
@@ -779,8 +780,12 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
      * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
      * client_version in client hello and not resetting it to
      * the negotiated version.
+     *
+     * For TLS 1.3 we always set the ClientHello version to 1.2 and rely on the
+     * supported_versions extension for the real supported versions.
      */
-    if (!WPACKET_put_bytes_u16(pkt, s->client_version)
+    client_version = SSL_IS_TLS13(s) ? TLS1_2_VERSION : s->client_version;
+    if (!WPACKET_put_bytes_u16(pkt, client_version)
             || !WPACKET_memcpy(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
         return 0;
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index a3a31bc..46ffb47 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -996,11 +996,17 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
     const version_info *vent;
     const version_info *table;
     int disabled = 0;
+    RAW_EXTENSION *suppversions;
 
     s->client_version = client_version;
 
     switch (server_version) {
     default:
+        /*
+         * TODO(TLS1.3): This check will fail if someone attempts to do
+         * renegotiation in TLS1.3 at the moment. We need to ensure we disable
+         * renegotiation for TLS1.3
+         */
         if (version_cmp(s, client_version, s->version) < 0)
             return SSL_R_WRONG_SSL_VERSION;
         /*
@@ -1019,6 +1025,72 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
         break;
     }
 
+    suppversions = tls_get_extension_by_type(hello->pre_proc_exts,
+                                             hello->num_extensions,
+                                             TLSEXT_TYPE_supported_versions);
+
+    if (suppversions != NULL && !SSL_IS_DTLS(s)) {
+        unsigned int candidate_vers = 0;
+        unsigned int best_vers = 0;
+        const SSL_METHOD *best_method = NULL;
+        PACKET versionslist;
+
+        if (!PACKET_as_length_prefixed_1(&suppversions->data, &versionslist)) {
+            /* Trailing or invalid data? */
+            return SSL_R_LENGTH_MISMATCH;
+        }
+
+        while (PACKET_get_net_2(&versionslist, &candidate_vers)) {
+            /* TODO(TLS1.3): Remove this before release */
+            if (candidate_vers == TLS1_3_VERSION_DRAFT)
+                candidate_vers = TLS1_3_VERSION;
+            /*
+             * TODO(TLS1.3): There is some discussion on the TLS list about
+             * wheter to ignore versions <TLS1.2 in supported_versions. At the
+             * moment we honour them if present. To be reviewed later
+             */
+            if ((int)candidate_vers > s->client_version)
+                s->client_version = candidate_vers;
+            if (version_cmp(s, candidate_vers, best_vers) <= 0)
+                continue;
+            for (vent = table;
+                 vent->version != 0 && vent->version != (int)candidate_vers;
+                 ++vent)
+                continue;
+            if (vent->version != 0 && vent->smeth != NULL) {
+                const SSL_METHOD *method;
+
+                method = vent->smeth();
+                if (ssl_method_error(s, method) == 0) {
+                    best_vers = candidate_vers;
+                    best_method = method;
+                }
+            }
+        }
+        if (PACKET_remaining(&versionslist) != 0) {
+            /* Trailing data? */
+            return SSL_R_LENGTH_MISMATCH;
+        }
+
+        if (best_vers > 0) {
+            s->version = best_vers;
+            s->method = best_method;
+            return 0;
+        }
+        return SSL_R_UNSUPPORTED_PROTOCOL;
+    }
+
+    /*
+     * If the supported versions extension isn't present, then the highest
+     * version we can negotiate is TLSv1.2
+     */
+    if (version_cmp(s, client_version, TLS1_3_VERSION) >= 0)
+        client_version = TLS1_2_VERSION;
+
+    /*
+     * No supported versions extension, so we just use the version supplied in
+     * the ClientHello.
+     */
     for (vent = table; vent->version != 0; ++vent) {
         const SSL_METHOD *method;
 
@@ -1051,6 +1123,10 @@ int ssl_choose_client_version(SSL *s, int version)
     const version_info *vent;
     const version_info *table;
 
+    /* TODO(TLS1.3): Remove this before release */
+    if (version == TLS1_3_VERSION_DRAFT)
+        version = TLS1_3_VERSION;
+
     switch (s->method->version) {
     default:
         if (version != s->version)
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 89de025..ba3457d 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1546,8 +1546,11 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt)
 {
     int compm, al = SSL_AD_INTERNAL_ERROR;
     size_t sl, len;
+    int version;
 
-    if (!WPACKET_put_bytes_u16(pkt, s->version)
+    /* TODO(TLS1.3): Remove the DRAFT conditional before release */
+    version = SSL_IS_TLS13(s) ? TLS1_3_VERSION_DRAFT : s->version;
+    if (!WPACKET_put_bytes_u16(pkt, version)
                /*
                 * Random stuff. Filling of the server_random takes place in
                 * tls_process_client_hello()
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 6598776..e79c37e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1371,6 +1371,43 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
         return 0;
     }
 
+    if (SSL_IS_TLS13(s)) {
+        int min_version, max_version, reason, currv;
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_start_sub_packet_u8(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        reason = ssl_get_client_min_max_version(s, &min_version, &max_version);
+        if (reason != 0) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, reason);
+            return 0;
+        }
+        /*
+         * TODO(TLS1.3): There is some discussion on the TLS list as to wheter
+         * we should include versions <TLS1.2. For the moment we do. To be
+         * reviewed later.
+         */
+        for (currv = max_version; currv >= min_version; currv--) {
+            /* TODO(TLS1.3): Remove this first if clause prior to release!! */
+            if (currv == TLS1_3_VERSION) {
+                if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)) {
+                    SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
+                           ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
+            } else if (!WPACKET_put_bytes_u16(pkt, currv)) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+        }
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
     /*
      * Add padding to workaround bugs in F5 terminators. See
      * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
@@ -2792,8 +2829,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt)
  *
  * Returns a pointer to the found RAW_EXTENSION data, or NULL if not found.
  */
-static RAW_EXTENSION *get_extension_by_type(RAW_EXTENSION *exts, size_t numexts,
-                                            unsigned int type)
+RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts, size_t numexts,
+                                         unsigned int type)
 {
     size_t loop;
 
@@ -2851,9 +2888,9 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
     if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
         return 0;
 
-    ticketext = get_extension_by_type(hello->pre_proc_exts,
-                                      hello->num_extensions,
-                                      TLSEXT_TYPE_session_ticket);
+    ticketext = tls_get_extension_by_type(hello->pre_proc_exts,
+                                          hello->num_extensions,
+                                          TLSEXT_TYPE_session_ticket);
     if (ticketext == NULL)
         return 0;
 
@@ -2914,8 +2951,9 @@ int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
     if (s->version <= SSL3_VERSION)
         return 1;
 
-    emsext = get_extension_by_type(hello->pre_proc_exts, hello->num_extensions,
-                                   TLSEXT_TYPE_extended_master_secret);
+    emsext = tls_get_extension_by_type(hello->pre_proc_exts,
+                                       hello->num_extensions,
+                                       TLSEXT_TYPE_extended_master_secret);
 
     /*
      * No extensions is a success - we have successfully discovered that the
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index d8ad103..c8d0053 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -62,6 +62,8 @@ static ssl_trace_tbl ssl_version_tbl[] = {
     {TLS1_1_VERSION, "TLS 1.1"},
     {TLS1_2_VERSION, "TLS 1.2"},
     {TLS1_3_VERSION, "TLS 1.3"},
+    /* TODO(TLS1.3): Remove this line before release */
+    {TLS1_3_VERSION_DRAFT, TLS1_3_VERSION_DRAFT_TXT},
     {DTLS1_VERSION, "DTLS 1.0"},
     {DTLS1_2_VERSION, "DTLS 1.2"},
     {DTLS1_BAD_VER, "DTLS 1.0 (bad)"}
@@ -453,6 +455,7 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_use_srtp, "use_srtp"},
     {TLSEXT_TYPE_heartbeat, "heartbeat"},
     {TLSEXT_TYPE_session_ticket, "session_ticket"},
+    {TLSEXT_TYPE_supported_versions, "supported_versions"},
     {TLSEXT_TYPE_renegotiate, "renegotiate"},
 # ifndef OPENSSL_NO_NEXTPROTONEG
     {TLSEXT_TYPE_next_proto_neg, "next_proto_neg"},
@@ -727,6 +730,15 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
             ssl_print_hex(bio, indent + 4, "ticket", ext, extlen);
         break;
 
+    case TLSEXT_TYPE_supported_versions:
+        if (extlen < 1)
+            return 0;
+        xlen = ext[0];
+        if (extlen != xlen + 1)
+            return 0;
+        return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 2,
+                              ssl_version_tbl);
+
     default:
         BIO_dump_indent(bio, (const char *)ext, extlen, indent + 2);
     }
diff --git a/test/recipes/70-test_sslversions.t b/test/recipes/70-test_sslversions.t
new file mode 100755
index 0000000..d2e6eb6
--- /dev/null
+++ b/test/recipes/70-test_sslversions.t
@@ -0,0 +1,164 @@
+#! /usr/bin/env perl
+# Copyright 2015-2016 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;
+use File::Temp qw(tempfile);
+
+use constant {
+    REVERSE_ORDER_VERSIONS => 1,
+    UNRECOGNISED_VERSIONS => 2,
+    NO_EXTENSION => 3,
+    EMPTY_EXTENSION => 4,
+    TLS1_1_AND_1_0_ONLY => 5,
+    WITH_TLS1_4 => 6
+};
+
+my $testtype;
+
+my $test_name = "test_sslversions";
+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, TLS1.2 and TLS1.1 enabled"
+    if disabled("tls1_3") || disabled("tls1_2") || disabled("tls1_1");
+
+$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})
+);
+
+#We're just testing various negative and unusual scenarios here. ssltest with
+#02-protocol-version.conf should check all the various combinations of normal
+#version neg
+
+#Test 1: An empty supported_versions extension should not succeed
+$testtype = EMPTY_EXTENSION;
+$proxy->filter(\&modify_supported_versions_filter);
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 7;
+ok(TLSProxy::Message->fail(), "Empty supported versions");
+
+#Test 2: supported_versions extension with no recognised versions should not
+#succeed
+$proxy->clear();
+$testtype = UNRECOGNISED_VERSIONS;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "No recognised versions");
+
+#Test 3: No supported versions extensions should succeed and select TLSv1.2
+$proxy->clear();
+$testtype = NO_EXTENSION;
+$proxy->start();
+my $record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_2,
+   "No supported versions extension");
+
+#Test 4: No supported versions extensions should fail if only TLS1.3 available
+$proxy->clear();
+$proxy->serverflags("-tls1_3");
+$proxy->start();
+ok(TLSProxy::Message->fail(), "No supported versions extension (only TLS1.3)");
+
+#Test 5: supported versions extension with best version last should succeed
+#and select TLSv1.3
+$proxy->clear();
+$testtype = REVERSE_ORDER_VERSIONS;
+$proxy->start();
+$record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_3,
+   "Reverse order versions");
+
+#Test 6: no TLSv1.3 or TLSv1.2 version in supported versions extension, but
+#TLSv1.1 and TLSv1.0 are present. Should just use TLSv1.1 and succeed
+$proxy->clear();
+$testtype = TLS1_1_AND_1_0_ONLY;
+$proxy->start();
+$record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_1,
+   "TLS1.1 and TLS1.0 in supported versions extension only");
+
+#Test 7: TLS1.4 and TLS1.3 in supported versions. Should succeed and use TLS1.3
+$proxy->clear();
+$testtype = WITH_TLS1_4;
+$proxy->start();
+$record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_3,
+   "TLS1.4 in supported versions extension");
+
+sub modify_supported_versions_filter
+{
+    my $proxy = shift;
+
+    # We're only interested in the initial ClientHello
+    if ($proxy->flight != 0) {
+        return;
+    }
+
+    foreach my $message (@{$proxy->message_list}) {
+        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
+            my $ext;
+            if ($testtype == REVERSE_ORDER_VERSIONS) {
+                $ext = pack "C5",
+                    0x04, # Length
+                    0x03, 0x03, #TLSv1.2
+                    0x03, 0x04; #TLSv1.3
+            } elsif ($testtype == UNRECOGNISED_VERSIONS) {
+                $ext = pack "C5",
+                    0x04, # Length
+                    0x04, 0x04, #Some unrecognised version
+                    0x04, 0x03; #Another unrecognised version
+            } elsif ($testtype == TLS1_1_AND_1_0_ONLY) {
+                $ext = pack "C5",
+                    0x04, # Length
+                    0x03, 0x02, #TLSv1.1
+                    0x03, 0x01; #TLSv1.0
+            } elsif ($testtype == WITH_TLS1_4) {
+                    $ext = pack "C5",
+                        0x04, # Length
+                        0x03, 0x05, #TLSv1.4
+                        0x03, 0x04; #TLSv1.3
+            }
+            if ($testtype == REVERSE_ORDER_VERSIONS
+                    || $testtype == UNRECOGNISED_VERSIONS
+                    || $testtype == TLS1_1_AND_1_0_ONLY
+                    || $testtype == WITH_TLS1_4) {
+                $message->set_extension(
+                    TLSProxy::Message::EXT_SUPPORTED_VERSIONS, $ext);
+            } elsif ($testtype == EMPTY_EXTENSION) {
+                $message->set_extension(
+                    TLSProxy::Message::EXT_SUPPORTED_VERSIONS, "");
+            } else {
+                $message->delete_extension(
+                    TLSProxy::Message::EXT_SUPPORTED_VERSIONS);
+            }
+
+            $message->repack();
+        }
+    }
+}
+
+
diff --git a/test/recipes/70-test_sslvertol.t b/test/recipes/70-test_sslvertol.t
index f8c94e9..108166f 100755
--- a/test/recipes/70-test_sslvertol.t
+++ b/test/recipes/70-test_sslvertol.t
@@ -34,15 +34,31 @@ my $proxy = TLSProxy::Proxy->new(
     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
 );
 
-#Test 1: Asking for TLS1.3 should pass
-my $client_version = TLSProxy::Record::VERS_TLS_1_3;
+#This file does tests without the supported_versions extension.
+#See 70-test_sslversions.t for tests with supported versions.
+#Test 1: Asking for TLS1.4 should pass and negotiate TLS1.2
+my $client_version = TLSProxy::Record::VERS_TLS_1_4;
+$proxy->clientflags("-no_tls1_3");
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 2;
-ok(TLSProxy::Message->success(), "Version tolerance test, TLS 1.3");
+plan tests => 3;
+my $record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_2,
+   "Version tolerance test, TLS 1.4");
 
-#Test 2: Testing something below SSLv3 should fail
+#Test 2: Asking for TLS1.3 should succeed and negotiate TLS1.2
+$proxy->clear();
+$proxy->clientflags("-no_tls1_3");
+$proxy->start();
+$record = pop @{$proxy->record_list};
+ok(TLSProxy::Message->success()
+   && $record->version() == TLSProxy::Record::VERS_TLS_1_2,
+   "Version tolerance test, TLS 1.3");
+
+#Test 3: Testing something below SSLv3 should fail
 $client_version = TLSProxy::Record::VERS_SSL_3_0 - 1;
 $proxy->clear();
+$proxy->clientflags("-no_tls1_3");
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Version tolerance test, SSL < 3.0");
 
diff --git a/test/ssl-tests/17-renegotiate.conf b/test/ssl-tests/17-renegotiate.conf
index c47a956..fffb572 100644
--- a/test/ssl-tests/17-renegotiate.conf
+++ b/test/ssl-tests/17-renegotiate.conf
@@ -18,6 +18,7 @@ client = 0-renegotiate-client-no-resume-client
 [0-renegotiate-client-no-resume-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 Options = NoResumptionOnRenegotiation
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
@@ -45,6 +46,7 @@ client = 1-renegotiate-client-resume-client
 [1-renegotiate-client-resume-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [1-renegotiate-client-resume-client]
@@ -71,6 +73,7 @@ client = 2-renegotiate-server-no-resume-client
 [2-renegotiate-server-no-resume-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 Options = NoResumptionOnRenegotiation
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
@@ -98,6 +101,7 @@ client = 3-renegotiate-server-resume-client
 [3-renegotiate-server-resume-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [3-renegotiate-server-resume-client]
diff --git a/test/ssl-tests/17-renegotiate.conf.in b/test/ssl-tests/17-renegotiate.conf.in
index a081617..ab581ec 100644
--- a/test/ssl-tests/17-renegotiate.conf.in
+++ b/test/ssl-tests/17-renegotiate.conf.in
@@ -19,7 +19,8 @@ our @tests = (
     {
         name => "renegotiate-client-no-resume",
         server => {
-            "Options" => "NoResumptionOnRenegotiation"
+            "Options" => "NoResumptionOnRenegotiation",
+            "MaxProtocol" => "TLSv1.2"
         },
         client => {},
         test => {
@@ -31,7 +32,9 @@ our @tests = (
     },
     {
         name => "renegotiate-client-resume",
-        server => {},
+        server => {
+            "MaxProtocol" => "TLSv1.2"
+        },
         client => {},
         test => {
             "Method" => "TLS",
@@ -43,7 +46,8 @@ our @tests = (
     {
         name => "renegotiate-server-no-resume",
         server => {
-            "Options" => "NoResumptionOnRenegotiation"
+            "Options" => "NoResumptionOnRenegotiation",
+            "MaxProtocol" => "TLSv1.2"
         },
         client => {},
         test => {
@@ -55,7 +59,9 @@ our @tests = (
     },
     {
         name => "renegotiate-server-resume",
-        server => {},
+        server => {
+            "MaxProtocol" => "TLSv1.2"
+        },
         client => {},
         test => {
             "Method" => "TLS",
diff --git a/test/ssl-tests/protocol_version.pm b/test/ssl-tests/protocol_version.pm
index 9abcaae..cc39c75 100644
--- a/test/ssl-tests/protocol_version.pm
+++ b/test/ssl-tests/protocol_version.pm
@@ -236,9 +236,10 @@ sub expected_result {
         return ("ServerFail", undef);
     } elsif ($c_min > $s_max) {
         my @prots = @$protocols;
-        if ($prots[$c_min] eq "TLSv1.3") {
-            # Client won't have sent any ciphersuite the server recognises
-                        return ("ServerFail", undef);
+        if ($prots[$c_max] eq "TLSv1.3") {
+            # Client will have sent supported_versions, so server will know
+            # that there are no overlapping versions.
+            return ("ServerFail", undef);
         } else {
             # Server will try with a version that is lower than the lowest
             # supported client version.
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index 1810d8c..8a14dea 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -62,6 +62,7 @@ use constant {
     EXT_ENCRYPT_THEN_MAC => 22,
     EXT_EXTENDED_MASTER_SECRET => 23,
     EXT_SESSION_TICKET => 35,
+    EXT_SUPPORTED_VERSIONS => 43,
     # This extension does not exist and isn't recognised by OpenSSL.
     # We use it to test handling of duplicate extensions.
     EXT_DUPLICATE_EXTENSION => 1234
diff --git a/util/TLSProxy/Record.pm b/util/TLSProxy/Record.pm
index a4e7adc..bf6de43 100644
--- a/util/TLSProxy/Record.pm
+++ b/util/TLSProxy/Record.pm
@@ -35,6 +35,7 @@ my %record_type = (
 );
 
 use constant {
+    VERS_TLS_1_4 => 773,
     VERS_TLS_1_3 => 772,
     VERS_TLS_1_2 => 771,
     VERS_TLS_1_1 => 770,


More information about the openssl-commits mailing list