xref: /src/crypto/openssl/test/tls13groupselection_test.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
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