]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Merge dtls and tls records tests
authorFrederik Wedel-Heinen <frederik.wedel-heinen@dencrypt.dk>
Tue, 30 Jan 2024 09:00:39 +0000 (10:00 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 9 Feb 2024 08:16:56 +0000 (08:16 +0000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23319)

test/recipes/70-test_dtlsrecords.t [deleted file]
test/recipes/70-test_sslrecords.t
util/perl/TLSProxy/Proxy.pm

diff --git a/test/recipes/70-test_dtlsrecords.t b/test/recipes/70-test_dtlsrecords.t
deleted file mode 100644 (file)
index dc223ea..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-#! /usr/bin/env perl
-# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
-#
-# Licensed under the Apache License 2.0 (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 feature 'state';
-
-use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
-use OpenSSL::Test::Utils;
-use TLSProxy::Proxy;
-use TLSProxy::Message;
-
-my $test_name = "test_dtlsrecords";
-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 DTLSv1.2 enabled"
-    if disabled("dtls1_2");
-
-my $proxy = TLSProxy::Proxy->new_dtls(
-    undef,
-    cmdstr(app(["openssl"]), display => 1),
-    srctop_file("apps", "server.pem"),
-    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
-);
-
-plan tests => 4;
-
-my $fatal_alert = 0;        # set by filters at expected fatal alerts
-my $inject_recs_num = 0;    # used by add_empty_recs_filter
-my $proxy_start_success = 0;
-
-#Test 1: Injecting out of context empty records should succeed
-my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
-$inject_recs_num = 1;
-$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2");
-$proxy->clientflags("-max_protocol DTLSv1.2");
-$proxy->filter(\&add_empty_recs_filter);
-$proxy_start_success = $proxy->start();
-ok($proxy_start_success && TLSProxy::Message->success(), "Out of context empty records test");
-
-#Test 2: Injecting in context empty records should succeed
-$proxy->clear();
-$content_type = TLSProxy::Record::RT_HANDSHAKE;
-$inject_recs_num = 1;
-$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2");
-$proxy->clientflags("-max_protocol DTLSv1.2");
-$proxy->filter(\&add_empty_recs_filter);
-$proxy_start_success = $proxy->start();
-ok($proxy_start_success && TLSProxy::Message->success(), "In context empty records test");
-
-#Unrecognised record type tests
-
-#Test 3: Sending an unrecognised record type in DTLSv1.2 should fail
-$fatal_alert = 0;
-$proxy->clear();
-$proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2");
-$proxy->clientflags("-max_protocol DTLSv1.2");
-$proxy->filter(\&add_unknown_record_type);
-ok($proxy->start() == 0, "Unrecognised record type in DTLS1.2");
-
-SKIP: {
-    skip "DTLSv1 disabled", 1 if disabled("dtls1");
-
-    #Test 4: Sending an unrecognised record type in DTLSv1 should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $proxy->clientflags("-min_protocol DTLSv1 -max_protocol DTLSv1 -cipher DEFAULT:\@SECLEVEL=0");
-    $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-    $proxy->filter(\&add_unknown_record_type);
-    ok($proxy->start() == 0, "Unrecognised record type in DTLSv1");
-}
-
-sub add_empty_recs_filter
-{
-    my $proxy = shift;
-    my $records = $proxy->record_list;
-
-    # We're only interested in the initial ClientHello
-    if ($proxy->flight != 0) {
-        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(1) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE;
-        return;
-    }
-
-    for (my $i = 0; $i < $inject_recs_num; $i++) {
-        my $record = TLSProxy::Record->new_dtls(
-            0,
-            $content_type,
-            TLSProxy::Record::VERS_TLS_1_2,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0,
-            "",
-            ""
-        );
-        push @{$records}, $record;
-    }
-}
-
-sub add_unknown_record_type
-{
-    my $proxy = shift;
-    my $records = $proxy->record_list;
-    state $added_record;
-
-    # We'll change a record after the initial version neg has taken place
-    if ($proxy->flight == 0) {
-        $added_record = 0;
-        return;
-    } elsif ($proxy->flight != 1 || $added_record) {
-        $fatal_alert = 1 if @{$records}[-1]->is_fatal_alert(0) == TLSProxy::Message::AL_DESC_UNEXPECTED_MESSAGE;
-        return;
-    }
-
-    my $record = TLSProxy::Record->new_dtls(
-        1,
-        TLSProxy::Record::RT_UNKNOWN,
-        @{$records}[-1]->version(),
-        @{$records}[-1]->epoch(),
-        @{$records}[-1]->seq() +1,
-        1,
-        0,
-        1,
-        1,
-        "X",
-        "X"
-    );
-
-    #Find ServerHello record and insert after that
-    my $i;
-    for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
-        next;
-    }
-    $i++;
-
-    splice @{$proxy->record_list}, $i, 0, $record;
-    $added_record = 1;
-}
index 43e288b63e5648413d52150de0881ab047161bce..02110714e9e7ae598b8387f1225fdf55a4523b65 100644 (file)
@@ -29,248 +29,311 @@ plan skip_all => "$test_name needs the sock feature enabled"
 plan skip_all => "$test_name needs TLSv1.2 enabled"
     if disabled("tls1_2");
 
