1 /*
2 * Copyright 2025 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 */
9
10 #include "testutil.h"
11 #include "helpers/ssltestlib.h"
12 #include <openssl/objects.h>
13
14 #define TEST_true_or_end(a) \
15 if (!TEST_true(a)) \
16 goto end;
17
18 #define TEST_false_or_end(a) \
19 if (!TEST_false(a)) \
20 goto end;
21
22 #define SERVER_PREFERENCE 1
23 #define CLIENT_PREFERENCE 0
24
25 #define WORK_ON_SSL_OBJECT 1
26 #define WORK_ON_CONTEXT 0
27
28 #define SYNTAX_FAILURE "SYNTAX_FAILURE"
29 #define NEGOTIATION_FAILURE "NEGOTIATION_FAILURE"
30
31 typedef enum TEST_TYPE {
32 TEST_NEGOTIATION_FAILURE = 0,
33 TEST_NEGOTIATION_SUCCESS = 1,
34 TEST_SYNTAX_FAILURE = 2
35 } TEST_TYPE;
36
37 typedef enum SERVER_RESPONSE {
38 HRR = 0,
39 INIT = 1,
40 SH = 2
41 } SERVER_RESPONSE;
42
43 static char *cert = NULL;
44 static char *privkey = NULL;
45
46 struct tls13groupselection_test_st {
47 const char *client_groups;
48 const char *server_groups;
49 const int preference;
50 const char *expected_group;
51 const enum SERVER_RESPONSE expected_server_response;
52 };
53
54 static const struct tls13groupselection_test_st tls13groupselection_tests[] = {
55
56 /*
57 * (A) Test with no explicit key share (backward compatibility)
58 * Key share is implicitly sent for first client group
59 * Test (implicitly) that the key share group is used
60 */
61 { "secp384r1:secp521r1:X25519:prime256v1:X448", /* test 0 */
62 "X25519:secp521r1:secp384r1:prime256v1:X448",
63 CLIENT_PREFERENCE,
64 "secp384r1", SH },
65 { "secp521r1:secp384r1:X25519:prime256v1:X448", /* test 1 */
66 "X25519:secp521r1:secp384r1:prime256v1:X448",
67 SERVER_PREFERENCE,
68 "secp521r1", SH },
69
70 /*
71 * (B) No explicit key share test (backward compatibility)
72 * Key share is implicitly sent for first client group
73 * Check HRR if server does not support key share group
74 */
75 { "secp521r1:secp384r1:X25519:prime256v1:X448", /* test 2 */
76 "X25519:secp384r1:prime256v1",
77 CLIENT_PREFERENCE,
78 "secp384r1", HRR },
79 { "secp521r1:secp384r1:X25519:prime256v1:X448", /* test 3 */
80 "X25519:secp384r1:prime256v1",
81 SERVER_PREFERENCE,
82 "x25519", HRR },
83
84 /*
85 * (C) Explicit key shares, SH tests
86 * Test key share selection as function of client-/server-preference
87 * Test (implicitly) that multiple key shares are generated
88 * Test (implicitly) that multiple tuples don't influence the client
89 * Test (implicitly) that key share prefix doesn't influence the server
90 */
91 { "secp521r1:secp384r1:*X25519/*prime256v1:X448", /* test 4 */
92 "secp521r1:*prime256v1:X25519:X448",
93 CLIENT_PREFERENCE,
94 "x25519", SH },
95 { "secp521r1:secp384r1:*X25519/*prime256v1:X448", /* test 5 */
96 "secp521r1:*prime256v1:X25519:X448",
97 SERVER_PREFERENCE,
98 "secp256r1", SH },
99
100 /*
101 * (D) Explicit key shares, HRR tests
102 * Check that HRR is issued if group in first tuple
103 * is supported but no key share is available for the tuple
104 */
105 { "secp521r1:secp384r1:*X25519:prime256v1:*X448", /* test 6 */
106 "secp384r1:secp521r1:prime256v1/X25519:X448",
107 CLIENT_PREFERENCE,
108 "secp521r1", HRR },
109 { "secp521r1:secp384r1:*X25519:prime256v1:*X448", /* test 7 */
110 "secp384r1:secp521r1:prime256v1/X25519:X448",
111 SERVER_PREFERENCE,
112 "secp384r1", HRR },
113
114 /*
115 * (E) Multiple tuples tests, client without tuple delimiters
116 * Check that second tuple is evaluated if there isn't any match
117 * first tuple
118 */
119 { "*X25519:prime256v1:*X448", /* test 8 */
120 "secp521r1:secp384r1/X448:X25519",
121 CLIENT_PREFERENCE,
122 "x25519", SH },
123 { "*X25519:prime256v1:*X448", /* test 9 */
124 "secp521r1:secp384r1/X448:X25519",
125 SERVER_PREFERENCE,
126 "x448", SH },
127
128 /* (F) Check that '?' will ignore unknown group but use known group */
129 { "*X25519:?unknown_group_123:prime256v1:*X448", /* test 10 */
130 "secp521r1:secp384r1/X448:?unknown_group_456:?X25519",
131 CLIENT_PREFERENCE,
132 "x25519", SH },
133 { "*X25519:prime256v1:*X448:?*unknown_group_789", /* test 11 */
134 "secp521r1:secp384r1/?X448:?unknown_group_456:X25519",
135 SERVER_PREFERENCE,
136 "x448", SH },
137
138 /*
139 * (G) Check full backward compatibility (= don't explicitly set any groups)
140 */
141 { NULL, /* test 12 */
142 NULL,
143 CLIENT_PREFERENCE,
144 #ifndef OPENSSL_NO_ML_KEM
145 "X25519MLKEM768", SH
146 #else
147 "x25519", SH
148 #endif
149 },
150 { NULL, /* test 13 */
151 NULL,
152 SERVER_PREFERENCE,
153 #ifndef OPENSSL_NO_ML_KEM
154 "X25519MLKEM768", SH
155 #else
156 "x25519", SH
157 #endif
158 },
159
160 /*
161 * (H) Check that removal of group is 'active'
162 */
163 { "*X25519:*X448", /* test 14 */
164 "secp521r1:X25519:prime256v1:-X25519:secp384r1/X448",
165 CLIENT_PREFERENCE,
166 "x448", SH },
167 { "*X25519:*X448", /* test 15 */
168 "secp521r1:X25519:prime256v1:-X25519:secp384r1/X448",
169 SERVER_PREFERENCE,
170 "x448", SH },
171 { "*X25519:prime256v1:*X448", /* test 16 */
172 "X25519:prime256v1/X448:-X25519",
173 CLIENT_PREFERENCE,
174 "secp256r1", HRR },
175 { "*X25519:prime256v1:*X448", /* test 17 */
176 "X25519:prime256v1/X448:-X25519",
177 SERVER_PREFERENCE,
178 "secp256r1", HRR },
179 /*
180 * (I) Check handling of the "DEFAULT" 'pseudo group name'
181 */
182 { "*X25519:DEFAULT:-prime256v1:-X448", /* test 18 */
183 "DEFAULT:-X25519:-?X25519MLKEM768",
184 CLIENT_PREFERENCE,
185 "secp384r1", HRR },
186 { "*X25519:DEFAULT:-prime256v1:-X448", /* test 19 */
187 "DEFAULT:-X25519:-?X25519MLKEM768",
188 SERVER_PREFERENCE,
189 "secp384r1", HRR },
190 /*
191 * (J) Deduplication check
192 */
193 { "secp521r1:X25519:prime256v1/X25519:prime256v1/X448", /* test 20 */
194 "secp521r1:X25519:prime256v1/X25519:prime256v1/X448",
195 CLIENT_PREFERENCE,
196 "secp521r1", SH },
197 { "secp521r1:X25519:prime256v1/X25519:prime256v1/X448", /* test 21 */
198 "secp521r1:X25519:prime256v1/X25519:prime256v1/X448",
199 SERVER_PREFERENCE,
200 "secp521r1", SH },
201 /*
202 * (K) Check group removal when first entry requested a keyshare
203 */
204 { "*X25519:*prime256v1:-X25519", /* test 22 */
205 "X25519:prime256v1",
206 CLIENT_PREFERENCE,
207 "secp256r1", SH },
208 /*
209 * (L) Syntax errors
210 */
211 { "*X25519:*prime256v1:NOTVALID", /* test 23 */
212 "",
213 CLIENT_PREFERENCE,
214 SYNTAX_FAILURE },
215 { "X25519//prime256v1", /* test 24 */
216 "",
217 CLIENT_PREFERENCE,
218 SYNTAX_FAILURE },
219 { "**X25519:*prime256v1", /* test 25 */
220 "",
221 CLIENT_PREFERENCE,
222 SYNTAX_FAILURE },
223 { "*X25519:*secp256r1:*X448:*secp521r1:*secp384r1", /* test 26 */
224 "",
225 CLIENT_PREFERENCE,
226 SYNTAX_FAILURE },
227 { "*X25519:*secp256r1:?:*secp521r1", /* test 27 */
228 "",
229 CLIENT_PREFERENCE,
230 SYNTAX_FAILURE },
231 { "*X25519:*secp256r1::secp521r1", /* test 28 */
232 "",
233 CLIENT_PREFERENCE,
234 SYNTAX_FAILURE },
235 { ":*secp256r1:secp521r1", /* test 29 */
236 "",
237 CLIENT_PREFERENCE,
238 SYNTAX_FAILURE },
239 { "*secp256r1:secp521r1:", /* test 30 */
240 "",
241 CLIENT_PREFERENCE,
242 SYNTAX_FAILURE },
243 { "/secp256r1/secp521r1", /* test 31 */
244 "",
245 CLIENT_PREFERENCE,
246 SYNTAX_FAILURE },
247 { "secp256r1/secp521r1/", /* test 32 */
248 "",
249 CLIENT_PREFERENCE,
250 SYNTAX_FAILURE },
251 { "X25519:??secp256r1:X448", /* test 33 */
252 "",
253 CLIENT_PREFERENCE,
254 SYNTAX_FAILURE },
255 { "X25519:secp256r1:**X448", /* test 34 */
256 "",
257 CLIENT_PREFERENCE,
258 SYNTAX_FAILURE },
259 { "--X25519:secp256r1:X448", /* test 35 */
260 "",
261 CLIENT_PREFERENCE,
262 SYNTAX_FAILURE },
263 { "-DEFAULT", /* test 36 */
264 "",
265 CLIENT_PREFERENCE,
266 SYNTAX_FAILURE },
267 { "?DEFAULT", /* test 37 */
268 "",
269 CLIENT_PREFERENCE,
270 SYNTAX_FAILURE },
271 /*
272 * Negotiation Failures
273 * No overlapping groups between client and server
274 */
275 /* test 38 remove all groups */
276 { "X25519:secp256r1:X448:secp521r1:-X448:-secp256r1:-X25519:-secp521r1",
277 "",
278 CLIENT_PREFERENCE,
279 NEGOTIATION_FAILURE, INIT },
280 { "secp384r1:secp521r1:X25519", /* test 39 */
281 "prime256v1:X448",
282 CLIENT_PREFERENCE,
283 NEGOTIATION_FAILURE, INIT },
284 { "secp521r1:secp384r1:X25519", /* test 40 */
285 "prime256v1:X448",
286 SERVER_PREFERENCE,
287 NEGOTIATION_FAILURE, INIT },
288 /*
289 * These are allowed
290 * "X25519/prime256v1:-X448", "X25519:-*X25519:*prime256v1, "*DEFAULT"
291 */
292 /*
293 * Tests to show that spaces between tuples are allowed
294 */
295 { "secp521r1:X25519 / prime256v1/X25519 / prime256v1/X448", /* test 41 */
296 "secp521r1:X25519 / prime256v1/X25519 / prime256v1/X448",
297 CLIENT_PREFERENCE,
298 "secp521r1", SH },
299 { "secp521r1 / prime256v1:X25519 / prime256v1/X448", /* test 42 */
300 "secp521r1 / prime256v1:X25519 / prime256v1/X448",
301 SERVER_PREFERENCE,
302 "secp521r1", SH },
303 /*
304 * Not a syntax error, but invalid because brainpoolP256r1 is the only
305 * key share and is not valid in TLSv1.3
306 */
307 { "*brainpoolP256r1:X25519", /* test 43 */
308 "X25519",
309 SERVER_PREFERENCE,
310 NEGOTIATION_FAILURE, INIT }
311 };
312
server_response_check_cb(int write_p,int version,int content_type,const void * buf,size_t len,SSL * ssl,void * arg)313 static void server_response_check_cb(int write_p, int version,
314 int content_type, const void *buf,
315 size_t len, SSL *ssl, void *arg)
316 {
317 /* Cast arg to SERVER_RESPONSE */
318 enum SERVER_RESPONSE *server_response = (enum SERVER_RESPONSE *)arg;
319 /* Prepare check for HRR */
320 const uint8_t *incoming_random = (uint8_t *)buf + 6;
321 const uint8_t magic_HRR_random[32] = { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
322 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
323 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
324 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C };
325
326 /* Did a server hello arrive? */
327 if (write_p == 0 && /* Incoming data... */
328 content_type == SSL3_RT_HANDSHAKE && /* carrying a handshake record type ... */
329 version == TLS1_3_VERSION && /* for TLSv1.3 ... */
330 ((uint8_t *)buf)[0] == SSL3_MT_SERVER_HELLO) { /* with message type "ServerHello" */
331 /* Check what it is: SH or HRR (compare the 'random' data field with HRR magic number) */
332 if (memcmp((void *)incoming_random, (void *)magic_HRR_random, 32) == 0)
333 *server_response *= HRR;
334 else
335 *server_response *= SH;
336 }
337 }
338
test_invalidsyntax(const struct tls13groupselection_test_st * current_test_vector,int ssl_or_ctx)339 static int test_invalidsyntax(const struct tls13groupselection_test_st *current_test_vector,
340 int ssl_or_ctx)
341 {
342 int ok = 0;
343 SSL_CTX *client_ctx = NULL, *server_ctx = NULL;
344 SSL *clientssl = NULL, *serverssl = NULL;
345
346 if (!TEST_ptr(current_test_vector->client_groups)
347 || !TEST_size_t_ne(strlen(current_test_vector->client_groups), 0))
348 goto end;
349
350 /* Creation of the contexts */
351 TEST_true_or_end(create_ssl_ctx_pair(NULL, TLS_server_method(),
352 TLS_client_method(),
353 TLS1_VERSION, 0,
354 &server_ctx, &client_ctx,
355 cert, privkey));
356
357 /* Customization of the contexts */
358 if (ssl_or_ctx == WORK_ON_CONTEXT)
359 TEST_false_or_end(SSL_CTX_set1_groups_list(client_ctx,
360 current_test_vector->client_groups));
361 /* Creation of the SSL objects */
362 TEST_true_or_end(create_ssl_objects(server_ctx, client_ctx,
363 &serverssl, &clientssl,
364 NULL, NULL));
365
366 /* Customization of the SSL objects */
367 if (ssl_or_ctx == WORK_ON_SSL_OBJECT)
368 TEST_false_or_end(SSL_set1_groups_list(clientssl, current_test_vector->client_groups));
369
370 ok = 1;
371
372 end:
373 SSL_free(serverssl);
374 SSL_free(clientssl);
375 SSL_CTX_free(server_ctx);
376 SSL_CTX_free(client_ctx);
377 return ok;
378 }
379
test_groupnegotiation(const struct tls13groupselection_test_st * current_test_vector,int ssl_or_ctx,TEST_TYPE test_type)380 static int test_groupnegotiation(const struct tls13groupselection_test_st *current_test_vector,
381 int ssl_or_ctx, TEST_TYPE test_type)
382 {
383 int ok = 0;
384 int negotiated_group_client = 0;
385 int negotiated_group_server = 0;
386 const char *group_name_client;
387 SSL_CTX *client_ctx = NULL, *server_ctx = NULL;
388 SSL *clientssl = NULL, *serverssl = NULL;
389 enum SERVER_RESPONSE server_response;
390
391 /* Creation of the contexts */
392 TEST_true_or_end(create_ssl_ctx_pair(NULL, TLS_server_method(),
393 TLS_client_method(),
394 TLS1_VERSION, 0,
395 &server_ctx, &client_ctx,
396 cert, privkey));
397
398 /* Customization of the contexts */
399 if (ssl_or_ctx == WORK_ON_CONTEXT) {
400 if (current_test_vector->client_groups != NULL) {
401 TEST_true_or_end(SSL_CTX_set1_groups_list(client_ctx,
402 current_test_vector->client_groups));
403 }
404 if (current_test_vector->server_groups != NULL) {
405 TEST_true_or_end(SSL_CTX_set1_groups_list(server_ctx,
406 current_test_vector->server_groups));
407 }
408 TEST_true_or_end(SSL_CTX_set_min_proto_version(client_ctx, TLS1_3_VERSION));
409 TEST_true_or_end(SSL_CTX_set_min_proto_version(server_ctx, TLS1_3_VERSION));
410 if (current_test_vector->preference == SERVER_PREFERENCE)
411 SSL_CTX_set_options(server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
412 }
413 /* Creation of the SSL objects */
414 if (!TEST_true(create_ssl_objects(server_ctx, client_ctx,
415 &serverssl, &clientssl,
416 NULL, NULL)))
417 goto end;
418
419 /* Customization of the SSL objects */
420 if (ssl_or_ctx == WORK_ON_SSL_OBJECT) {
421 if (current_test_vector->client_groups != NULL)
422 TEST_true_or_end(SSL_set1_groups_list(clientssl, current_test_vector->client_groups));
423
424 if (current_test_vector->server_groups != NULL)
425 TEST_true_or_end(SSL_set1_groups_list(serverssl, current_test_vector->server_groups));
426
427 TEST_true_or_end(SSL_set_min_proto_version(clientssl, TLS1_3_VERSION));
428 TEST_true_or_end(SSL_set_min_proto_version(serverssl, TLS1_3_VERSION));
429
430 if (current_test_vector->preference == SERVER_PREFERENCE)
431 SSL_set_options(serverssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
432 }
433
434 /* We set the message callback on the client side (which checks SH/HRR) */
435 server_response = INIT; /* Variable to hold server response info */
436 SSL_set_msg_callback_arg(clientssl, &server_response); /* add it to the callback */
437 SSL_set_msg_callback(clientssl, server_response_check_cb); /* and activate callback */
438
439 /* Creating a test connection */
440 if (test_type == TEST_NEGOTIATION_SUCCESS) {
441 TEST_true_or_end(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE));
442
443 /*
444 * Checking that the negotiated group matches our expectation
445 * and must be identical on server and client
446 * and must be expected SH or HRR
447 */
448 negotiated_group_client = SSL_get_negotiated_group(clientssl);
449 negotiated_group_server = SSL_get_negotiated_group(serverssl);
450 group_name_client = SSL_group_to_name(clientssl, negotiated_group_client);
451 if (!TEST_int_eq(negotiated_group_client, negotiated_group_server))
452 goto end;
453 if (!TEST_int_eq((int)current_test_vector->expected_server_response, (int)server_response))
454 goto end;
455 if (TEST_str_eq(group_name_client, current_test_vector->expected_group))
456 ok = 1;
457 } else {
458 TEST_false_or_end(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE));
459 if (test_type == TEST_NEGOTIATION_FAILURE && !TEST_int_eq((int)current_test_vector->expected_server_response, (int)server_response))
460 goto end;
461 ok = 1;
462 }
463
464 end:
465 SSL_free(serverssl);
466 SSL_free(clientssl);
467 SSL_CTX_free(server_ctx);
468 SSL_CTX_free(client_ctx);
469 return ok;
470 }
471
tls13groupselection_test(int i)472 static int tls13groupselection_test(int i)
473 {
474 int testresult = 1; /* Assume the test will succeed */
475 int res = 0;
476 TEST_TYPE test_type = TEST_NEGOTIATION_SUCCESS;
477
478 /*
479 * Call the code under test, once such that the ssl object is used and
480 * once such that the ctx is used. If any of the tests fail (= return 0),
481 * the end result will be 0 thanks to multiplication
482 */
483 TEST_info("==> Running TLSv1.3 test %d", i);
484
485 if (strncmp(tls13groupselection_tests[i].expected_group,
486 SYNTAX_FAILURE, sizeof(SYNTAX_FAILURE))
487 == 0)
488 test_type = TEST_SYNTAX_FAILURE;
489 else if (strncmp(tls13groupselection_tests[i].expected_group,
490 NEGOTIATION_FAILURE, sizeof(NEGOTIATION_FAILURE))
491 == 0)
492 test_type = TEST_NEGOTIATION_FAILURE;
493
494 if (test_type == TEST_SYNTAX_FAILURE)
495 res = test_invalidsyntax(&tls13groupselection_tests[i],
496 WORK_ON_SSL_OBJECT);
497 else
498 res = test_groupnegotiation(&tls13groupselection_tests[i],
499 WORK_ON_SSL_OBJECT, test_type);
500
501 if (!res)
502 TEST_error("====> [ERROR] TLSv1.3 test %d with WORK_ON_SSL_OBJECT failed", i);
503 testresult *= res;
504
505 if (test_type == TEST_SYNTAX_FAILURE)
506 res = test_invalidsyntax(&tls13groupselection_tests[i],
507 WORK_ON_CONTEXT);
508 else
509 res = test_groupnegotiation(&tls13groupselection_tests[i],
510 WORK_ON_CONTEXT, test_type);
511
512 if (!res)
513 TEST_error("====> [ERROR] TLSv1.3 test %d with WORK_ON_CONTEXT failed", i);
514 testresult *= res;
515
516 return testresult;
517 }
518
setup_tests(void)519 int setup_tests(void)
520 {
521 if (!TEST_ptr(cert = test_get_argument(0))
522 || !TEST_ptr(privkey = test_get_argument(1)))
523 return 0;
524
525 ADD_ALL_TESTS(tls13groupselection_test, OSSL_NELEM(tls13groupselection_tests));
526 return 1;
527 }
528