diff options
author | tb <> | 2021-01-10 07:30:00 +0000 |
---|---|---|
committer | tb <> | 2021-01-10 07:30:00 +0000 |
commit | f87a04119b2512f09158a91231f8aad3831e4c9c (patch) | |
tree | fa0dd5d9d8e9e4e2f5dc08bfd4d7529d6c8d0351 /src/regress/lib | |
parent | dec687c524087eacbd4e3bcb58c7abec75fc5664 (diff) | |
download | openbsd-f87a04119b2512f09158a91231f8aad3831e4c9c.tar.gz openbsd-f87a04119b2512f09158a91231f8aad3831e4c9c.tar.bz2 openbsd-f87a04119b2512f09158a91231f8aad3831e4c9c.zip |
Add a regress for SSL_get_shared_ciphers() for the change of returned
ciphers in ssl_lib.c r1.240 and TLSv1.3 support in tls13_server.c r1.69.
requested by jsing
Diffstat (limited to 'src/regress/lib')
-rw-r--r-- | src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c | 457 |
1 files changed, 457 insertions, 0 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 new file mode 100644 index 0000000000..f83da3e2fa --- /dev/null +++ b/src/regress/lib/libssl/unit/ssl_get_shared_ciphers.c | |||
@@ -0,0 +1,457 @@ | |||
1 | /* $OpenBSD: ssl_get_shared_ciphers.c,v 1.1 2021/01/10 07:30:00 tb 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 <openssl/err.h> | ||
20 | #include <openssl/ssl.h> | ||
21 | |||
22 | struct peer_config { | ||
23 | const char *name; | ||
24 | int server; | ||
25 | uint16_t max_version; | ||
26 | uint16_t min_version; | ||
27 | const char *ciphers; | ||
28 | }; | ||
29 | |||
30 | struct ssl_shared_ciphers_test_data { | ||
31 | const char *description; | ||
32 | struct peer_config client_config; | ||
33 | struct peer_config server_config; | ||
34 | const char *shared_ciphers; | ||
35 | const char *shared_ciphers_without_aesni; | ||
36 | }; | ||
37 | |||
38 | char *server_cert; | ||
39 | char *server_key; | ||
40 | |||
41 | static const struct ssl_shared_ciphers_test_data ssl_shared_ciphers_tests[] = { | ||
42 | { | ||
43 | .description = "TLSv1.3 defaults", | ||
44 | .client_config = { | ||
45 | .name = "client", | ||
46 | .server = 0, | ||
47 | .max_version = TLS1_3_VERSION, | ||
48 | .min_version = TLS1_3_VERSION, | ||
49 | .ciphers = | ||
50 | "AEAD-AES256-GCM-SHA384:" | ||
51 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
52 | "AEAD-AES128-GCM-SHA256", | ||
53 | }, | ||
54 | .server_config = { | ||
55 | .name = "server", | ||
56 | .server = 1, | ||
57 | .max_version = TLS1_3_VERSION, | ||
58 | .min_version = TLS1_3_VERSION, | ||
59 | .ciphers = | ||
60 | "AEAD-AES256-GCM-SHA384:" | ||
61 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
62 | "AEAD-AES128-GCM-SHA256", | ||
63 | }, | ||
64 | .shared_ciphers = | ||
65 | "AEAD-AES256-GCM-SHA384:" | ||
66 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
67 | "AEAD-AES128-GCM-SHA256", | ||
68 | }, | ||
69 | |||
70 | { | ||
71 | .description = "TLSv1.3, client without ChaCha", | ||
72 | .client_config = { | ||
73 | .name = "client", | ||
74 | .server = 0, | ||
75 | .max_version = TLS1_3_VERSION, | ||
76 | .min_version = TLS1_3_VERSION, | ||
77 | .ciphers = | ||
78 | "AEAD-AES256-GCM-SHA384:" | ||
79 | "AEAD-AES128-GCM-SHA256", | ||
80 | }, | ||
81 | .server_config = { | ||
82 | .name = "server", | ||
83 | .server = 1, | ||
84 | .max_version = TLS1_3_VERSION, | ||
85 | .min_version = TLS1_3_VERSION, | ||
86 | .ciphers = | ||
87 | "AEAD-AES256-GCM-SHA384:" | ||
88 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
89 | "AEAD-AES128-GCM-SHA256", | ||
90 | }, | ||
91 | .shared_ciphers = | ||
92 | "AEAD-AES256-GCM-SHA384:" | ||
93 | "AEAD-AES128-GCM-SHA256", | ||
94 | }, | ||
95 | |||
96 | { | ||
97 | .description = "TLSv1.2", | ||
98 | .client_config = { | ||
99 | .name = "client", | ||
100 | .server = 0, | ||
101 | .max_version = TLS1_2_VERSION, | ||
102 | .min_version = TLS1_2_VERSION, | ||
103 | .ciphers = | ||
104 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
105 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
106 | "ECDHE-RSA-AES256-SHA384:" | ||
107 | "ECDHE-ECDSA-AES256-SHA384:" | ||
108 | "ECDHE-RSA-AES256-SHA:" | ||
109 | "ECDHE-ECDSA-AES256-SHA", | ||
110 | }, | ||
111 | .server_config = { | ||
112 | .name = "server", | ||
113 | .server = 1, | ||
114 | .max_version = TLS1_2_VERSION, | ||
115 | .min_version = TLS1_2_VERSION, | ||
116 | .ciphers = | ||
117 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
118 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
119 | "ECDHE-RSA-AES256-SHA384:" | ||
120 | "ECDHE-ECDSA-AES256-SHA384:" | ||
121 | "ECDHE-RSA-AES256-SHA:" | ||
122 | "ECDHE-ECDSA-AES256-SHA", | ||
123 | }, | ||
124 | .shared_ciphers = | ||
125 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
126 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
127 | "ECDHE-RSA-AES256-SHA384:" | ||
128 | "ECDHE-ECDSA-AES256-SHA384:" | ||
129 | "ECDHE-RSA-AES256-SHA:" | ||
130 | "ECDHE-ECDSA-AES256-SHA", | ||
131 | }, | ||
132 | |||
133 | { | ||
134 | .description = "TLSv1.2, server without ECDSA", | ||
135 | .client_config = { | ||
136 | .name = "client", | ||
137 | .server = 0, | ||
138 | .max_version = TLS1_2_VERSION, | ||
139 | .min_version = TLS1_2_VERSION, | ||
140 | .ciphers = | ||
141 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
142 | "ECDHE-ECDSA-AES256-GCM-SHA384:" | ||
143 | "ECDHE-RSA-AES256-SHA384:" | ||
144 | "ECDHE-ECDSA-AES256-SHA384:" | ||
145 | "ECDHE-RSA-AES256-SHA:" | ||
146 | "ECDHE-ECDSA-AES256-SHA", | ||
147 | }, | ||
148 | .server_config = { | ||
149 | .name = "server", | ||
150 | .server = 1, | ||
151 | .max_version = TLS1_2_VERSION, | ||
152 | .min_version = TLS1_2_VERSION, | ||
153 | .ciphers = | ||
154 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
155 | "ECDHE-RSA-AES256-SHA384:" | ||
156 | "ECDHE-RSA-AES256-SHA", | ||
157 | }, | ||
158 | .shared_ciphers = | ||
159 | "ECDHE-RSA-AES256-GCM-SHA384:" | ||
160 | "ECDHE-RSA-AES256-SHA384:" | ||
161 | "ECDHE-RSA-AES256-SHA", | ||
162 | }, | ||
163 | |||
164 | { | ||
165 | .description = "TLSv1.3 ciphers are prepended", | ||
166 | .client_config = { | ||
167 | .name = "client", | ||
168 | .server = 0, | ||
169 | .max_version = TLS1_3_VERSION, | ||
170 | .min_version = TLS1_2_VERSION, | ||
171 | .ciphers = | ||
172 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
173 | }, | ||
174 | .server_config = { | ||
175 | .name = "server", | ||
176 | .server = 1, | ||
177 | .max_version = TLS1_3_VERSION, | ||
178 | .min_version = TLS1_2_VERSION, | ||
179 | .ciphers = | ||
180 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
181 | }, | ||
182 | .shared_ciphers = | ||
183 | "AEAD-AES256-GCM-SHA384:" | ||
184 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
185 | "AEAD-AES128-GCM-SHA256:" | ||
186 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
187 | .shared_ciphers_without_aesni = | ||
188 | "AEAD-CHACHA20-POLY1305-SHA256:" | ||
189 | "AEAD-AES256-GCM-SHA384:" | ||
190 | "AEAD-AES128-GCM-SHA256:" | ||
191 | "ECDHE-RSA-AES256-GCM-SHA384", | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | static const size_t N_SHARED_CIPHERS_TESTS = | ||
196 | sizeof(ssl_shared_ciphers_tests) / sizeof(ssl_shared_ciphers_tests[0]); | ||
197 | |||
198 | static SSL_CTX * | ||
199 | peer_config_to_ssl_ctx(const struct peer_config *config) | ||
200 | { | ||
201 | SSL_CTX *ctx; | ||
202 | |||
203 | if ((ctx = SSL_CTX_new(TLS_method())) == NULL) { | ||
204 | fprintf(stderr, "SSL_CTX_new(%s) failed\n", config->name); | ||
205 | goto err; | ||
206 | } | ||
207 | if (!SSL_CTX_set_max_proto_version(ctx, config->max_version)) { | ||
208 | fprintf(stderr, "max_proto_version(%s) failed\n", config->name); | ||
209 | goto err; | ||
210 | } | ||
211 | if (!SSL_CTX_set_min_proto_version(ctx, config->min_version)) { | ||
212 | fprintf(stderr, "min_proto_version(%s) failed\n", config->name); | ||
213 | goto err; | ||
214 | } | ||
215 | if (!SSL_CTX_set_cipher_list(ctx, config->ciphers)) { | ||
216 | fprintf(stderr, "set_cipher_list(%s) failed\n", | ||
217 | config->name); | ||
218 | goto err; | ||
219 | } | ||
220 | |||
221 | SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); | ||
222 | |||
223 | if (config->server) { | ||
224 | if (!SSL_CTX_use_certificate_file(ctx, server_cert, | ||
225 | SSL_FILETYPE_PEM)) { | ||
226 | fprintf(stderr, "use_certificate_file(%s) failed\n", | ||
227 | config->name); | ||
228 | goto err; | ||
229 | } | ||
230 | if (!SSL_CTX_use_PrivateKey_file(ctx, server_key, | ||
231 | SSL_FILETYPE_PEM)) { | ||
232 | fprintf(stderr, "use_PrivateKey_file(%s) failed\n", | ||
233 | config->name); | ||
234 | goto err; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | return ctx; | ||
239 | |||
240 | err: | ||
241 | SSL_CTX_free(ctx); | ||
242 | return NULL; | ||
243 | } | ||
244 | |||
245 | /* Connect client and server via a pair of "nonblocking" memory BIOs. */ | ||
246 | static int | ||
247 | connect_peers(SSL *client_ssl, SSL *server_ssl, const char *description) | ||
248 | { | ||
249 | BIO *client_wbio = NULL, *server_wbio = NULL; | ||
250 | int ret = 0; | ||
251 | |||
252 | if ((client_wbio = BIO_new(BIO_s_mem())) == NULL) { | ||
253 | fprintf(stderr, "%s: failed to create client BIO\n", | ||
254 | description); | ||
255 | goto err; | ||
256 | } | ||
257 | if ((server_wbio = BIO_new(BIO_s_mem())) == NULL) { | ||
258 | fprintf(stderr, "%s: failed to create server BIO\n", | ||
259 | description); | ||
260 | goto err; | ||
261 | } | ||
262 | if (BIO_set_mem_eof_return(client_wbio, -1) <= 0) { | ||
263 | fprintf(stderr, "%s: failed to set client eof return\n", | ||
264 | description); | ||
265 | goto err; | ||
266 | } | ||
267 | if (BIO_set_mem_eof_return(server_wbio, -1) <= 0) { | ||
268 | fprintf(stderr, "%s: failed to set server eof return\n", | ||
269 | description); | ||
270 | goto err; | ||
271 | } | ||
272 | |||
273 | /* Avoid double free. SSL_set_bio() takes ownership of the BIOs. */ | ||
274 | BIO_up_ref(client_wbio); | ||
275 | BIO_up_ref(server_wbio); | ||
276 | |||
277 | SSL_set_bio(client_ssl, server_wbio, client_wbio); | ||
278 | SSL_set_bio(server_ssl, client_wbio, server_wbio); | ||
279 | client_wbio = NULL; | ||
280 | server_wbio = NULL; | ||
281 | |||
282 | ret = 1; | ||
283 | |||
284 | err: | ||
285 | BIO_free(client_wbio); | ||
286 | BIO_free(server_wbio); | ||
287 | |||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | push_data_to_peer(SSL *ssl, int *ret, int (*func)(SSL *), const char *func_name, | ||
293 | const char *description) | ||
294 | { | ||
295 | int ssl_err = 0; | ||
296 | |||
297 | if (*ret == 1) | ||
298 | return 1; | ||
299 | |||
300 | /* | ||
301 | * Do SSL_connect/SSL_accept once and loop while hitting WANT_WRITE. | ||
302 | * If done or on WANT_READ hand off to peer. | ||
303 | */ | ||
304 | |||
305 | do { | ||
306 | if ((*ret = func(ssl)) <= 0) | ||
307 | ssl_err = SSL_get_error(ssl, *ret); | ||
308 | } while (*ret <= 0 && ssl_err == SSL_ERROR_WANT_WRITE); | ||
309 | |||
310 | if (*ret <= 0 && ssl_err != SSL_ERROR_WANT_READ) { | ||
311 | fprintf(stderr, "%s: %s failed\n", description, func_name); | ||
312 | ERR_print_errors_fp(stderr); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | return 1; | ||
317 | } | ||
318 | |||
319 | static int | ||
320 | handshake_loop(SSL *client_ssl, int *client_ret, SSL *server_ssl, | ||
321 | int *server_ret, const char *description) | ||
322 | { | ||
323 | if (!push_data_to_peer(client_ssl, client_ret, SSL_connect, | ||
324 | "SSL_connect", description)) | ||
325 | return 0; | ||
326 | |||
327 | if (!push_data_to_peer(server_ssl, server_ret, SSL_accept, | ||
328 | "SSL_accept", description)) | ||
329 | return 0; | ||
330 | |||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Alternate between loops of SSL_connect() and SSL_accept() as long as only | ||
336 | * WANT_READ and WANT_WRITE situations are encountered. A function is repeated | ||
337 | * while WANT_WRITE is returned or it succeeds, then it's the other functions | ||
338 | * turn to make progress. Success: both functions returned 1. | ||
339 | */ | ||
340 | static int | ||
341 | handshake(SSL *client_ssl, SSL *server_ssl, const char *description) | ||
342 | { | ||
343 | int loops = 0, client_ret = 0, server_ret = 0; | ||
344 | |||
345 | while (loops++ < 10 && (client_ret <= 0 || server_ret <= 0)) { | ||
346 | if (!handshake_loop(client_ssl, &client_ret, server_ssl, | ||
347 | &server_ret, description)) | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | return client_ret == 1 && server_ret == 1; | ||
352 | } | ||
353 | |||
354 | /* from ssl_ciph.c */ | ||
355 | static inline int | ||
356 | ssl_aes_is_accelerated(void) | ||
357 | { | ||
358 | #if defined(__i386__) || defined(__x86_64__) | ||
359 | return ((OPENSSL_cpu_caps() & (1ULL << 57)) != 0); | ||
360 | #else | ||
361 | return (0); | ||
362 | #endif | ||
363 | } | ||
364 | |||
365 | static int | ||
366 | check_shared_ciphers(const struct ssl_shared_ciphers_test_data *test, | ||
367 | const char *got) | ||
368 | { | ||
369 | const char *want = test->shared_ciphers; | ||
370 | int failed; | ||
371 | |||
372 | failed = strcmp(want, got); | ||
373 | |||
374 | if (failed && !ssl_aes_is_accelerated() && | ||
375 | test->shared_ciphers_without_aesni != NULL) { | ||
376 | want = test->shared_ciphers_without_aesni; | ||
377 | failed = strcmp(want, got); | ||
378 | } | ||
379 | |||
380 | if (failed) | ||
381 | fprintf(stderr, "%s: want \"%s\", got \"%s\"\n", | ||
382 | test->description, want, got); | ||
383 | |||
384 | return failed; | ||
385 | } | ||
386 | |||
387 | static int | ||
388 | test_get_shared_ciphers(const struct ssl_shared_ciphers_test_data *test) | ||
389 | { | ||
390 | SSL_CTX *client_ctx = NULL, *server_ctx = NULL; | ||
391 | SSL *client_ssl = NULL, *server_ssl = NULL; | ||
392 | char buf[4096]; | ||
393 | int failed = 1; | ||
394 | |||
395 | if ((client_ctx = peer_config_to_ssl_ctx(&test->client_config)) == NULL) | ||
396 | goto err; | ||
397 | if ((server_ctx = peer_config_to_ssl_ctx(&test->server_config)) == NULL) | ||
398 | goto err; | ||
399 | |||
400 | if ((client_ssl = SSL_new(client_ctx)) == NULL) { | ||
401 | fprintf(stderr, "%s: failed to create client SSL\n", | ||
402 | test->description); | ||
403 | goto err; | ||
404 | } | ||
405 | if ((server_ssl = SSL_new(server_ctx)) == NULL) { | ||
406 | fprintf(stderr, "%s: failed to create server SSL\n", | ||
407 | test->description); | ||
408 | goto err; | ||
409 | } | ||
410 | |||
411 | if (!connect_peers(client_ssl, server_ssl, test->description)) | ||
412 | goto err; | ||
413 | |||
414 | if (!handshake(client_ssl, server_ssl, test->description)) | ||
415 | goto err; | ||
416 | |||
417 | if (SSL_get_shared_ciphers(server_ssl, buf, sizeof(buf)) == NULL) { | ||
418 | fprintf(stderr, "%s: failed to get shared ciphers\n", | ||
419 | test->description); | ||
420 | goto err; | ||
421 | } | ||
422 | |||
423 | failed = check_shared_ciphers(test, buf); | ||
424 | |||
425 | err: | ||
426 | SSL_CTX_free(client_ctx); | ||
427 | SSL_CTX_free(server_ctx); | ||
428 | SSL_free(client_ssl); | ||
429 | SSL_free(server_ssl); | ||
430 | |||
431 | return failed; | ||
432 | } | ||
433 | |||
434 | int | ||
435 | main(int argc, char **argv) | ||
436 | { | ||
437 | size_t i; | ||
438 | int failed = 0; | ||
439 | |||
440 | if (asprintf(&server_cert, "%s/../certs/server.pem", CURDIR) == -1) { | ||
441 | fprintf(stderr, "asprintf server_cert failed\n"); | ||
442 | failed = 1; | ||
443 | goto err; | ||
444 | } | ||
445 | server_key = server_cert; | ||
446 | |||
447 | for (i = 0; i < N_SHARED_CIPHERS_TESTS; i++) | ||
448 | failed |= test_get_shared_ciphers(&ssl_shared_ciphers_tests[i]); | ||
449 | |||
450 | if (failed == 0) | ||
451 | printf("PASS %s\n", __FILE__); | ||
452 | |||
453 | err: | ||
454 | free(server_cert); | ||
455 | |||
456 | return failed; | ||
457 | } | ||