diff options
Diffstat (limited to 'src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c')
-rw-r--r-- | src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c | 478 |
1 files changed, 0 insertions, 478 deletions
diff --git a/src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c b/src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c deleted file mode 100644 index e26f614e53..0000000000 --- a/src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c +++ /dev/null | |||
@@ -1,478 +0,0 @@ | |||
1 | /* $OpenBSD: ssl_get_shared_ciphers.c,v 1.13 2024/08/31 12:47:24 jsing Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2021 Theo Buehler <tb@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <stdint.h> | ||
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | |||
23 | #include <openssl/bio.h> | ||
24 | #include <openssl/crypto.h> | ||
25 | #include <openssl/err.h> | ||
26 | #include <openssl/ssl.h> | ||
27 | |||
28 | struct peer_config { | ||
29 | const char *name; | ||
30 | int server; | ||
31 | uint16_t max_version; | ||
32 | uint16_t min_version; | ||
33 | const char *ciphers; | ||
34 | }; | ||
35 | |||
36 | struct ssl_shared_ciphers_test_data { | ||
37 | const char *description; | ||
38 | struct peer_config client_config; | ||
39 | struct peer_config server_config; | ||
40 | const char *shared_ciphers; | ||
41 | const char *shared_ciphers_without_aesni; | ||
42 | }; | ||
43 | |||
44 | char *server_cert; | ||
45 | char *server_key; | ||
46 | |||
47 | static const struct ssl_shared_ciphers_test_data ssl_shared_ciphers_tests[] = { | ||
48 | { | ||
49 | .description = "TLSv1.3 defaults", | ||
50 | .client_config = { | ||
51 | .name = "client", | ||
52 | .server = 0, | ||
53 | .max_version = TLS1_3_VERSION, | ||
54 | .min_version = TLS1_3_VERSION, | ||
55 | .ciphers = | ||
56 | "TLS_AES_256_GCM_SHA384:" | ||
57 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
58 | "TLS_AES_128_GCM_SHA256", | ||
59 | }, | ||
60 | .server_config = { | ||
61 | .name = "server", | ||
62 | .server = 1, | ||
63 | .max_version = TLS1_3_VERSION, | ||
64 | .min_version = TLS1_3_VERSION, | ||
65 | .ciphers = | ||
66 | "TLS_AES_256_GCM_SHA384:" | ||
67 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
68 | "TLS_AES_128_GCM_SHA256", | ||
69 | }, | ||
70 | .shared_ciphers = | ||
71 | "TLS_AES_256_GCM_SHA384:" | ||
72 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
73 | "TLS_AES_128_GCM_SHA256", | ||
74 | }, | ||
75 | |||
76 | { | ||
77 | .description = "TLSv1.3, client without ChaCha", | ||
78 | .client_config = { | ||
79 | .name = "client", | ||
80 | .server = 0, | ||
81 | .max_version = TLS1_3_VERSION, | ||
82 | .min_version = TLS1_3_VERSION, | ||
83 | .ciphers = | ||
84 | "TLS_AES_256_GCM_SHA384:" | ||
85 | "TLS_AES_128_GCM_SHA256", | ||
86 | }, | ||
87 | .server_config = { | ||
88 | .name = "server", | ||
89 | .server = 1, | ||
90 | .max_version = TLS1_3_VERSION, | ||
91 | .min_version = TLS1_3_VERSION, | ||
92 | .ciphers = | ||
93 | "TLS_AES_256_GCM_SHA384:" | ||
94 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
95 | "TLS_AES_128_GCM_SHA256", | ||
96 | }, | ||
97 | .shared_ciphers = | ||
98 | "TLS_AES_256_GCM_SHA384:" | ||
99 | "TLS_AES_128_GCM_SHA256", | ||
100 | }, | ||
101 | |||
102 | { | ||
103 | .description = "TLSv1.2", | ||
104 | .client_config = { | ||
105 | .name = "client", | ||
106 | .server = 0, | ||
107 | .max_version = TLS1_2_VERSION, | ||
108 | .min_version = TLS1_2_VERSION, | ||
109 | .ciphers = | ||
110 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
111 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
112 | "ECDHE-RSA-AES256-SHA384:" | ||
113 | "ECDHE-ECDSA-AES256-SHA384:" | ||
114 | "ECDHE-RSA-AES256-SHA:" | ||
115 | "ECDHE-ECDSA-AES256-SHA", | ||
116 | }, | ||
117 | .server_config = { | ||
118 | .name = "server", | ||
119 | .server = 1, | ||
120 | .max_version = TLS1_2_VERSION, | ||
121 | .min_version = TLS1_2_VERSION, | ||
122 | .ciphers = | ||
123 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
124 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
125 | "ECDHE-RSA-AES256-SHA384:" | ||
126 | "ECDHE-ECDSA-AES256-SHA384:" | ||
127 | "ECDHE-RSA-AES256-SHA:" | ||
128 | "ECDHE-ECDSA-AES256-SHA", | ||
129 | }, | ||
130 | .shared_ciphers = | ||
131 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
132 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
133 | "ECDHE-RSA-AES256-SHA384:" | ||
134 | "ECDHE-ECDSA-AES256-SHA384:" | ||
135 | "ECDHE-RSA-AES256-SHA:" | ||
136 | "ECDHE-ECDSA-AES256-SHA", | ||
137 | }, | ||
138 | |||
139 | { | ||
140 | .description = "TLSv1.2, server without ECDSA", | ||
141 | .client_config = { | ||
142 | .name = "client", | ||
143 | .server = 0, | ||
144 | .max_version = TLS1_2_VERSION, | ||
145 | .min_version = TLS1_2_VERSION, | ||
146 | .ciphers = | ||
147 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
148 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
149 | "ECDHE-RSA-AES256-SHA384:" | ||
150 | "ECDHE-ECDSA-AES256-SHA384:" | ||
151 | "ECDHE-RSA-AES256-SHA:" | ||
152 | "ECDHE-ECDSA-AES256-SHA", | ||
153 | }, | ||
154 | .server_config = { | ||
155 | .name = "server", | ||
156 | .server = 1, | ||
157 | .max_version = TLS1_2_VERSION, | ||
158 | .min_version = TLS1_2_VERSION, | ||
159 | .ciphers = | ||
160 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
161 | "ECDHE-RSA-AES256-SHA384:" | ||
162 | "ECDHE-RSA-AES256-SHA", | ||
163 | }, | ||
164 | .shared_ciphers = | ||
165 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
166 | "ECDHE-RSA-AES256-SHA384:" | ||
167 | "ECDHE-RSA-AES256-SHA", | ||
168 | }, | ||
169 | |||
170 | { | ||
171 | .description = "TLSv1.3 ciphers are prepended", | ||
172 | .client_config = { | ||
173 | .name = "client", | ||
174 | .server = 0, | ||
175 | .max_version = TLS1_3_VERSION, | ||
176 | .min_version = TLS1_2_VERSION, | ||
177 | .ciphers = | ||
178 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
179 | }, | ||
180 | .server_config = { | ||
181 | .name = "server", | ||
182 | .server = 1, | ||
183 | .max_version = TLS1_3_VERSION, | ||
184 | .min_version = TLS1_2_VERSION, | ||
185 | .ciphers = | ||
186 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
187 | }, | ||
188 | .shared_ciphers = | ||
189 | "TLS_AES_256_GCM_SHA384:" | ||
190 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
191 | "TLS_AES_128_GCM_SHA256:" | ||
192 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
193 | .shared_ciphers_without_aesni = | ||
194 | "TLS_CHACHA20_POLY1305_SHA256:" | ||
195 | "TLS_AES_256_GCM_SHA384:" | ||
196 | "TLS_AES_128_GCM_SHA256:" | ||
197 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
198 | }, | ||
199 | }; | ||
200 | |||
201 | static const size_t N_SHARED_CIPHERS_TESTS = | ||
202 | sizeof(ssl_shared_ciphers_tests) / sizeof(ssl_shared_ciphers_tests[0]); | ||
203 | |||
204 | static SSL_CTX * | ||
205 | peer_config_to_ssl_ctx(const struct peer_config *config) | ||
206 | { | ||
207 | SSL_CTX *ctx; | ||
208 | |||
209 | if ((ctx = SSL_CTX_new(TLS_method())) == NULL) { | ||
210 | fprintf(stderr, "SSL_CTX_new(%s) failed\n", config->name); | ||
211 | goto err; | ||
212 | } | ||
213 | if (!SSL_CTX_set_max_proto_version(ctx, config->max_version)) { | ||
214 | fprintf(stderr, "max_proto_version(%s) failed\n", config->name); | ||
215 | goto err; | ||
216 | } | ||
217 | if (!SSL_CTX_set_min_proto_version(ctx, config->min_version)) { | ||
218 | fprintf(stderr, "min_proto_version(%s) failed\n", config->name); | ||
219 | goto err; | ||
220 | } | ||
221 | if (!SSL_CTX_set_cipher_list(ctx, config->ciphers)) { | ||
222 | fprintf(stderr, "set_cipher_list(%s) failed\n", config->name); | ||
223 | goto err; | ||
224 | } | ||
225 | |||
226 | if (config->server) { | ||
227 | if (!SSL_CTX_use_certificate_file(ctx, server_cert, | ||
228 | SSL_FILETYPE_PEM)) { | ||
229 | fprintf(stderr, "use_certificate_file(%s) failed\n", | ||
230 | config->name); | ||
231 | goto err; | ||
232 | } | ||
233 | if (!SSL_CTX_use_PrivateKey_file(ctx, server_key, | ||
234 | SSL_FILETYPE_PEM)) { | ||
235 | fprintf(stderr, "use_PrivateKey_file(%s) failed\n", | ||
236 | config->name); | ||
237 | goto err; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return ctx; | ||
242 | |||
243 | err: | ||
244 | SSL_CTX_free(ctx); | ||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | /* Connect client and server via a pair of "nonblocking" memory BIOs. */ | ||
249 | static int | ||
250 | connect_peers(SSL *client_ssl, SSL *server_ssl, const char *description) | ||
251 | { | ||
252 | BIO *client_wbio = NULL, *server_wbio = NULL; | ||
253 | int ret = 0; | ||
254 | |||
255 | if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) { | ||
256 | fprintf(stderr, "%s: failed to create client BIO\n", | ||
257 | description); | ||
258 | goto err; | ||
259 | } | ||
260 | if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) { | ||
261 | fprintf(stderr, "%s: failed to create server BIO\n", | ||
262 | description); | ||
263 | goto err; | ||
264 | } | ||
265 | if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) { | ||
266 | fprintf(stderr, "%s: failed to set client eof return\n", | ||
267 | description); | ||
268 | goto err; | ||
269 | } | ||
270 | if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) { | ||
271 | fprintf(stderr, "%s: failed to set server eof return\n", | ||
272 | description); | ||
273 | goto err; | ||
274 | } | ||
275 | |||
276 | /* Avoid double free. SSL_set_bio() takes ownership of the BIOs. */ | ||
277 | BIO_up_ref(client_wbio); | ||
278 | BIO_up_ref(server_wbio); | ||
279 | |||
280 | SSL_set_bio(client_ssl, server_wbio, client_wbio); | ||
281 | SSL_set_bio(server_ssl, client_wbio, server_wbio); | ||
282 | client_wbio = NULL; | ||
283 | server_wbio = NULL; | ||
284 | |||
285 | ret = 1; | ||
286 | |||
287 | err: | ||
288 | BIO_free(client_wbio); | ||
289 | BIO_free(server_wbio); | ||
290 | |||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | static int | ||
295 | push_data_to_peer(SSL *ssl, int *ret, int (*func)(SSL *), const char *func_name, | ||
296 | const char *description) | ||
297 | { | ||
298 | int ssl_err = 0; | ||
299 | |||
300 | if (*ret == 1) | ||
301 | return 1; | ||
302 | |||
303 | /* | ||
304 | * Do SSL_connect/SSL_accept/SSL_shutdown once and loop while hitting | ||
305 | * WANT_WRITE. If done or on WANT_READ hand off to peer. | ||
306 | */ | ||
307 | |||
308 | do { | ||
309 | if ((*ret = func(ssl)) <= 0) | ||
310 | ssl_err = SSL_get_error(ssl, *ret); | ||
311 | } while (*ret <= 0 && ssl_err == SSL_ERROR_WANT_WRITE); | ||
312 | |||
313 | /* Ignore erroneous error - see SSL_shutdown(3)... */ | ||
314 | if (func == SSL_shutdown && ssl_err == SSL_ERROR_SYSCALL) | ||
315 | return 1; | ||
316 | |||
317 | if (*ret <= 0 && ssl_err != SSL_ERROR_WANT_READ) { | ||
318 | fprintf(stderr, "%s: %s failed\n", description, func_name); | ||
319 | ERR_print_errors_fp(stderr); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * Alternate between loops of SSL_connect() and SSL_accept() as long as only | ||
328 | * WANT_READ and WANT_WRITE situations are encountered. A function is repeated | ||
329 | * until WANT_READ is returned or it succeeds, then it's the other function's | ||
330 | * turn to make progress. Succeeds if SSL_connect() and SSL_accept() return 1. | ||
331 | */ | ||
332 | static int | ||
333 | handshake(SSL *client_ssl, SSL *server_ssl, const char *description) | ||
334 | { | ||
335 | int loops = 0, client_ret = 0, server_ret = 0; | ||
336 | |||
337 | while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) { | ||
338 | if (!push_data_to_peer(client_ssl, &client_ret, SSL_connect, | ||
339 | "SSL_connect", description)) | ||
340 | return 0; | ||
341 | |||
342 | if (!push_data_to_peer(server_ssl, &server_ret, SSL_accept, | ||
343 | "SSL_accept", description)) | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | if (client_ret != 1 || server_ret != 1) { | ||
348 | fprintf(stderr, "%s: failed\n", __func__); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | return 1; | ||
353 | } | ||
354 | |||
355 | static int | ||
356 | shutdown_peers(SSL *client_ssl, SSL *server_ssl, const char *description) | ||
357 | { | ||
358 | int loops = 0, client_ret = 0, server_ret = 0; | ||
359 | |||
360 | while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) { | ||
361 | if (!push_data_to_peer(client_ssl, &client_ret, SSL_shutdown, | ||
362 | "client shutdown", description)) | ||
363 | return 0; | ||
364 | |||
365 | if (!push_data_to_peer(server_ssl, &server_ret, SSL_shutdown, | ||
366 | "server shutdown", description)) | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | if (client_ret != 1 || server_ret != 1) { | ||
371 | fprintf(stderr, "%s: failed\n", __func__); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | return 1; | ||
376 | } | ||
377 | |||
378 | /* from ssl_ciph.c */ | ||
379 | static inline int | ||
380 | ssl_aes_is_accelerated(void) | ||
381 | { | ||
382 | return (OPENSSL_cpu_caps() & CRYPTO_CPU_CAPS_ACCELERATED_AES) != 0; | ||
383 | } | ||
384 | |||
385 | static int | ||
386 | check_shared_ciphers(const struct ssl_shared_ciphers_test_data *test, | ||
387 | const char *got) | ||
388 | { | ||
389 | const char *want = test->shared_ciphers; | ||
390 | int failed; | ||
391 | |||
392 | if (!ssl_aes_is_accelerated() && | ||
393 | test->shared_ciphers_without_aesni != NULL) | ||
394 | want = test->shared_ciphers_without_aesni; | ||
395 | |||
396 | failed = strcmp(want, got); | ||
397 | |||
398 | if (failed) | ||
399 | fprintf(stderr, "%s: want \"%s\", got \"%s\"\n", | ||
400 | test->description, want, got); | ||
401 | |||
402 | return failed; | ||
403 | } | ||
404 | |||
405 | static int | ||
406 | test_get_shared_ciphers(const struct ssl_shared_ciphers_test_data *test) | ||
407 | { | ||
408 | SSL_CTX *client_ctx = NULL, *server_ctx = NULL; | ||
409 | SSL *client_ssl = NULL, *server_ssl = NULL; | ||
410 | char buf[4096]; | ||
411 | int failed = 1; | ||
412 | |||
413 | if ((client_ctx = peer_config_to_ssl_ctx(&test->client_config)) == NULL) | ||
414 | goto err; | ||
415 | if ((server_ctx = peer_config_to_ssl_ctx(&test->server_config)) == NULL) | ||
416 | goto err; | ||
417 | |||
418 | if ((client_ssl = SSL_new(client_ctx)) == NULL) { | ||
419 | fprintf(stderr, "%s: failed to create client SSL\n", | ||
420 | test->description); | ||
421 | goto err; | ||
422 | } | ||
423 | if ((server_ssl = SSL_new(server_ctx)) == NULL) { | ||
424 | fprintf(stderr, "%s: failed to create server SSL\n", | ||
425 | test->description); | ||
426 | goto err; | ||
427 | } | ||
428 | |||
429 | if (!connect_peers(client_ssl, server_ssl, test->description)) | ||
430 | goto err; | ||
431 | |||
432 | if (!handshake(client_ssl, server_ssl, test->description)) | ||
433 | goto err; | ||
434 | |||
435 | if (SSL_get_shared_ciphers(server_ssl, buf, sizeof(buf)) == NULL) { | ||
436 | fprintf(stderr, "%s: failed to get shared ciphers\n", | ||
437 | test->description); | ||
438 | goto err; | ||
439 | } | ||
440 | |||
441 | if (!shutdown_peers(client_ssl, server_ssl, test->description)) | ||
442 | goto err; | ||
443 | |||
444 | failed = check_shared_ciphers(test, buf); | ||
445 | |||
446 | err: | ||
447 | SSL_CTX_free(client_ctx); | ||
448 | SSL_CTX_free(server_ctx); | ||
449 | SSL_free(client_ssl); | ||
450 | SSL_free(server_ssl); | ||
451 | |||
452 | return failed; | ||
453 | } | ||
454 | |||
455 | int | ||
456 | main(int argc, char **argv) | ||
457 | { | ||
458 | size_t i; | ||
459 | int failed = 0; | ||
460 | |||
461 | if (asprintf(&server_cert, "%s/server1-rsa.pem", CERTSDIR) == -1) { | ||
462 | fprintf(stderr, "asprintf server_cert failed\n"); | ||
463 | failed = 1; | ||
464 | goto err; | ||
465 | } | ||
466 | server_key = server_cert; | ||
467 | |||
468 | for (i = 0; i < N_SHARED_CIPHERS_TESTS; i++) | ||
469 | failed |= test_get_shared_ciphers(&ssl_shared_ciphers_tests[i]); | ||
470 | |||
471 | if (failed == 0) | ||
472 | printf("PASS %s\n", __FILE__); | ||
473 | |||
474 | err: | ||
475 | free(server_cert); | ||
476 | |||
477 | return failed; | ||
478 | } | ||