xref: /openbsd-src/regress/lib/libcrypto/x509/constraints.c (revision db6a0a3b32f53931c98946b1160f865bc6579dfe)
1 /* $OpenBSD: constraints.c */
2 /*
3  * Copyright (c) 2020 Bob Beck <beck@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 <string.h>
20 
21 #include <openssl/safestack.h>
22 #include <openssl/x509.h>
23 #include <openssl/x509v3.h>
24 #include "x509_internal.h"
25 
26 
27 #define FAIL(msg, ...)						\
28 do {								\
29 	fprintf(stderr, "[%s:%d] FAIL: ", __FILE__, __LINE__);	\
30 	fprintf(stderr, msg, ##__VA_ARGS__);			\
31 } while(0)
32 
33 unsigned char *valid_hostnames[] = {
34 	"openbsd.org",
35 	"op3nbsd.org",
36 	"org",
37 	"3openbsd.com",
38 	"3-0penb-d.c-m",
39 	"a",
40 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
41 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
42 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
43 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
44 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
45 	"open_bsd.org", /* because this is liberal */
46 	NULL,
47 };
48 
49 unsigned char *valid_sandns_names[] = {
50 	"*.ca",
51 	"*.op3nbsd.org",
52 	NULL,
53 };
54 
55 unsigned char *valid_domain_constraints[] = {
56 	"",
57 	".ca",
58 	".op3nbsd.org",
59 	".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
60 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
61 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
62 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
63 	"www.openbsd.org",
64 	NULL,
65 };
66 
67 unsigned char *valid_mbox_names[] = {
68 	"\"!#$%&\\\"*+-/=?\002^_`{|}~.\"@openbsd.org",
69 	"beck@openbsd.org",
70 	"beck@openbsd.org",
71 	"beck@op3nbsd.org",
72 	"beck@org",
73 	"beck@3openbsd.com",
74 	"beck@3-0penb-d.c-m",
75 	"bec@a",
76 	"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
77 	"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
78 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
79 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
80 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
81 	"beck@open_bsd.org", /* because this is liberal */
82 	NULL,
83 };
84 
85 unsigned char *invalid_hostnames[] = {
86 	"openbsd.org.",
87 	"openbsd..org",
88 	"openbsd.org-",
89 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
90 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
91 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
92 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
93 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
94 	"-p3nbsd.org",
95 	"openbs-.org",
96 	"openbsd\n.org",
97 	"open\178bsd.org",
98 	"open\255bsd.org",
99 	NULL,
100 };
101 
102 unsigned char *invalid_sandns_names[] = {
103 	"",
104 	".",
105 	"*.a",
106 	"*.",
107 	"*.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
108 	".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
109 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
110 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
111 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
112 	"*.-p3nbsd.org",
113 	"a*.openbsd.org",
114 	"*.*..openbsd.org",
115 	"*..openbsd.org",
116 	".openbsd.org",
117 	NULL,
118 };
119 
120 unsigned char *invalid_mbox_names[] = {
121 	"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
122 	"beck@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
123 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
124 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
125 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
126 	"beck@.-openbsd.org",
127 	"beck@.openbsd.org.",
128 	"beck@.a",
129 	"beck@.",
130 	"beck@",
131 	"beck@.ca",
132 	"@openbsd.org",
133 	NULL,
134 };
135 
136 unsigned char *invalid_domain_constraints[] = {
137 	".",
138 	".a",
139 	"..",
140 	".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
141 	".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
142 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
143 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
144 	"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
145 	".-p3nbsd.org",
146 	"..openbsd.org",
147 	NULL,
148 };
149 
150 unsigned char *invaliduri[] = {
151 	"https://-www.openbsd.org",
152 	"https://.www.openbsd.org/",
153 	"https://www.ope|nbsd.org%",
154 	"https://www.openbsd.org.#",
155 	NULL,
156 };
157 
158 static int
159 test_valid_hostnames(void)
160 {
161 	int i, failure = 0;
162 
163 	for (i = 0; valid_hostnames[i] != NULL; i++) {
164 		if (!x509_constraints_valid_host(valid_hostnames[i],
165 			strlen(valid_hostnames[i]))) {
166 			FAIL("Valid hostname '%s' rejected\n",
167 			    valid_hostnames[i]);
168 			failure = 1;
169 			goto done;
170 		}
171 		if (!x509_constraints_valid_sandns(valid_hostnames[i],
172 			strlen(valid_hostnames[i]))) {
173 			FAIL("Valid sandns '%s' rejected\n",
174 			    valid_hostnames[i]);
175 			failure = 1;
176 			goto done;
177 		}
178 	}
179  done:
180 	return failure;
181 }
182 
183 static int
184 test_valid_sandns_names(void)
185 {
186 	int i, failure = 0;
187 	for (i = 0; valid_sandns_names[i] != NULL; i++) {
188 		if (!x509_constraints_valid_sandns(valid_sandns_names[i],
189 			strlen(valid_sandns_names[i]))) {
190 			FAIL("Valid dnsname '%s' rejected\n",
191 			    valid_sandns_names[i]);
192 			failure = 1;
193 			goto done;
194 		}
195 	}
196  done:
197 	return failure;
198 }
199 
200 static int
201 test_valid_domain_constraints(void)
202 {
203 	int i, failure = 0;
204 	for (i = 0; valid_domain_constraints[i] != NULL; i++) {
205 		if (!x509_constraints_valid_domain_constraint(valid_domain_constraints[i],
206 		    strlen(valid_domain_constraints[i]))) {
207 			FAIL("Valid dnsname '%s' rejected\n",
208 			    valid_domain_constraints[i]);
209 			failure = 1;
210 			goto done;
211 		}
212 	}
213  done:
214 	return failure;
215 }
216 
217 static int
218 test_valid_mbox_names(void)
219 {
220 	struct x509_constraints_name name = {0};
221 	int i, failure = 0;
222 	for (i = 0; valid_mbox_names[i] != NULL; i++) {
223 		if (!x509_constraints_parse_mailbox(valid_mbox_names[i],
224 		    strlen(valid_mbox_names[i]), &name)) {
225 			FAIL("Valid mailbox name '%s' rejected\n",
226 			    valid_mbox_names[i]);
227 			failure = 1;
228 			goto done;
229 		}
230 		free(name.name);
231 		name.name = NULL;
232 		free(name.local);
233 		name.local = NULL;
234 	}
235  done:
236 	return failure;
237 }
238 
239 static int
240 test_invalid_hostnames(void)
241 {
242 	int i, failure = 0;
243 	char *nulhost = "www.openbsd.org\0";
244 
245 	for (i = 0; invalid_hostnames[i] != NULL; i++) {
246 		if (x509_constraints_valid_host(invalid_hostnames[i],
247 		    strlen(invalid_hostnames[i]))) {
248 			FAIL("Invalid hostname '%s' accepted\n",
249 			    invalid_hostnames[i]);
250 			failure = 1;
251 			goto done;
252 		}
253 		if (x509_constraints_valid_sandns(invalid_hostnames[i],
254 		    strlen(invalid_hostnames[i]))) {
255 			FAIL("Invalid sandns '%s' accepted\n",
256 			    invalid_hostnames[i]);
257 			failure = 1;
258 			goto done;
259 		}
260 	}
261 	if (x509_constraints_valid_host(nulhost,
262 	    strlen(nulhost) + 1)) {
263 		FAIL("hostname with NUL byte accepted\n");
264 		failure = 1;
265 		goto done;
266 	}
267 	if (x509_constraints_valid_sandns(nulhost,
268 	    strlen(nulhost) + 1)) {
269 		FAIL("sandns with NUL byte accepted\n");
270 		failure = 1;
271 		goto done;
272 	}
273  done:
274 	return failure;
275 }
276 
277 static int
278 test_invalid_sandns_names(void)
279 {
280 	int i, failure = 0;
281 	for (i = 0; invalid_sandns_names[i] != NULL; i++) {
282 		if (x509_constraints_valid_sandns(invalid_sandns_names[i],
283 		    strlen(invalid_sandns_names[i]))) {
284 			FAIL("Valid dnsname '%s' rejected\n",
285 			    invalid_sandns_names[i]);
286 			failure = 1;
287 			goto done;
288 		}
289 	}
290  done:
291 	return failure;
292 }
293 
294 static int
295 test_invalid_mbox_names(void)
296 {
297 	int i, failure = 0;
298 	struct x509_constraints_name name = {0};
299 	for (i = 0; invalid_mbox_names[i] != NULL; i++) {
300 		if (x509_constraints_parse_mailbox(invalid_mbox_names[i],
301 		    strlen(invalid_mbox_names[i]), &name)) {
302 			FAIL("invalid mailbox name '%s' accepted\n",
303 			    invalid_mbox_names[i]);
304 			failure = 1;
305 			goto done;
306 		}
307 		free(name.name);
308 		name.name = NULL;
309 		free(name.local);
310 		name.local = NULL;
311 	}
312  done:
313 	return failure;
314 }
315 
316 static int
317 test_invalid_domain_constraints(void)
318 {
319 	int i, failure = 0;
320 	for (i = 0; invalid_domain_constraints[i] != NULL; i++) {
321 		if (x509_constraints_valid_domain_constraint(invalid_domain_constraints[i],
322 		    strlen(invalid_domain_constraints[i]))) {
323 			FAIL("invalid dnsname '%s' accepted\n",
324 			    invalid_domain_constraints[i]);
325 			failure = 1;
326 			goto done;
327 		}
328 	}
329  done:
330 	return failure;
331 }
332 
333 static int
334 test_invalid_uri(void) {
335 	int j, failure=0;
336 	char *hostpart;
337 	for (j = 0; invaliduri[j] != NULL; j++) {
338 		if (x509_constraints_uri_host(invaliduri[j],
339 			strlen(invaliduri[j]), &hostpart) != 0) {
340 			FAIL("invalid URI '%s' accepted\n",
341 			    invaliduri[j]);
342 			failure = 1;
343 		}
344 		goto done;
345 	}
346  done:
347 	return failure;
348 }
349 
350 static int
351 test_constraints1(void)
352 {
353 	char *c; size_t cl;
354 	char *d; size_t dl;
355 	int failure = 0;
356 	int error = 0;
357 	int i, j;
358 	unsigned char *constraints[] = {
359 		".org",
360 		".openbsd.org",
361 		"www.openbsd.org",
362 		NULL,
363 	};
364 	unsigned char *failing[] = {
365 		".ca",
366 		"openbsd.ca",
367 		"org",
368 		NULL,
369 	};
370 	unsigned char *matching[] = {
371 		"www.openbsd.org",
372 		NULL,
373 	};
374 	unsigned char *matchinguri[] = {
375 		"https://www.openbsd.org",
376 		"https://www.openbsd.org/",
377 		"https://www.openbsd.org?",
378 		"https://www.openbsd.org#",
379 		"herp://beck@www.openbsd.org:",
380 		"spiffe://beck@www.openbsd.org/this/is/so/spiffe/",
381 		NULL,
382 	};
383 	unsigned char *failinguri[] = {
384 		"https://www.openbsd.ca",
385 		"https://www.freebsd.com/",
386 		"https://www.openbsd.net?",
387 		"https://org#",
388 		"herp://beck@org:",
389 		NULL,
390 	};
391 	for (i = 0; constraints[i] != NULL; i++) {
392 		char *constraint = constraints[i];
393 		size_t clen = strlen(constraints[i]);
394 		for (j = 0; matching[j] != NULL; j++) {
395 			if (!x509_constraints_domain(matching[j],
396 			    strlen(matching[j]), constraint, clen)) {
397 				FAIL("constraint '%s' should have matched"
398 				    " '%s'\n",
399 				    constraint, matching[j]);
400 				failure = 1;
401 				goto done;
402 			}
403 		}
404 		for (j = 0; matchinguri[j] != NULL; j++) {
405 			error = 0;
406 			if (!x509_constraints_uri(matchinguri[j],
407 			    strlen(matchinguri[j]), constraint, clen, &error)) {
408 				FAIL("constraint '%s' should have matched URI"
409 				    " '%s' (error %d)\n",
410 				    constraint, matchinguri[j], error);
411 				failure = 1;
412 				goto done;
413 			}
414 		}
415 		for (j = 0; failing[j] != NULL; j++) {
416 			if (x509_constraints_domain(failing[j],
417 			    strlen(failing[j]), constraint, clen)) {
418 				FAIL("constraint '%s' should not have matched"
419 				    " '%s'\n",
420 				    constraint, failing[j]);
421 				failure = 1;
422 				goto done;
423 			}
424 		}
425 		for (j = 0; failinguri[j] != NULL; j++) {
426 			error = 0;
427 			if (x509_constraints_uri(failinguri[j],
428 			    strlen(failinguri[j]), constraint, clen, &error)) {
429 				FAIL("constraint '%s' should not have matched URI"
430 				    " '%s' (error %d)\n",
431 				    constraint, failinguri[j], error);
432 				failure = 1;
433 				goto done;
434 			}
435 		}
436 	}
437 	c = ".openbsd.org";
438 	cl = strlen(".openbsd.org");
439 	d = "*.openbsd.org";
440 	dl = strlen("*.openbsd.org");
441 	if (!x509_constraints_domain(d, dl, c, cl)) {
442 		FAIL("constraint '%s' should have matched '%s'\n",
443 		    c, d);
444 		failure = 1;
445 		goto done;
446 	}
447 	c = "www.openbsd.org";
448 	cl = strlen("www.openbsd.org");
449 	if (x509_constraints_domain(d, dl, c, cl)) {
450 		FAIL("constraint '%s' should not have matched '%s'\n",
451 		    c, d);
452 		failure = 1;
453 		goto done;
454 	}
455 	c = "";
456 	cl = 0;
457 	if (!x509_constraints_domain(d, dl, c, cl)) {
458 		FAIL("constraint '%s' should have matched '%s'\n",
459 		    c, d);
460 		failure = 1;
461 		goto done;
462 	}
463  done:
464 	return failure;
465 }
466 
467 int
468 main(int argc, char **argv)
469 {
470 	int failed = 0;
471 
472 	failed |= test_valid_hostnames();
473 	failed |= test_invalid_hostnames();
474 	failed |= test_valid_sandns_names();
475 	failed |= test_invalid_sandns_names();
476 	failed |= test_valid_mbox_names();
477 	failed |= test_invalid_mbox_names();
478 	failed |= test_valid_domain_constraints();
479 	failed |= test_invalid_domain_constraints();
480 	failed |= test_invalid_uri();
481 	failed |= test_constraints1();
482 
483 	return (failed);
484 }
485