libressl: Fix validation errors in certificate chains with expired certificates
[dragonfly.git] / crypto / libressl / crypto / x509 / x509_constraints.c
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 }