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