]>
Commit | Line | Data |
---|---|---|
5a8e54d9 | 1 | #! /usr/bin/env perl |
6738bf14 | 2 | # Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. |
5a8e54d9 | 3 | # |
909f1a2e | 4 | # Licensed under the Apache License 2.0 (the "License"). You may not use |
5a8e54d9 MC |
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 | ||
9 | use strict; | |
10 | use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; | |
11 | use OpenSSL::Test::Utils; | |
12 | use TLSProxy::Proxy; | |
13 | use File::Temp qw(tempfile); | |
14 | ||
15 | use constant { | |
16 | LOOK_ONLY => 0, | |
17 | EMPTY_EXTENSION => 1, | |
18 | MISSING_EXTENSION => 2, | |
19 | NO_ACCEPTABLE_KEY_SHARES => 3, | |
20 | NON_PREFERRED_KEY_SHARE => 4, | |
21 | ACCEPTABLE_AT_END => 5, | |
22 | NOT_IN_SUPPORTED_GROUPS => 6, | |
23 | GROUP_ID_TOO_SHORT => 7, | |
24 | KEX_LEN_MISMATCH => 8, | |
25 | ZERO_LEN_KEX_DATA => 9, | |
26 | TRAILING_DATA => 10, | |
5e3766e2 MC |
27 | SELECT_X25519 => 11, |
28 | NO_KEY_SHARES_IN_HRR => 12 | |
5a8e54d9 MC |
29 | }; |
30 | ||
31 | use constant { | |
32 | CLIENT_TO_SERVER => 1, | |
33 | SERVER_TO_CLIENT => 2 | |
34 | }; | |
35 | ||
36 | ||
37 | use constant { | |
38 | X25519 => 0x1d, | |
dbc6268f MC |
39 | P_256 => 0x17, |
40 | FFDHE2048 => 0x0100, | |
41 | FFDHE3072 => 0x0101 | |
5a8e54d9 MC |
42 | }; |
43 | ||
44 | my $testtype; | |
45 | my $direction; | |
46 | my $selectedgroupid; | |
47 | ||
48 | my $test_name = "test_key_share"; | |
49 | setup($test_name); | |
50 | ||
51 | plan skip_all => "TLSProxy isn't usable on $^O" | |
c5856878 | 52 | if $^O =~ /^(VMS)$/; |
5a8e54d9 MC |
53 | |
54 | plan skip_all => "$test_name needs the dynamic engine feature enabled" | |
55 | if disabled("engine") || disabled("dynamic-engine"); | |
56 | ||
57 | plan skip_all => "$test_name needs the sock feature enabled" | |
58 | if disabled("sock"); | |
59 | ||
60 | plan skip_all => "$test_name needs TLS1.3 enabled" | |
61 | if disabled("tls1_3"); | |
62 | ||
63 | $ENV{OPENSSL_ia32cap} = '~0x200000200000000'; | |
64 | ||
65 | my $proxy = TLSProxy::Proxy->new( | |
66 | undef, | |
67 | cmdstr(app(["openssl"]), display => 1), | |
68 | srctop_file("apps", "server.pem"), | |
69 | (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) | |
70 | ); | |
71 | ||
72 | #We assume that test_ssl_new and friends will test the happy path for this, | |
73 | #so we concentrate on the less common scenarios | |
74 | ||
38f5c30b | 75 | #Test 1: An empty key_shares extension should succeed after a HelloRetryRequest |
5a8e54d9 MC |
76 | $testtype = EMPTY_EXTENSION; |
77 | $direction = CLIENT_TO_SERVER; | |
78 | $proxy->filter(\&modify_key_shares_filter); | |
dbc6268f MC |
79 | if (disabled("ec")) { |
80 | $proxy->serverflags("-groups ffdhe3072"); | |
81 | } else { | |
82 | $proxy->serverflags("-groups P-256"); | |
83 | } | |
5a8e54d9 | 84 | $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; |
5e3766e2 | 85 | plan tests => 22; |
38f5c30b | 86 | ok(TLSProxy::Message->success(), "Success after HRR"); |
5a8e54d9 | 87 | |
38f5c30b MC |
88 | #Test 2: The server sending an HRR requesting a group the client already sent |
89 | # should fail | |
90 | $proxy->clear(); | |
91 | $proxy->start(); | |
92 | ok(TLSProxy::Message->fail(), "Server asks for group already provided"); | |
93 | ||
94 | #Test 3: A missing key_shares extension should not succeed | |
5a8e54d9 MC |
95 | $proxy->clear(); |
96 | $testtype = MISSING_EXTENSION; | |
97 | $proxy->start(); | |
5a8e54d9 MC |
98 | ok(TLSProxy::Message->fail(), "Missing key_shares extension"); |
99 | ||
38f5c30b MC |
100 | #Test 4: No initial acceptable key_shares should succeed after a |
101 | # HelloRetryRequest | |
5a8e54d9 | 102 | $proxy->clear(); |
38f5c30b | 103 | $proxy->filter(undef); |
dbc6268f MC |
104 | if (disabled("ec")) { |
105 | $proxy->serverflags("-groups ffdhe3072"); | |
106 | } else { | |
107 | $proxy->serverflags("-groups P-256"); | |
108 | } | |
5a8e54d9 | 109 | $proxy->start(); |
38f5c30b | 110 | ok(TLSProxy::Message->success(), "No initial acceptable key_shares"); |
5a8e54d9 | 111 | |
38f5c30b | 112 | #Test 5: No acceptable key_shares and no shared groups should fail |
5a8e54d9 MC |
113 | $proxy->clear(); |
114 | $proxy->filter(undef); | |
dbc6268f MC |
115 | if (disabled("ec")) { |
116 | $proxy->serverflags("-groups ffdhe2048"); | |
117 | } else { | |
118 | $proxy->serverflags("-groups P-256"); | |
119 | } | |
120 | if (disabled("ec")) { | |
121 | $proxy->clientflags("-groups ffdhe3072"); | |
122 | } else { | |
123 | $proxy->clientflags("-groups P-384"); | |
124 | } | |
38f5c30b MC |
125 | $proxy->start(); |
126 | ok(TLSProxy::Message->fail(), "No acceptable key_shares"); | |
127 | ||
128 | #Test 6: A non preferred but acceptable key_share should succeed | |
129 | $proxy->clear(); | |
5a8e54d9 | 130 | $proxy->clientflags("-curves P-256"); |
dbc6268f MC |
131 | if (disabled("ec")) { |
132 | $proxy->clientflags("-groups ffdhe3072"); | |
133 | } else { | |
134 | $proxy->clientflags("-groups P-256"); | |
135 | } | |
5a8e54d9 MC |
136 | $proxy->start(); |
137 | ok(TLSProxy::Message->success(), "Non preferred key_share"); | |
138 | $proxy->filter(\&modify_key_shares_filter); | |
139 | ||
dbc6268f MC |
140 | SKIP: { |
141 | skip "No ec support in this OpenSSL build", 1 if disabled("ec"); | |
142 | ||
143 | #Test 7: An acceptable key_share after a list of non-acceptable ones should | |
144 | #succeed | |
145 | $proxy->clear(); | |
146 | $testtype = ACCEPTABLE_AT_END; | |
147 | $proxy->start(); | |
148 | ok(TLSProxy::Message->success(), "Acceptable key_share at end of list"); | |
149 | } | |
5a8e54d9 | 150 | |
38f5c30b | 151 | #Test 8: An acceptable key_share but for a group not in supported_groups should |
5a8e54d9 MC |
152 | #fail |
153 | $proxy->clear(); | |
154 | $testtype = NOT_IN_SUPPORTED_GROUPS; | |
155 | $proxy->start(); | |
156 | ok(TLSProxy::Message->fail(), "Acceptable key_share not in supported_groups"); | |
157 | ||
38f5c30b | 158 | #Test 9: Too short group_id should fail |
5a8e54d9 MC |
159 | $proxy->clear(); |
160 | $testtype = GROUP_ID_TOO_SHORT; | |
161 | $proxy->start(); | |
162 | ok(TLSProxy::Message->fail(), "Group id too short"); | |
163 | ||
38f5c30b | 164 | #Test 10: key_exchange length mismatch should fail |
5a8e54d9 MC |
165 | $proxy->clear(); |
166 | $testtype = KEX_LEN_MISMATCH; | |
167 | $proxy->start(); | |
168 | ok(TLSProxy::Message->fail(), "key_exchange length mismatch"); | |
169 | ||
38f5c30b | 170 | #Test 11: Zero length key_exchange should fail |
5a8e54d9 MC |
171 | $proxy->clear(); |
172 | $testtype = ZERO_LEN_KEX_DATA; | |
173 | $proxy->start(); | |
174 | ok(TLSProxy::Message->fail(), "zero length key_exchange data"); | |
175 | ||
38f5c30b | 176 | #Test 12: Trailing data on key_share list should fail |
5a8e54d9 MC |
177 | $proxy->clear(); |
178 | $testtype = TRAILING_DATA; | |
179 | $proxy->start(); | |
180 | ok(TLSProxy::Message->fail(), "key_share list trailing data"); | |
181 | ||
38f5c30b | 182 | #Test 13: Multiple acceptable key_shares - we choose the first one |
5a8e54d9 MC |
183 | $proxy->clear(); |
184 | $direction = SERVER_TO_CLIENT; | |
185 | $testtype = LOOK_ONLY; | |
dbc6268f MC |
186 | $selectedgroupid = 0; |
187 | if (disabled("ec")) { | |
188 | $proxy->clientflags("-groups ffdhe3072:ffdhe2048"); | |
189 | } else { | |
190 | $proxy->clientflags("-groups P-256:X25519"); | |
191 | } | |
5a8e54d9 | 192 | $proxy->start(); |
dbc6268f MC |
193 | if (disabled("ec")) { |
194 | ok(TLSProxy::Message->success() && ($selectedgroupid == FFDHE3072), | |
195 | "Multiple acceptable key_shares"); | |
196 | } else { | |
197 | ok(TLSProxy::Message->success() && ($selectedgroupid == P_256), | |
198 | "Multiple acceptable key_shares"); | |
199 | } | |
5a8e54d9 | 200 | |
38f5c30b | 201 | #Test 14: Multiple acceptable key_shares - we choose the first one (part 2) |
5a8e54d9 | 202 | $proxy->clear(); |
dbc6268f MC |
203 | if (disabled("ec")) { |
204 | $proxy->clientflags("-curves ffdhe2048:ffdhe3072"); | |
205 | } else { | |
206 | $proxy->clientflags("-curves X25519:P-256"); | |
207 | } | |
5a8e54d9 | 208 | $proxy->start(); |
dbc6268f MC |
209 | if (disabled("ec")) { |
210 | ok(TLSProxy::Message->success() && ($selectedgroupid == FFDHE2048), | |
211 | "Multiple acceptable key_shares (part 2)"); | |
212 | } else { | |
213 | ok(TLSProxy::Message->success() && ($selectedgroupid == X25519), | |
214 | "Multiple acceptable key_shares (part 2)"); | |
215 | } | |
5a8e54d9 | 216 | |
46f4e1be | 217 | #Test 15: Server sends key_share that wasn't offered should fail |
5a8e54d9 MC |
218 | $proxy->clear(); |
219 | $testtype = SELECT_X25519; | |
dbc6268f MC |
220 | if (disabled("ec")) { |
221 | $proxy->clientflags("-groups ffdhe3072"); | |
222 | } else { | |
223 | $proxy->clientflags("-groups P-256"); | |
224 | } | |
5a8e54d9 MC |
225 | $proxy->start(); |
226 | ok(TLSProxy::Message->fail(), "Non offered key_share"); | |
227 | ||
38f5c30b | 228 | #Test 16: Too short group_id in ServerHello should fail |
5a8e54d9 MC |
229 | $proxy->clear(); |
230 | $testtype = GROUP_ID_TOO_SHORT; | |
231 | $proxy->start(); | |
232 | ok(TLSProxy::Message->fail(), "Group id too short in ServerHello"); | |
233 | ||
38f5c30b | 234 | #Test 17: key_exchange length mismatch in ServerHello should fail |
5a8e54d9 MC |
235 | $proxy->clear(); |
236 | $testtype = KEX_LEN_MISMATCH; | |
237 | $proxy->start(); | |
238 | ok(TLSProxy::Message->fail(), "key_exchange length mismatch in ServerHello"); | |
239 | ||
38f5c30b | 240 | #Test 18: Zero length key_exchange in ServerHello should fail |
5a8e54d9 MC |
241 | $proxy->clear(); |
242 | $testtype = ZERO_LEN_KEX_DATA; | |
243 | $proxy->start(); | |
244 | ok(TLSProxy::Message->fail(), "zero length key_exchange data in ServerHello"); | |
245 | ||
38f5c30b | 246 | #Test 19: Trailing data on key_share in ServerHello should fail |
5a8e54d9 MC |
247 | $proxy->clear(); |
248 | $testtype = TRAILING_DATA; | |
249 | $proxy->start(); | |
250 | ok(TLSProxy::Message->fail(), "key_share trailing data in ServerHello"); | |
251 | ||
c423ecaa MC |
252 | SKIP: { |
253 | skip "No TLSv1.2 support in this OpenSSL build", 2 if disabled("tls1_2"); | |
254 | ||
255 | #Test 20: key_share should not be sent if the client is not capable of | |
256 | # negotiating TLSv1.3 | |
257 | $proxy->clear(); | |
258 | $proxy->filter(undef); | |
259 | $proxy->clientflags("-no_tls1_3"); | |
260 | $proxy->start(); | |
261 | my $clienthello = $proxy->message_list->[0]; | |
262 | ok(TLSProxy::Message->success() | |
263 | && !defined $clienthello->extension_data->{TLSProxy::Message::EXT_KEY_SHARE}, | |
264 | "No key_share for TLS<=1.2 client"); | |
265 | $proxy->filter(\&modify_key_shares_filter); | |
266 | ||
267 | #Test 21: A server not capable of negotiating TLSv1.3 should not attempt to | |
268 | # process a key_share | |
269 | $proxy->clear(); | |
270 | $direction = CLIENT_TO_SERVER; | |
271 | $testtype = NO_ACCEPTABLE_KEY_SHARES; | |
272 | $proxy->serverflags("-no_tls1_3"); | |
273 | $proxy->start(); | |
274 | ok(TLSProxy::Message->success(), "Ignore key_share for TLS<=1.2 server"); | |
275 | } | |
5a8e54d9 | 276 | |
5e3766e2 MC |
277 | #Test 22: The server sending an HRR but not requesting a new key_share should |
278 | # fail | |
279 | $proxy->clear(); | |
597c51bc | 280 | $direction = SERVER_TO_CLIENT; |
5e3766e2 | 281 | $testtype = NO_KEY_SHARES_IN_HRR; |
dbc6268f MC |
282 | if (disabled("ec")) { |
283 | $proxy->serverflags("-groups ffdhe2048"); | |
284 | } else { | |
285 | $proxy->serverflags("-groups X25519"); | |
286 | } | |
5e3766e2 MC |
287 | $proxy->start(); |
288 | ok(TLSProxy::Message->fail(), "Server sends HRR with no key_shares"); | |
289 | ||
5a8e54d9 MC |
290 | sub modify_key_shares_filter |
291 | { | |
292 | my $proxy = shift; | |
293 | ||
294 | # We're only interested in the initial ClientHello | |
5e3766e2 MC |
295 | if (($direction == CLIENT_TO_SERVER && $proxy->flight != 0 |
296 | && ($proxy->flight != 1 || $testtype != NO_KEY_SHARES_IN_HRR)) | |
5a8e54d9 MC |
297 | || ($direction == SERVER_TO_CLIENT && $proxy->flight != 1)) { |
298 | return; | |
299 | } | |
300 | ||
301 | foreach my $message (@{$proxy->message_list}) { | |
302 | if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO | |
303 | && $direction == CLIENT_TO_SERVER) { | |
304 | my $ext; | |
305 | my $suppgroups; | |
306 | ||
307 | #Setup supported groups to include some unrecognised groups | |
308 | $suppgroups = pack "C8", | |
309 | 0x00, 0x06, #List Length | |
310 | 0xff, 0xfe, #Non existing group 1 | |
311 | 0xff, 0xff, #Non existing group 2 | |
312 | 0x00, 0x1d; #x25519 | |
313 | ||
314 | if ($testtype == EMPTY_EXTENSION) { | |
315 | $ext = pack "C2", | |
316 | 0x00, 0x00; | |
317 | } elsif ($testtype == NO_ACCEPTABLE_KEY_SHARES) { | |
318 | $ext = pack "C12", | |
319 | 0x00, 0x0a, #List Length | |
320 | 0xff, 0xfe, #Non existing group 1 | |
321 | 0x00, 0x01, 0xff, #key_exchange data | |
322 | 0xff, 0xff, #Non existing group 2 | |
323 | 0x00, 0x01, 0xff; #key_exchange data | |
324 | } elsif ($testtype == ACCEPTABLE_AT_END) { | |
325 | $ext = pack "C11H64", | |
326 | 0x00, 0x29, #List Length | |
327 | 0xff, 0xfe, #Non existing group 1 | |
328 | 0x00, 0x01, 0xff, #key_exchange data | |
329 | 0x00, 0x1d, #x25519 | |
330 | 0x00, 0x20, #key_exchange data length | |
331 | "155155B95269ED5C87EAA99C2EF5A593". | |
332 | "EDF83495E80380089F831B94D14B1421"; #key_exchange data | |
333 | } elsif ($testtype == NOT_IN_SUPPORTED_GROUPS) { | |
334 | $suppgroups = pack "C4", | |
335 | 0x00, 0x02, #List Length | |
336 | 0x00, 0xfe; #Non existing group 1 | |
337 | } elsif ($testtype == GROUP_ID_TOO_SHORT) { | |
338 | $ext = pack "C6H64C1", | |
339 | 0x00, 0x25, #List Length | |
340 | 0x00, 0x1d, #x25519 | |
341 | 0x00, 0x20, #key_exchange data length | |
342 | "155155B95269ED5C87EAA99C2EF5A593". | |
343 | "EDF83495E80380089F831B94D14B1421"; #key_exchange data | |
344 | 0x00; #Group id too short | |
345 | } elsif ($testtype == KEX_LEN_MISMATCH) { | |
346 | $ext = pack "C8", | |
347 | 0x00, 0x06, #List Length | |
348 | 0x00, 0x1d, #x25519 | |
349 | 0x00, 0x20, #key_exchange data length | |
350 | 0x15, 0x51; #Only two bytes of data, but length should be 32 | |
351 | } elsif ($testtype == ZERO_LEN_KEX_DATA) { | |
352 | $ext = pack "C10H64", | |
353 | 0x00, 0x28, #List Length | |
354 | 0xff, 0xfe, #Non existing group 1 | |
355 | 0x00, 0x00, #zero length key_exchange data is invalid | |
356 | 0x00, 0x1d, #x25519 | |
357 | 0x00, 0x20, #key_exchange data length | |
358 | "155155B95269ED5C87EAA99C2EF5A593". | |
359 | "EDF83495E80380089F831B94D14B1421"; #key_exchange data | |
360 | } elsif ($testtype == TRAILING_DATA) { | |
361 | $ext = pack "C6H64C1", | |
362 | 0x00, 0x24, #List Length | |
363 | 0x00, 0x1d, #x25519 | |
364 | 0x00, 0x20, #key_exchange data length | |
365 | "155155B95269ED5C87EAA99C2EF5A593". | |
366 | "EDF83495E80380089F831B94D14B1421", #key_exchange data | |
367 | 0x00; #Trailing garbage | |
5e3766e2 MC |
368 | } elsif ($testtype == NO_KEY_SHARES_IN_HRR) { |
369 | #We trick the server into thinking we sent a P-256 key_share - | |
370 | #but the client actually sent X25519 | |
371 | $ext = pack "C7", | |
372 | 0x00, 0x05, #List Length | |
373 | 0x00, 0x17, #P-256 | |
374 | 0x00, 0x01, #key_exchange data length | |
375 | 0xff; #Dummy key_share data | |
5a8e54d9 MC |
376 | } |
377 | ||
5e3766e2 MC |
378 | if ($testtype != EMPTY_EXTENSION |
379 | && $testtype != NO_KEY_SHARES_IN_HRR) { | |
38f5c30b MC |
380 | $message->set_extension( |
381 | TLSProxy::Message::EXT_SUPPORTED_GROUPS, $suppgroups); | |
382 | } | |
5a8e54d9 MC |
383 | |
384 | if ($testtype == MISSING_EXTENSION) { | |
385 | $message->delete_extension( | |
386 | TLSProxy::Message::EXT_KEY_SHARE); | |
387 | } elsif ($testtype != NOT_IN_SUPPORTED_GROUPS) { | |
388 | $message->set_extension( | |
389 | TLSProxy::Message::EXT_KEY_SHARE, $ext); | |
390 | } | |
391 | ||
392 | $message->repack(); | |
393 | } elsif ($message->mt == TLSProxy::Message::MT_SERVER_HELLO | |
394 | && $direction == SERVER_TO_CLIENT) { | |
395 | my $ext; | |
396 | my $key_share = | |
ecc2f938 | 397 | $message->extension_data->{TLSProxy::Message::EXT_KEY_SHARE}; |
5a8e54d9 MC |
398 | $selectedgroupid = unpack("n", $key_share); |
399 | ||
400 | if ($testtype == LOOK_ONLY) { | |
401 | return; | |
402 | } | |
597c51bc MC |
403 | if ($testtype == NO_KEY_SHARES_IN_HRR) { |
404 | $message->delete_extension(TLSProxy::Message::EXT_KEY_SHARE); | |
405 | $message->set_extension(TLSProxy::Message::EXT_UNKNOWN, ""); | |
406 | $message->repack(); | |
407 | return; | |
408 | } | |
5a8e54d9 MC |
409 | if ($testtype == SELECT_X25519) { |
410 | $ext = pack "C4H64", | |
411 | 0x00, 0x1d, #x25519 | |
412 | 0x00, 0x20, #key_exchange data length | |
413 | "155155B95269ED5C87EAA99C2EF5A593". | |
414 | "EDF83495E80380089F831B94D14B1421"; #key_exchange data | |
415 | } elsif ($testtype == GROUP_ID_TOO_SHORT) { | |
416 | $ext = pack "C1", | |
417 | 0x00; | |
418 | } elsif ($testtype == KEX_LEN_MISMATCH) { | |
419 | $ext = pack "C6", | |
420 | 0x00, 0x1d, #x25519 | |
421 | 0x00, 0x20, #key_exchange data length | |
422 | 0x15, 0x51; #Only two bytes of data, but length should be 32 | |
423 | } elsif ($testtype == ZERO_LEN_KEX_DATA) { | |
424 | $ext = pack "C4", | |
425 | 0x00, 0x1d, #x25519 | |
426 | 0x00, 0x00, #zero length key_exchange data is invalid | |
427 | } elsif ($testtype == TRAILING_DATA) { | |
428 | $ext = pack "C4H64C1", | |
429 | 0x00, 0x1d, #x25519 | |
430 | 0x00, 0x20, #key_exchange data length | |
431 | "155155B95269ED5C87EAA99C2EF5A593". | |
432 | "EDF83495E80380089F831B94D14B1421", #key_exchange data | |
433 | 0x00; #Trailing garbage | |
434 | } | |
ecc2f938 | 435 | $message->set_extension(TLSProxy::Message::EXT_KEY_SHARE, $ext); |
5a8e54d9 MC |
436 | |
437 | $message->repack(); | |
597c51bc | 438 | } |
5a8e54d9 MC |
439 | } |
440 | } | |
441 | ||
442 |