xref: /openbsd-src/lib/libcrypto/x509/x509_constraints.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /* $OpenBSD: x509_constraints.c,v 1.12 2020/11/25 21:17:52 tb Exp $ */
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 <ctype.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 
28 #include <openssl/safestack.h>
29 #include <openssl/x509.h>
30 #include <openssl/x509v3.h>
31 
32 #include "x509_internal.h"
33 
34 /* RFC 2821 section 4.5.3.1 */
35 #define LOCAL_PART_MAX_LEN 64
36 #define DOMAIN_PART_MAX_LEN 255
37 
38 struct x509_constraints_name *
39 x509_constraints_name_new()
40 {
41 	return (calloc(1, sizeof(struct x509_constraints_name)));
42 }
43 
44 void
45 x509_constraints_name_clear(struct x509_constraints_name *name)
46 {
47 	free(name->name);
48 	free(name->local);
49 	free(name->der);
50 	memset(name, 0, sizeof(*name));
51 }
52 
53 void
54 x509_constraints_name_free(struct x509_constraints_name *name)
55 {
56 	if (name == NULL)
57 		return;
58 	x509_constraints_name_clear(name);
59 	free(name);
60 }
61 
62 struct x509_constraints_name *
63 x509_constraints_name_dup(struct x509_constraints_name *name)
64 {
65 	struct x509_constraints_name *new;
66 
67 	if ((new = x509_constraints_name_new()) == NULL)
68 		goto err;
69 	new->type = name->type;
70 	new->af = name->af;
71 	new->der_len = name->der_len;
72 	if (name->der_len > 0) {
73 		if ((new->der = malloc(name->der_len)) == NULL)
74 			goto err;
75 		memcpy(new->der, name->der, name->der_len);
76 	}
77 	if (name->name != NULL && (new->name = strdup(name->name)) == NULL)
78 		goto err;
79 	if (name->local != NULL && (new->local = strdup(name->local)) == NULL)
80 		goto err;
81 	memcpy(new->address, name->address, sizeof(name->address));
82 	return new;
83  err:
84 	x509_constraints_name_free(new);
85 	return NULL;
86 }
87 
88 struct x509_constraints_names *
89 x509_constraints_names_new()
90 {
91 	return (calloc(1, sizeof(struct x509_constraints_names)));
92 }
93 
94 void
95 x509_constraints_names_clear(struct x509_constraints_names *names)
96 {
97 	size_t i;
98 
99 	for (i = 0; i < names->names_count; i++)
100 		x509_constraints_name_free(names->names[i]);
101 	free(names->names);
102 	memset(names, 0, sizeof(*names));
103 }
104 
105 void
106 x509_constraints_names_free(struct x509_constraints_names *names)
107 {
108 	if (names == NULL)
109 		return;
110 
111 	x509_constraints_names_clear(names);
112 	free(names);
113 }
114 
115 int
116 x509_constraints_names_add(struct x509_constraints_names *names,
117     struct x509_constraints_name *name)
118 {
119 	size_t i = names->names_count;
120 
121 	if (names->names_count == names->names_len) {
122 		struct x509_constraints_name **tmp;
123 		if ((tmp = recallocarray(names->names, names->names_len,
124 		    names->names_len + 32, sizeof(*tmp))) == NULL)
125 			return 0;
126 		names->names_len += 32;
127 		names->names = tmp;
128 	}
129 	names->names[i] = name;
130 	names->names_count++;
131 	return 1;
132 }
133 
134 struct x509_constraints_names *
135 x509_constraints_names_dup(struct x509_constraints_names *names)
136 {
137 	struct x509_constraints_names *new = NULL;
138 	struct x509_constraints_name *name = NULL;
139 	size_t i;
140 
141 	if (names == NULL)
142 		return NULL;
143 
144 	if ((new = x509_constraints_names_new()) == NULL)
145 		goto err;
146 	for (i = 0; i < names->names_count; i++) {
147 		if ((name = x509_constraints_name_dup(names->names[i])) == NULL)
148 			goto err;
149 		if (!x509_constraints_names_add(new, name))
150 			goto err;
151 	}
152 	return new;
153  err:
154 	x509_constraints_names_free(new);
155 	x509_constraints_name_free(name);
156 	return NULL;
157 }
158 
159 
160 /*
161  * Validate that the name contains only a hostname consisting of RFC
162  * 5890 compliant A-labels (see RFC 6066 section 3). This is more
163  * permissive to allow for a leading '*' for a SAN DNSname wildcard,
164  * or a leading '.'  for a subdomain based constraint, as well as
165  * allowing for '_' which is commonly accepted by nonconformant
166  * DNS implementaitons.
167  */
168 static int
169 x509_constraints_valid_domain_internal(uint8_t *name, size_t len)
170 {
171 	uint8_t prev, c = 0;
172 	int component = 0;
173 	int first;
174 	size_t i;
175 
176 	if (len > DOMAIN_PART_MAX_LEN)
177 		return 0;
178 
179 	for (i = 0; i < len; i++) {
180 		prev = c;
181 		c = name[i];
182 
183 		first = (i == 0);
184 
185 		/* Everything has to be ASCII, with no NUL byte */
186 		if (!isascii(c) || c == '\0')
187 			return 0;
188 		/* It must be alphanumeric, a '-', '.', '_' or '*' */
189 		if (!isalnum(c) && c != '-' && c != '.' && c != '_' && c != '*')
190 			return 0;
191 
192 		/* '*' can only be the first thing. */
193 		if (c == '*' && !first)
194 			return 0;
195 
196 		/* '-' must not start a component or be at the end. */
197 		if (c == '-' && (component == 0 || i == len - 1))
198 			return 0;
199 
200 		/*
201 		 * '.' must not be at the end. It may be first overall
202 		 * but must not otherwise start a component.
203 		 */
204 		if (c == '.' && ((component == 0 && !first) || i == len - 1))
205 			return 0;
206 
207 		if (c == '.') {
208 			/* Components can not end with a dash. */
209 			if (prev == '-')
210 				return 0;
211 			/* Start new component */
212 			component = 0;
213 			continue;
214 		}
215 		/* Components must be 63 chars or less. */
216 		if (++component > 63)
217 			return 0;
218 	}
219 	return 1;
220 }
221 
222 int
223 x509_constraints_valid_domain(uint8_t *name, size_t len)
224 {
225 	if (len == 0)
226 		return 0;
227 	if (name[0] == '*') /* wildcard not allowed in a domain name */
228 		return 0;
229 	/*
230 	 * A domain may not be less than two characters, so you can't
231 	 * have a require subdomain name with less than that.
232 	 */
233 	if (len < 3 && name[0] == '.')
234 		return 0;
235 	return x509_constraints_valid_domain_internal(name, len);
236 }
237 
238 int
239 x509_constraints_valid_host(uint8_t *name, size_t len)
240 {
241 	struct sockaddr_in sin4;
242 	struct sockaddr_in6 sin6;
243 
244 	if (len == 0)
245 		return 0;
246 	if (name[0] == '*') /* wildcard not allowed in a host name */
247 		return 0;
248 	if (name[0] == '.') /* leading . not allowed in a host name*/
249 		return 0;
250 	if (inet_pton(AF_INET, name, &sin4) == 1)
251 		return 0;
252 	if (inet_pton(AF_INET6, name, &sin6) == 1)
253 		return 0;
254 	return x509_constraints_valid_domain_internal(name, len);
255 }
256 
257 int
258 x509_constraints_valid_sandns(uint8_t *name, size_t len)
259 {
260 	if (len == 0)
261 		return 0;
262 
263 	if (name[0] == '.') /* leading . not allowed in a SAN DNS name */
264 		return 0;
265 	/*
266 	 * A domain may not be less than two characters, so you
267 	 * can't wildcard a single domain of less than that
268 	 */
269 	if (len < 4 && name[0] == '*')
270 		return 0;
271 	/*
272 	 * A wildcard may only be followed by a '.'
273 	 */
274 	if (len >= 4 && name[0] == '*' && name[1] != '.')
275 		return 0;
276 
277 	return x509_constraints_valid_domain_internal(name, len);
278 }
279 
280 static inline int
281 local_part_ok(char c)
282 {
283 	return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
284 	    ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' ||
285 	    c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' ||
286 	    c == '-' || c == '/' || c == '=' || c == '?' ||  c == '^' ||
287 	    c == '_' || c == '`' || c == '{' || c == '|' || c == '}' ||
288 	    c == '~' || c == '.');
289 }
290 
291 /*
292  * Parse "candidate" as an RFC 2821 mailbox.
293  * Returns 0 if candidate is not a valid mailbox or if an error occurs.
294  * Returns 1 if candidate is a mailbox and adds newly allocated
295  * local and domain parts of the mailbox to "name->local" and name->name"
296  */
297 int
298 x509_constraints_parse_mailbox(uint8_t *candidate, size_t len,
299     struct x509_constraints_name *name)
300 {
301 	char working[DOMAIN_PART_MAX_LEN + 1] = { 0 };
302 	char *candidate_local = NULL;
303 	char *candidate_domain = NULL;
304 	size_t i, wi = 0;
305 	int accept = 0;
306 	int quoted = 0;
307 
308 	if (candidate == NULL)
309 		return 0;
310 
311 	/* It can't be bigger than the local part, domain part and the '@' */
312 	if (len > LOCAL_PART_MAX_LEN + DOMAIN_PART_MAX_LEN + 1)
313 		return 0;
314 
315 	for (i = 0; i < len; i++) {
316 		char c = candidate[i];
317 		/* non ascii, cr, lf, or nul is never allowed */
318 		if (!isascii(c) || c == '\r' || c == '\n' || c == '\0')
319 			goto bad;
320 		if (i == 0) {
321 			/* local part is quoted part */
322 			if (c == '"')
323 				quoted = 1;
324 			/* can not start with a . */
325 			if (c == '.')
326 				goto bad;
327 		}
328 		if (wi > DOMAIN_PART_MAX_LEN)
329 			goto bad;
330 		if (accept) {
331 			working[wi++] = c;
332 			accept = 0;
333 			continue;
334 		}
335 		if (candidate_local != NULL) {
336 			/* We are looking for the domain part */
337 			if (wi > DOMAIN_PART_MAX_LEN)
338 				goto bad;
339 			working[wi++] = c;
340 			if (i == len - 1) {
341 				if (wi == 0)
342 					goto bad;
343 				if (candidate_domain != NULL)
344 					goto bad;
345 				candidate_domain = strdup(working);
346 				if (candidate_domain == NULL)
347 					goto bad;
348 			}
349 			continue;
350 		}
351 		/* We are looking for the local part */
352 		if (wi > LOCAL_PART_MAX_LEN)
353 			break;
354 
355 		if (quoted) {
356 			if (c == '\\') {
357 				accept = 1;
358 				continue;
359 			}
360 			if (c == '"' && i != 0) {
361 				/* end the quoted part. @ must be next */
362 				if (i + 1 == len || candidate[i + 1] != '@')
363 					goto bad;
364 				quoted = 0;
365 			}
366 			/*
367 			 * XXX Go strangely permits sp but forbids ht
368 			 * mimic that for now
369 			 */
370 			if (c == 9)
371 				goto bad;
372 			working[wi++] = c;
373 			continue; /* all's good inside our quoted string */
374 		}
375 		if (c == '@') {
376 			if (wi == 0)
377 				goto bad;;
378 			if (candidate_local != NULL)
379 				goto bad;
380 			candidate_local = strdup(working);
381 			if (candidate_local == NULL)
382 				goto bad;
383 			memset(working, 0, sizeof(working));
384 			wi = 0;
385 			continue;
386 		}
387 		if (c == '\\') {
388 			/*
389 			 * RFC 3936 hints these can happen outside of
390 			 * quotend string. don't include the \ but
391 			 * next character must be ok.
392 			 */
393 			if (i + 1 == len)
394 				goto bad;
395 			if (!local_part_ok(candidate[i + 1]))
396 				goto bad;
397 			accept = 1;
398 		}
399 		if (!local_part_ok(c))
400 			goto bad;
401 		working[wi++] = c;
402 	}
403 	if (candidate_local == NULL || candidate_domain == NULL)
404 		goto bad;
405 	if (!x509_constraints_valid_host(candidate_domain,
406 	    strlen(candidate_domain)))
407 		goto bad;
408 
409 	name->local = candidate_local;
410 	name->name = candidate_domain;
411 	name->type = GEN_EMAIL;
412 	return 1;
413  bad:
414 	free(candidate_local);
415 	free(candidate_domain);
416 	return 0;
417 }
418 
419 int
420 x509_constraints_valid_domain_constraint(uint8_t *constraint, size_t len)
421 {
422 	if (len == 0)
423 		return 1;	/* empty constraints match */
424 
425 	if (constraint[0] == '*') /* wildcard not allowed in a constraint */
426 		return 0;
427 
428 	/*
429 	 * A domain may not be less than two characters, so you
430 	 * can't match a single domain of less than that
431 	 */
432 	if (len < 3 && constraint[0] == '.')
433 		return 0;
434 	return x509_constraints_valid_domain_internal(constraint, len);
435 }
436 
437 /*
438  * Extract the host part of a URI, returns the host part as a c string
439  * the caller must free, or or NULL if it could not be found or is
440  * invalid.
441  *
442  * RFC 3986:
443  * the authority part of a uri starts with // and is terminated with
444  * the next '/', '?', '#' or end of the URI.
445  *
446  * The authority itself contains [userinfo '@'] host [: port]
447  *
448  * so the host starts at the start or after the '@', and ends
449  * with end of URI, '/', '?', "#', or ':'.
450  */
451 int
452 x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart)
453 {
454 	size_t i, hostlen = 0;
455 	uint8_t *authority = NULL;
456 	char *host = NULL;
457 
458 	/*
459 	 * Find first '//'. there must be at least a '//' and
460 	 * something else.
461 	 */
462 	if (len < 3)
463 		return 0;
464 	for (i = 0; i < len - 1; i++) {
465 		if (!isascii(uri[i]))
466 			return 0;
467 		if (uri[i] == '/' && uri[i + 1] == '/') {
468 			authority = uri + i + 2;
469 			break;
470 		}
471 	}
472 	if (authority == NULL)
473 		return 0;
474 	for (i = authority - uri; i < len; i++) {
475 		if (!isascii(uri[i]))
476 			return 0;
477 		/* it has a userinfo part */
478 		if (uri[i] == '@') {
479 			hostlen = 0;
480 			/* it can only have one */
481 			if (host != NULL)
482 				break;
483 			/* start after the userinfo part */
484 			host = uri + i + 1;
485 			continue;
486 		}
487 		/* did we find the end? */
488 		if (uri[i] == ':' || uri[i] == '/' || uri[i] == '?' ||
489 		    uri[i] == '#')
490 			break;
491 		hostlen++;
492 	}
493 	if (hostlen == 0)
494 		return 0;
495 	if (host == NULL)
496 		host = authority;
497 	if (!x509_constraints_valid_host(host, hostlen))
498 		return 0;
499 	*hostpart = strndup(host, hostlen);
500 	return 1;
501 }
502 
503 int
504 x509_constraints_sandns(char *sandns, size_t dlen, char *constraint, size_t len)
505 {
506 	char *suffix;
507 
508 	if (len == 0)
509 		return 1; /* an empty constraint matches everything */
510 
511 	/* match the end of the domain */
512 	if (dlen < len)
513 		return 0;
514 	suffix = sandns + (dlen - len);
515 	return (strncasecmp(suffix, constraint, len) == 0);
516 }
517 
518 /*
519  * Validate a pre-validated domain of length dlen against a pre-validated
520  * constraint of length len.
521  *
522  * returns 1 if the domain and constraint match.
523  * returns 0 otherwise.
524  *
525  * an empty constraint matches everyting.
526  * constraint will be matched against the domain as a suffix if it
527  * starts with a '.'.
528  * domain will be matched against the constraint as a suffix if it
529  * starts with a '.'.
530  */
531 int
532 x509_constraints_domain(char *domain, size_t dlen, char *constraint, size_t len)
533 {
534 	if (len == 0)
535 		return 1; /* an empty constraint matches everything */
536 
537 	if (constraint[0] == '.') {
538 		/* match the end of the domain */
539 		char *suffix;
540 		if (dlen < len)
541 			return 0;
542 		suffix = domain + (dlen - len);
543 		return (strncasecmp(suffix, constraint, len) == 0);
544 	}
545 	if (domain[0] == '.') {
546 		/* match the end of the constraint */
547 		char *suffix;
548 		if (len < dlen)
549 			return 0;
550 		suffix = constraint + (len - dlen);
551 		return (strncasecmp(suffix, domain, dlen) == 0);
552 	}
553 	/* otherwise we must exactly match the constraint */
554 	if (dlen != len)
555 		return 0;
556 	return (strncasecmp(domain, constraint, len) == 0);
557 }
558 
559 int
560 x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, size_t len,
561     int *error)
562 {
563 	int ret = 0;
564 	char *hostpart = NULL;
565 
566 	if (!x509_constraints_uri_host(uri, ulen, &hostpart)) {
567 		*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
568 		goto err;
569 	}
570 	if (hostpart == NULL) {
571 		*error = X509_V_ERR_OUT_OF_MEM;
572 		goto err;
573 	}
574 	if (!x509_constraints_valid_domain_constraint(constraint, len)) {
575 		*error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
576 		goto err;
577 	}
578 	ret = x509_constraints_domain(hostpart, strlen(hostpart), constraint,
579 	    len);
580  err:
581 	free(hostpart);
582 	return ret;
583 }
584 
585 /*
586  * Verify a validated address of size alen with a validated contraint
587  * of size constraint_len. returns 1 if matching, 0 if not.
588  * Addresses are assumed to be pre-validated for a length of 4 and 8
589  * respectively for ipv4 addreses and constraints, and a length of
590  * 16 and 32 respectively for ipv6 address constraints by the caller.
591  */
592 int
593 x509_constraints_ipaddr(uint8_t *address, size_t alen, uint8_t *constraint,
594     size_t len)
595 {
596 	uint8_t *mask;
597 	size_t i;
598 
599 	if (alen * 2 != len)
600 		return 0;
601 
602 	mask = constraint + alen;
603 	for (i = 0; i < alen; i++) {
604 		if ((address[i] & mask[i]) != (constraint[i] & mask[i]))
605 			return 0;
606 	}
607 	return 1;
608 }
609 
610 /*
611  * Verify a canonicalized der encoded constraint dirname
612  * a canonicalized der encoded constraint.
613  */
614 int
615 x509_constraints_dirname(uint8_t *dirname, size_t dlen,
616     uint8_t *constraint, size_t len)
617 {
618 	if (len != dlen)
619 		return 0;
620 	return (memcmp(constraint, dirname, len) == 0);
621 }
622 
623 /*
624  * De-obfuscate a GENERAL_NAME into useful bytes for a name or constraint.
625  */
626 int
627 x509_constraints_general_to_bytes(GENERAL_NAME *name, uint8_t **bytes,
628     size_t *len)
629 {
630 	*bytes = NULL;
631 	*len = 0;
632 
633 	if (name->type == GEN_DNS) {
634 		ASN1_IA5STRING *aname = name->d.dNSName;
635 		*bytes = aname->data;
636 		*len = strlen(aname->data);
637 		return name->type;
638 	}
639 	if (name->type == GEN_EMAIL) {
640 		ASN1_IA5STRING *aname = name->d.rfc822Name;
641 		*bytes = aname->data;
642 		*len = strlen(aname->data);
643 		return name->type;
644 	}
645 	if (name->type == GEN_URI) {
646 		ASN1_IA5STRING *aname = name->d.uniformResourceIdentifier;
647 		*bytes = aname->data;
648 		*len = strlen(aname->data);
649 		return name->type;
650 	}
651 	if (name->type == GEN_DIRNAME) {
652 		X509_NAME *dname = name->d.directoryName;
653 		if (!dname->modified || i2d_X509_NAME(dname, NULL) >= 0) {
654 			*bytes = dname->canon_enc;
655 			*len = dname->canon_enclen;
656 			return name->type;
657 		}
658 	}
659 	if (name->type == GEN_IPADD) {
660 		*bytes = name->d.ip->data;
661 		*len = name->d.ip->length;
662 		return name->type;
663 	}
664 	return 0;
665 }
666 
667 
668 /*
669  * Extract the relevant names for constraint checking from "cert",
670  * validate them, and add them to the list of cert names for "chain".
671  * returns 1 on success sets error and returns 0 on failure.
672  */
673 int
674 x509_constraints_extract_names(struct x509_constraints_names *names,
675     X509 *cert, int is_leaf, int *error)
676 {
677 	struct x509_constraints_name *vname = NULL;
678 	X509_NAME *subject_name;
679 	GENERAL_NAME *name;
680 	ssize_t i = 0;
681 	int name_type, include_cn = is_leaf, include_email = is_leaf;
682 
683 	/* first grab the altnames */
684 	while ((name = sk_GENERAL_NAME_value(cert->altname, i++)) != NULL) {
685 		uint8_t *bytes = NULL;
686 		size_t len = 0;
687 
688 		if ((vname = x509_constraints_name_new()) == NULL) {
689 			*error = X509_V_ERR_OUT_OF_MEM;
690 			goto err;
691 		}
692 
693 		name_type = x509_constraints_general_to_bytes(name, &bytes,
694 		    &len);
695 		switch(name_type) {
696 		case GEN_DNS:
697 			if (!x509_constraints_valid_sandns(bytes, len)) {
698 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
699 				goto err;
700 			}
701 			if ((vname->name = strdup(bytes)) == NULL) {
702 				*error = X509_V_ERR_OUT_OF_MEM;
703 				goto err;
704 			}
705 			vname->type = GEN_DNS;
706 			include_cn = 0; /* don't use cn from subject */
707 			break;
708 		case GEN_EMAIL:
709 			if (!x509_constraints_parse_mailbox(bytes, len,
710 			    vname)) {
711 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
712 				goto err;
713 			}
714 			vname->type = GEN_EMAIL;
715 			include_email = 0; /* don't use email from subject */
716 			break;
717 		case GEN_URI:
718 			if (!x509_constraints_uri_host(bytes, len, &vname->name)) {
719 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
720 				goto err;
721 			}
722 			if (vname->name == NULL) {
723 				*error = X509_V_ERR_OUT_OF_MEM;
724 				goto err;
725 			}
726 			vname->type = GEN_URI;
727 			break;
728 		case GEN_DIRNAME:
729 			if (bytes == NULL || ((vname->der = malloc(len)) ==
730 			    NULL)) {
731 				*error = X509_V_ERR_OUT_OF_MEM;
732 				goto err;
733 			}
734 			if (len == 0) {
735 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
736 				goto err;
737 			}
738 			memcpy(vname->der, bytes, len);
739 			vname->der_len = len;
740 			vname->type = GEN_DIRNAME;
741 			break;
742 		case GEN_IPADD:
743 			if (len == 4)
744 				vname->af = AF_INET;
745 			if (len == 16)
746 				vname->af = AF_INET6;
747 			if (vname->af != AF_INET && vname->af !=
748 			    AF_INET6) {
749 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
750 				goto err;
751 			}
752 			memcpy(vname->address, bytes, len);
753 			vname->type = GEN_IPADD;
754 			break;
755 		default:
756 			/* Ignore this name */
757 			x509_constraints_name_free(vname);
758 			vname = NULL;
759 			continue;
760 		}
761 		if (!x509_constraints_names_add(names, vname)) {
762 			*error = X509_V_ERR_OUT_OF_MEM;
763 			goto err;
764 		}
765 		vname = NULL;
766 	}
767 
768 	x509_constraints_name_free(vname);
769 	vname = NULL;
770 
771 	subject_name = X509_get_subject_name(cert);
772 	if (X509_NAME_entry_count(subject_name) > 0) {
773 		X509_NAME_ENTRY *email;
774 		X509_NAME_ENTRY *cn;
775 		/*
776 		 * This cert has a non-empty subject, so we must add
777 		 * the subject as a dirname to be compared against
778 		 * any dirname constraints
779 		 */
780 		if ((subject_name->modified &&
781 		    i2d_X509_NAME(subject_name, NULL) < 0) ||
782 		    (vname = x509_constraints_name_new()) == NULL ||
783 		    (vname->der = malloc(subject_name->canon_enclen)) == NULL) {
784 			*error = X509_V_ERR_OUT_OF_MEM;
785 			goto err;
786 		}
787 
788 		memcpy(vname->der, subject_name->canon_enc,
789 		    subject_name->canon_enclen);
790 		vname->der_len = subject_name->canon_enclen;
791 		vname->type = GEN_DIRNAME;
792 		if (!x509_constraints_names_add(names, vname)) {
793 			*error = X509_V_ERR_OUT_OF_MEM;
794 			goto err;
795 		}
796 		vname = NULL;
797 		/*
798 		 * Get any email addresses from the subject line, and
799 		 * add them as mbox names to be compared against any
800 		 * email constraints
801 		 */
802 		while (include_email &&
803 		    (i = X509_NAME_get_index_by_NID(subject_name,
804 		    NID_pkcs9_emailAddress, i)) >= 0) {
805 			ASN1_STRING *aname;
806 			if ((email = X509_NAME_get_entry(subject_name, i)) == NULL ||
807 			    (aname = X509_NAME_ENTRY_get_data(email)) == NULL) {
808 				*error = X509_V_ERR_OUT_OF_MEM;
809 				goto err;
810 			}
811 			if ((vname = x509_constraints_name_new()) == NULL) {
812 				*error = X509_V_ERR_OUT_OF_MEM;
813 				goto err;
814 			}
815 			if (!x509_constraints_parse_mailbox(aname->data,
816 			    aname->length, vname)) {
817 				*error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
818 				goto err;
819 			}
820 			vname->type = GEN_EMAIL;
821 			if (!x509_constraints_names_add(names, vname)) {
822 				*error = X509_V_ERR_OUT_OF_MEM;
823 				goto err;
824 			}
825 			vname = NULL;
826 		}
827 		/*
828 		 * Include the CN as a hostname to be checked againt
829 		 * name constraints if it looks like a hostname.
830 		 */
831 		while (include_cn &&
832 		    (i = X509_NAME_get_index_by_NID(subject_name,
833 		    NID_commonName, i)) >= 0) {
834 			ASN1_STRING *aname;
835 			if ((cn = X509_NAME_get_entry(subject_name, i)) == NULL ||
836 			    (aname = X509_NAME_ENTRY_get_data(cn)) == NULL) {
837 				*error = X509_V_ERR_OUT_OF_MEM;
838 				goto err;
839 			}
840 			if (!x509_constraints_valid_host(aname->data,
841 			    aname->length))
842 				continue; /* ignore it if not a hostname */
843 			if ((vname = x509_constraints_name_new()) == NULL) {
844 				*error = X509_V_ERR_OUT_OF_MEM;
845 				goto err;
846 			}
847 			if ((vname->name = strndup(aname->data,
848 			    aname->length)) == NULL) {
849 				*error = X509_V_ERR_OUT_OF_MEM;
850 				goto err;
851 			}
852 			vname->type = GEN_DNS;
853 			if (!x509_constraints_names_add(names, vname)) {
854 				*error = X509_V_ERR_OUT_OF_MEM;
855 				goto err;
856 			}
857 			vname = NULL;
858 		}
859 	}
860 	return 1;
861  err:
862 	x509_constraints_name_free(vname);
863 	return 0;
864 }
865 
866 /*
867  * Validate a constraint in a general name, putting the relevant data
868  * into "name" if valid. returns 0, and sets error if the constraint is
869  * not valid. returns 1 if the constraint validated. name->type will be
870  * set to a valid type if there is constraint data in name, or unmodified
871  * if the GENERAL_NAME had a valid type but was ignored.
872  */
873 int
874 x509_constraints_validate(GENERAL_NAME *constraint,
875     struct x509_constraints_name *name, int *error)
876 {
877 	uint8_t *bytes = NULL;
878 	size_t len = 0;
879 	int name_type;
880 
881 	name_type = x509_constraints_general_to_bytes(constraint, &bytes, &len);
882 	switch (name_type) {
883 	case GEN_DIRNAME:
884 		if (bytes == NULL || (name->der = malloc(len)) == NULL) {
885 			*error = X509_V_ERR_OUT_OF_MEM;
886 			return 0;
887 		}
888 		if (len == 0)
889 			goto err; /* XXX The RFCs are delightfully vague */
890 		memcpy(name->der, bytes, len);
891 		name->der_len = len;
892 		name->type = GEN_DIRNAME;
893 		break;
894 	case GEN_DNS:
895 		if (!x509_constraints_valid_domain_constraint(bytes, len))
896 			goto err;
897 		if ((name->name = strdup(bytes)) == NULL) {
898 			*error = X509_V_ERR_OUT_OF_MEM;
899 			return 0;
900 		}
901 		name->type = GEN_DNS;
902 		break;
903 	case GEN_EMAIL:
904 		if (memchr(bytes, '@', len) != NULL) {
905 			if (!x509_constraints_parse_mailbox(bytes, len, name))
906 				goto err;
907 		} else {
908 			if (!x509_constraints_valid_domain_constraint(bytes,
909 			    len))
910 				goto err;
911 			if ((name->name = strdup(bytes)) == NULL) {
912 				*error = X509_V_ERR_OUT_OF_MEM;
913 				return 0;
914 			}
915 		}
916 		name->type = GEN_EMAIL;
917 		break;
918 	case GEN_IPADD:
919 		/* Constraints are ip then mask */
920 		if (len == 8)
921 			name->af = AF_INET;
922 		else if (len == 32)
923 			name->af = AF_INET6;
924 		else
925 			goto err;
926 		memcpy(&name->address[0], bytes, len);
927 		name->type = GEN_IPADD;
928 		break;
929 	case GEN_URI:
930 		if (!x509_constraints_valid_domain_constraint(bytes, len))
931 			goto err;
932 		name->name = strdup(bytes);
933 		name->type = GEN_URI;
934 		break;
935 	default:
936 		break;
937 	}
938 	return 1;
939  err:
940 	*error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
941 	return 0;
942 }
943 
944 int
945 x509_constraints_extract_constraints(X509 *cert,
946     struct x509_constraints_names *permitted,
947     struct x509_constraints_names *excluded,
948     int *error)
949 {
950 	struct x509_constraints_name *vname;
951 	NAME_CONSTRAINTS *nc = cert->nc;
952 	GENERAL_SUBTREE *subtree;
953 	int i;
954 
955 	if (nc == NULL)
956 		return 1;
957 
958 	for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
959 
960 		subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
961 		if (subtree->minimum || subtree->maximum) {
962 			*error = X509_V_ERR_SUBTREE_MINMAX;
963 			return 0;
964 		}
965 		if ((vname = x509_constraints_name_new()) == NULL) {
966 			*error = X509_V_ERR_OUT_OF_MEM;
967 			return 0;
968 		}
969 		if (x509_constraints_validate(subtree->base, vname, error) ==
970 		    0) {
971 			x509_constraints_name_free(vname);
972 			return 0;
973 		}
974 		if (vname->type == 0) {
975 			x509_constraints_name_free(vname);
976 			continue;
977 		}
978 		if (!x509_constraints_names_add(permitted, vname)) {
979 			x509_constraints_name_free(vname);
980 			*error = X509_V_ERR_OUT_OF_MEM;
981 			return 0;
982 		}
983 	}
984 
985 	for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
986 		subtree = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
987 		if (subtree->minimum || subtree->maximum) {
988 			*error = X509_V_ERR_SUBTREE_MINMAX;
989 			return 0;
990 		}
991 		if ((vname = x509_constraints_name_new()) == NULL) {
992 			*error = X509_V_ERR_OUT_OF_MEM;
993 			return 0;
994 		}
995 		if (x509_constraints_validate(subtree->base, vname, error) ==
996 		    0) {
997 			x509_constraints_name_free(vname);
998 			return 0;
999 		}
1000 		if (vname->type == 0) {
1001 			x509_constraints_name_free(vname);
1002 			continue;
1003 		}
1004 		if (!x509_constraints_names_add(excluded, vname)) {
1005 			x509_constraints_name_free(vname);
1006 			*error = X509_V_ERR_OUT_OF_MEM;
1007 			return 0;
1008 		}
1009 	}
1010 
1011 	return 1;
1012 }
1013 
1014 /*
1015  * Match a validated name in "name" against a validated constraint in
1016  * "constraint" return 1 if then name matches, 0 otherwise.
1017  */
1018 int
1019 x509_constraints_match(struct x509_constraints_name *name,
1020     struct x509_constraints_name *constraint)
1021 {
1022 	if (name->type != constraint->type)
1023 		return 0;
1024 	if (name->type == GEN_DNS)
1025 		return x509_constraints_sandns(name->name, strlen(name->name),
1026 		    constraint->name, strlen(constraint->name));
1027 	if (name->type == GEN_URI)
1028 		return x509_constraints_domain(name->name, strlen(name->name),
1029 		    constraint->name, strlen(constraint->name));
1030 	if (name->type == GEN_IPADD) {
1031 		size_t nlen = name->af == AF_INET ? 4 : 16;
1032 		size_t clen = name->af == AF_INET ? 8 : 32;
1033 		if (name->af != AF_INET && name->af != AF_INET6)
1034 			return 0;
1035 		if (constraint->af != AF_INET && constraint->af != AF_INET6)
1036 			return 0;
1037 		if (name->af != constraint->af)
1038 			return 0;
1039 		return x509_constraints_ipaddr(name->address, nlen,
1040 		    constraint->address, clen);
1041 	}
1042 	if (name->type == GEN_EMAIL) {
1043 		if (constraint->local) {
1044 			/* mailbox local and domain parts must exactly match */
1045 			return (strcmp(name->local, constraint->local) == 0 &&
1046 			    strcmp(name->name, constraint->name) == 0);
1047 		}
1048 		/* otherwise match the constraint to the domain part */
1049 		return x509_constraints_domain(name->name, strlen(name->name),
1050 		    constraint->name, strlen(constraint->name));
1051 	}
1052 	if (name->type == GEN_DIRNAME)
1053 		return x509_constraints_dirname(name->der, name->der_len,
1054 		    constraint->der, constraint->der_len);
1055 	return 0;
1056 }
1057 
1058 /*
1059  * Make sure every name in names does not match any excluded
1060  * constraints, and does match at least one permitted constraint if
1061  * any are present. Returns 1 if ok, 0, and sets error if not.
1062  */
1063 int
1064 x509_constraints_check(struct x509_constraints_names *names,
1065     struct x509_constraints_names *permitted,
1066     struct x509_constraints_names *excluded, int *error)
1067 {
1068 	size_t i, j;
1069 
1070 	for (i = 0; i < names->names_count; i++) {
1071 		int permitted_seen = 0;
1072 		int permitted_matched = 0;
1073 
1074 		for (j = 0; j < excluded->names_count; j++) {
1075 			if (x509_constraints_match(names->names[i],
1076 			    excluded->names[j])) {
1077 				*error = X509_V_ERR_EXCLUDED_VIOLATION;
1078 				return 0;
1079 			}
1080 		}
1081 		for (j = 0; j < permitted->names_count; j++) {
1082 			if (permitted->names[j]->type == names->names[i]->type)
1083 				permitted_seen++;
1084 			if (x509_constraints_match(names->names[i],
1085 			    permitted->names[j])) {
1086 				permitted_matched++;
1087 				break;
1088 			}
1089 		}
1090 		if (permitted_seen && !permitted_matched) {
1091 			*error = X509_V_ERR_PERMITTED_VIOLATION;
1092 			return 0;
1093 		}
1094 	}
1095 	return 1;
1096 }
1097 
1098 /*
1099  * Walk a validated chain of X509 certs, starting at the leaf, and
1100  * validate the name constraints in the chain. Intended for use with
1101  * the legacy X509 validtion code in x509_vfy.c
1102  *
1103  * returns 1 if the constraints are ok, 0 otherwise, setting error and
1104  * depth
1105  */
1106 int
1107 x509_constraints_chain(STACK_OF(X509) *chain, int *error, int *depth)
1108 {
1109 	int chain_length, verify_err = X509_V_ERR_UNSPECIFIED, i = 0;
1110 	struct x509_constraints_names *names = NULL;
1111 	struct x509_constraints_names *excluded = NULL;
1112 	struct x509_constraints_names *permitted = NULL;
1113 	size_t constraints_count = 0;
1114 	X509 *cert;
1115 
1116 	if (chain == NULL || (chain_length = sk_X509_num(chain)) == 0)
1117 		goto err;
1118 	if (chain_length == 1)
1119 		return 1;
1120 	if ((names = x509_constraints_names_new()) == NULL) {
1121 		verify_err = X509_V_ERR_OUT_OF_MEM;
1122 		goto err;
1123 	}
1124 
1125 	if ((cert = sk_X509_value(chain, 0)) == NULL)
1126 		goto err;
1127 	if (!x509_constraints_extract_names(names, cert, 1, &verify_err))
1128 		goto err;
1129 	for (i = 1; i < chain_length; i++) {
1130 		if ((cert = sk_X509_value(chain, i)) == NULL)
1131 			goto err;
1132 		if (cert->nc != NULL) {
1133 			if ((permitted =
1134 			    x509_constraints_names_new()) == NULL) {
1135 				verify_err = X509_V_ERR_OUT_OF_MEM;
1136 				goto err;
1137 			}
1138 			if ((excluded =
1139 			    x509_constraints_names_new()) == NULL) {
1140 				verify_err = X509_V_ERR_OUT_OF_MEM;
1141 				goto err;
1142 			}
1143 			if (!x509_constraints_extract_constraints(cert,
1144 			    permitted, excluded, &verify_err))
1145 				goto err;
1146 			constraints_count += permitted->names_count;
1147 			constraints_count += excluded->names_count;
1148 			if (constraints_count >
1149 			    X509_VERIFY_MAX_CHAIN_CONSTRAINTS) {
1150 				verify_err = X509_V_ERR_OUT_OF_MEM;
1151 				goto err;
1152 			}
1153 			if (!x509_constraints_check(names, permitted, excluded,
1154 			    &verify_err))
1155 				goto err;
1156 			x509_constraints_names_free(excluded);
1157 			excluded = NULL;
1158 			x509_constraints_names_free(permitted);
1159 			permitted = NULL;
1160 		}
1161 		if (!x509_constraints_extract_names(names, cert, 0,
1162 		    &verify_err))
1163 			goto err;
1164 		if (names->names_count > X509_VERIFY_MAX_CHAIN_NAMES) {
1165 			verify_err = X509_V_ERR_OUT_OF_MEM;
1166 			goto err;
1167 		}
1168 	}
1169 
1170 	x509_constraints_names_free(names);
1171 	return 1;
1172 
1173  err:
1174 	*error = verify_err;
1175 	*depth = i;
1176 	x509_constraints_names_free(excluded);
1177 	x509_constraints_names_free(permitted);
1178 	x509_constraints_names_free(names);
1179 	return 0;
1180 }
1181