crypto/*: Fix various typos, repeated words, align some spelling to LDP.
[openssl.git] / crypto / x509 / v3_ncons.c
1 /*
2  * Copyright 2003-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11 #include "internal/numbers.h"
12 #include "internal/safe_math.h"
13 #include <stdio.h>
14 #include "crypto/asn1.h"
15 #include <openssl/asn1t.h>
16 #include <openssl/conf.h>
17 #include <openssl/x509v3.h>
18 #include <openssl/bn.h>
19
20 #include "crypto/x509.h"
21 #include "crypto/punycode.h"
22 #include "ext_dat.h"
23
24 OSSL_SAFE_MATH_SIGNED(int, int)
25
26 static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
27                                   X509V3_CTX *ctx,
28                                   STACK_OF(CONF_VALUE) *nval);
29 static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
30                                 BIO *bp, int ind);
31 static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
32                                    STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp,
33                                    int ind, const char *name);
34 static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
35
36 static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
37 static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
38 static int nc_dn(const X509_NAME *sub, const X509_NAME *nm);
39 static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
40 static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
41 static int nc_email_eai(ASN1_TYPE *emltype, ASN1_IA5STRING *base);
42 static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
43 static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base);
44
45 const X509V3_EXT_METHOD ossl_v3_name_constraints = {
46     NID_name_constraints, 0,
47     ASN1_ITEM_ref(NAME_CONSTRAINTS),
48     0, 0, 0, 0,
49     0, 0,
50     0, v2i_NAME_CONSTRAINTS,
51     i2r_NAME_CONSTRAINTS, 0,
52     NULL
53 };
54
55 ASN1_SEQUENCE(GENERAL_SUBTREE) = {
56         ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME),
57         ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0),
58         ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1)
59 } ASN1_SEQUENCE_END(GENERAL_SUBTREE)
60
61 ASN1_SEQUENCE(NAME_CONSTRAINTS) = {
62         ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees,
63                                                         GENERAL_SUBTREE, 0),
64         ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees,
65                                                         GENERAL_SUBTREE, 1),
66 } ASN1_SEQUENCE_END(NAME_CONSTRAINTS)
67
68
69 IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
70 IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
71
72
73 #define IA5_OFFSET_LEN(ia5base, offset) \
74     ((ia5base)->length - ((unsigned char *)(offset) - (ia5base)->data))
75
76 /* Like memchr but for ASN1_IA5STRING. Additionally you can specify the
77  * starting point to search from
78  */
79 # define ia5memchr(str, start, c) memchr(start, c, IA5_OFFSET_LEN(str, start))
80
81 /* Like memrrchr but for ASN1_IA5STRING */
82 static char *ia5memrchr(ASN1_IA5STRING *str, int c)
83 {
84     int i;
85
86     for (i = str->length; i > 0 && str->data[i - 1] != c; i--);
87
88     if (i == 0)
89         return NULL;
90
91     return (char *)&str->data[i - 1];
92 }
93
94 /*
95  * We cannot use strncasecmp here because that applies locale specific rules. It
96  * also doesn't work with ASN1_STRINGs that may have embedded NUL characters.
97  * For example in Turkish 'I' is not the uppercase character for 'i'. We need to
98  * do a simple ASCII case comparison ignoring the locale (that is why we use
99  * numeric constants below).
100  */
101 static int ia5ncasecmp(const char *s1, const char *s2, size_t n)
102 {
103     for (; n > 0; n--, s1++, s2++) {
104         if (*s1 != *s2) {
105             unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2;
106
107             /* Convert to lower case */
108             if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */)
109                 c1 += 0x20;
110             if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */)
111                 c2 += 0x20;
112
113             if (c1 == c2)
114                 continue;
115
116             if (c1 < c2)
117                 return -1;
118
119             /* c1 > c2 */
120             return 1;
121         }
122     }
123
124     return 0;
125 }
126
127 static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
128                                   X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
129 {
130     int i;
131     CONF_VALUE tval, *val;
132     STACK_OF(GENERAL_SUBTREE) **ptree = NULL;
133     NAME_CONSTRAINTS *ncons = NULL;
134     GENERAL_SUBTREE *sub = NULL;
135
136     ncons = NAME_CONSTRAINTS_new();
137     if (ncons == NULL) {
138         ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
139         goto err;
140     }
141     for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
142         val = sk_CONF_VALUE_value(nval, i);
143         if (HAS_PREFIX(val->name, "permitted") && val->name[9]) {
144             ptree = &ncons->permittedSubtrees;
145             tval.name = val->name + 10;
146         } else if (HAS_PREFIX(val->name, "excluded") && val->name[8]) {
147             ptree = &ncons->excludedSubtrees;
148             tval.name = val->name + 9;
149         } else {
150             ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SYNTAX);
151             goto err;
152         }
153         tval.value = val->value;
154         sub = GENERAL_SUBTREE_new();
155         if (sub == NULL) {
156             ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
157             goto err;
158         }
159         if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1)) {
160             ERR_raise(ERR_LIB_X509V3, ERR_R_X509V3_LIB);
161             goto err;
162         }
163         if (*ptree == NULL)
164             *ptree = sk_GENERAL_SUBTREE_new_null();
165         if (*ptree == NULL || !sk_GENERAL_SUBTREE_push(*ptree, sub)) {
166             ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB);
167             goto err;
168         }
169         sub = NULL;
170     }
171
172     return ncons;
173
174  err:
175     NAME_CONSTRAINTS_free(ncons);
176     GENERAL_SUBTREE_free(sub);
177
178     return NULL;
179 }
180
181 static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
182                                 BIO *bp, int ind)
183 {
184     NAME_CONSTRAINTS *ncons = a;
185     do_i2r_name_constraints(method, ncons->permittedSubtrees,
186                             bp, ind, "Permitted");
187     if (ncons->permittedSubtrees && ncons->excludedSubtrees)
188         BIO_puts(bp, "\n");
189     do_i2r_name_constraints(method, ncons->excludedSubtrees,
190                             bp, ind, "Excluded");
191     return 1;
192 }
193
194 static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
195                                    STACK_OF(GENERAL_SUBTREE) *trees,
196                                    BIO *bp, int ind, const char *name)
197 {
198     GENERAL_SUBTREE *tree;
199     int i;
200     if (sk_GENERAL_SUBTREE_num(trees) > 0)
201         BIO_printf(bp, "%*s%s:\n", ind, "", name);
202     for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
203         if (i > 0)
204             BIO_puts(bp, "\n");
205         tree = sk_GENERAL_SUBTREE_value(trees, i);
206         BIO_printf(bp, "%*s", ind + 2, "");
207         if (tree->base->type == GEN_IPADD)
208             print_nc_ipadd(bp, tree->base->d.ip);
209         else
210             GENERAL_NAME_print(bp, tree->base);
211     }
212     return 1;
213 }
214
215 static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
216 {
217     /* ip->length should be 8 or 32 and len1 == len2 == 4 or len1 == len2 == 16 */
218     int len1 = ip->length >= 16 ? 16 : ip->length >= 4 ? 4 : ip->length;
219     int len2 = ip->length - len1;
220     char *ip1 = ossl_ipaddr_to_asc(ip->data, len1);
221     char *ip2 = ossl_ipaddr_to_asc(ip->data + len1, len2);
222     int ret = ip1 != NULL && ip2 != NULL
223         && BIO_printf(bp, "IP:%s/%s", ip1, ip2) > 0;
224
225     OPENSSL_free(ip1);
226     OPENSSL_free(ip2);
227     return ret;
228 }
229
230 #define NAME_CHECK_MAX (1 << 20)
231
232 static int add_lengths(int *out, int a, int b)
233 {
234     int err = 0;
235
236     /* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */
237     if (a < 0)
238         a = 0;
239     if (b < 0)
240         b = 0;
241
242     *out = safe_add_int(a, b, &err);
243     return !err;
244 }
245
246 /*-
247  * Check a certificate conforms to a specified set of constraints.
248  * Return values:
249  *  X509_V_OK: All constraints obeyed.
250  *  X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
251  *  X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
252  *  X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
253  *  X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:  Unsupported constraint type.
254  *  X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
255  *  X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
256  */
257
258 int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
259 {
260     int r, i, name_count, constraint_count;
261     X509_NAME *nm;
262
263     nm = X509_get_subject_name(x);
264
265     /*
266      * Guard against certificates with an excessive number of names or
267      * constraints causing a computationally expensive name constraints check.
268      */
269     if (!add_lengths(&name_count, X509_NAME_entry_count(nm),
270                      sk_GENERAL_NAME_num(x->altname))
271         || !add_lengths(&constraint_count,
272                         sk_GENERAL_SUBTREE_num(nc->permittedSubtrees),
273                         sk_GENERAL_SUBTREE_num(nc->excludedSubtrees))
274         || (name_count > 0 && constraint_count > NAME_CHECK_MAX / name_count))
275         return X509_V_ERR_UNSPECIFIED;
276
277     if (X509_NAME_entry_count(nm) > 0) {
278         GENERAL_NAME gntmp;
279         gntmp.type = GEN_DIRNAME;
280         gntmp.d.directoryName = nm;
281
282         r = nc_match(&gntmp, nc);
283
284         if (r != X509_V_OK)
285             return r;
286
287         gntmp.type = GEN_EMAIL;
288
289         /* Process any email address attributes in subject name */
290
291         for (i = -1;;) {
292             const X509_NAME_ENTRY *ne;
293
294             i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i);
295             if (i == -1)
296                 break;
297             ne = X509_NAME_get_entry(nm, i);
298             gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
299             if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING)
300                 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
301
302             r = nc_match(&gntmp, nc);
303
304             if (r != X509_V_OK)
305                 return r;
306         }
307
308     }
309
310     for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) {
311         GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i);
312         r = nc_match(gen, nc);
313         if (r != X509_V_OK)
314             return r;
315     }
316
317     return X509_V_OK;
318
319 }
320
321 static int cn2dnsid(ASN1_STRING *cn, unsigned char **dnsid, size_t *idlen)
322 {
323     int utf8_length;
324     unsigned char *utf8_value;
325     int i;
326     int isdnsname = 0;
327
328     /* Don't leave outputs uninitialized */
329     *dnsid = NULL;
330     *idlen = 0;
331
332     /*-
333      * Per RFC 6125, DNS-IDs representing internationalized domain names appear
334      * in certificates in A-label encoded form:
335      *
336      *   https://tools.ietf.org/html/rfc6125#section-6.4.2
337      *
338      * The same applies to CNs which are intended to represent DNS names.
339      * However, while in the SAN DNS-IDs are IA5Strings, as CNs they may be
340      * needlessly encoded in 16-bit Unicode.  We perform a conversion to UTF-8
341      * to ensure that we get an ASCII representation of any CNs that are
342      * representable as ASCII, but just not encoded as ASCII.  The UTF-8 form
343      * may contain some non-ASCII octets, and that's fine, such CNs are not
344      * valid legacy DNS names.
345      *
346      * Note, 'int' is the return type of ASN1_STRING_to_UTF8() so that's what
347      * we must use for 'utf8_length'.
348      */
349     if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, cn)) < 0)
350         return X509_V_ERR_OUT_OF_MEM;
351
352     /*
353      * Some certificates have had names that include a *trailing* NUL byte.
354      * Remove these harmless NUL characters. They would otherwise yield false
355      * alarms with the following embedded NUL check.
356      */
357     while (utf8_length > 0 && utf8_value[utf8_length - 1] == '\0')
358         --utf8_length;
359
360     /* Reject *embedded* NULs */
361     if (memchr(utf8_value, 0, utf8_length) != NULL) {
362         OPENSSL_free(utf8_value);
363         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
364     }
365
366     /*
367      * XXX: Deviation from strict DNS name syntax, also check names with '_'
368      * Check DNS name syntax, any '-' or '.' must be internal,
369      * and on either side of each '.' we can't have a '-' or '.'.
370      *
371      * If the name has just one label, we don't consider it a DNS name.  This
372      * means that "CN=sometld" cannot be precluded by DNS name constraints, but
373      * that is not a problem.
374      */
375     for (i = 0; i < utf8_length; ++i) {
376         unsigned char c = utf8_value[i];
377
378         if ((c >= 'a' && c <= 'z')
379             || (c >= 'A' && c <= 'Z')
380             || (c >= '0' && c <= '9')
381             || c == '_')
382             continue;
383
384         /* Dot and hyphen cannot be first or last. */
385         if (i > 0 && i < utf8_length - 1) {
386             if (c == '-')
387                 continue;
388             /*
389              * Next to a dot the preceding and following characters must not be
390              * another dot or a hyphen.  Otherwise, record that the name is
391              * plausible, since it has two or more labels.
392              */
393             if (c == '.'
394                 && utf8_value[i + 1] != '.'
395                 && utf8_value[i - 1] != '-'
396                 && utf8_value[i + 1] != '-') {
397                 isdnsname = 1;
398                 continue;
399             }
400         }
401         isdnsname = 0;
402         break;
403     }
404
405     if (isdnsname) {
406         *dnsid = utf8_value;
407         *idlen = (size_t)utf8_length;
408         return X509_V_OK;
409     }
410     OPENSSL_free(utf8_value);
411     return X509_V_OK;
412 }
413
414 /*
415  * Check CN against DNS-ID name constraints.
416  */
417 int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc)
418 {
419     int r, i;
420     const X509_NAME *nm = X509_get_subject_name(x);
421     ASN1_STRING stmp;
422     GENERAL_NAME gntmp;
423
424     stmp.flags = 0;
425     stmp.type = V_ASN1_IA5STRING;
426     gntmp.type = GEN_DNS;
427     gntmp.d.dNSName = &stmp;
428
429     /* Process any commonName attributes in subject name */
430
431     for (i = -1;;) {
432         X509_NAME_ENTRY *ne;
433         ASN1_STRING *cn;
434         unsigned char *idval;
435         size_t idlen;
436
437         i = X509_NAME_get_index_by_NID(nm, NID_commonName, i);
438         if (i == -1)
439             break;
440         ne = X509_NAME_get_entry(nm, i);
441         cn = X509_NAME_ENTRY_get_data(ne);
442
443         /* Only process attributes that look like hostnames */
444         if ((r = cn2dnsid(cn, &idval, &idlen)) != X509_V_OK)
445             return r;
446         if (idlen == 0)
447             continue;
448
449         stmp.length = idlen;
450         stmp.data = idval;
451         r = nc_match(&gntmp, nc);
452         OPENSSL_free(idval);
453         if (r != X509_V_OK)
454             return r;
455     }
456     return X509_V_OK;
457 }
458
459 /*
460  * Return nonzero if the GeneralSubtree has valid 'minimum' field
461  * (must be absent or 0) and valid 'maximum' field (must be absent).
462  */
463 static int nc_minmax_valid(GENERAL_SUBTREE *sub) {
464     BIGNUM *bn = NULL;
465     int ok = 1;
466
467     if (sub->maximum)
468         ok = 0;
469
470     if (sub->minimum) {
471         bn = ASN1_INTEGER_to_BN(sub->minimum, NULL);
472         if (bn == NULL || !BN_is_zero(bn))
473             ok = 0;
474         BN_free(bn);
475     }
476
477     return ok;
478 }
479
480 static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
481 {
482     GENERAL_SUBTREE *sub;
483     int i, r, match = 0;
484     /*
485      * We need to compare not gen->type field but an "effective" type because
486      * the otherName field may contain EAI email address treated specially
487      * according to RFC 8398, section 6
488      */
489     int effective_type = ((gen->type == GEN_OTHERNAME) &&
490                           (OBJ_obj2nid(gen->d.otherName->type_id) ==
491                            NID_id_on_SmtpUTF8Mailbox)) ? GEN_EMAIL : gen->type;
492
493     /*
494      * Permitted subtrees: if any subtrees exist of matching the type at
495      * least one subtree must match.
496      */
497
498     for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
499         sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
500         if (effective_type != sub->base->type)
501             continue;
502         if (!nc_minmax_valid(sub))
503             return X509_V_ERR_SUBTREE_MINMAX;
504         /* If we already have a match don't bother trying any more */
505         if (match == 2)
506             continue;
507         if (match == 0)
508             match = 1;
509         r = nc_match_single(gen, sub->base);
510         if (r == X509_V_OK)
511             match = 2;
512         else if (r != X509_V_ERR_PERMITTED_VIOLATION)
513             return r;
514     }
515
516     if (match == 1)
517         return X509_V_ERR_PERMITTED_VIOLATION;
518
519     /* Excluded subtrees: must not match any of these */
520
521     for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
522         sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
523         if (effective_type != sub->base->type)
524             continue;
525         if (!nc_minmax_valid(sub))
526             return X509_V_ERR_SUBTREE_MINMAX;
527
528         r = nc_match_single(gen, sub->base);
529         if (r == X509_V_OK)
530             return X509_V_ERR_EXCLUDED_VIOLATION;
531         else if (r != X509_V_ERR_PERMITTED_VIOLATION)
532             return r;
533
534     }
535
536     return X509_V_OK;
537
538 }
539
540 static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base)
541 {
542     switch (gen->type) {
543     case GEN_OTHERNAME:
544         /*
545          * We are here only when we have SmtpUTF8 name,
546          * so we match the value of othername with base->d.rfc822Name
547          */
548         return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name);
549
550     case GEN_DIRNAME:
551         return nc_dn(gen->d.directoryName, base->d.directoryName);
552
553     case GEN_DNS:
554         return nc_dns(gen->d.dNSName, base->d.dNSName);
555
556     case GEN_EMAIL:
557         return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
558
559     case GEN_URI:
560         return nc_uri(gen->d.uniformResourceIdentifier,
561                       base->d.uniformResourceIdentifier);
562
563     case GEN_IPADD:
564         return nc_ip(gen->d.iPAddress, base->d.iPAddress);
565
566     default:
567         return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
568     }
569
570 }
571
572 /*
573  * directoryName name constraint matching. The canonical encoding of
574  * X509_NAME makes this comparison easy. It is matched if the subtree is a
575  * subset of the name.
576  */
577
578 static int nc_dn(const X509_NAME *nm, const X509_NAME *base)
579 {
580     /* Ensure canonical encodings are up to date.  */
581     if (nm->modified && i2d_X509_NAME(nm, NULL) < 0)
582         return X509_V_ERR_OUT_OF_MEM;
583     if (base->modified && i2d_X509_NAME(base, NULL) < 0)
584         return X509_V_ERR_OUT_OF_MEM;
585     if (base->canon_enclen > nm->canon_enclen)
586         return X509_V_ERR_PERMITTED_VIOLATION;
587     if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen))
588         return X509_V_ERR_PERMITTED_VIOLATION;
589     return X509_V_OK;
590 }
591
592 static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
593 {
594     char *baseptr = (char *)base->data;
595     char *dnsptr = (char *)dns->data;
596
597     /* Empty matches everything */
598     if (base->length == 0)
599         return X509_V_OK;
600
601     if (dns->length < base->length)
602         return X509_V_ERR_PERMITTED_VIOLATION;
603
604     /*
605      * Otherwise can add zero or more components on the left so compare RHS
606      * and if dns is longer and expect '.' as preceding character.
607      */
608     if (dns->length > base->length) {
609         dnsptr += dns->length - base->length;
610         if (*baseptr != '.' && dnsptr[-1] != '.')
611             return X509_V_ERR_PERMITTED_VIOLATION;
612     }
613
614     if (ia5ncasecmp(baseptr, dnsptr, base->length))
615         return X509_V_ERR_PERMITTED_VIOLATION;
616
617     return X509_V_OK;
618
619 }
620
621 /*
622  * This function implements comparison between ASCII/U-label in emltype
623  * and A-label in base according to RFC 8398, section 6.
624  * Convert base to U-label and ASCII-parts of domain names, for base
625  * Octet-to-octet comparison of `emltype` and `base` hostname parts
626  * (ASCII-parts should be compared in case-insensitive manner)
627  */
628 static int nc_email_eai(ASN1_TYPE *emltype, ASN1_IA5STRING *base)
629 {
630     ASN1_UTF8STRING *eml;
631     char *baseptr = NULL;
632     const char *emlptr;
633     const char *emlat;
634     char ulabel[256];
635     size_t size = sizeof(ulabel) - 1;
636     int ret = X509_V_OK;
637     size_t emlhostlen;
638
639     /* We do not accept embedded NUL characters */
640     if (base->length > 0 && memchr(base->data, 0, base->length) != NULL)
641         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
642
643     /* 'base' may not be NUL terminated. Create a copy that is */
644     baseptr = OPENSSL_strndup((char *)base->data, base->length);
645     if (baseptr == NULL)
646         return X509_V_ERR_OUT_OF_MEM;
647
648     if (emltype->type != V_ASN1_UTF8STRING) {
649         ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
650         goto end;
651     }
652
653     eml = emltype->value.utf8string;
654     emlptr = (char *)eml->data;
655     emlat = ia5memrchr(eml, '@');
656
657     if (emlat == NULL) {
658         ret = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
659         goto end;
660     }
661
662     memset(ulabel, 0, sizeof(ulabel));
663     /* Special case: initial '.' is RHS match */
664     if (*baseptr == '.') {
665         ulabel[0] = '.';
666         size -= 1;
667         if (ossl_a2ulabel(baseptr, ulabel + 1, &size) <= 0) {
668             ret = X509_V_ERR_UNSPECIFIED;
669             goto end;
670         }
671
672         if ((size_t)eml->length > strlen(ulabel)) {
673             emlptr += eml->length - (strlen(ulabel));
674             /* X509_V_OK */
675             if (ia5ncasecmp(ulabel, emlptr, strlen(ulabel)) == 0)
676                 goto end;
677         }
678         ret = X509_V_ERR_PERMITTED_VIOLATION;
679         goto end;
680     }
681
682     if (ossl_a2ulabel(baseptr, ulabel, &size) <= 0) {
683         ret = X509_V_ERR_UNSPECIFIED;
684         goto end;
685     }
686     /* Just have hostname left to match: case insensitive */
687     emlptr = emlat + 1;
688     emlhostlen = IA5_OFFSET_LEN(eml, emlptr);
689     if (emlhostlen != strlen(ulabel)
690             || ia5ncasecmp(ulabel, emlptr, emlhostlen) != 0) {
691         ret = X509_V_ERR_PERMITTED_VIOLATION;
692         goto end;
693     }
694
695  end:
696     OPENSSL_free(baseptr);
697     return ret;
698 }
699
700 static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
701 {
702     const char *baseptr = (char *)base->data;
703     const char *emlptr = (char *)eml->data;
704     const char *baseat = ia5memrchr(base, '@');
705     const char *emlat = ia5memrchr(eml, '@');
706     size_t basehostlen, emlhostlen;
707
708     if (!emlat)
709         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
710     /* Special case: initial '.' is RHS match */
711     if (!baseat && base->length > 0 && (*baseptr == '.')) {
712         if (eml->length > base->length) {
713             emlptr += eml->length - base->length;
714             if (ia5ncasecmp(baseptr, emlptr, base->length) == 0)
715                 return X509_V_OK;
716         }
717         return X509_V_ERR_PERMITTED_VIOLATION;
718     }
719
720     /* If we have anything before '@' match local part */
721
722     if (baseat) {
723         if (baseat != baseptr) {
724             if ((baseat - baseptr) != (emlat - emlptr))
725                 return X509_V_ERR_PERMITTED_VIOLATION;
726             if (memchr(baseptr, 0, baseat - baseptr) ||
727                 memchr(emlptr, 0, emlat - emlptr))
728                 return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
729             /* Case sensitive match of local part */
730             if (strncmp(baseptr, emlptr, emlat - emlptr))
731                 return X509_V_ERR_PERMITTED_VIOLATION;
732         }
733         /* Position base after '@' */
734         baseptr = baseat + 1;
735     }
736     emlptr = emlat + 1;
737     basehostlen = IA5_OFFSET_LEN(base, baseptr);
738     emlhostlen = IA5_OFFSET_LEN(eml, emlptr);
739     /* Just have hostname left to match: case insensitive */
740     if (basehostlen != emlhostlen || ia5ncasecmp(baseptr, emlptr, emlhostlen))
741         return X509_V_ERR_PERMITTED_VIOLATION;
742
743     return X509_V_OK;
744
745 }
746
747 static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
748 {
749     const char *baseptr = (char *)base->data;
750     const char *hostptr = (char *)uri->data;
751     const char *p = ia5memchr(uri, (char *)uri->data, ':');
752     int hostlen;
753
754     /* Check for foo:// and skip past it */
755     if (p == NULL
756             || IA5_OFFSET_LEN(uri, p) < 3
757             || p[1] != '/'
758             || p[2] != '/')
759         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
760     hostptr = p + 3;
761
762     /* Determine length of hostname part of URI */
763
764     /* Look for a port indicator as end of hostname first */
765
766     p = ia5memchr(uri, hostptr, ':');
767     /* Otherwise look for trailing slash */
768     if (p == NULL)
769         p = ia5memchr(uri, hostptr, '/');
770
771     if (p == NULL)
772         hostlen = IA5_OFFSET_LEN(uri, hostptr);
773     else
774         hostlen = p - hostptr;
775
776     if (hostlen == 0)
777         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
778
779     /* Special case: initial '.' is RHS match */
780     if (base->length > 0 && *baseptr == '.') {
781         if (hostlen > base->length) {
782             p = hostptr + hostlen - base->length;
783             if (ia5ncasecmp(p, baseptr, base->length) == 0)
784                 return X509_V_OK;
785         }
786         return X509_V_ERR_PERMITTED_VIOLATION;
787     }
788
789     if ((base->length != (int)hostlen)
790         || ia5ncasecmp(hostptr, baseptr, hostlen))
791         return X509_V_ERR_PERMITTED_VIOLATION;
792
793     return X509_V_OK;
794
795 }
796
797 static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base)
798 {
799     int hostlen, baselen, i;
800     unsigned char *hostptr, *baseptr, *maskptr;
801     hostptr = ip->data;
802     hostlen = ip->length;
803     baseptr = base->data;
804     baselen = base->length;
805
806     /* Invalid if not IPv4 or IPv6 */
807     if (!((hostlen == 4) || (hostlen == 16)))
808         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
809     if (!((baselen == 8) || (baselen == 32)))
810         return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
811
812     /* Do not match IPv4 with IPv6 */
813     if (hostlen * 2 != baselen)
814         return X509_V_ERR_PERMITTED_VIOLATION;
815
816     maskptr = base->data + hostlen;
817
818     /* Considering possible not aligned base ipAddress */
819     /* Not checking for wrong mask definition: i.e.: 255.0.255.0 */
820     for (i = 0; i < hostlen; i++)
821         if ((hostptr[i] & maskptr[i]) != (baseptr[i] & maskptr[i]))
822             return X509_V_ERR_PERMITTED_VIOLATION;
823
824     return X509_V_OK;
825
826 }