105901b04Schristos#! /usr/bin/env perl
2aa42b575Schristos# Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
305901b04Schristos#
4*66bae5e7Schristos# Licensed under the Apache License 2.0 (the "License").  You may not use
505901b04Schristos# this file except in compliance with the License.  You can obtain a copy
605901b04Schristos# in the file LICENSE in the source distribution or at
705901b04Schristos# https://www.openssl.org/source/license.html
805901b04Schristos
905901b04Schristosuse strict;
1005901b04Schristosuse OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
1105901b04Schristosuse OpenSSL::Test::Utils;
1205901b04Schristosuse TLSProxy::Proxy;
1305901b04Schristos
1405901b04Schristosmy $test_name = "test_tls13hrr";
1505901b04Schristossetup($test_name);
1605901b04Schristos
1705901b04Schristosplan skip_all => "TLSProxy isn't usable on $^O"
1805901b04Schristos    if $^O =~ /^(VMS)$/;
1905901b04Schristos
2005901b04Schristosplan skip_all => "$test_name needs the dynamic engine feature enabled"
2105901b04Schristos    if disabled("engine") || disabled("dynamic-engine");
2205901b04Schristos
2305901b04Schristosplan skip_all => "$test_name needs the sock feature enabled"
2405901b04Schristos    if disabled("sock");
2505901b04Schristos
2605901b04Schristosplan skip_all => "$test_name needs TLS1.3 enabled"
27*66bae5e7Schristos    if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
2805901b04Schristos
2905901b04Schristos$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
3005901b04Schristos
3105901b04Schristosmy $proxy = TLSProxy::Proxy->new(
3205901b04Schristos    undef,
3305901b04Schristos    cmdstr(app(["openssl"]), display => 1),
3405901b04Schristos    srctop_file("apps", "server.pem"),
3505901b04Schristos    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
3605901b04Schristos);
3705901b04Schristos
3805901b04Schristosuse constant {
3905901b04Schristos    CHANGE_HRR_CIPHERSUITE => 0,
40aa42b575Schristos    CHANGE_CH1_CIPHERSUITE => 1,
41aa42b575Schristos    DUPLICATE_HRR => 2
4205901b04Schristos};
4305901b04Schristos
4405901b04Schristos#Test 1: A client should fail if the server changes the ciphersuite between the
4505901b04Schristos#        HRR and the SH
4605901b04Schristos$proxy->filter(\&hrr_filter);
47*66bae5e7Schristosif (disabled("ec")) {
48*66bae5e7Schristos    $proxy->serverflags("-curves ffdhe3072");
49*66bae5e7Schristos} else {
5005901b04Schristos    $proxy->serverflags("-curves P-256");
51*66bae5e7Schristos}
5205901b04Schristosmy $testtype = CHANGE_HRR_CIPHERSUITE;
5305901b04Schristos$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
54aa42b575Schristosplan tests => 3;
5505901b04Schristosok(TLSProxy::Message->fail(), "Server ciphersuite changes");
5605901b04Schristos
5705901b04Schristos#Test 2: It is an error if the client changes the offered ciphersuites so that
5805901b04Schristos#        we end up selecting a different ciphersuite between HRR and the SH
5905901b04Schristos$proxy->clear();
60*66bae5e7Schristosif (disabled("ec")) {
61*66bae5e7Schristos    $proxy->serverflags("-curves ffdhe3072");
62*66bae5e7Schristos} else {
6305901b04Schristos    $proxy->serverflags("-curves P-256");
64*66bae5e7Schristos}
6505901b04Schristos$proxy->ciphersuitess("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384");
6605901b04Schristos$testtype = CHANGE_CH1_CIPHERSUITE;
6705901b04Schristos$proxy->start();
6805901b04Schristosok(TLSProxy::Message->fail(), "Client ciphersuite changes");
6905901b04Schristos
70aa42b575Schristos#Test 3: A client should fail with unexpected_message alert if the server
71aa42b575Schristos#        sends more than 1 HRR
72aa42b575Schristosmy $fatal_alert = 0;
73aa42b575Schristos$proxy->clear();
74aa42b575Schristosif (disabled("ec")) {
75aa42b575Schristos    $proxy->serverflags("-curves ffdhe3072");
76aa42b575Schristos} else {
77aa42b575Schristos    $proxy->serverflags("-curves P-256");
78aa42b575Schristos}
79aa42b575Schristos$testtype = DUPLICATE_HRR;
80aa42b575Schristos$proxy->start();
81aa42b575Schristosok($fatal_alert, "Server duplicated HRR");
82aa42b575Schristos
8305901b04Schristossub hrr_filter
8405901b04Schristos{
8505901b04Schristos    my $proxy = shift;
8605901b04Schristos
8705901b04Schristos    if ($testtype == CHANGE_HRR_CIPHERSUITE) {
8805901b04Schristos        # We're only interested in the HRR
8905901b04Schristos        if ($proxy->flight != 1) {
9005901b04Schristos            return;
9105901b04Schristos        }
9205901b04Schristos
9305901b04Schristos        my $hrr = ${$proxy->message_list}[1];
9405901b04Schristos
9505901b04Schristos        # We will normally only ever select CIPHER_TLS13_AES_128_GCM_SHA256
9605901b04Schristos        # because that's what Proxy tells s_server to do. Setting as below means
9705901b04Schristos        # the ciphersuite will change will we get the ServerHello
9805901b04Schristos        $hrr->ciphersuite(TLSProxy::Message::CIPHER_TLS13_AES_256_GCM_SHA384);
9905901b04Schristos        $hrr->repack();
10005901b04Schristos        return;
10105901b04Schristos    }
10205901b04Schristos
103aa42b575Schristos    if ($testtype == DUPLICATE_HRR) {
104aa42b575Schristos        # We're only interested in the HRR
105aa42b575Schristos        # and the unexpected_message alert from client
106aa42b575Schristos        if ($proxy->flight == 4) {
107aa42b575Schristos            $fatal_alert = 1
108aa42b575Schristos                if @{$proxy->record_list}[-1]->is_fatal_alert(0) == 10;
109aa42b575Schristos            return;
110aa42b575Schristos        }
111aa42b575Schristos        if ($proxy->flight != 3) {
112aa42b575Schristos            return;
113aa42b575Schristos        }
114aa42b575Schristos
115aa42b575Schristos        # Find ServerHello record (HRR actually) and insert after that
116aa42b575Schristos        my $i;
117aa42b575Schristos        for ($i = 0; ${$proxy->record_list}[$i]->flight() < 1; $i++) {
118aa42b575Schristos            next;
119aa42b575Schristos        }
120aa42b575Schristos        my $hrr_record = ${$proxy->record_list}[$i];
121aa42b575Schristos        my $dup_hrr = TLSProxy::Record->new(3,
122aa42b575Schristos            $hrr_record->content_type(),
123aa42b575Schristos            $hrr_record->version(),
124aa42b575Schristos            $hrr_record->len(),
125aa42b575Schristos            $hrr_record->sslv2(),
126aa42b575Schristos            $hrr_record->len_real(),
127aa42b575Schristos            $hrr_record->decrypt_len(),
128aa42b575Schristos            $hrr_record->data(),
129aa42b575Schristos            $hrr_record->decrypt_data());
130aa42b575Schristos
131aa42b575Schristos        $i++;
132aa42b575Schristos        splice @{$proxy->record_list}, $i, 0, $dup_hrr;
133aa42b575Schristos        return;
134aa42b575Schristos    }
135aa42b575Schristos
13605901b04Schristos    # CHANGE_CH1_CIPHERSUITE
13705901b04Schristos    if ($proxy->flight != 0) {
13805901b04Schristos        return;
13905901b04Schristos    }
14005901b04Schristos
14105901b04Schristos    my $ch1 = ${$proxy->message_list}[0];
14205901b04Schristos
14305901b04Schristos    # The server will always pick TLS_AES_256_GCM_SHA384
14405901b04Schristos    my @ciphersuites = (TLSProxy::Message::CIPHER_TLS13_AES_128_GCM_SHA256);
14505901b04Schristos    $ch1->ciphersuite_len(2 * scalar @ciphersuites);
14605901b04Schristos    $ch1->ciphersuites(\@ciphersuites);
14705901b04Schristos    $ch1->repack();
14805901b04Schristos}
149