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