xref: /openbsd/regress/lib/libtls/verify/verifytest.c (revision f23ec8ef)
1 /*	$OpenBSD: verifytest.c,v 1.8 2023/05/28 09:02:01 beck Exp $	*/
2 /*
3  * Copyright (c) 2014 Joel Sing <jsing@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 <err.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include <openssl/x509v3.h>
23 #include <tls.h>
24 
25 extern int tls_check_name(struct tls *ctx, X509 *cert, const char *name,
26     int *match);
27 
28 struct alt_name {
29 	const char name[128];
30 	int name_len;
31 	int name_type;
32 };
33 
34 struct verify_test {
35 	const char common_name[128];
36 	int common_name_len;
37 	struct alt_name alt_name1;
38 	struct alt_name alt_name2;
39 	struct alt_name alt_name3;
40 	const char name[128];
41 	int want_return;
42 	int want_match;
43 	int name_type;
44 };
45 
46 struct verify_test verify_tests[] = {
47 	{
48 		/* CN without SANs - matching. */
49 		.common_name = "www.openbsd.org",
50 		.common_name_len = -1,
51 		.name = "www.openbsd.org",
52 		.want_return = 0,
53 		.want_match = 1,
54 	},
55 	{
56 		/* Zero length name - non-matching. */
57 		.common_name = "www.openbsd.org",
58 		.common_name_len = -1,
59 		.name = "",
60 		.want_return = 0,
61 		.want_match = 0,
62 	},
63 	{
64 		/* CN wildcard without SANs - matching. */
65 		.common_name = "*.openbsd.org",
66 		.common_name_len = -1,
67 		.name = "www.openbsd.org",
68 		.want_return = 0,
69 		.want_match = 1,
70 	},
71 	{
72 		/* CN without SANs - non-matching. */
73 		.common_name = "www.openbsdfoundation.org",
74 		.common_name_len = -1,
75 		.name = "www.openbsd.org",
76 		.want_return = 0,
77 		.want_match = 0,
78 	},
79 	{
80 		/* CN wildcard without SANs - invalid CN wildcard. */
81 		.common_name = "w*.openbsd.org",
82 		.common_name_len = -1,
83 		.name = "www.openbsd.org",
84 		.want_return = 0,
85 		.want_match = 0,
86 	},
87 	{
88 		/* CN wildcard without SANs - invalid CN wildcard. */
89 		.common_name = "www.*.org",
90 		.common_name_len = -1,
91 		.name = "www.openbsd.org",
92 		.want_return = 0,
93 		.want_match = 0,
94 	},
95 	{
96 		/* CN wildcard without SANs - invalid CN wildcard. */
97 		.common_name = "www.openbsd.*",
98 		.common_name_len = -1,
99 		.name = "www.openbsd.org",
100 		.want_return = 0,
101 		.want_match = 0,
102 	},
103 	{
104 		/* CN wildcard without SANs - invalid CN wildcard. */
105 		.common_name = "*",
106 		.common_name_len = -1,
107 		.name = "www.openbsd.org",
108 		.want_return = 0,
109 		.want_match = 0,
110 	},
111 	{
112 		/* CN wildcard without SANs - invalid CN wildcard. */
113 		.common_name = "*.org",
114 		.common_name_len = -1,
115 		.name = "www.openbsd.org",
116 		.want_return = 0,
117 		.want_match = 0,
118 	},
119 	{
120 		/* CN wildcard without SANs - invalid CN wildcard. */
121 		.common_name = "*.org",
122 		.common_name_len = -1,
123 		.name = "openbsd.org",
124 		.want_return = 0,
125 		.want_match = 0,
126 	},
127 	{
128 		/* CN IPv4 without SANs - matching. */
129 		.common_name = "1.2.3.4",
130 		.common_name_len = -1,
131 		.name = "1.2.3.4",
132 		.want_return = 0,
133 		.want_match = 1,
134 	},
135 	{
136 		/* CN IPv4 wildcard without SANS - invalid IP wildcard. */
137 		.common_name = "*.2.3.4",
138 		.common_name_len = -1,
139 		.name = "1.2.3.4",
140 		.want_return = 0,
141 		.want_match = 0,
142 	},
143 	{
144 		/* CN IPv6 without SANs - matching. */
145 		.common_name = "cafe::beef",
146 		.common_name_len = -1,
147 		.name = "cafe::beef",
148 		.want_return = 0,
149 		.want_match = 1,
150 	},
151 	{
152 		/* CN without SANs - error due to embedded NUL in CN. */
153 		.common_name = {
154 			0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
155 			0x62, 0x73, 0x64, 0x2e, 0x6f, 0x72, 0x67, 0x00,
156 			0x6e, 0x61, 0x73, 0x74, 0x79, 0x2e, 0x6f, 0x72,
157 			0x67,
158 		},
159 		.common_name_len = 25,
160 		.name = "www.openbsd.org",
161 		.want_return = -1,
162 		.want_match = 0,
163 	},
164 	{
165 		/* CN wildcard without SANs - invalid non-matching name. */
166 		.common_name = "*.openbsd.org",
167 		.common_name_len = -1,
168 		.name = ".openbsd.org",
169 		.want_return = 0,
170 		.want_match = 0,
171 	},
172 	{
173 		/* CN with SANs - matching on first SAN. */
174 		.common_name = "www.openbsd.org",
175 		.common_name_len = -1,
176 		.alt_name1 = {
177 			.name = "www.openbsd.org",
178 			.name_len = -1,
179 			.name_type = GEN_DNS,
180 		},
181 		.alt_name2 = {
182 			.name = "ftp.openbsd.org",
183 			.name_len = -1,
184 			.name_type = GEN_DNS,
185 		},
186 		.name = "www.openbsd.org",
187 		.want_return = 0,
188 		.want_match = 1,
189 	},
190 	{
191 		/* SANs only - matching on first SAN. */
192 		.common_name_len = 0,
193 		.alt_name1 = {
194 			.name = "www.openbsd.org",
195 			.name_len = -1,
196 			.name_type = GEN_DNS,
197 		},
198 		.alt_name2 = {
199 			.name = "ftp.openbsd.org",
200 			.name_len = -1,
201 			.name_type = GEN_DNS,
202 		},
203 		.name = "www.openbsd.org",
204 		.want_return = 0,
205 		.want_match = 1,
206 	},
207 	{
208 		/* SANs only - matching on second SAN. */
209 		.common_name_len = 0,
210 		.alt_name1 = {
211 			.name = "www.openbsd.org",
212 			.name_len = -1,
213 			.name_type = GEN_DNS,
214 		},
215 		.alt_name2 = {
216 			.name = "ftp.openbsd.org",
217 			.name_len = -1,
218 			.name_type = GEN_DNS,
219 		},
220 		.name = "ftp.openbsd.org",
221 		.want_return = 0,
222 		.want_match = 1,
223 	},
224 	{
225 		/* SANs only - non-matching. */
226 		.common_name_len = 0,
227 		.alt_name1 = {
228 			.name = "www.openbsd.org",
229 			.name_len = -1,
230 			.name_type = GEN_DNS,
231 		},
232 		.alt_name2 = {
233 			.name = "ftp.openbsd.org",
234 			.name_len = -1,
235 			.name_type = GEN_DNS,
236 		},
237 		.name = "mail.openbsd.org",
238 		.want_return = 0,
239 		.want_match = 0,
240 	},
241 	{
242 		/* CN with SANs - matching on second SAN. */
243 		.common_name = "www.openbsd.org",
244 		.common_name_len = -1,
245 		.alt_name1 = {
246 			.name = "www.openbsd.org",
247 			.name_len = -1,
248 			.name_type = GEN_DNS,
249 		},
250 		.alt_name2 = {
251 			.name = "ftp.openbsd.org",
252 			.name_len = -1,
253 			.name_type = GEN_DNS,
254 		},
255 		.name = "ftp.openbsd.org",
256 		.want_return = 0,
257 		.want_match = 1,
258 	},
259 	{
260 		/* CN with SANs - matching on wildcard second SAN. */
261 		.common_name = "www.openbsdfoundation.org",
262 		.common_name_len = -1,
263 		.alt_name1 = {
264 			.name = "www.openbsdfoundation.org",
265 			.name_len = -1,
266 			.name_type = GEN_DNS,
267 		},
268 		.alt_name2 = {
269 			.name = "*.openbsd.org",
270 			.name_len = -1,
271 			.name_type = GEN_DNS,
272 		},
273 		.name = "www.openbsd.org",
274 		.want_return = 0,
275 		.want_match = 1,
276 	},
277 	{
278 		/* CN with SANs - non-matching invalid wildcard. */
279 		.common_name = "www.openbsdfoundation.org",
280 		.common_name_len = -1,
281 		.alt_name1 = {
282 			.name = "www.openbsdfoundation.org",
283 			.name_len = -1,
284 			.name_type = GEN_DNS,
285 		},
286 		.alt_name2 = {
287 			.name = "*.org",
288 			.name_len = -1,
289 			.name_type = GEN_DNS,
290 		},
291 		.name = "www.openbsd.org",
292 		.want_return = 0,
293 		.want_match = 0,
294 	},
295 	{
296 		/* CN with SANs - non-matching IPv4 due to GEN_DNS SAN. */
297 		.common_name = "www.openbsd.org",
298 		.common_name_len = -1,
299 		.alt_name1 = {
300 			.name = "www.openbsd.org",
301 			.name_len = -1,
302 			.name_type = GEN_DNS,
303 		},
304 		.alt_name2 = {
305 			.name = "1.2.3.4",
306 			.name_len = -1,
307 			.name_type = GEN_DNS,
308 		},
309 		.name = "1.2.3.4",
310 		.want_return = 0,
311 		.want_match = 0,
312 	},
313 	{
314 		/* CN with SANs - matching IPv4 on GEN_IPADD SAN. */
315 		.common_name = "www.openbsd.org",
316 		.common_name_len = -1,
317 		.alt_name1 = {
318 			.name = "www.openbsd.org",
319 			.name_len = -1,
320 			.name_type = GEN_DNS,
321 		},
322 		.alt_name2 = {
323 			.name = {0x01, 0x02, 0x03, 0x04},
324 			.name_len = 4,
325 			.name_type = GEN_IPADD,
326 		},
327 		.name = "1.2.3.4",
328 		.want_return = 0,
329 		.want_match = 1,
330 	},
331 	{
332 		/* CN with SANs - matching IPv6 on GEN_IPADD SAN. */
333 		.common_name = "www.openbsd.org",
334 		.common_name_len = -1,
335 		.alt_name1 = {
336 			.name = "www.openbsd.org",
337 			.name_len = -1,
338 			.name_type = GEN_DNS,
339 		},
340 		.alt_name2 = {
341 			.name = {
342 				0xca, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xef,
344 			},
345 			.name_len = 16,
346 			.name_type = GEN_IPADD,
347 		},
348 		.name = "cafe::beef",
349 		.want_return = 0,
350 		.want_match = 1,
351 	},
352 	{
353 		/* CN with SANs - error due to embedded NUL in GEN_DNS. */
354 		.common_name = "www.openbsd.org.nasty.org",
355 		.common_name_len = -1,
356 		.alt_name1 = {
357 			.name = "www.openbsd.org.nasty.org",
358 			.name_len = -1,
359 			.name_type = GEN_DNS,
360 		},
361 		.alt_name2 = {
362 			.name = {
363 				0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
364 				0x62, 0x73, 0x64, 0x2e, 0x6f, 0x72, 0x67, 0x00,
365 				0x6e, 0x61, 0x73, 0x74, 0x79, 0x2e, 0x6f, 0x72,
366 				0x67,
367 			},
368 			.name_len = 25,
369 			.name_type = GEN_DNS,
370 		},
371 		.name = "www.openbsd.org",
372 		.want_return = -1,
373 		.want_match = 0,
374 	},
375 	{
376 		/* CN with SAN - non-matching due to non-matching SAN. */
377 		.common_name = "www.openbsd.org",
378 		.common_name_len = -1,
379 		.alt_name1 = {
380 			.name = "ftp.openbsd.org",
381 			.name_len = -1,
382 			.name_type = GEN_DNS,
383 		},
384 		.name = "www.openbsd.org",
385 		.want_return = 0,
386 		.want_match = 0,
387 	},
388 	{
389 		/* CN with SAN - error due to illegal dNSName. */
390 		.common_name = "www.openbsd.org",
391 		.common_name_len = -1,
392 		.alt_name1 = {
393 			.name = " ",
394 			.name_len = -1,
395 			.name_type = GEN_DNS,
396 		},
397 		.name = "www.openbsd.org",
398 		.want_return = -1,
399 		.want_match = 0,
400 	},
401 };
402 
403 #define N_VERIFY_TESTS \
404     (sizeof(verify_tests) / sizeof(*verify_tests))
405 
406 static void
alt_names_add(STACK_OF (GENERAL_NAME)* alt_name_stack,struct alt_name * alt)407 alt_names_add(STACK_OF(GENERAL_NAME) *alt_name_stack, struct alt_name *alt)
408 {
409 	ASN1_STRING *alt_name_str;
410 	GENERAL_NAME *alt_name;
411 
412 	if ((alt_name = GENERAL_NAME_new()) == NULL)
413 		errx(1, "failed to malloc GENERAL_NAME");
414 	alt_name->type = alt->name_type;
415 
416 	if ((alt_name_str = ASN1_STRING_new()) == NULL)
417 		errx(1, "failed to malloc alt name");
418 	if (ASN1_STRING_set(alt_name_str, alt->name, alt->name_len) == 0)
419 		errx(1, "failed to set alt name");
420 
421 	switch (alt_name->type) {
422 	case GEN_DNS:
423 		alt_name->d.dNSName = alt_name_str;
424 		break;
425 	case GEN_IPADD:
426 		alt_name->d.iPAddress = alt_name_str;
427 		break;
428 	default:
429 		errx(1, "unknown alt name type (%i)", alt_name->type);
430 	}
431 
432 	if (sk_GENERAL_NAME_push(alt_name_stack, alt_name) == 0)
433 		errx(1, "failed to push alt_name");
434 }
435 
436 static void
cert_add_alt_names(X509 * cert,struct verify_test * vt)437 cert_add_alt_names(X509 *cert, struct verify_test *vt)
438 {
439 	STACK_OF(GENERAL_NAME) *alt_name_stack = NULL;
440 
441 	if (vt->alt_name1.name_type == 0)
442 		return;
443 
444 	if ((alt_name_stack = sk_GENERAL_NAME_new_null()) == NULL)
445 		errx(1, "failed to malloc sk_GENERAL_NAME");
446 
447 	if (vt->alt_name1.name_type != 0)
448 		alt_names_add(alt_name_stack, &vt->alt_name1);
449 	if (vt->alt_name2.name_type != 0)
450 		alt_names_add(alt_name_stack, &vt->alt_name2);
451 	if (vt->alt_name3.name_type != 0)
452 		alt_names_add(alt_name_stack, &vt->alt_name3);
453 
454 	if (X509_add1_ext_i2d(cert, NID_subject_alt_name,
455 	    alt_name_stack, 0, 0) == 0)
456 		errx(1, "failed to set subject alt name");
457 
458 	sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
459 }
460 
461 static int
do_verify_test(int test_no,struct verify_test * vt)462 do_verify_test(int test_no, struct verify_test *vt)
463 {
464 	struct tls *tls;
465 	X509_NAME *name;
466 	X509 *cert;
467 	int failed = 1;
468 	int match;
469 
470 	/* Build certificate structure. */
471 	if ((cert = X509_new()) == NULL)
472 		errx(1, "failed to malloc X509");
473 
474 	if (vt->common_name_len != 0) {
475 		if ((name = X509_NAME_new()) == NULL)
476 			errx(1, "failed to malloc X509_NAME");
477 		if (X509_NAME_add_entry_by_NID(name, NID_commonName,
478 		    vt->name_type ? vt->name_type : MBSTRING_ASC,
479 		    (unsigned char *)vt->common_name,
480 		    vt->common_name_len, -1, 0) == 0)
481 			errx(1, "failed to add name entry");
482 		if (X509_set_subject_name(cert, name) == 0)
483 			errx(1, "failed to set subject name");
484 		X509_NAME_free(name);
485 	}
486 
487 	if ((tls = tls_client()) == NULL)
488 		errx(1, "failed to malloc tls_client");
489 
490 	cert_add_alt_names(cert, vt);
491 
492 	match = 1;
493 
494 	if (tls_check_name(tls, cert, vt->name, &match) != vt->want_return) {
495 		fprintf(stderr, "FAIL: test %i failed for check name '%s': "
496 		    "%s\n", test_no, vt->name, tls_error(tls));
497 		goto done;
498 	}
499 	if (match != vt->want_match) {
500 		fprintf(stderr, "FAIL: test %i failed to match name '%s'\n",
501 		    test_no, vt->name);
502 		goto done;
503 	}
504 
505 	failed = 0;
506 
507  done:
508 	X509_free(cert);
509 	tls_free(tls);
510 
511 	return (failed);
512 }
513 
514 int
main(int argc,char ** argv)515 main(int argc, char **argv)
516 {
517 	int failed = 0;
518 	size_t i;
519 
520 	tls_init();
521 
522 	for (i = 0; i < N_VERIFY_TESTS; i++)
523 		failed += do_verify_test(i, &verify_tests[i]);
524 
525 	return (failed);
526 }
527