xref: /openssl/test/recipes/70-test_comp.t (revision 80008d4a)
1#! /usr/bin/env perl
2# Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9use strict;
10use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
11use OpenSSL::Test::Utils;
12use File::Temp qw(tempfile);
13use TLSProxy::Proxy;
14
15my $test_name = "test_comp";
16setup($test_name);
17
18plan skip_all => "TLSProxy isn't usable on $^O"
19    if $^O =~ /^(VMS)$/;
20
21plan skip_all => "$test_name needs the dynamic engine feature enabled"
22    if disabled("engine") || disabled("dynamic-engine");
23
24plan skip_all => "$test_name needs the sock feature enabled"
25    if disabled("sock");
26
27plan skip_all => "$test_name needs TLSv1.3 or TLSv1.2 enabled"
28    if disabled("tls1_3") && disabled("tls1_2");
29
30# The injected compression field.
31use constant {
32    MULTIPLE_COMPRESSIONS => 0, # Includes NULL, OK for >=TLS1.2
33    NON_NULL_COMPRESSION => 1, # Alert for all TLS versions
34    MULTIPLE_NO_NULL => 2, # Alert for all TLS versions
35    NO_COMPRESSION => 3, # Alert for all TLS versions
36    NULL_COMPRESSION => 4, # OK for all TLS versions
37};
38my %test_type_message = (
39    MULTIPLE_COMPRESSIONS, "multiple, including null compression",
40    NON_NULL_COMPRESSION, "one, not null compression",
41    MULTIPLE_NO_NULL, "multiple, no null compression",
42    NO_COMPRESSION, "no compression",
43    NULL_COMPRESSION, "one, null compression",
44);
45my %compression_field_for_test = (
46    # [null, unknown]
47    MULTIPLE_COMPRESSIONS, [0x00, 0xff],
48    # [unknown]
49    NON_NULL_COMPRESSION, [0xff],
50    # [unknown, unknown, unknown]
51    MULTIPLE_NO_NULL, [0xfd, 0xfe, 0xff],
52    # []
53    NO_COMPRESSION, [],
54    # [null]
55    NULL_COMPRESSION, [0x00],
56);
57my $testtype;
58
59# The tested TLS version
60use constant {
61    TEST_TLS_1_2 => 0, # Test TLSv1.2 and older
62    TEST_TLS_1_3 => 1, # Test TLSv1.3 and newer
63};
64my %test_tls_message = (
65    TEST_TLS_1_2, "TLS version 1.2 or older",
66    TEST_TLS_1_3, "TLS version 1.3 or newer",
67);
68
69# The expected result from a test
70use constant {
71    EXPECT_SUCCESS => 0,
72    EXPECT_DECODE_ERROR => 1,
73    EXPECT_ILLEGAL_PARAMETER => 2,
74};
75my %expect_message = (
76    EXPECT_SUCCESS, "Expected success",
77    EXPECT_DECODE_ERROR, "Expected decode error",
78    EXPECT_ILLEGAL_PARAMETER, "Expected illegal parameter alert",
79);
80
81my $proxy = TLSProxy::Proxy->new(
82    undef,
83    cmdstr(app(["openssl"]), display => 1),
84    srctop_file("apps", "server.pem"),
85    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
86);
87
88$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
89plan tests => 10;
90
91SKIP: {
92    skip "TLSv1.2 disabled", 5 if disabled("tls1_2");
93
94    # Test 1: Check that sending multiple compression methods in a TLSv1.2
95    #         ClientHello succeeds
96    do_test(TEST_TLS_1_2, MULTIPLE_COMPRESSIONS, EXPECT_SUCCESS);
97
98    # Test 2: Check that sending a non-null compression method in a TLSv1.2
99    #         ClientHello results in an illegal parameter alert
100    do_test(TEST_TLS_1_2, NON_NULL_COMPRESSION, EXPECT_ILLEGAL_PARAMETER);
101
102    # Test 3: Check that sending multiple compression methods without null in
103    #         a TLSv1.2 ClientHello results in an illegal parameter alert
104    do_test(TEST_TLS_1_2, MULTIPLE_NO_NULL, EXPECT_ILLEGAL_PARAMETER);
105
106    # Test 4: Check that sending no compression methods in a TLSv1.2
107    #         ClientHello results in a decode error
108    do_test(TEST_TLS_1_2, NO_COMPRESSION, EXPECT_DECODE_ERROR);
109
110    # Test 5: Check that sending only null compression in a TLSv1.2
111    #         ClientHello succeeds
112    do_test(TEST_TLS_1_2, NULL_COMPRESSION, EXPECT_SUCCESS);
113}
114
115SKIP: {
116    skip "TLSv1.3 disabled", 5
117        if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
118
119    # Test 6: Check that sending multiple compression methods in a TLSv1.3
120    #         ClientHello results in an illegal parameter alert
121    do_test(TEST_TLS_1_3, MULTIPLE_COMPRESSIONS, EXPECT_ILLEGAL_PARAMETER);
122
123    # Test 7: Check that sending a non-null compression method in a TLSv1.3
124    #         ClientHello results in an illegal parameter alert
125    do_test(TEST_TLS_1_3, NON_NULL_COMPRESSION, EXPECT_ILLEGAL_PARAMETER);
126
127    # Test 8: Check that sending multiple compression methods without null in
128    #         a TLSv1.3 ClientHello results in an illegal parameter alert
129    do_test(TEST_TLS_1_3, MULTIPLE_NO_NULL, EXPECT_ILLEGAL_PARAMETER);
130
131    # Test 9: Check that sending no compression methods in a TLSv1.3
132    #         ClientHello results in a decode error
133    do_test(TEST_TLS_1_3, NO_COMPRESSION, EXPECT_DECODE_ERROR);
134
135    # Test 10: Check that sending only null compression in a TLSv1.3
136    #          ClientHello succeeds
137    do_test(TEST_TLS_1_3, NULL_COMPRESSION, EXPECT_SUCCESS);
138}
139
140sub do_test
141{
142    my $tls = shift; # The tested TLS version.
143    my $type = shift; # The test type to perform.
144    my $expect = shift; # The expected result.
145
146    $proxy->clear();
147    $proxy->filter(\&add_comp_filter);
148    if ($tls == TEST_TLS_1_2) {
149        $proxy->clientflags("-no_tls1_3");
150    } else {
151        $proxy->clientflags("-min_protocol TLSv1.3");
152    }
153    $testtype = $type;
154    $proxy->start();
155    print $expect, $tls, $type , "\n";
156    my $failure_message = $expect_message{$expect} . " for " .
157                          $test_tls_message{$tls} . " with " .
158                          $test_type_message{$type};
159    if ($expect == EXPECT_SUCCESS) {
160        ok(TLSProxy::Message->success(), $failure_message);
161    } elsif ($expect == EXPECT_DECODE_ERROR) {
162        ok(is_alert_message(TLSProxy::Message::AL_DESC_DECODE_ERROR),
163           $failure_message);
164    } elsif ($expect == EXPECT_ILLEGAL_PARAMETER) {
165        ok(is_alert_message(TLSProxy::Message::AL_DESC_ILLEGAL_PARAMETER),
166           $failure_message);
167    } else {
168        die "Unexpected test expectation: $expect";
169    }
170}
171
172# Test if the last message was a failure and matches the expected type.
173sub is_alert_message
174{
175    my $alert_type = shift;
176    return 0 unless TLSProxy::Message->fail();
177    return 1 if TLSProxy::Message->alert->description() == $alert_type;
178    return 0;
179}
180
181# Filter to insert the selected compression method into the hello message.
182sub add_comp_filter
183{
184    my $proxy = shift;
185    my $message;
186    my @comp;
187
188    # Only look at the ClientHello
189    return if $proxy->flight != 0;
190
191    $message = ${$proxy->message_list}[0];
192
193    return if (!defined $message
194               || $message->mt != TLSProxy::Message::MT_CLIENT_HELLO);
195
196    @comp = @{$compression_field_for_test{$testtype}};
197    $message->comp_meths(\@comp);
198    $message->comp_meth_len(scalar @comp);
199    $message->repack();
200}
201