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