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