xref: /openbsd-src/regress/lib/libssl/ciphers/cipherstest.c (revision 513cf72f82c16dd38f89b0e7a0ec4a163d87f81f)
1 /*
2  * Copyright (c) 2015, 2020 Joel Sing <jsing@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <openssl/ssl.h>
18 
19 #include <err.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 int ssl3_num_ciphers(void);
24 const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
25 
26 int ssl_parse_ciphersuites(STACK_OF(SSL_CIPHER) **out_ciphers, const char *str);
27 
28 static inline int
29 ssl_aes_is_accelerated(void)
30 {
31 #if defined(__i386__) || defined(__x86_64__)
32 	return ((OPENSSL_cpu_caps() & (1ULL << 57)) != 0);
33 #else
34 	return (0);
35 #endif
36 }
37 
38 static int
39 check_cipher_order(void)
40 {
41 	unsigned long id, prev_id = 0;
42 	const SSL_CIPHER *cipher;
43 	int num_ciphers;
44 	int i;
45 
46 	num_ciphers = ssl3_num_ciphers();
47 
48 	for (i = 1; i <= num_ciphers; i++) {
49 		/*
50 		 * For some reason, ssl3_get_cipher() returns ciphers in
51 		 * reverse order.
52 		 */
53 		if ((cipher = ssl3_get_cipher(num_ciphers - i)) == NULL) {
54 			fprintf(stderr, "FAIL: ssl3_get_cipher(%d) returned "
55 			    "NULL\n", i);
56 			return 1;
57 		}
58 		if ((id = SSL_CIPHER_get_id(cipher)) <= prev_id) {
59 			fprintf(stderr, "FAIL: ssl3_ciphers is not sorted by "
60 			    "id - cipher %d (%lx) <= cipher %d (%lx)\n",
61 			    i, id, i - 1, prev_id);
62 			return 1;
63 		}
64 		prev_id = id;
65 	}
66 
67 	return 0;
68 }
69 
70 static int
71 cipher_find_test(void)
72 {
73 	STACK_OF(SSL_CIPHER) *ciphers;
74 	const SSL_CIPHER *cipher;
75 	unsigned char buf[2];
76 	SSL_CTX *ssl_ctx = NULL;
77 	SSL *ssl = NULL;
78 	int ret = 1;
79 	int i;
80 
81 	if ((ssl_ctx = SSL_CTX_new(TLS_method())) == NULL) {
82 		fprintf(stderr, "SSL_CTX_new() returned NULL\n");
83 		goto failure;
84 	}
85 	if ((ssl = SSL_new(ssl_ctx)) == NULL) {
86 		fprintf(stderr, "SSL_new() returned NULL\n");
87 		goto failure;
88 	}
89 	if (!SSL_set_cipher_list(ssl, "ALL")) {
90 		fprintf(stderr, "SSL_set_cipher_list failed\n");
91 		goto failure;
92 	}
93 
94 	if ((ciphers = SSL_get_ciphers(ssl)) == NULL) {
95 		fprintf(stderr, "no ciphers\n");
96 		goto failure;
97 	}
98 
99 	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
100 		uint16_t cipher_value;
101 
102 		cipher = sk_SSL_CIPHER_value(ciphers, i);
103 		cipher_value = SSL_CIPHER_get_value(cipher);
104 
105 		buf[0] = cipher_value >> 8;
106 		buf[1] = cipher_value & 0xff;
107 
108 		if ((cipher = SSL_CIPHER_find(ssl, buf)) == NULL) {
109 			fprintf(stderr,
110 			    "SSL_CIPHER_find() returned NULL for %s\n",
111 			    SSL_CIPHER_get_name(cipher));
112 			goto failure;
113 		}
114 
115 		if (SSL_CIPHER_get_value(cipher) != cipher_value) {
116 			fprintf(stderr,
117 			    "got cipher with value 0x%x, want 0x%x\n",
118 			    SSL_CIPHER_get_value(cipher), cipher_value);
119 			goto failure;
120 		}
121 	}
122 
123 	ret = 0;
124 
125  failure:
126 	SSL_CTX_free(ssl_ctx);
127 	SSL_free(ssl);
128 
129 	return (ret);
130 }
131 
132 struct parse_ciphersuites_test {
133 	const char *str;
134 	const int want;
135 	const unsigned long cids[32];
136 };
137 
138 struct parse_ciphersuites_test parse_ciphersuites_tests[] = {
139 	{
140 		/* LibreSSL names. */
141 		.str = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256:AEAD-AES128-GCM-SHA256",
142 		.want = 1,
143 		.cids = {
144 			TLS1_3_CK_AES_256_GCM_SHA384,
145 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
146 			TLS1_3_CK_AES_128_GCM_SHA256,
147 		},
148 	},
149 	{
150 		/* OpenSSL names. */
151 		.str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256",
152 		.want = 1,
153 		.cids = {
154 			TLS1_3_CK_AES_256_GCM_SHA384,
155 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
156 			TLS1_3_CK_AES_128_GCM_SHA256,
157 		},
158 	},
159 	{
160 		/* Different priority order. */
161 		.str = "AEAD-AES128-GCM-SHA256:AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
162 		.want = 1,
163 		.cids = {
164 			TLS1_3_CK_AES_128_GCM_SHA256,
165 			TLS1_3_CK_AES_256_GCM_SHA384,
166 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
167 		},
168 	},
169 	{
170 		/* Known but unsupported names. */
171 		.str = "AEAD-AES256-GCM-SHA384:AEAD-AES128-CCM-SHA256:AEAD-AES128-CCM-8-SHA256",
172 		.want = 1,
173 		.cids = {
174 			TLS1_3_CK_AES_256_GCM_SHA384,
175 		},
176 	},
177 	{
178 		/* Empty string means no TLSv1.3 ciphersuites. */
179 		.str = "",
180 		.want = 1,
181 		.cids = { 0 },
182 	},
183 	{
184 		.str = "TLS_CHACHA20_POLY1305_SHA256:TLS_NOT_A_CIPHERSUITE",
185 		.want = 0,
186 	},
187 	{
188 		.str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256",
189 		.want = 0,
190 	},
191 };
192 
193 #define N_PARSE_CIPHERSUITES_TESTS \
194     (sizeof(parse_ciphersuites_tests) / sizeof(*parse_ciphersuites_tests))
195 
196 static int
197 parse_ciphersuites_test(void)
198 {
199 	struct parse_ciphersuites_test *pct;
200 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
201 	SSL_CIPHER *cipher;
202 	int failed = 1;
203 	int j, ret;
204 	size_t i;
205 
206 	for (i = 0; i < N_PARSE_CIPHERSUITES_TESTS; i++) {
207 		pct = &parse_ciphersuites_tests[i];
208 
209 		ret = ssl_parse_ciphersuites(&ciphers, pct->str);
210 		if (ret != pct->want) {
211 			fprintf(stderr, "FAIL: test %zu - "
212 			    "ssl_parse_ciphersuites returned %d, want %d\n",
213 			    i, ret, pct->want);
214 			goto failed;
215 		}
216 		if (ret == 0)
217 			continue;
218 
219 		for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) {
220 			cipher = sk_SSL_CIPHER_value(ciphers, j);
221 			if (SSL_CIPHER_get_id(cipher) == pct->cids[j])
222 				continue;
223 			fprintf(stderr, "FAIL: test %zu - got cipher %d with "
224 			    "id %lx, want %lx\n", i, j,
225 			    SSL_CIPHER_get_id(cipher), pct->cids[j]);
226 			goto failed;
227 		}
228 		if (pct->cids[j] != 0) {
229 			fprintf(stderr, "FAIL: test %zu - got %d ciphers, "
230 			    "expected more", i, sk_SSL_CIPHER_num(ciphers));
231 			goto failed;
232 		}
233 	}
234 
235 	failed = 0;
236 
237  failed:
238 	sk_SSL_CIPHER_free(ciphers);
239 
240 	return failed;
241 }
242 
243 struct cipher_set_test {
244 	int ctx_ciphersuites_first;
245 	const char *ctx_ciphersuites;
246 	const char *ctx_rulestr;
247 	int ssl_ciphersuites_first;
248 	const char *ssl_ciphersuites;
249 	const char *ssl_rulestr;
250 	int cids_aes_accel_fixup;
251 	unsigned long cids[32];
252 };
253 
254 struct cipher_set_test cipher_set_tests[] = {
255 	{
256 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
257 		.cids_aes_accel_fixup = 1,
258 		.cids = {
259 			TLS1_3_CK_AES_256_GCM_SHA384,
260 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
261 			TLS1_3_CK_AES_128_GCM_SHA256,
262 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
263 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
264 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
265 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
266 		},
267 	},
268 	{
269 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
270 		.cids_aes_accel_fixup = 1,
271 		.cids = {
272 			TLS1_3_CK_AES_256_GCM_SHA384,
273 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
274 			TLS1_3_CK_AES_128_GCM_SHA256,
275 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
276 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
277 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
278 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
279 		},
280 	},
281 	{
282 		.ctx_ciphersuites_first = 1,
283 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
284 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
285 		.cids = {
286 			TLS1_3_CK_AES_256_GCM_SHA384,
287 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
288 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
289 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
290 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
291 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
292 		},
293 	},
294 	{
295 		.ssl_ciphersuites_first = 1,
296 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
297 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
298 		.cids = {
299 			TLS1_3_CK_AES_256_GCM_SHA384,
300 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
301 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
302 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
303 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
304 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
305 		},
306 	},
307 	{
308 		.ctx_ciphersuites_first = 0,
309 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
310 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
311 		.cids = {
312 			TLS1_3_CK_AES_256_GCM_SHA384,
313 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
314 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
315 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
316 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
317 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
318 		},
319 	},
320 	{
321 		.ssl_ciphersuites_first = 0,
322 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
323 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
324 		.cids = {
325 			TLS1_3_CK_AES_256_GCM_SHA384,
326 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
327 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
328 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
329 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
330 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
331 		},
332 	},
333 	{
334 		.ssl_ciphersuites_first = 1,
335 		.ssl_ciphersuites = "",
336 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
337 		.cids = {
338 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
339 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
340 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
341 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
342 		},
343 	},
344 	{
345 		.ssl_ciphersuites_first = 0,
346 		.ssl_ciphersuites = "",
347 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
348 		.cids = {
349 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
350 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
351 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
352 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
353 		},
354 	},
355 	{
356 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
357 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
358 		.cids = {
359 			TLS1_3_CK_AES_256_GCM_SHA384,
360 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
361 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
362 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
363 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
364 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
365 		},
366 	},
367 	{
368 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
369 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
370 		.cids = {
371 			TLS1_3_CK_AES_256_GCM_SHA384,
372 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
373 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
374 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
375 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
376 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
377 		},
378 	},
379 };
380 
381 #define N_CIPHER_SET_TESTS \
382     (sizeof(cipher_set_tests) / sizeof(*cipher_set_tests))
383 
384 static int
385 cipher_set_test(void)
386 {
387 	struct cipher_set_test *cst;
388 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
389 	SSL_CIPHER *cipher;
390 	SSL_CTX *ctx = NULL;
391 	SSL *ssl = NULL;
392 	int failed = 0;
393 	size_t i;
394 	int j;
395 
396 	for (i = 0; i < N_CIPHER_SET_TESTS; i++) {
397 		cst = &cipher_set_tests[i];
398 
399 		if (!ssl_aes_is_accelerated() && cst->cids_aes_accel_fixup) {
400 			cst->cids[0] = TLS1_3_CK_CHACHA20_POLY1305_SHA256;
401 			cst->cids[1] = TLS1_3_CK_AES_256_GCM_SHA384;
402 		}
403 
404 		if ((ctx = SSL_CTX_new(TLS_method())) == NULL)
405 			errx(1, "SSL_CTX_new");
406 
407 		if (cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) {
408 			if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites))
409 				errx(1, "SSL_CTX_set_ciphersuites");
410 		}
411 		if (cst->ctx_rulestr != NULL) {
412 			if (!SSL_CTX_set_cipher_list(ctx, cst->ctx_rulestr))
413 				errx(1, "SSL_CTX_set_cipher_list");
414 		}
415 		if (!cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) {
416 			if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites))
417 				errx(1, "SSL_CTX_set_ciphersuites");
418 		}
419 
420 		/* XXX - check SSL_CTX_get_ciphers(ctx) */
421 
422 		if ((ssl = SSL_new(ctx)) == NULL)
423 			errx(1, "SSL_new");
424 
425 		if (cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) {
426 			if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites))
427 				errx(1, "SSL_set_ciphersuites");
428 		}
429 		if (cst->ssl_rulestr != NULL) {
430 			if (!SSL_set_cipher_list(ssl, cst->ssl_rulestr))
431 				errx(1, "SSL_set_cipher_list");
432 		}
433 		if (!cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) {
434 			if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites))
435 				errx(1, "SSL_set_ciphersuites");
436 		}
437 
438 		ciphers = SSL_get_ciphers(ssl);
439 
440 		for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) {
441 			cipher = sk_SSL_CIPHER_value(ciphers, j);
442 			if (SSL_CIPHER_get_id(cipher) == cst->cids[j])
443 				continue;
444 			fprintf(stderr, "FAIL: test %zu - got cipher %d with "
445 			    "id %lx, want %lx\n", i, j,
446 			    SSL_CIPHER_get_id(cipher), cst->cids[j]);
447 			failed |= 1;
448 		}
449 		if (cst->cids[j] != 0) {
450 			fprintf(stderr, "FAIL: test %zu - got %d ciphers, "
451 			    "expected more", i, sk_SSL_CIPHER_num(ciphers));
452 			failed |= 1;
453 		}
454 
455 		SSL_CTX_free(ctx);
456 		SSL_free(ssl);
457 	}
458 
459 	return failed;
460 }
461 
462 int
463 main(int argc, char **argv)
464 {
465 	int failed = 0;
466 
467 	failed |= check_cipher_order();
468 
469 	failed |= cipher_find_test();
470 
471 	failed |= parse_ciphersuites_test();
472 	failed |= cipher_set_test();
473 
474 	return (failed);
475 }
476