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