Home | History | Annotate | Line # | Download | only in recipes
      1  1.1  christos #! /usr/bin/env perl
      2  1.1  christos # Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
      3  1.1  christos #
      4  1.1  christos # Licensed under the OpenSSL license (the "License").  You may not use
      5  1.1  christos # this file except in compliance with the License.  You can obtain a copy
      6  1.1  christos # in the file LICENSE in the source distribution or at
      7  1.1  christos # https://www.openssl.org/source/license.html
      8  1.1  christos 
      9  1.1  christos use strict;
     10  1.1  christos use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
     11  1.1  christos use OpenSSL::Test::Utils;
     12  1.1  christos use TLSProxy::Proxy;
     13  1.1  christos 
     14  1.1  christos my $test_name = "test_tls13hrr";
     15  1.1  christos setup($test_name);
     16  1.1  christos 
     17  1.1  christos plan skip_all => "TLSProxy isn't usable on $^O"
     18  1.1  christos     if $^O =~ /^(VMS)$/;
     19  1.1  christos 
     20  1.1  christos plan skip_all => "$test_name needs the dynamic engine feature enabled"
     21  1.1  christos     if disabled("engine") || disabled("dynamic-engine");
     22  1.1  christos 
     23  1.1  christos plan skip_all => "$test_name needs the sock feature enabled"
     24  1.1  christos     if disabled("sock");
     25  1.1  christos 
     26  1.1  christos plan skip_all => "$test_name needs TLS1.3 enabled"
     27  1.1  christos     if disabled("tls1_3");
     28  1.1  christos 
     29  1.1  christos $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
     30  1.1  christos 
     31  1.1  christos my $proxy = TLSProxy::Proxy->new(
     32  1.1  christos     undef,
     33  1.1  christos     cmdstr(app(["openssl"]), display => 1),
     34  1.1  christos     srctop_file("apps", "server.pem"),
     35  1.1  christos     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
     36  1.1  christos );
     37  1.1  christos 
     38  1.1  christos use constant {
     39  1.1  christos     CHANGE_HRR_CIPHERSUITE => 0,
     40  1.1  christos     CHANGE_CH1_CIPHERSUITE => 1,
     41  1.1  christos     DUPLICATE_HRR => 2
     42  1.1  christos };
     43  1.1  christos 
     44  1.1  christos #Test 1: A client should fail if the server changes the ciphersuite between the
     45  1.1  christos #        HRR and the SH
     46  1.1  christos $proxy->filter(\&hrr_filter);
     47  1.1  christos $proxy->serverflags("-curves P-256");
     48  1.1  christos my $testtype = CHANGE_HRR_CIPHERSUITE;
     49  1.1  christos $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
     50  1.1  christos plan tests => 3;
     51  1.1  christos ok(TLSProxy::Message->fail(), "Server ciphersuite changes");
     52  1.1  christos 
     53  1.1  christos #Test 2: It is an error if the client changes the offered ciphersuites so that
     54  1.1  christos #        we end up selecting a different ciphersuite between HRR and the SH
     55  1.1  christos $proxy->clear();
     56  1.1  christos $proxy->serverflags("-curves P-256");
     57  1.1  christos $proxy->ciphersuitess("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384");
     58  1.1  christos $testtype = CHANGE_CH1_CIPHERSUITE;
     59  1.1  christos $proxy->start();
     60  1.1  christos ok(TLSProxy::Message->fail(), "Client ciphersuite changes");
     61  1.1  christos 
     62  1.1  christos #Test 3: A client should fail with unexpected_message alert if the server
     63  1.1  christos #        sends more than 1 HRR
     64  1.1  christos my $fatal_alert = 0;
     65  1.1  christos $proxy->clear();
     66  1.1  christos if (disabled("ec")) {
     67  1.1  christos     $proxy->serverflags("-curves ffdhe3072");
     68  1.1  christos } else {
     69  1.1  christos     $proxy->serverflags("-curves P-256");
     70  1.1  christos }
     71  1.1  christos $testtype = DUPLICATE_HRR;
     72  1.1  christos $proxy->start();
     73  1.1  christos ok($fatal_alert, "Server duplicated HRR");
     74  1.1  christos 
     75  1.1  christos sub hrr_filter
     76  1.1  christos {
     77  1.1  christos     my $proxy = shift;
     78  1.1  christos 
     79  1.1  christos     if ($testtype == CHANGE_HRR_CIPHERSUITE) {
     80  1.1  christos         # We're only interested in the HRR
     81  1.1  christos         if ($proxy->flight != 1) {
     82  1.1  christos             return;
     83  1.1  christos         }
     84  1.1  christos 
     85  1.1  christos         my $hrr = ${$proxy->message_list}[1];
     86  1.1  christos 
     87  1.1  christos         # We will normally only ever select CIPHER_TLS13_AES_128_GCM_SHA256
     88  1.1  christos         # because that's what Proxy tells s_server to do. Setting as below means
     89  1.1  christos         # the ciphersuite will change will we get the ServerHello
     90  1.1  christos         $hrr->ciphersuite(TLSProxy::Message::CIPHER_TLS13_AES_256_GCM_SHA384);
     91  1.1  christos         $hrr->repack();
     92  1.1  christos         return;
     93  1.1  christos     }
     94  1.1  christos 
     95  1.1  christos     if ($testtype == DUPLICATE_HRR) {
     96  1.1  christos         # We're only interested in the HRR
     97  1.1  christos         # and the unexpected_message alert from client
     98  1.1  christos         if ($proxy->flight == 4) {
     99  1.1  christos             $fatal_alert = 1
    100  1.1  christos                 if @{$proxy->record_list}[-1]->is_fatal_alert(0) == 10;
    101  1.1  christos             return;
    102  1.1  christos         }
    103  1.1  christos         if ($proxy->flight != 3) {
    104  1.1  christos             return;
    105  1.1  christos         }
    106  1.1  christos 
    107  1.1  christos         # Find ServerHello record (HRR actually) and insert after that
    108  1.1  christos         my $i;
    109  1.1  christos         for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
    110  1.1  christos             next;
    111  1.1  christos         }
    112  1.1  christos         my $hrr_record = ${$proxy->record_list}[$i];
    113  1.1  christos         my $dup_hrr = TLSProxy::Record->new(3,
    114  1.1  christos             $hrr_record->content_type(),
    115  1.1  christos             $hrr_record->version(),
    116  1.1  christos             $hrr_record->len(),
    117  1.1  christos             $hrr_record->sslv2(),
    118  1.1  christos             $hrr_record->len_real(),
    119  1.1  christos             $hrr_record->decrypt_len(),
    120  1.1  christos             $hrr_record->data(),
    121  1.1  christos             $hrr_record->decrypt_data());
    122  1.1  christos 
    123  1.1  christos         $i++;
    124  1.1  christos         splice @{$proxy->record_list}, $i, 0, $dup_hrr;
    125  1.1  christos         return;
    126  1.1  christos     }
    127  1.1  christos 
    128  1.1  christos     # CHANGE_CH1_CIPHERSUITE
    129  1.1  christos     if ($proxy->flight != 0) {
    130  1.1  christos         return;
    131  1.1  christos     }
    132  1.1  christos 
    133  1.1  christos     my $ch1 = ${$proxy->message_list}[0];
    134  1.1  christos 
    135  1.1  christos     # The server will always pick TLS_AES_256_GCM_SHA384
    136  1.1  christos     my @ciphersuites = (TLSProxy::Message::CIPHER_TLS13_AES_128_GCM_SHA256);
    137  1.1  christos     $ch1->ciphersuite_len(2 * scalar @ciphersuites);
    138  1.1  christos     $ch1->ciphersuites(\@ciphersuites);
    139  1.1  christos     $ch1->repack();
    140  1.1  christos }
    141