-my $proxy = TLSProxy::Proxy->new(
-    \&add_empty_recs_filter,
-    cmdstr(app(["openssl"]), display => 1),
-    srctop_file("apps", "server.pem"),
-    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
-);
-
-my $boundary_test_type;
-my $fatal_alert = 0;    # set by filters at expected fatal alerts
-
-#Test 1: Injecting out of context empty records should fail
-my $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
-my $inject_recs_num = 1;
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 21;
-ok($fatal_alert, "Out of context empty records test");
-
-#Test 2: Injecting in context empty records should succeed
-$proxy->clear();
-$content_type = TLSProxy::Record::RT_HANDSHAKE;
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->start();
-ok(TLSProxy::Message->success(), "In context empty records test");
-
-#Test 3: Injecting too many in context empty records should fail
-$fatal_alert = 0;
-$proxy->clear();
-#We allow 32 consecutive in context empty records
-$inject_recs_num = 33;
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->start();
-ok($fatal_alert, "Too many in context empty records test");
-
-#Test 4: Injecting a fragmented fatal alert should fail. We expect the server to
-#        send back an alert of its own because it cannot handle fragmented
-#        alerts
-$fatal_alert = 0;
-$proxy->clear();
-$proxy->filter(\&add_frag_alert_filter);
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->start();
-ok($fatal_alert, "Fragmented alert records test");
-
-#Run some SSLv2 ClientHello tests
-
-use constant {
-    TLSV1_2_IN_SSLV2 => 0,
-    SSLV2_IN_SSLV2 => 1,
-    FRAGMENTED_IN_TLSV1_2 => 2,
-    FRAGMENTED_IN_SSLV2 => 3,
-    ALERT_BEFORE_SSLV2 => 4
-};
-
-# The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
-# because in a SSLv2 ClientHello we can't send extensions to indicate
-# which signature algorithm we want to use, and the default is SHA1.
-
-#Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
-my $sslv2testtype = TLSV1_2_IN_SSLV2;
-$proxy->clear();
-$proxy->filter(\&add_sslv2_filter);
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3 -legacy_renegotiation");
-$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-$proxy->start();
-ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
-
-#Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
-#        support this so it should fail. We actually treat it as an unknown
-#        protocol so we don't even send an alert in this case.
-$sslv2testtype = SSLV2_IN_SSLV2;
-$proxy->clear();
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-$proxy->start();
-ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
-
-#Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
-#        at all, but it gives us confidence that Test 8 fails for the right
-#        reasons
-$sslv2testtype = FRAGMENTED_IN_TLSV1_2;
-$proxy->clear();
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-$proxy->start();
-ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
-
-#Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
-#        record; and another TLS1.2 record. This isn't allowed so should fail
-$sslv2testtype = FRAGMENTED_IN_SSLV2;
-$proxy->clear();
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-$proxy->start();
-ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
-
-#Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
-#        fail because an SSLv2 ClientHello must be the first record.
-$sslv2testtype = ALERT_BEFORE_SSLV2;
-$proxy->clear();
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-$proxy->start();
-ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
-
-#Unrecognised record type tests
-
-#Test 10: Sending an unrecognised record type in TLS1.2 should fail
-$fatal_alert = 0;
-$proxy->clear();
-$proxy->serverflags("-tls1_2");
-$proxy->clientflags("-no_tls1_3");
-$proxy->filter(\&add_unknown_record_type);
-$proxy->start();
-ok($fatal_alert, "Unrecognised record type in TLS1.2");
-
-SKIP: {
-    skip "TLSv1.1 disabled", 1 if disabled("tls1_1");
-
-    #Test 11: Sending an unrecognised record type in TLS1.1 should fail
-    $fatal_alert = 0;
+my $testplanisset = 0;
+my $inject_recs_num = undef;
+my $content_type = undef;
+my $boundary_test_type = undef;
+my $fatal_alert = undef; # set by filters at expected fatal alerts
+my $sslv2testtype = undef;
+my $proxy_start_success = 0;
+
+# Run tests with TLS
+run_tests(0);
+# Run tests with DTLS
+run_tests(1);
+
+sub run_tests
+{
+    my $run_test_as_dtls = shift;
+    my $proxy;
+    if ($run_test_as_dtls == 1) {
+        $proxy = TLSProxy::Proxy->new_dtls(
+            \&add_empty_recs_filter,
+            cmdstr(app([ "openssl" ]), display => 1),
+            srctop_file("apps", "server.pem"),
+            (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+        );
+    } else {
+        $proxy = TLSProxy::Proxy->new(
+            \&add_empty_recs_filter,
+            cmdstr(app([ "openssl" ]), display => 1),
+            srctop_file("apps", "server.pem"),
+            (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+        );
+    }
+
+    $fatal_alert = 0; # set by filters at expected fatal alerts
+    SKIP: {
+        skip "Record tests not intended for dtls", 1 if $run_test_as_dtls == 1;
+        #Test 1: Injecting out of context empty records should fail
+        $content_type = TLSProxy::Record::RT_APPLICATION_DATA;
+        $inject_recs_num = 1;
+        $fatal_alert = 0;
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+        if ($testplanisset == 0) {
+            plan tests => 42;
+            $testplanisset = 1;
+        }
+        ok($fatal_alert, "Out of context empty records test");
+    }
+
+    #Test 2: Injecting in context empty records should succeed
     $proxy->clear();
-    $proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
-    $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
-    $proxy->start();
-    ok($fatal_alert, "Unrecognised record type in TLS1.1");
-}
+    $content_type = TLSProxy::Record::RT_HANDSHAKE;
+    if ($run_test_as_dtls == 1) {
+        $proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2");
+        $proxy->clientflags("-max_protocol DTLSv1.2");
+    } else {
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+    }
+    $proxy_start_success = $proxy->start();
+    ok($proxy_start_success && TLSProxy::Message->success(),
+       "In context empty records test".($run_test_as_dtls == 1) ? " for DTLS" : " for TLS");
 
-#Test 12: Sending a different record version in TLS1.2 should fail
-$fatal_alert = 0;
-$proxy->clear();
-$proxy->clientflags("-tls1_2");
-$proxy->filter(\&change_version);
-$proxy->start();
-ok($fatal_alert, "Changed record version in TLS1.2");
+    SKIP: {
+        skip "Record tests not intended for dtls", 7 if $run_test_as_dtls == 1;
+        #Test 3: Injecting too many in context empty records should fail
+        $fatal_alert = 0;
+        $proxy->clear();
+        #We allow 32 consecutive in context empty records
+        $inject_recs_num = 33;
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->start();
+        ok($fatal_alert, "Too many in context empty records test");
 
-#TLS1.3 specific tests
-SKIP: {
-    skip "TLSv1.3 disabled", 9
-        if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
+        #Test 4: Injecting a fragmented fatal alert should fail. We expect the server to
+        #        send back an alert of its own because it cannot handle fragmented
+        #        alerts
+        $fatal_alert = 0;
+        $proxy->clear();
+        $proxy->filter(\&add_frag_alert_filter);
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->start();
+        ok($fatal_alert, "Fragmented alert records test");
 
-    #Test 13: Sending a different record version in TLS1.3 should fail
-    $proxy->clear();
-    $proxy->filter(\&change_version);
-    $proxy->start();
-    ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
+        #Run some SSLv2 ClientHello tests
 
-    #Test 14: Sending an unrecognised record type in TLS1.3 should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $proxy->filter(\&add_unknown_record_type);
-    $proxy->start();
-    ok($fatal_alert, "Unrecognised record type in TLS1.3");
+        use constant {
+            TLSV1_2_IN_SSLV2      => 0,
+            SSLV2_IN_SSLV2        => 1,
+            FRAGMENTED_IN_TLSV1_2 => 2,
+            FRAGMENTED_IN_SSLV2   => 3,
+            ALERT_BEFORE_SSLV2    => 4
+        };
 
-    #Test 15: Sending an outer record type other than app data once encrypted
-    #should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $proxy->filter(\&change_outer_record_type);
-    $proxy->start();
-    ok($fatal_alert, "Wrong outer record type in TLS1.3");
-
-    use constant {
-        DATA_AFTER_SERVER_HELLO => 0,
-        DATA_AFTER_FINISHED => 1,
-        DATA_AFTER_KEY_UPDATE => 2,
-        DATA_BETWEEN_KEY_UPDATE => 3,
-        NO_DATA_BETWEEN_KEY_UPDATE => 4,
-    };
-
-    #Test 16: Sending a ServerHello which doesn't end on a record boundary
-    #         should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $boundary_test_type = DATA_AFTER_SERVER_HELLO;
-    $proxy->filter(\&not_on_record_boundary);
-    $proxy->start();
-    ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
+        # The TLSv1.2 in SSLv2 ClientHello need to run at security level 0
+        # because in a SSLv2 ClientHello we can't send extensions to indicate
+        # which signature algorithm we want to use, and the default is SHA1.
 
-    #Test 17: Sending a Finished which doesn't end on a record boundary
-    #         should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $boundary_test_type = DATA_AFTER_FINISHED;
-    $proxy->start();
-    ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
+        #Test 5: Inject an SSLv2 style record format for a TLSv1.2 ClientHello
+        $sslv2testtype = TLSV1_2_IN_SSLV2;
+        $proxy->clear();
+        $proxy->filter(\&add_sslv2_filter);
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3 -legacy_renegotiation");
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy->start();
+        ok(TLSProxy::Message->success(), "TLSv1.2 in SSLv2 ClientHello test");
 
-    #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
-    #         should fail
-    $fatal_alert = 0;
-    $proxy->clear();
-    $boundary_test_type = DATA_AFTER_KEY_UPDATE;
-    $proxy->start();
-    ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
+        #Test 6: Inject an SSLv2 style record format for an SSLv2 ClientHello. We don't
+        #        support this so it should fail. We actually treat it as an unknown
+        #        protocol so we don't even send an alert in this case.
+        $sslv2testtype = SSLV2_IN_SSLV2;
+        $proxy->clear();
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy->start();
+        ok(TLSProxy::Message->fail(), "SSLv2 in SSLv2 ClientHello test");
+
+        #Test 7: Sanity check ClientHello fragmentation. This isn't really an SSLv2 test
+        #        at all, but it gives us confidence that Test 8 fails for the right
+        #        reasons
+        $sslv2testtype = FRAGMENTED_IN_TLSV1_2;
+        $proxy->clear();
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy->start();
+        ok(TLSProxy::Message->success(), "Fragmented ClientHello in TLSv1.2 test");
 
-    #Test 19: Sending application data in the middle of a fragmented KeyUpdate
-    #         should fail. Strictly speaking this is not a record boundary test
-    #         but we use the same filter.
+        #Test 8: Fragment a TLSv1.2 ClientHello across a TLS1.2 record; an SSLv2
+        #        record; and another TLS1.2 record. This isn't allowed so should fail
+        $sslv2testtype = FRAGMENTED_IN_SSLV2;
+        $proxy->clear();
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy->start();
+        ok(TLSProxy::Message->fail(), "Fragmented ClientHello in TLSv1.2/SSLv2 test");
+
+        #Test 9: Send a TLS warning alert before an SSLv2 ClientHello. This should
+        #        fail because an SSLv2 ClientHello must be the first record.
+        $sslv2testtype = ALERT_BEFORE_SSLV2;
+        $proxy->clear();
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy->start();
+        ok(TLSProxy::Message->fail(), "Alert before SSLv2 ClientHello test");
+   }
+    #Unrecognised record type tests
+
+    #Test 10: Sending an unrecognised record type in TLS1.2 should fail
     $fatal_alert = 0;
     $proxy->clear();
-    $boundary_test_type = DATA_BETWEEN_KEY_UPDATE;
-    $proxy->start();
-    ok($fatal_alert, "Data between KeyUpdate");
+    if ($run_test_as_dtls == 1) {
+        $proxy->serverflags("-min_protocol DTLSv1.2 -max_protocol DTLSv1.2");
+        $proxy->clientflags("-max_protocol DTLSv1.2");
+    } else {
+        $proxy->serverflags("-tls1_2");
+        $proxy->clientflags("-no_tls1_3");
+    }
+    $proxy->filter(\&add_unknown_record_type);
+    $proxy_start_success = $proxy->start();
 
-    #Test 20: Fragmented KeyUpdate. This should succeed. Strictly speaking this
-    #         is not a record boundary test but we use the same filter.
-    $proxy->clear();
-    $boundary_test_type = NO_DATA_BETWEEN_KEY_UPDATE;
-    $proxy->start();
-    ok(TLSProxy::Message->success(), "No data between KeyUpdate");
+    if ($run_test_as_dtls == 1) {
+        ok($proxy_start_success == 0, "Unrecognised record type in DTLS1.2");
+    } else {
+        ok($fatal_alert, "Unrecognised record type in TLS1.2");
+    }
+
+    SKIP: {
+        skip "TLSv1.1 or DTLSv1 disabled", 1 if ($run_test_as_dtls == 0 && disabled("tls1_1"))
+                                                 || ($run_test_as_dtls == 1 && disabled("dtls1"));
+
+        #Test 11: Sending an unrecognised record type in TLS1.1 should fail
+        $fatal_alert = 0;
+        $proxy->clear();
+        if ($run_test_as_dtls == 1) {
+            $proxy->clientflags("-min_protocol DTLSv1 -max_protocol DTLSv1 -cipher DEFAULT:\@SECLEVEL=0");
+        } else {
+            $proxy->clientflags("-tls1_1 -cipher DEFAULT:\@SECLEVEL=0");
+        }
+        $proxy->ciphers("AES128-SHA:\@SECLEVEL=0");
+        $proxy_start_success = $proxy->start();
+        if ($run_test_as_dtls == 1) {
+            ok($proxy_start_success == 0, "Unrecognised record type in DTLSv1");
+        } else {
+            ok($fatal_alert, "Unrecognised record type in TLSv1.1");
+        }
+    }
 
     SKIP: {
-        skip "EC disabled", 1 if disabled("ec");
-
-        #Test 21: Force an HRR and change the "real" ServerHello to have a protocol
-        #         record version of 0x0301 (TLSv1.0). At this point we have already
-        #         decided that we are doing TLSv1.3 but are still using plaintext
-        #         records. The server should be sending a record version of 0x303
-        #         (TLSv1.2), but the RFC requires us to ignore this field so we
-        #         should tolerate the incorrect version.
+        skip "Record tests not intended for dtls", 10 if $run_test_as_dtls == 1;
+        #Test 12: Sending a different record version in TLS1.2 should fail
+        $fatal_alert = 0;
         $proxy->clear();
-        $proxy->filter(\&change_server_hello_version);
-        $proxy->serverflags("-groups P-256"); # Force an HRR
+        $proxy->clientflags("-tls1_2");
+        $proxy->filter(\&change_version);
         $proxy->start();
-        ok(TLSProxy::Message->success(), "Bad ServerHello record version after HRR");
+        ok($fatal_alert, "Changed record version in TLS1.2");
+
+        #TLS1.3 specific tests
+        SKIP: {
+            skip "TLSv1.3 disabled", 9
+                if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
+
+            #Test 13: Sending a different record version in TLS1.3 should fail
+            $proxy->clear();
+            $proxy->filter(\&change_version);
+            $proxy->start();
+            ok(TLSProxy::Message->fail(), "Changed record version in TLS1.3");
+
+            #Test 14: Sending an unrecognised record type in TLS1.3 should fail
+            $fatal_alert = 0;
+            $proxy->clear();
+            $proxy->filter(\&add_unknown_record_type);
+            $proxy->start();
+            ok($fatal_alert, "Unrecognised record type in TLS1.3");
+
+            #Test 15: Sending an outer record type other than app data once encrypted
+            #should fail
+            $fatal_alert = 0;
+            $proxy->clear();
+            $proxy->filter(\&change_outer_record_type);
+            $proxy->start();
+            ok($fatal_alert, "Wrong outer record type in TLS1.3");
+
+            use constant {
+                DATA_AFTER_SERVER_HELLO    => 0,
+                DATA_AFTER_FINISHED        => 1,
+                DATA_AFTER_KEY_UPDATE      => 2,
+                DATA_BETWEEN_KEY_UPDATE    => 3,
+                NO_DATA_BETWEEN_KEY_UPDATE => 4,
+            };
+
+            #Test 16: Sending a ServerHello which doesn't end on a record boundary
+            #         should fail
+            $fatal_alert = 0;
+            $proxy->clear();
+            $boundary_test_type = DATA_AFTER_SERVER_HELLO;
+            $proxy->filter(\&not_on_record_boundary);
+            $proxy->start();
+            ok($fatal_alert, "Record not on boundary in TLS1.3 (ServerHello)");
+
+            #Test 17: Sending a Finished which doesn't end on a record boundary
+            #         should fail
+            $fatal_alert = 0;
+            $proxy->clear();
+            $boundary_test_type = DATA_AFTER_FINISHED;
+            $proxy->start();
+            ok($fatal_alert, "Record not on boundary in TLS1.3 (Finished)");
+
+            #Test 18: Sending a KeyUpdate which doesn't end on a record boundary
+            #         should fail
+            $fatal_alert = 0;
+            $proxy->clear();
+            $boundary_test_type = DATA_AFTER_KEY_UPDATE;
+            $proxy->start();
+            ok($fatal_alert, "Record not on boundary in TLS1.3 (KeyUpdate)");
+
+            #Test 19: Sending application data in the middle of a fragmented KeyUpdate
+            #         should fail. Strictly speaking this is not a record boundary test
+            #         but we use the same filter.
+            $fatal_alert = 0;
+            $proxy->clear();
+            $boundary_test_type = DATA_BETWEEN_KEY_UPDATE;
+            $proxy->start();
+            ok($fatal_alert, "Data between KeyUpdate");
+
+            #Test 20: Fragmented KeyUpdate. This should succeed. Strictly speaking this
+            #         is not a record boundary test but we use the same filter.
+            $proxy->clear();
+            $boundary_test_type = NO_DATA_BETWEEN_KEY_UPDATE;
+            $proxy->start();
+            ok(TLSProxy::Message->success(), "No data between KeyUpdate");
+
+            SKIP: {
+                skip "EC disabled", 1 if disabled("ec");
+
+                #Test 21: Force an HRR and change the "real" ServerHello to have a protocol
+                #         record version of 0x0301 (TLSv1.0). At this point we have already
+                #         decided that we are doing TLSv1.3 but are still using plaintext
+                #         records. The server should be sending a record version of 0x303
+                #         (TLSv1.2), but the RFC requires us to ignore this field so we
+                #         should tolerate the incorrect version.
+                $proxy->clear();
+                $proxy->filter(\&change_server_hello_version);
+                $proxy->serverflags("-groups P-256"); # Force an HRR
+                $proxy->start();
+                ok(TLSProxy::Message->success(), "Bad ServerHello record version after HRR");
+            }
+        }
     }
- }
+}
 
 
 sub add_empty_recs_filter
 {
     my $proxy = shift;
     my $records = $proxy->record_list;
+    my $isdtls = $proxy->isdtls();
 
     # We're only interested in the initial ClientHello
     if ($proxy->flight != 0) {
@@ -279,17 +342,34 @@ sub add_empty_recs_filter
     }
 
     for (my $i = 0; $i < $inject_recs_num; $i++) {
-        my $record = TLSProxy::Record->new(
-            0,
-            $content_type,
-            TLSProxy::Record::VERS_TLS_1_2,
-            0,
-            0,
-            0,
-            0,
-            "",
-            ""
-        );
+        my $record;
+        if ($isdtls == 1) {
+            $record = TLSProxy::Record->new_dtls(
+                0,
+                $content_type,
+                TLSProxy::Record::VERS_DTLS_1_2,
+                0,
+                0,
+                0,
+                0,
+                0,
+                0,
+                "",
+                ""
+            );
+        } else {
+            $record = TLSProxy::Record->new(
+                0,
+                $content_type,
+                TLSProxy::Record::VERS_TLS_1_2,
+                0,
+                0,
+                0,
+                0,
+                "",
+                ""
+            );
+        }
         push @{$records}, $record;
     }
 }
@@ -501,6 +581,7 @@ sub add_unknown_record_type
 {
     my $proxy = shift;
     my $records = $proxy->record_list;
+    my $isdtls = $proxy->isdtls;
     state $added_record;
 
     # We'll change a record after the initial version neg has taken place
@@ -512,17 +593,35 @@ sub add_unknown_record_type
         return;
     }
 
-    my $record = TLSProxy::Record->new(
-        1,
-        TLSProxy::Record::RT_UNKNOWN,
-        @{$records}[-1]->version(),
-        1,
-        0,
-        1,
-        1,
-        "X",
-        "X"
-    );
+    my $record;
+
+    if ($isdtls) {
+        $record = TLSProxy::Record->new_dtls(
+            1,
+            TLSProxy::Record::RT_UNKNOWN,
+            @{$records}[-1]->version(),
+            @{$records}[-1]->epoch(),
+            @{$records}[-1]->seq() +1,
+            1,
+            0,
+            1,
+            1,
+            "X",
+            "X"
+        );
+    } else {
+        $record = TLSProxy::Record->new(
+            1,
+            TLSProxy::Record::RT_UNKNOWN,
+            @{$records}[-1]->version(),
+            1,
+            0,
+            1,
+            1,
+            "X",
+            "X"
+        );
+    }
 
     #Find ServerHello record and insert after that
     my $i;
index 3ecbd1893e03abdfb3d49d3d92372532b1fc22ac..06de4fbb395e6c9d0c4cc08c22e2f0ce427a3a8d 100644 (file)
@@ -750,4 +750,10 @@ sub ciphersuite
     return $ciphersuite;
 }
 
+sub isdtls
+{
+    my $self = shift;
+    return $self->{isdtls}; #read-only
+}
+
 1;