summaryrefslogtreecommitdiff
path: root/src/regress/lib
diff options
context:
space:
mode:
authortb <>2021-01-10 07:30:00 +0000
committertb <>2021-01-10 07:30:00 +0000
commitf87a04119b2512f09158a91231f8aad3831e4c9c (patch)
treefa0dd5d9d8e9e4e2f5dc08bfd4d7529d6c8d0351 /src/regress/lib
parentdec687c524087eacbd4e3bcb58c7abec75fc5664 (diff)
downloadopenbsd-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.c457
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
22struct 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
30struct 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
38char *server_cert;
39char *server_key;
40
41static 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
195static const size_t N_SHARED_CIPHERS_TESTS =
196 sizeof(ssl_shared_ciphers_tests) / sizeof(ssl_shared_ciphers_tests[0]);
197
198static SSL_CTX *
199peer_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. */
246static int
247connect_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
291static int
292push_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
319static int
320handshake_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 */
340static int
341handshake(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 */
355static inline int
356ssl_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
365static int
366check_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
387static int
388test_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
434int
435main(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}