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