xref: /freebsd/crypto/openssl/test/recipes/70-test_tls13hrr.t (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1*e0c4386eSCy Schubert#! /usr/bin/env perl
2*e0c4386eSCy Schubert# Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert#
4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License").  You may not use
5*e0c4386eSCy Schubert# this file except in compliance with the License.  You can obtain a copy
6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert
9*e0c4386eSCy Schubertuse strict;
10*e0c4386eSCy Schubertuse OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
11*e0c4386eSCy Schubertuse OpenSSL::Test::Utils;
12*e0c4386eSCy Schubertuse TLSProxy::Proxy;
13*e0c4386eSCy Schubert
14*e0c4386eSCy Schubertmy $test_name = "test_tls13hrr";
15*e0c4386eSCy Schubertsetup($test_name);
16*e0c4386eSCy Schubert
17*e0c4386eSCy Schubertplan skip_all => "TLSProxy isn't usable on $^O"
18*e0c4386eSCy Schubert    if $^O =~ /^(VMS)$/;
19*e0c4386eSCy Schubert
20*e0c4386eSCy Schubertplan skip_all => "$test_name needs the dynamic engine feature enabled"
21*e0c4386eSCy Schubert    if disabled("engine") || disabled("dynamic-engine");
22*e0c4386eSCy Schubert
23*e0c4386eSCy Schubertplan skip_all => "$test_name needs the sock feature enabled"
24*e0c4386eSCy Schubert    if disabled("sock");
25*e0c4386eSCy Schubert
26*e0c4386eSCy Schubertplan skip_all => "$test_name needs TLS1.3 enabled"
27*e0c4386eSCy Schubert    if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
28*e0c4386eSCy Schubert
29*e0c4386eSCy Schubert$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
30*e0c4386eSCy Schubert
31*e0c4386eSCy Schubertmy $proxy = TLSProxy::Proxy->new(
32*e0c4386eSCy Schubert    undef,
33*e0c4386eSCy Schubert    cmdstr(app(["openssl"]), display => 1),
34*e0c4386eSCy Schubert    srctop_file("apps", "server.pem"),
35*e0c4386eSCy Schubert    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
36*e0c4386eSCy Schubert);
37*e0c4386eSCy Schubert
38*e0c4386eSCy Schubertuse constant {
39*e0c4386eSCy Schubert    CHANGE_HRR_CIPHERSUITE => 0,
40*e0c4386eSCy Schubert    CHANGE_CH1_CIPHERSUITE => 1,
41*e0c4386eSCy Schubert    DUPLICATE_HRR => 2,
42*e0c4386eSCy Schubert    INVALID_GROUP => 3
43*e0c4386eSCy Schubert};
44*e0c4386eSCy Schubert
45*e0c4386eSCy Schubert#Test 1: A client should fail if the server changes the ciphersuite between the
46*e0c4386eSCy Schubert#        HRR and the SH
47*e0c4386eSCy Schubert$proxy->filter(\&hrr_filter);
48*e0c4386eSCy Schubertif (disabled("ec")) {
49*e0c4386eSCy Schubert    $proxy->serverflags("-curves ffdhe3072");
50*e0c4386eSCy Schubert} else {
51*e0c4386eSCy Schubert    $proxy->serverflags("-curves P-256");
52*e0c4386eSCy Schubert}
53*e0c4386eSCy Schubertmy $testtype = CHANGE_HRR_CIPHERSUITE;
54*e0c4386eSCy Schubert$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
55*e0c4386eSCy Schubertplan tests => 4;
56*e0c4386eSCy Schubertok(TLSProxy::Message->fail(), "Server ciphersuite changes");
57*e0c4386eSCy Schubert
58*e0c4386eSCy Schubert#Test 2: It is an error if the client changes the offered ciphersuites so that
59*e0c4386eSCy Schubert#        we end up selecting a different ciphersuite between HRR and the SH
60*e0c4386eSCy Schubert$proxy->clear();
61*e0c4386eSCy Schubertif (disabled("ec")) {
62*e0c4386eSCy Schubert    $proxy->serverflags("-curves ffdhe3072");
63*e0c4386eSCy Schubert} else {
64*e0c4386eSCy Schubert    $proxy->serverflags("-curves P-256");
65*e0c4386eSCy Schubert}
66*e0c4386eSCy Schubert$proxy->ciphersuitess("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384");
67*e0c4386eSCy Schubert$testtype = CHANGE_CH1_CIPHERSUITE;
68*e0c4386eSCy Schubert$proxy->start();
69*e0c4386eSCy Schubertok(TLSProxy::Message->fail(), "Client ciphersuite changes");
70*e0c4386eSCy Schubert
71*e0c4386eSCy Schubert#Test 3: A client should fail with unexpected_message alert if the server
72*e0c4386eSCy Schubert#        sends more than 1 HRR
73*e0c4386eSCy Schubertmy $fatal_alert = 0;
74*e0c4386eSCy Schubert$proxy->clear();
75*e0c4386eSCy Schubertif (disabled("ec")) {
76*e0c4386eSCy Schubert    $proxy->serverflags("-curves ffdhe3072");
77*e0c4386eSCy Schubert} else {
78*e0c4386eSCy Schubert    $proxy->serverflags("-curves P-256");
79*e0c4386eSCy Schubert}
80*e0c4386eSCy Schubert$testtype = DUPLICATE_HRR;
81*e0c4386eSCy Schubert$proxy->start();
82*e0c4386eSCy Schubertok($fatal_alert, "Server duplicated HRR");
83*e0c4386eSCy Schubert
84*e0c4386eSCy Schubert#Test 4: If the client sends a group that is in the supported_groups list but
85*e0c4386eSCy Schubert#        otherwise not valid (e.g. not suitable for TLSv1.3) we should reject it
86*e0c4386eSCy Schubert#        and not consider it when sending the HRR. We send brainpoolP512r1 in
87*e0c4386eSCy Schubert#        the ClientHello, which is acceptable to the server but is not valid in
88*e0c4386eSCy Schubert#        TLSv1.3. We expect the server to select X25519 in the HRR and the
89*e0c4386eSCy Schubert#        handshake to complete successfully
90*e0c4386eSCy SchubertSKIP: {
91*e0c4386eSCy Schubert    skip "EC/TLSv1.2 is disabled in this build", 1
92*e0c4386eSCy Schubert        if disabled("ec") || disabled("tls1_2");
93*e0c4386eSCy Schubert
94*e0c4386eSCy Schubert    $proxy->clear();
95*e0c4386eSCy Schubert    $proxy->clientflags("-groups P-256:brainpoolP512r1:X25519");
96*e0c4386eSCy Schubert    $proxy->serverflags("-groups brainpoolP512r1:X25519");
97*e0c4386eSCy Schubert    $testtype = INVALID_GROUP;
98*e0c4386eSCy Schubert    $proxy->start();
99*e0c4386eSCy Schubert    ok(TLSProxy::Message->success(), "Invalid group with HRR");
100*e0c4386eSCy Schubert}
101*e0c4386eSCy Schubert
102*e0c4386eSCy Schubertsub hrr_filter
103*e0c4386eSCy Schubert{
104*e0c4386eSCy Schubert    my $proxy = shift;
105*e0c4386eSCy Schubert
106*e0c4386eSCy Schubert    if ($testtype == CHANGE_HRR_CIPHERSUITE) {
107*e0c4386eSCy Schubert        # We're only interested in the HRR
108*e0c4386eSCy Schubert        if ($proxy->flight != 1) {
109*e0c4386eSCy Schubert            return;
110*e0c4386eSCy Schubert        }
111*e0c4386eSCy Schubert
112*e0c4386eSCy Schubert        my $hrr = ${$proxy->message_list}[1];
113*e0c4386eSCy Schubert
114*e0c4386eSCy Schubert        # We will normally only ever select CIPHER_TLS13_AES_128_GCM_SHA256
115*e0c4386eSCy Schubert        # because that's what Proxy tells s_server to do. Setting as below means
116*e0c4386eSCy Schubert        # the ciphersuite will change will we get the ServerHello
117*e0c4386eSCy Schubert        $hrr->ciphersuite(TLSProxy::Message::CIPHER_TLS13_AES_256_GCM_SHA384);
118*e0c4386eSCy Schubert        $hrr->repack();
119*e0c4386eSCy Schubert        return;
120*e0c4386eSCy Schubert    }
121*e0c4386eSCy Schubert
122*e0c4386eSCy Schubert    if ($testtype == DUPLICATE_HRR) {
123*e0c4386eSCy Schubert        # We're only interested in the HRR
124*e0c4386eSCy Schubert        # and the unexpected_message alert from client
125*e0c4386eSCy Schubert        if ($proxy->flight == 4) {
126*e0c4386eSCy Schubert            $fatal_alert = 1
127*e0c4386eSCy Schubert                if @{$proxy->record_list}[-1]->is_fatal_alert(0) == 10;
128*e0c4386eSCy Schubert            return;
129*e0c4386eSCy Schubert        }
130*e0c4386eSCy Schubert        if ($proxy->flight != 3) {
131*e0c4386eSCy Schubert            return;
132*e0c4386eSCy Schubert        }
133*e0c4386eSCy Schubert
134*e0c4386eSCy Schubert        # Find ServerHello record (HRR actually) and insert after that
135*e0c4386eSCy Schubert        my $i;
136*e0c4386eSCy Schubert        for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
137*e0c4386eSCy Schubert            next;
138*e0c4386eSCy Schubert        }
139*e0c4386eSCy Schubert        my $hrr_record = ${$proxy->record_list}[$i];
140*e0c4386eSCy Schubert        my $dup_hrr = TLSProxy::Record->new(3,
141*e0c4386eSCy Schubert            $hrr_record->content_type(),
142*e0c4386eSCy Schubert            $hrr_record->version(),
143*e0c4386eSCy Schubert            $hrr_record->len(),
144*e0c4386eSCy Schubert            $hrr_record->sslv2(),
145*e0c4386eSCy Schubert            $hrr_record->len_real(),
146*e0c4386eSCy Schubert            $hrr_record->decrypt_len(),
147*e0c4386eSCy Schubert            $hrr_record->data(),
148*e0c4386eSCy Schubert            $hrr_record->decrypt_data());
149*e0c4386eSCy Schubert
150*e0c4386eSCy Schubert        $i++;
151*e0c4386eSCy Schubert        splice @{$proxy->record_list}, $i, 0, $dup_hrr;
152*e0c4386eSCy Schubert        return;
153*e0c4386eSCy Schubert    }
154*e0c4386eSCy Schubert
155*e0c4386eSCy Schubert    if ($proxy->flight != 0) {
156*e0c4386eSCy Schubert        return;
157*e0c4386eSCy Schubert    }
158*e0c4386eSCy Schubert
159*e0c4386eSCy Schubert    my $ch1 = ${$proxy->message_list}[0];
160*e0c4386eSCy Schubert
161*e0c4386eSCy Schubert    if ($testtype == CHANGE_CH1_CIPHERSUITE) {
162*e0c4386eSCy Schubert        # The server will always pick TLS_AES_256_GCM_SHA384
163*e0c4386eSCy Schubert        my @ciphersuites = (TLSProxy::Message::CIPHER_TLS13_AES_128_GCM_SHA256);
164*e0c4386eSCy Schubert        $ch1->ciphersuite_len(2 * scalar @ciphersuites);
165*e0c4386eSCy Schubert        $ch1->ciphersuites(\@ciphersuites);
166*e0c4386eSCy Schubert    } elsif ($testtype == INVALID_GROUP) {
167*e0c4386eSCy Schubert        # INVALID_GROUP
168*e0c4386eSCy Schubert        my $ext = pack "C7",
169*e0c4386eSCy Schubert            0x00, 0x05, #List Length
170*e0c4386eSCy Schubert            0x00, 0x1c, #brainpoolP512r1 (not compatible with TLSv1.3)
171*e0c4386eSCy Schubert            0x00, 0x01, 0xff; #key_exchange data
172*e0c4386eSCy Schubert        $ch1->set_extension(
173*e0c4386eSCy Schubert            TLSProxy::Message::EXT_KEY_SHARE, $ext);
174*e0c4386eSCy Schubert    }
175*e0c4386eSCy Schubert    $ch1->repack();
176*e0c4386eSCy Schubert}
177