2 # Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
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
10 use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file srctop_dir bldtop_dir/;
11 use OpenSSL::Test::Utils;
12 use File::Temp qw(tempfile);
14 use checkhandshake qw(checkhandshake @handmessages @extensions);
16 my $test_name = "test_tls13kexmodes";
19 plan skip_all => "TLSProxy isn't usable on $^O"
22 plan skip_all => "$test_name needs the dynamic engine feature enabled"
23 if disabled("engine") || disabled("dynamic-engine");
25 plan skip_all => "$test_name needs the sock feature enabled"
28 plan skip_all => "$test_name needs TLSv1.3 enabled"
29 if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
31 plan skip_all => "$test_name needs EC enabled"
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],
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],
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],
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],
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],
166 [TLSProxy::Message::MT_CERTIFICATE, TLSProxy::Message::EXT_STATUS_REQUEST,
167 TLSProxy::Message::SERVER,
168 checkhandshake::STATUS_REQUEST_SRV_EXTENSION],
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,
181 my $proxy = TLSProxy::Proxy->new(
183 cmdstr(app(["openssl"]), display => 1),
184 srctop_file("apps", "server.pem"),
185 (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
188 #Test 1: First get a session
189 (undef, my $session) = tempfile();
190 $proxy->clientflags("-no_rx_cert_comp -sess_out ".$session);
191 $proxy->serverflags("-no_rx_cert_comp -servername localhost");
192 $proxy->sessionfile($session);
193 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
195 ok(TLSProxy::Message->success(), "Initial connection");
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)
200 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
201 my $testtype = DELETE_EXTENSION;
202 $proxy->filter(\&modify_kex_modes_filter);
204 ok(TLSProxy::Message->fail(), "Resume with no kex modes");
206 #Test 3: Attempt a resume with empty kex modes extension. Should fail (empty
207 # extension is invalid)
209 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
210 $testtype = EMPTY_EXTENSION;
212 ok(TLSProxy::Message->fail(), "Resume with empty kex modes");
214 #Test 4: Attempt a resume with non-dhe kex mode only. Should resume without a
217 $proxy->clientflags("-no_rx_cert_comp -allow_no_dhe_kex -sess_in ".$session);
218 $proxy->serverflags("-no_rx_cert_comp -allow_no_dhe_kex");
219 $testtype = NON_DHE_KEX_MODE_ONLY;
221 checkhandshake($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");
228 #Test 5: Attempt a resume with dhe kex mode only. Should resume with a key_share
230 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
231 $testtype = DHE_KEX_MODE_ONLY;
233 checkhandshake($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");
241 #Test 6: Attempt a resume with only unrecognised kex modes. Should not resume
242 # but rather fall back to full handshake
244 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
245 $testtype = UNKNOWN_KEX_MODES;
247 checkhandshake($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");
254 #Test 7: Attempt a resume with both non-dhe and dhe kex mode. Should resume with
257 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
258 $testtype = BOTH_KEX_MODES;
260 checkhandshake($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");
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
271 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
272 $proxy->serverflags("-no_rx_cert_comp -curves P-256");
273 $testtype = BOTH_KEX_MODES;
275 checkhandshake($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");
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
287 $proxy->clientflags("-no_rx_cert_comp -sess_in ".$session);
288 $proxy->serverflags("-no_rx_cert_comp -curves P-256");
289 $testtype = DHE_KEX_MODE_ONLY;
291 checkhandshake($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");
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
304 $proxy->clientflags("-no_rx_cert_comp -allow_no_dhe_kex -curves P-384 -sess_in ".$session);
305 $proxy->serverflags("-no_rx_cert_comp -allow_no_dhe_kex -curves P-256");
306 $testtype = BOTH_KEX_MODES;
308 checkhandshake($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");
315 #Test 11: Attempt a resume with dhe kex mode only, unacceptable
316 # initial key_share and no overlapping groups. Should fail
318 $proxy->clientflags("-no_rx_cert_comp -curves P-384 -sess_in ".$session);
319 $proxy->serverflags("-no_rx_cert_comp -curves P-256");
320 $testtype = DHE_KEX_MODE_ONLY;
322 ok(TLSProxy::Message->fail(), "Resume with dhe kex mode, no overlapping groups");
326 sub modify_kex_modes_filter
330 # We're only interested in the initial ClientHello
331 return if ($proxy->flight != 0);
333 foreach my $message (@{$proxy->message_list}) {
334 if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
337 if ($testtype == EMPTY_EXTENSION) {
340 } elsif ($testtype == NON_DHE_KEX_MODE_ONLY) {
344 } elsif ($testtype == DHE_KEX_MODE_ONLY) {
348 } elsif ($testtype == UNKNOWN_KEX_MODES) {
353 } elsif ($testtype == BOTH_KEX_MODES) {
354 #We deliberately list psk_ke first...should still use psk_dhe_ke
361 if ($testtype == DELETE_EXTENSION) {
362 $message->delete_extension(
363 TLSProxy::Message::EXT_PSK_KEX_MODES);
365 $message->set_extension(
366 TLSProxy::Message::EXT_PSK_KEX_MODES, $ext);