1#! /usr/bin/env perl 2# Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved. 3# 4# Licensed under the Apache License 2.0 (the "License"). You may not use 5# this file except in compliance with the License. You can obtain a copy 6# in the file LICENSE in the source distribution or at 7# https://www.openssl.org/source/license.html 8 9use strict; 10use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/; 11use OpenSSL::Test::Utils; 12use File::Temp qw(tempfile); 13use TLSProxy::Proxy; 14use checkhandshake qw(checkhandshake @handmessages @extensions); 15 16my $test_name = "test_tls13kexmodes"; 17setup($test_name); 18 19plan skip_all => "TLSProxy isn't usable on $^O" 20 if $^O =~ /^(VMS)$/; 21 22plan skip_all => "$test_name needs the dynamic engine feature enabled" 23 if disabled("engine") || disabled("dynamic-engine"); 24 25plan skip_all => "$test_name needs the sock feature enabled" 26 if disabled("sock"); 27 28plan skip_all => "$test_name needs TLSv1.3 enabled" 29 if disabled("tls1_3") || (disabled("ec") && disabled("dh")); 30 31plan skip_all => "$test_name needs EC enabled" 32 if disabled("ec"); 33 34@handmessages = ( 35 [TLSProxy::Message::MT_CLIENT_HELLO, 36 checkhandshake::ALL_HANDSHAKES], 37 [TLSProxy::Message::MT_SERVER_HELLO, 38 checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], 39 [TLSProxy::Message::MT_CLIENT_HELLO, 40 checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE], 41 [TLSProxy::Message::MT_SERVER_HELLO, 42 checkhandshake::ALL_HANDSHAKES], 43 [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS, 44 checkhandshake::ALL_HANDSHAKES], 45 [TLSProxy::Message::MT_CERTIFICATE_REQUEST, 46 checkhandshake::CLIENT_AUTH_HANDSHAKE], 47 [TLSProxy::Message::MT_CERTIFICATE, 48 checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)], 49 [TLSProxy::Message::MT_CERTIFICATE_VERIFY, 50 checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)], 51 [TLSProxy::Message::MT_FINISHED, 52 checkhandshake::ALL_HANDSHAKES], 53 [TLSProxy::Message::MT_CERTIFICATE, 54 checkhandshake::CLIENT_AUTH_HANDSHAKE], 55 [TLSProxy::Message::MT_CERTIFICATE_VERIFY, 56 checkhandshake::CLIENT_AUTH_HANDSHAKE], 57 [TLSProxy::Message::MT_FINISHED, 58 checkhandshake::ALL_HANDSHAKES], 59 [0, 0] 60); 61 62@extensions = ( 63 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, 64 TLSProxy::Message::CLIENT, 65 checkhandshake::SERVER_NAME_CLI_EXTENSION], 66 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST, 67 TLSProxy::Message::CLIENT, 68 checkhandshake::STATUS_REQUEST_CLI_EXTENSION], 69 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS, 70 TLSProxy::Message::CLIENT, 71 checkhandshake::DEFAULT_EXTENSIONS], 72 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS, 73 TLSProxy::Message::CLIENT, 74 checkhandshake::DEFAULT_EXTENSIONS], 75 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS, 76 TLSProxy::Message::CLIENT, 77 checkhandshake::DEFAULT_EXTENSIONS], 78 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN, 79 TLSProxy::Message::CLIENT, 80 checkhandshake::ALPN_CLI_EXTENSION], 81 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT, 82 TLSProxy::Message::CLIENT, 83 checkhandshake::SCT_CLI_EXTENSION], 84 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC, 85 TLSProxy::Message::CLIENT, 86 checkhandshake::DEFAULT_EXTENSIONS], 87 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET, 88 TLSProxy::Message::CLIENT, 89 checkhandshake::DEFAULT_EXTENSIONS], 90 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET, 91 TLSProxy::Message::CLIENT, 92 checkhandshake::DEFAULT_EXTENSIONS], 93 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE, 94 TLSProxy::Message::CLIENT, 95 checkhandshake::DEFAULT_EXTENSIONS], 96 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, 97 TLSProxy::Message::CLIENT, 98 checkhandshake::DEFAULT_EXTENSIONS], 99 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES, 100 TLSProxy::Message::CLIENT, 101 checkhandshake::PSK_KEX_MODES_EXTENSION], 102 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, 103 TLSProxy::Message::CLIENT, 104 checkhandshake::PSK_CLI_EXTENSION], 105 106 [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, 107 TLSProxy::Message::SERVER, 108 checkhandshake::DEFAULT_EXTENSIONS], 109 [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, 110 TLSProxy::Message::SERVER, 111 checkhandshake::KEY_SHARE_HRR_EXTENSION], 112 113 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME, 114 TLSProxy::Message::CLIENT, 115 checkhandshake::SERVER_NAME_CLI_EXTENSION], 116 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST, 117 TLSProxy::Message::CLIENT, 118 checkhandshake::STATUS_REQUEST_CLI_EXTENSION], 119 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS, 120 TLSProxy::Message::CLIENT, 121 checkhandshake::DEFAULT_EXTENSIONS], 122 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EC_POINT_FORMATS, 123 TLSProxy::Message::CLIENT, 124 checkhandshake::DEFAULT_EXTENSIONS], 125 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS, 126 TLSProxy::Message::CLIENT, 127 checkhandshake::DEFAULT_EXTENSIONS], 128 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN, 129 TLSProxy::Message::CLIENT, 130 checkhandshake::ALPN_CLI_EXTENSION], 131 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT, 132 TLSProxy::Message::CLIENT, 133 checkhandshake::SCT_CLI_EXTENSION], 134 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ENCRYPT_THEN_MAC, 135 TLSProxy::Message::CLIENT, 136 checkhandshake::DEFAULT_EXTENSIONS], 137 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_EXTENDED_MASTER_SECRET, 138 TLSProxy::Message::CLIENT, 139 checkhandshake::DEFAULT_EXTENSIONS], 140 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SESSION_TICKET, 141 TLSProxy::Message::CLIENT, 142 checkhandshake::DEFAULT_EXTENSIONS], 143 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE, 144 TLSProxy::Message::CLIENT, 145 checkhandshake::DEFAULT_EXTENSIONS], 146 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, 147 TLSProxy::Message::CLIENT, 148 checkhandshake::DEFAULT_EXTENSIONS], 149 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES, 150 TLSProxy::Message::CLIENT, 151 checkhandshake::PSK_KEX_MODES_EXTENSION], 152 [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK, 153 TLSProxy::Message::CLIENT, 154 checkhandshake::PSK_CLI_EXTENSION], 155 156 [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS, 157 TLSProxy::Message::SERVER, 158 checkhandshake::DEFAULT_EXTENSIONS], 159 [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE, 160 TLSProxy::Message::SERVER, 161 checkhandshake::KEY_SHARE_SRV_EXTENSION], 162 [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK, 163 TLSProxy::Message::SERVER, 164 checkhandshake::PSK_SRV_EXTENSION], 165 166 [TLSProxy::Message::MT_CERTIFICATE, TLSProxy::Message::EXT_STATUS_REQUEST, 167 TLSProxy::Message::SERVER, 168 checkhandshake::STATUS_REQUEST_SRV_EXTENSION], 169 [0,0,0,0] 170); 171 172use constant { 173 DELETE_EXTENSION => 0, 174 EMPTY_EXTENSION => 1, 175 NON_DHE_KEX_MODE_ONLY => 2, 176 DHE_KEX_MODE_ONLY => 3, 177 UNKNOWN_KEX_MODES => 4, 178 BOTH_KEX_MODES => 5 179}; 180 181my $proxy = TLSProxy::Proxy->new( 182 undef, 183 cmdstr(app(["openssl"]), display => 1), 184 srctop_file("apps", "server.pem"), 185 (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) 186); 187 188#Test 1: First get a session 189(undef, my $session) = tempfile(); 190$proxy->clientflags("-sess_out ".$session); 191$proxy->serverflags("-servername localhost"); 192$proxy->sessionfile($session); 193$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; 194plan tests => 11; 195ok(TLSProxy::Message->success(), "Initial connection"); 196 197#Test 2: Attempt a resume with no kex modes extension. Should fail (server 198# MUST abort handshake with pre_shared key and no psk_kex_modes) 199$proxy->clear(); 200$proxy->clientflags("-sess_in ".$session); 201my $testtype = DELETE_EXTENSION; 202$proxy->filter(\&modify_kex_modes_filter); 203$proxy->start(); 204ok(TLSProxy::Message->fail(), "Resume with no kex modes"); 205 206#Test 3: Attempt a resume with empty kex modes extension. Should fail (empty 207# extension is invalid) 208$proxy->clear(); 209$proxy->clientflags("-sess_in ".$session); 210$testtype = EMPTY_EXTENSION; 211$proxy->start(); 212ok(TLSProxy::Message->fail(), "Resume with empty kex modes"); 213 214#Test 4: Attempt a resume with non-dhe kex mode only. Should resume without a 215# key_share 216$proxy->clear(); 217$proxy->clientflags("-allow_no_dhe_kex -sess_in ".$session); 218$proxy->serverflags("-allow_no_dhe_kex"); 219$testtype = NON_DHE_KEX_MODE_ONLY; 220$proxy->start(); 221checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE, 222 checkhandshake::DEFAULT_EXTENSIONS 223 | checkhandshake::PSK_KEX_MODES_EXTENSION 224 | checkhandshake::PSK_CLI_EXTENSION 225 | checkhandshake::PSK_SRV_EXTENSION, 226 "Resume with non-dhe kex mode"); 227 228#Test 5: Attempt a resume with dhe kex mode only. Should resume with a key_share 229$proxy->clear(); 230$proxy->clientflags("-sess_in ".$session); 231$testtype = DHE_KEX_MODE_ONLY; 232$proxy->start(); 233checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE, 234 checkhandshake::DEFAULT_EXTENSIONS 235 | checkhandshake::PSK_KEX_MODES_EXTENSION 236 | checkhandshake::KEY_SHARE_SRV_EXTENSION 237 | checkhandshake::PSK_CLI_EXTENSION 238 | checkhandshake::PSK_SRV_EXTENSION, 239 "Resume with non-dhe kex mode"); 240 241#Test 6: Attempt a resume with only unrecognised kex modes. Should not resume 242# but rather fall back to full handshake 243$proxy->clear(); 244$proxy->clientflags("-sess_in ".$session); 245$testtype = UNKNOWN_KEX_MODES; 246$proxy->start(); 247checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE, 248 checkhandshake::DEFAULT_EXTENSIONS 249 | checkhandshake::PSK_KEX_MODES_EXTENSION 250 | checkhandshake::KEY_SHARE_SRV_EXTENSION 251 | checkhandshake::PSK_CLI_EXTENSION, 252 "Resume with unrecognized kex mode"); 253 254#Test 7: Attempt a resume with both non-dhe and dhe kex mode. Should resume with 255# a key_share 256$proxy->clear(); 257$proxy->clientflags("-sess_in ".$session); 258$testtype = BOTH_KEX_MODES; 259$proxy->start(); 260checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE, 261 checkhandshake::DEFAULT_EXTENSIONS 262 | checkhandshake::PSK_KEX_MODES_EXTENSION 263 | checkhandshake::KEY_SHARE_SRV_EXTENSION 264 | checkhandshake::PSK_CLI_EXTENSION 265 | checkhandshake::PSK_SRV_EXTENSION, 266 "Resume with non-dhe kex mode"); 267 268#Test 8: Attempt a resume with both non-dhe and dhe kex mode, but unacceptable 269# initial key_share. Should resume with a key_share following an HRR 270$proxy->clear(); 271$proxy->clientflags("-sess_in ".$session); 272$proxy->serverflags("-curves P-256"); 273$testtype = BOTH_KEX_MODES; 274$proxy->start(); 275checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE, 276 checkhandshake::DEFAULT_EXTENSIONS 277 | checkhandshake::PSK_KEX_MODES_EXTENSION 278 | checkhandshake::KEY_SHARE_SRV_EXTENSION 279 | checkhandshake::KEY_SHARE_HRR_EXTENSION 280 | checkhandshake::PSK_CLI_EXTENSION 281 | checkhandshake::PSK_SRV_EXTENSION, 282 "Resume with both kex modes and HRR"); 283 284#Test 9: Attempt a resume with dhe kex mode only and an unacceptable initial 285# key_share. Should resume with a key_share following an HRR 286$proxy->clear(); 287$proxy->clientflags("-sess_in ".$session); 288$proxy->serverflags("-curves P-256"); 289$testtype = DHE_KEX_MODE_ONLY; 290$proxy->start(); 291checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE, 292 checkhandshake::DEFAULT_EXTENSIONS 293 | checkhandshake::PSK_KEX_MODES_EXTENSION 294 | checkhandshake::KEY_SHARE_SRV_EXTENSION 295 | checkhandshake::KEY_SHARE_HRR_EXTENSION 296 | checkhandshake::PSK_CLI_EXTENSION 297 | checkhandshake::PSK_SRV_EXTENSION, 298 "Resume with dhe kex mode and HRR"); 299 300#Test 10: Attempt a resume with both non-dhe and dhe kex mode, unacceptable 301# initial key_share and no overlapping groups. Should resume without a 302# key_share 303$proxy->clear(); 304$proxy->clientflags("-allow_no_dhe_kex -curves P-384 -sess_in ".$session); 305$proxy->serverflags("-allow_no_dhe_kex -curves P-256"); 306$testtype = BOTH_KEX_MODES; 307$proxy->start(); 308checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE, 309 checkhandshake::DEFAULT_EXTENSIONS 310 | checkhandshake::PSK_KEX_MODES_EXTENSION 311 | checkhandshake::PSK_CLI_EXTENSION 312 | checkhandshake::PSK_SRV_EXTENSION, 313 "Resume with both kex modes, no overlapping groups"); 314 315#Test 11: Attempt a resume with dhe kex mode only, unacceptable 316# initial key_share and no overlapping groups. Should fail 317$proxy->clear(); 318$proxy->clientflags("-curves P-384 -sess_in ".$session); 319$proxy->serverflags("-curves P-256"); 320$testtype = DHE_KEX_MODE_ONLY; 321$proxy->start(); 322ok(TLSProxy::Message->fail(), "Resume with dhe kex mode, no overlapping groups"); 323 324unlink $session; 325 326sub modify_kex_modes_filter 327{ 328 my $proxy = shift; 329 330 # We're only interested in the initial ClientHello 331 return if ($proxy->flight != 0); 332 333 foreach my $message (@{$proxy->message_list}) { 334 if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) { 335 my $ext; 336 337 if ($testtype == EMPTY_EXTENSION) { 338 $ext = pack "C", 339 0x00; #List length 340 } elsif ($testtype == NON_DHE_KEX_MODE_ONLY) { 341 $ext = pack "C2", 342 0x01, #List length 343 0x00; #psk_ke 344 } elsif ($testtype == DHE_KEX_MODE_ONLY) { 345 $ext = pack "C2", 346 0x01, #List length 347 0x01; #psk_dhe_ke 348 } elsif ($testtype == UNKNOWN_KEX_MODES) { 349 $ext = pack "C3", 350 0x02, #List length 351 0xfe, #unknown 352 0xff; #unknown 353 } elsif ($testtype == BOTH_KEX_MODES) { 354 #We deliberately list psk_ke first...should still use psk_dhe_ke 355 $ext = pack "C3", 356 0x02, #List length 357 0x00, #psk_ke 358 0x01; #psk_dhe_ke 359 } 360 361 if ($testtype == DELETE_EXTENSION) { 362 $message->delete_extension( 363 TLSProxy::Message::EXT_PSK_KEX_MODES); 364 } else { 365 $message->set_extension( 366 TLSProxy::Message::EXT_PSK_KEX_MODES, $ext); 367 } 368 369 $message->repack(); 370 } 371 } 372} 373