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 ssl_parse_ciphersuites(STACK_OF(SSL_CIPHER) **out_ciphers, const char *str);
24 
25 static inline int
26 ssl_aes_is_accelerated(void)
27 {
28 #if defined(__i386__) || defined(__x86_64__)
29 	return ((OPENSSL_cpu_caps() & (1ULL << 57)) != 0);
30 #else
31 	return (0);
32 #endif
33 }
34 
35 static int
36 get_put_test(const char *name, const SSL_METHOD *method)
37 {
38 	STACK_OF(SSL_CIPHER) *ciphers;
39 	const SSL_CIPHER *cipher;
40 	unsigned char buf[2];
41 	SSL_CTX *ssl_ctx = NULL;
42 	SSL *ssl = NULL;
43 	int ret = 1;
44 	int i, len;
45 
46 	if ((len = method->put_cipher_by_char(NULL, NULL)) != 2) {
47 		fprintf(stderr,
48 		    "%s: put_cipher_by_char() returned len %i (want 2)\n",
49 		    name, len);
50 		return (1);
51 	}
52 
53 	if ((ssl_ctx = SSL_CTX_new(method)) == NULL) {
54 		fprintf(stderr, "%s: SSL_CTX_new() returned NULL\n", name);
55 		goto failure;
56 	}
57 	if ((ssl = SSL_new(ssl_ctx)) == NULL) {
58 		fprintf(stderr, "%s: SSL_new() returned NULL\n", name);
59 		goto failure;
60 	}
61 
62 	if ((ciphers = SSL_get_ciphers(ssl)) == NULL) {
63 		fprintf(stderr, "%s: no ciphers\n", name);
64 		goto failure;
65 	}
66 
67 	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
68 		cipher = sk_SSL_CIPHER_value(ciphers, i);
69 		if ((len = method->put_cipher_by_char(cipher, buf)) != 2) {
70 			fprintf(stderr,
71 			    "%s: put_cipher_by_char() returned len %i for %s "
72 			    "(want 2)\n",
73 			    name, len, SSL_CIPHER_get_name(cipher));
74 			goto failure;
75 		}
76 		if ((cipher = method->get_cipher_by_char(buf)) == NULL) {
77 			fprintf(stderr,
78 			    "%s: get_cipher_by_char() returned NULL for %s\n",
79 			    name, SSL_CIPHER_get_name(cipher));
80 			goto failure;
81 		}
82 	}
83 
84 	ret = 0;
85 
86  failure:
87 	SSL_CTX_free(ssl_ctx);
88 	SSL_free(ssl);
89 
90 	return (ret);
91 }
92 
93 static int
94 cipher_get_put_tests(void)
95 {
96 	int failed = 0;
97 
98 	failed |= get_put_test("SSLv23", SSLv23_method());
99 	failed |= get_put_test("SSLv23_client", SSLv23_client_method());
100 	failed |= get_put_test("SSLv23_server", SSLv23_server_method());
101 
102 	failed |= get_put_test("TLSv1", TLSv1_method());
103 	failed |= get_put_test("TLSv1_client", TLSv1_client_method());
104 	failed |= get_put_test("TLSv1_server", TLSv1_server_method());
105 
106 	failed |= get_put_test("TLSv1_1", TLSv1_1_method());
107 	failed |= get_put_test("TLSv1_1_client", TLSv1_1_client_method());
108 	failed |= get_put_test("TLSv1_1_server", TLSv1_1_server_method());
109 
110 	failed |= get_put_test("TLSv1_2", TLSv1_2_method());
111 	failed |= get_put_test("TLSv1_2_client", TLSv1_2_client_method());
112 	failed |= get_put_test("TLSv1_2_server", TLSv1_2_server_method());
113 
114 	failed |= get_put_test("DTLSv1", DTLSv1_method());
115 	failed |= get_put_test("DTLSv1_client", DTLSv1_client_method());
116 	failed |= get_put_test("DTLSv1_server", DTLSv1_server_method());
117 
118 	return failed;
119 }
120 
121 static int
122 cipher_get_by_value_tests(void)
123 {
124 	STACK_OF(SSL_CIPHER) *ciphers;
125 	const SSL_CIPHER *cipher;
126 	SSL_CTX *ssl_ctx = NULL;
127 	SSL *ssl = NULL;
128 	unsigned long id;
129 	uint16_t value;
130 	int ret = 1;
131 	int i;
132 
133 	if ((ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL) {
134 		fprintf(stderr, "SSL_CTX_new() returned NULL\n");
135 		goto failure;
136 	}
137 	if ((ssl = SSL_new(ssl_ctx)) == NULL) {
138 		fprintf(stderr, "SSL_new() returned NULL\n");
139 		goto failure;
140 	}
141 
142 	if ((ciphers = SSL_get_ciphers(ssl)) == NULL) {
143 		fprintf(stderr, "no ciphers\n");
144 		goto failure;
145 	}
146 
147 	for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
148 		cipher = sk_SSL_CIPHER_value(ciphers, i);
149 
150 		id = SSL_CIPHER_get_id(cipher);
151 		if (SSL_CIPHER_get_by_id(id) == NULL) {
152 			fprintf(stderr, "SSL_CIPHER_get_by_id() failed "
153 			    "for %s (0x%lx)\n", SSL_CIPHER_get_name(cipher),
154 			    id);
155 			goto failure;
156 		}
157 
158 		value = SSL_CIPHER_get_value(cipher);
159 		if (SSL_CIPHER_get_by_value(value) == NULL) {
160 			fprintf(stderr, "SSL_CIPHER_get_by_value() failed "
161 			    "for %s (0x%04hx)\n", SSL_CIPHER_get_name(cipher),
162 			    value);
163 			goto failure;
164 		}
165 	}
166 
167 	ret = 0;
168 
169  failure:
170 	SSL_CTX_free(ssl_ctx);
171 	SSL_free(ssl);
172 
173 	return (ret);
174 }
175 
176 struct parse_ciphersuites_test {
177 	const char *str;
178 	const int want;
179 	const unsigned long cids[32];
180 };
181 
182 struct parse_ciphersuites_test parse_ciphersuites_tests[] = {
183 	{
184 		/* LibreSSL names. */
185 		.str = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256:AEAD-AES128-GCM-SHA256",
186 		.want = 1,
187 		.cids = {
188 			TLS1_3_CK_AES_256_GCM_SHA384,
189 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
190 			TLS1_3_CK_AES_128_GCM_SHA256,
191 		},
192 	},
193 	{
194 		/* OpenSSL names. */
195 		.str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256",
196 		.want = 1,
197 		.cids = {
198 			TLS1_3_CK_AES_256_GCM_SHA384,
199 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
200 			TLS1_3_CK_AES_128_GCM_SHA256,
201 		},
202 	},
203 	{
204 		/* Different priority order. */
205 		.str = "AEAD-AES128-GCM-SHA256:AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
206 		.want = 1,
207 		.cids = {
208 			TLS1_3_CK_AES_128_GCM_SHA256,
209 			TLS1_3_CK_AES_256_GCM_SHA384,
210 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
211 		},
212 	},
213 	{
214 		/* Known but unsupported names. */
215 		.str = "AEAD-AES256-GCM-SHA384:AEAD-AES128-CCM-SHA256:AEAD-AES128-CCM-8-SHA256",
216 		.want = 1,
217 		.cids = {
218 			TLS1_3_CK_AES_256_GCM_SHA384,
219 		},
220 	},
221 	{
222 		/* Empty string means no TLSv1.3 ciphersuites. */
223 		.str = "",
224 		.want = 1,
225 		.cids = { 0 },
226 	},
227 	{
228 		.str = "TLS_CHACHA20_POLY1305_SHA256:TLS_NOT_A_CIPHERSUITE",
229 		.want = 0,
230 	},
231 	{
232 		.str = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256",
233 		.want = 0,
234 	},
235 };
236 
237 #define N_PARSE_CIPHERSUITES_TESTS \
238     (sizeof(parse_ciphersuites_tests) / sizeof(*parse_ciphersuites_tests))
239 
240 static int
241 parse_ciphersuites_test(void)
242 {
243 	struct parse_ciphersuites_test *pct;
244 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
245 	SSL_CIPHER *cipher;
246 	int failed = 1;
247 	int j, ret;
248 	size_t i;
249 
250 	for (i = 0; i < N_PARSE_CIPHERSUITES_TESTS; i++) {
251 		pct = &parse_ciphersuites_tests[i];
252 
253 		ret = ssl_parse_ciphersuites(&ciphers, pct->str);
254 		if (ret != pct->want) {
255 			fprintf(stderr, "FAIL: test %zu - "
256 			    "ssl_parse_ciphersuites returned %d, want %d\n",
257 			    i, ret, pct->want);
258 			goto failed;
259 		}
260 		if (ret == 0)
261 			continue;
262 
263 		for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) {
264 			cipher = sk_SSL_CIPHER_value(ciphers, j);
265 			if (SSL_CIPHER_get_id(cipher) == pct->cids[j])
266 				continue;
267 			fprintf(stderr, "FAIL: test %zu - got cipher %d with "
268 			    "id %lx, want %lx\n", i, j,
269 			    SSL_CIPHER_get_id(cipher), pct->cids[j]);
270 			goto failed;
271 		}
272 		if (pct->cids[j] != 0) {
273 			fprintf(stderr, "FAIL: test %zu - got %d ciphers, "
274 			    "expected more", i, sk_SSL_CIPHER_num(ciphers));
275 			goto failed;
276 		}
277 	}
278 
279 	failed = 0;
280 
281  failed:
282 	sk_SSL_CIPHER_free(ciphers);
283 
284 	return failed;
285 }
286 
287 struct cipher_set_test {
288 	int ctx_ciphersuites_first;
289 	const char *ctx_ciphersuites;
290 	const char *ctx_rulestr;
291 	int ssl_ciphersuites_first;
292 	const char *ssl_ciphersuites;
293 	const char *ssl_rulestr;
294 	int cids_aes_accel_fixup;
295 	unsigned long cids[32];
296 };
297 
298 struct cipher_set_test cipher_set_tests[] = {
299 	{
300 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
301 		.cids_aes_accel_fixup = 1,
302 		.cids = {
303 			TLS1_3_CK_AES_256_GCM_SHA384,
304 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
305 			TLS1_3_CK_AES_128_GCM_SHA256,
306 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
307 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
308 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
309 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
310 		},
311 	},
312 	{
313 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
314 		.cids_aes_accel_fixup = 1,
315 		.cids = {
316 			TLS1_3_CK_AES_256_GCM_SHA384,
317 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
318 			TLS1_3_CK_AES_128_GCM_SHA256,
319 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
320 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
321 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
322 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
323 		},
324 	},
325 	{
326 		.ctx_ciphersuites_first = 1,
327 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
328 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
329 		.cids = {
330 			TLS1_3_CK_AES_256_GCM_SHA384,
331 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
332 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
333 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
334 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
335 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
336 		},
337 	},
338 	{
339 		.ssl_ciphersuites_first = 1,
340 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
341 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
342 		.cids = {
343 			TLS1_3_CK_AES_256_GCM_SHA384,
344 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
345 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
346 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
347 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
348 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
349 		},
350 	},
351 	{
352 		.ctx_ciphersuites_first = 0,
353 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
354 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
355 		.cids = {
356 			TLS1_3_CK_AES_256_GCM_SHA384,
357 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
358 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
359 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
360 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
361 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
362 		},
363 	},
364 	{
365 		.ssl_ciphersuites_first = 0,
366 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
367 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
368 		.cids = {
369 			TLS1_3_CK_AES_256_GCM_SHA384,
370 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
371 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
372 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
373 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
374 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
375 		},
376 	},
377 	{
378 		.ssl_ciphersuites_first = 1,
379 		.ssl_ciphersuites = "",
380 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
381 		.cids = {
382 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
383 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
384 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
385 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
386 		},
387 	},
388 	{
389 		.ssl_ciphersuites_first = 0,
390 		.ssl_ciphersuites = "",
391 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
392 		.cids = {
393 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
394 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
395 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
396 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
397 		},
398 	},
399 	{
400 		.ctx_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
401 		.ssl_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
402 		.cids = {
403 			TLS1_3_CK_AES_256_GCM_SHA384,
404 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
405 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
406 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
407 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
408 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
409 		},
410 	},
411 	{
412 		.ctx_rulestr = "TLSv1.2+ECDHE+AEAD+AES",
413 		.ssl_ciphersuites = "AEAD-AES256-GCM-SHA384:AEAD-CHACHA20-POLY1305-SHA256",
414 		.cids = {
415 			TLS1_3_CK_AES_256_GCM_SHA384,
416 			TLS1_3_CK_CHACHA20_POLY1305_SHA256,
417 			TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
418 			TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
419 			TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
420 			TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
421 		},
422 	},
423 };
424 
425 #define N_CIPHER_SET_TESTS \
426     (sizeof(cipher_set_tests) / sizeof(*cipher_set_tests))
427 
428 static int
429 cipher_set_test(void)
430 {
431 	struct cipher_set_test *cst;
432 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
433 	SSL_CIPHER *cipher;
434 	SSL_CTX *ctx = NULL;
435 	SSL *ssl = NULL;
436 	int failed = 0;
437 	size_t i;
438 	int j;
439 
440 	for (i = 0; i < N_CIPHER_SET_TESTS; i++) {
441 		cst = &cipher_set_tests[i];
442 
443 		if (!ssl_aes_is_accelerated() && cst->cids_aes_accel_fixup) {
444 			cst->cids[0] = TLS1_3_CK_CHACHA20_POLY1305_SHA256;
445 			cst->cids[1] = TLS1_3_CK_AES_256_GCM_SHA384;
446 		}
447 
448 		if ((ctx = SSL_CTX_new(TLS_method())) == NULL)
449 			errx(1, "SSL_CTX_new");
450 
451 		if (cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) {
452 			if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites))
453 				errx(1, "SSL_CTX_set_ciphersuites");
454 		}
455 		if (cst->ctx_rulestr != NULL) {
456 			if (!SSL_CTX_set_cipher_list(ctx, cst->ctx_rulestr))
457 				errx(1, "SSL_CTX_set_cipher_list");
458 		}
459 		if (!cst->ctx_ciphersuites_first && cst->ctx_ciphersuites != NULL) {
460 			if (!SSL_CTX_set_ciphersuites(ctx, cst->ctx_ciphersuites))
461 				errx(1, "SSL_CTX_set_ciphersuites");
462 		}
463 
464 		/* XXX - check SSL_CTX_get_ciphers(ctx) */
465 
466 		if ((ssl = SSL_new(ctx)) == NULL)
467 			errx(1, "SSL_new");
468 
469 		if (cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) {
470 			if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites))
471 				errx(1, "SSL_set_ciphersuites");
472 		}
473 		if (cst->ssl_rulestr != NULL) {
474 			if (!SSL_set_cipher_list(ssl, cst->ssl_rulestr))
475 				errx(1, "SSL_set_cipher_list");
476 		}
477 		if (!cst->ssl_ciphersuites_first && cst->ssl_ciphersuites != NULL) {
478 			if (!SSL_set_ciphersuites(ssl, cst->ssl_ciphersuites))
479 				errx(1, "SSL_set_ciphersuites");
480 		}
481 
482 		ciphers = SSL_get_ciphers(ssl);
483 
484 		for (j = 0; j < sk_SSL_CIPHER_num(ciphers); j++) {
485 			cipher = sk_SSL_CIPHER_value(ciphers, j);
486 			if (SSL_CIPHER_get_id(cipher) == cst->cids[j])
487 				continue;
488 			fprintf(stderr, "FAIL: test %zu - got cipher %d with "
489 			    "id %lx, want %lx\n", i, j,
490 			    SSL_CIPHER_get_id(cipher), cst->cids[j]);
491 			failed |= 1;
492 		}
493 		if (cst->cids[j] != 0) {
494 			fprintf(stderr, "FAIL: test %zu - got %d ciphers, "
495 			    "expected more", i, sk_SSL_CIPHER_num(ciphers));
496 			failed |= 1;
497 		}
498 
499 		SSL_CTX_free(ctx);
500 		SSL_free(ssl);
501 	}
502 
503 	return failed;
504 }
505 
506 int
507 main(int argc, char **argv)
508 {
509 	int failed = 0;
510 
511 	failed |= cipher_get_put_tests();
512 	failed |= cipher_get_by_value_tests();
513 
514 	failed |= parse_ciphersuites_test();
515 	failed |= cipher_set_test();
516 
517 	return (failed);
518 }
519