xref: /netbsd-src/crypto/external/bsd/openssl.old/dist/test/recipes/70-test_sslextension.t (revision b2c35e17b976cf7ccd7250c86c6f5e95090ed636)
1#! /usr/bin/env perl
2# Copyright 2015-2019 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the OpenSSL license (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 feature 'state';
11
12use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
13use OpenSSL::Test::Utils;
14use TLSProxy::Proxy;
15
16my $test_name = "test_sslextension";
17setup($test_name);
18
19plan skip_all => "TLSProxy isn't usable on $^O"
20    if $^O =~ /^(VMS)$/;
21
22plan skip_all => "$test_name needs the dynamic engine feature enabled"
23    if disabled("engine") || disabled("dynamic-engine");
24
25plan skip_all => "$test_name needs the sock feature enabled"
26    if disabled("sock");
27
28plan skip_all => "$test_name needs TLS enabled"
29    if alldisabled(available_protocols("tls"));
30
31my $no_below_tls13 = alldisabled(("tls1", "tls1_1", "tls1_2"))
32                     || (!disabled("tls1_3") && disabled("tls1_2"));
33
34use constant {
35    UNSOLICITED_SERVER_NAME => 0,
36    UNSOLICITED_SERVER_NAME_TLS13 => 1,
37    UNSOLICITED_SCT => 2,
38    NONCOMPLIANT_SUPPORTED_GROUPS => 3
39};
40
41my $testtype;
42my $fatal_alert = 0;    # set by filter on fatal alert
43
44$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
45my $proxy = TLSProxy::Proxy->new(
46    \&inject_duplicate_extension_clienthello,
47    cmdstr(app(["openssl"]), display => 1),
48    srctop_file("apps", "server.pem"),
49    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
50);
51
52
53sub extension_filter
54{
55    my $proxy = shift;
56
57    if ($proxy->flight == 1) {
58        # Change the ServerRandom so that the downgrade sentinel doesn't cause
59        # the connection to fail
60        my $message = ${$proxy->message_list}[1];
61        $message->random("\0"x32);
62        $message->repack();
63        return;
64    }
65
66    # We're only interested in the initial ClientHello
67    if ($proxy->flight != 0) {
68        return;
69    }
70
71    foreach my $message (@{$proxy->message_list}) {
72        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
73            # Remove all extensions and set the extension len to zero
74            $message->extension_data({});
75            $message->extensions_len(0);
76            # Extensions have been removed so make sure we don't try to use them
77            $message->process_extensions();
78
79            $message->repack();
80        }
81    }
82}
83
84sub inject_duplicate_extension
85{
86  my ($proxy, $message_type) = @_;
87
88    foreach my $message (@{$proxy->message_list}) {
89        if ($message->mt == $message_type) {
90          my %extensions = %{$message->extension_data};
91            # Add a duplicate extension. We use cryptopro_bug since we never
92            # normally write that one, and it is allowed as unsolicited in the
93            # ServerHello
94            $message->set_extension(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION, "");
95            $message->dupext(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION);
96            $message->repack();
97        }
98    }
99}
100
101sub inject_duplicate_extension_clienthello
102{
103    my $proxy = shift;
104
105    # We're only interested in the initial ClientHello
106    if ($proxy->flight == 0) {
107        inject_duplicate_extension($proxy, TLSProxy::Message::MT_CLIENT_HELLO);
108        return;
109    }
110
111    my $last_record = @{$proxy->{record_list}}[-1];
112    $fatal_alert = 1 if $last_record->is_fatal_alert(1);
113}
114
115sub inject_duplicate_extension_serverhello
116{
117    my $proxy = shift;
118
119    # We're only interested in the initial ServerHello
120    if ($proxy->flight == 0) {
121        return;
122    } elsif ($proxy->flight == 1) {
123        inject_duplicate_extension($proxy, TLSProxy::Message::MT_SERVER_HELLO);
124        return;
125    }
126
127    my $last_record = @{$proxy->{record_list}}[-1];
128    $fatal_alert = 1 if $last_record->is_fatal_alert(0);
129}
130
131sub inject_unsolicited_extension
132{
133    my $proxy = shift;
134    my $message;
135    state $sent_unsolisited_extension;
136
137    if ($proxy->flight == 0) {
138        $sent_unsolisited_extension = 0;
139        return;
140    }
141
142    # We're only interested in the initial ServerHello/EncryptedExtensions
143    if ($proxy->flight != 1) {
144        if ($sent_unsolisited_extension) {
145            my $last_record = @{$proxy->record_list}[-1];
146            $fatal_alert = 1 if $last_record->is_fatal_alert(0);
147        }
148        return;
149    }
150
151    if ($testtype == UNSOLICITED_SERVER_NAME_TLS13) {
152        return if (!defined($message = ${$proxy->message_list}[2]));
153        die "Expecting EE message ".($message->mt).","
154                                   .${$proxy->message_list}[1]->mt.", "
155                                   .${$proxy->message_list}[3]->mt
156            if $message->mt != TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS;
157    } else {
158        $message = ${$proxy->message_list}[1];
159    }
160
161    my $ext = pack "C2",
162        0x00, 0x00; #Extension length
163
164    my $type;
165    if ($testtype == UNSOLICITED_SERVER_NAME
166            || $testtype == UNSOLICITED_SERVER_NAME_TLS13) {
167        $type = TLSProxy::Message::EXT_SERVER_NAME;
168    } elsif ($testtype == UNSOLICITED_SCT) {
169        $type = TLSProxy::Message::EXT_SCT;
170    } elsif ($testtype == NONCOMPLIANT_SUPPORTED_GROUPS) {
171        $type = TLSProxy::Message::EXT_SUPPORTED_GROUPS;
172    }
173    $message->set_extension($type, $ext);
174    $message->repack();
175    $sent_unsolisited_extension = 1;
176}
177
178sub inject_cryptopro_extension
179{
180    my $proxy = shift;
181
182    # We're only interested in the initial ClientHello
183    if ($proxy->flight != 0) {
184        return;
185    }
186
187    my $message = ${$proxy->message_list}[0];
188    $message->set_extension(TLSProxy::Message::EXT_CRYPTOPRO_BUG_EXTENSION, "");
189    $message->repack();
190}
191
192# Test 1-2: Sending a duplicate extension should fail.
193$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
194plan tests => 8;
195ok($fatal_alert, "Duplicate ClientHello extension");
196
197$fatal_alert = 0;
198$proxy->clear();
199$proxy->filter(\&inject_duplicate_extension_serverhello);
200$proxy->start();
201ok($fatal_alert, "Duplicate ServerHello extension");
202
203SKIP: {
204    skip "TLS <= 1.2 disabled", 3 if $no_below_tls13;
205
206    #Test 3: Sending a zero length extension block should pass
207    $proxy->clear();
208    $proxy->filter(\&extension_filter);
209    $proxy->start();
210    ok(TLSProxy::Message->success, "Zero extension length test");
211
212    #Test 4: Inject an unsolicited extension (<= TLSv1.2)
213    $fatal_alert = 0;
214    $proxy->clear();
215    $proxy->filter(\&inject_unsolicited_extension);
216    $testtype = UNSOLICITED_SERVER_NAME;
217    $proxy->clientflags("-no_tls1_3 -noservername");
218    $proxy->start();
219    ok($fatal_alert, "Unsolicited server name extension");
220
221    #Test 5: Inject a noncompliant supported_groups extension (<= TLSv1.2)
222    $proxy->clear();
223    $proxy->filter(\&inject_unsolicited_extension);
224    $testtype = NONCOMPLIANT_SUPPORTED_GROUPS;
225    $proxy->clientflags("-no_tls1_3");
226    $proxy->start();
227    ok(TLSProxy::Message->success(), "Noncompliant supported_groups extension");
228}
229
230SKIP: {
231    skip "TLS <= 1.2 or CT disabled", 1
232        if $no_below_tls13 || disabled("ct");
233    #Test 6: Same as above for the SCT extension which has special handling
234    $fatal_alert = 0;
235    $proxy->clear();
236    $testtype = UNSOLICITED_SCT;
237    $proxy->clientflags("-no_tls1_3");
238    $proxy->start();
239    ok($fatal_alert, "Unsolicited sct extension");
240}
241
242SKIP: {
243    skip "TLS 1.3 disabled", 1 if disabled("tls1_3");
244    #Test 7: Inject an unsolicited extension (TLSv1.3)
245    $fatal_alert = 0;
246    $proxy->clear();
247    $proxy->filter(\&inject_unsolicited_extension);
248    $testtype = UNSOLICITED_SERVER_NAME_TLS13;
249    $proxy->clientflags("-noservername");
250    $proxy->start();
251    ok($fatal_alert, "Unsolicited server name extension (TLSv1.3)");
252}
253
254#Test 8: Send the cryptopro extension in a ClientHello. Normally this is an
255#        unsolicited extension only ever seen in the ServerHello. We should
256#        ignore it in a ClientHello
257$proxy->clear();
258$proxy->filter(\&inject_cryptopro_extension);
259$proxy->start();
260ok(TLSProxy::Message->success(), "Cryptopro extension in ClientHello");
261