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