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