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