1 /* $NetBSD: name.c,v 1.3 2023/06/19 21:41:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2004 - 2009 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "hx_locl.h" 37 #include <krb5/wind.h> 38 #include "char_map.h" 39 40 /** 41 * @page page_name PKIX/X.509 Names 42 * 43 * There are several names in PKIX/X.509, GeneralName and Name. 44 * 45 * A Name consists of an ordered list of Relative Distinguished Names 46 * (RDN). Each RDN consists of an unordered list of typed strings. The 47 * types are defined by OID and have long and short description. For 48 * example id-at-commonName (2.5.4.3) have the long name CommonName 49 * and short name CN. The string itself can be of several encoding, 50 * UTF8, UTF16, Teltex string, etc. The type limit what encoding 51 * should be used. 52 * 53 * GeneralName is a broader nametype that can contains al kind of 54 * stuff like Name, IP addresses, partial Name, etc. 55 * 56 * Name is mapped into a hx509_name object. 57 * 58 * Parse and string name into a hx509_name object with hx509_parse_name(), 59 * make it back into string representation with hx509_name_to_string(). 60 * 61 * Name string are defined rfc2253, rfc1779 and X.501. 62 * 63 * See the library functions here: @ref hx509_name 64 */ 65 66 static const struct { 67 const char *n; 68 const heim_oid *o; 69 wind_profile_flags flags; 70 } no[] = { 71 { "C", &asn1_oid_id_at_countryName, 0 }, 72 { "CN", &asn1_oid_id_at_commonName, 0 }, 73 { "DC", &asn1_oid_id_domainComponent, 0 }, 74 { "L", &asn1_oid_id_at_localityName, 0 }, 75 { "O", &asn1_oid_id_at_organizationName, 0 }, 76 { "OU", &asn1_oid_id_at_organizationalUnitName, 0 }, 77 { "S", &asn1_oid_id_at_stateOrProvinceName, 0 }, 78 { "STREET", &asn1_oid_id_at_streetAddress, 0 }, 79 { "UID", &asn1_oid_id_Userid, 0 }, 80 { "emailAddress", &asn1_oid_id_pkcs9_emailAddress, 0 }, 81 { "serialNumber", &asn1_oid_id_at_serialNumber, 0 } 82 }; 83 84 static char * 85 quote_string(const char *f, size_t len, int flags, size_t *rlen) 86 { 87 size_t i, j, tolen; 88 const unsigned char *from = (const unsigned char *)f; 89 unsigned char *to; 90 91 tolen = len * 3 + 1; 92 to = malloc(tolen); 93 if (to == NULL) 94 return NULL; 95 96 for (i = 0, j = 0; i < len; i++) { 97 unsigned char map = char_map[from[i]] & flags; 98 if (i == 0 && (map & Q_RFC2253_QUOTE_FIRST)) { 99 to[j++] = '\\'; 100 to[j++] = from[i]; 101 } else if ((i + 1) == len && (map & Q_RFC2253_QUOTE_LAST)) { 102 103 to[j++] = '\\'; 104 to[j++] = from[i]; 105 } else if (map & Q_RFC2253_QUOTE) { 106 to[j++] = '\\'; 107 to[j++] = from[i]; 108 } else if (map & Q_RFC2253_HEX) { 109 int l = snprintf((char *)&to[j], tolen - j - 1, 110 "#%02x", (unsigned char)from[i]); 111 j += l; 112 } else { 113 to[j++] = from[i]; 114 } 115 } 116 to[j] = '\0'; 117 assert(j < tolen); 118 *rlen = j; 119 return (char *)to; 120 } 121 122 123 static int 124 append_string(char **str, size_t *total_len, const char *ss, 125 size_t len, int quote) 126 { 127 char *s, *qs; 128 129 if (quote) 130 qs = quote_string(ss, len, Q_RFC2253, &len); 131 else 132 qs = rk_UNCONST(ss); 133 134 s = realloc(*str, len + *total_len + 1); 135 if (s == NULL) 136 _hx509_abort("allocation failure"); /* XXX */ 137 memcpy(s + *total_len, qs, len); 138 if (qs != ss) 139 free(qs); 140 s[*total_len + len] = '\0'; 141 *str = s; 142 *total_len += len; 143 return 0; 144 } 145 146 static char * 147 oidtostring(const heim_oid *type) 148 { 149 char *s; 150 size_t i; 151 152 for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { 153 if (der_heim_oid_cmp(no[i].o, type) == 0) 154 return strdup(no[i].n); 155 } 156 if (der_print_heim_oid(type, '.', &s) != 0) 157 return NULL; 158 return s; 159 } 160 161 static int 162 stringtooid(const char *name, size_t len, heim_oid *oid) 163 { 164 int ret; 165 size_t i; 166 char *s; 167 168 memset(oid, 0, sizeof(*oid)); 169 170 for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) { 171 if (strncasecmp(no[i].n, name, len) == 0) 172 return der_copy_oid(no[i].o, oid); 173 } 174 s = malloc(len + 1); 175 if (s == NULL) 176 return ENOMEM; 177 memcpy(s, name, len); 178 s[len] = '\0'; 179 ret = der_parse_heim_oid(s, ".", oid); 180 free(s); 181 return ret; 182 } 183 184 /** 185 * Convert the hx509 name object into a printable string. 186 * The resulting string should be freed with free(). 187 * 188 * @param name name to print 189 * @param str the string to return 190 * 191 * @return An hx509 error code, see hx509_get_error_string(). 192 * 193 * @ingroup hx509_name 194 */ 195 196 int 197 hx509_name_to_string(const hx509_name name, char **str) 198 { 199 return _hx509_Name_to_string(&name->der_name, str); 200 } 201 202 int 203 _hx509_Name_to_string(const Name *n, char **str) 204 { 205 size_t total_len = 0; 206 size_t i, j, m; 207 int ret; 208 209 *str = strdup(""); 210 if (*str == NULL) 211 return ENOMEM; 212 213 for (m = n->u.rdnSequence.len; m > 0; m--) { 214 size_t len; 215 i = m - 1; 216 217 for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { 218 DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; 219 char *oidname; 220 char *ss; 221 222 oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type); 223 224 switch(ds->element) { 225 case choice_DirectoryString_ia5String: 226 ss = ds->u.ia5String.data; 227 len = ds->u.ia5String.length; 228 break; 229 case choice_DirectoryString_printableString: 230 ss = ds->u.printableString.data; 231 len = ds->u.printableString.length; 232 break; 233 case choice_DirectoryString_utf8String: 234 ss = ds->u.utf8String; 235 len = strlen(ss); 236 break; 237 case choice_DirectoryString_bmpString: { 238 const uint16_t *bmp = ds->u.bmpString.data; 239 size_t bmplen = ds->u.bmpString.length; 240 size_t k; 241 242 ret = wind_ucs2utf8_length(bmp, bmplen, &k); 243 if (ret) { 244 free(oidname); 245 free(*str); 246 *str = NULL; 247 return ret; 248 } 249 250 ss = malloc(k + 1); 251 if (ss == NULL) 252 _hx509_abort("allocation failure"); /* XXX */ 253 ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); 254 if (ret) { 255 free(oidname); 256 free(ss); 257 free(*str); 258 *str = NULL; 259 return ret; 260 } 261 ss[k] = '\0'; 262 len = k; 263 break; 264 } 265 case choice_DirectoryString_teletexString: 266 ss = ds->u.teletexString; 267 len = strlen(ss); 268 break; 269 case choice_DirectoryString_universalString: { 270 const uint32_t *uni = ds->u.universalString.data; 271 size_t unilen = ds->u.universalString.length; 272 size_t k; 273 274 ret = wind_ucs4utf8_length(uni, unilen, &k); 275 if (ret) { 276 free(oidname); 277 free(*str); 278 *str = NULL; 279 return ret; 280 } 281 282 ss = malloc(k + 1); 283 if (ss == NULL) 284 _hx509_abort("allocation failure"); /* XXX */ 285 ret = wind_ucs4utf8(uni, unilen, ss, NULL); 286 if (ret) { 287 free(ss); 288 free(oidname); 289 free(*str); 290 *str = NULL; 291 return ret; 292 } 293 ss[k] = '\0'; 294 len = k; 295 break; 296 } 297 default: 298 _hx509_abort("unknown directory type: %d", ds->element); 299 exit(1); 300 } 301 append_string(str, &total_len, oidname, strlen(oidname), 0); 302 free(oidname); 303 append_string(str, &total_len, "=", 1, 0); 304 append_string(str, &total_len, ss, len, 1); 305 if (ds->element == choice_DirectoryString_bmpString || 306 ds->element == choice_DirectoryString_universalString) 307 { 308 free(ss); 309 } 310 if (j + 1 < n->u.rdnSequence.val[i].len) 311 append_string(str, &total_len, "+", 1, 0); 312 } 313 314 if (i > 0) 315 append_string(str, &total_len, ",", 1, 0); 316 } 317 return 0; 318 } 319 320 #define COPYCHARARRAY(_ds,_el,_l,_n) \ 321 (_l) = strlen(_ds->u._el); \ 322 (_n) = malloc((_l) * sizeof((_n)[0])); \ 323 if ((_n) == NULL) \ 324 return ENOMEM; \ 325 for (i = 0; i < (_l); i++) \ 326 (_n)[i] = _ds->u._el[i] 327 328 329 #define COPYVALARRAY(_ds,_el,_l,_n) \ 330 (_l) = _ds->u._el.length; \ 331 (_n) = malloc((_l) * sizeof((_n)[0])); \ 332 if ((_n) == NULL) \ 333 return ENOMEM; \ 334 for (i = 0; i < (_l); i++) \ 335 (_n)[i] = _ds->u._el.data[i] 336 337 #define COPYVOIDARRAY(_ds,_el,_l,_n) \ 338 (_l) = _ds->u._el.length; \ 339 (_n) = malloc((_l) * sizeof((_n)[0])); \ 340 if ((_n) == NULL) \ 341 return ENOMEM; \ 342 for (i = 0; i < (_l); i++) \ 343 (_n)[i] = ((unsigned char *)_ds->u._el.data)[i] 344 345 346 347 static int 348 dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) 349 { 350 wind_profile_flags flags; 351 size_t i, len; 352 int ret; 353 uint32_t *name; 354 355 *rname = NULL; 356 *rlen = 0; 357 358 switch(ds->element) { 359 case choice_DirectoryString_ia5String: 360 flags = WIND_PROFILE_LDAP; 361 COPYVOIDARRAY(ds, ia5String, len, name); 362 break; 363 case choice_DirectoryString_printableString: 364 flags = WIND_PROFILE_LDAP; 365 flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE; 366 COPYVOIDARRAY(ds, printableString, len, name); 367 break; 368 case choice_DirectoryString_teletexString: 369 flags = WIND_PROFILE_LDAP_CASE; 370 COPYCHARARRAY(ds, teletexString, len, name); 371 break; 372 case choice_DirectoryString_bmpString: 373 flags = WIND_PROFILE_LDAP; 374 COPYVALARRAY(ds, bmpString, len, name); 375 break; 376 case choice_DirectoryString_universalString: 377 flags = WIND_PROFILE_LDAP; 378 COPYVALARRAY(ds, universalString, len, name); 379 break; 380 case choice_DirectoryString_utf8String: 381 flags = WIND_PROFILE_LDAP; 382 ret = wind_utf8ucs4_length(ds->u.utf8String, &len); 383 if (ret) 384 return ret; 385 name = malloc(len * sizeof(name[0])); 386 if (name == NULL) 387 return ENOMEM; 388 ret = wind_utf8ucs4(ds->u.utf8String, name, &len); 389 if (ret) { 390 free(name); 391 return ret; 392 } 393 break; 394 default: 395 _hx509_abort("unknown directory type: %d", ds->element); 396 } 397 398 *rlen = len; 399 /* try a couple of times to get the length right, XXX gross */ 400 for (i = 0; i < 4; i++) { 401 *rlen = *rlen * 2; 402 *rname = malloc(*rlen * sizeof((*rname)[0])); 403 404 ret = wind_stringprep(name, len, *rname, rlen, flags); 405 if (ret == WIND_ERR_OVERRUN) { 406 free(*rname); 407 *rname = NULL; 408 continue; 409 } else 410 break; 411 } 412 free(name); 413 if (ret) { 414 if (*rname) 415 free(*rname); 416 *rname = NULL; 417 *rlen = 0; 418 return ret; 419 } 420 421 return 0; 422 } 423 424 int 425 _hx509_name_ds_cmp(const DirectoryString *ds1, 426 const DirectoryString *ds2, 427 int *diff) 428 { 429 uint32_t *ds1lp, *ds2lp; 430 size_t ds1len, ds2len, i; 431 int ret; 432 433 ret = dsstringprep(ds1, &ds1lp, &ds1len); 434 if (ret) 435 return ret; 436 ret = dsstringprep(ds2, &ds2lp, &ds2len); 437 if (ret) { 438 free(ds1lp); 439 return ret; 440 } 441 442 if (ds1len != ds2len) 443 *diff = ds1len - ds2len; 444 else { 445 for (i = 0; i < ds1len; i++) { 446 *diff = ds1lp[i] - ds2lp[i]; 447 if (*diff) 448 break; 449 } 450 } 451 free(ds1lp); 452 free(ds2lp); 453 454 return 0; 455 } 456 457 int 458 _hx509_name_cmp(const Name *n1, const Name *n2, int *c) 459 { 460 int ret; 461 size_t i, j; 462 463 *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; 464 if (*c) 465 return 0; 466 467 for (i = 0 ; i < n1->u.rdnSequence.len; i++) { 468 *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; 469 if (*c) 470 return 0; 471 472 for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { 473 *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, 474 &n1->u.rdnSequence.val[i].val[j].type); 475 if (*c) 476 return 0; 477 478 ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, 479 &n2->u.rdnSequence.val[i].val[j].value, 480 c); 481 if (ret) 482 return ret; 483 if (*c) 484 return 0; 485 } 486 } 487 *c = 0; 488 return 0; 489 } 490 491 /** 492 * Compare to hx509 name object, useful for sorting. 493 * 494 * @param n1 a hx509 name object. 495 * @param n2 a hx509 name object. 496 * 497 * @return 0 the objects are the same, returns > 0 is n2 is "larger" 498 * then n2, < 0 if n1 is "smaller" then n2. 499 * 500 * @ingroup hx509_name 501 */ 502 503 int 504 hx509_name_cmp(hx509_name n1, hx509_name n2) 505 { 506 int ret, diff; 507 ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff); 508 if (ret) 509 return ret; 510 return diff; 511 } 512 513 514 int 515 _hx509_name_from_Name(const Name *n, hx509_name *name) 516 { 517 int ret; 518 *name = calloc(1, sizeof(**name)); 519 if (*name == NULL) 520 return ENOMEM; 521 ret = copy_Name(n, &(*name)->der_name); 522 if (ret) { 523 free(*name); 524 *name = NULL; 525 } 526 return ret; 527 } 528 529 int 530 _hx509_name_modify(hx509_context context, 531 Name *name, 532 int append, 533 const heim_oid *oid, 534 const char *str) 535 { 536 RelativeDistinguishedName *rdn; 537 int ret; 538 void *ptr; 539 540 ptr = realloc(name->u.rdnSequence.val, 541 sizeof(name->u.rdnSequence.val[0]) * 542 (name->u.rdnSequence.len + 1)); 543 if (ptr == NULL) { 544 hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); 545 return ENOMEM; 546 } 547 name->u.rdnSequence.val = ptr; 548 549 if (append) { 550 rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len]; 551 } else { 552 memmove(&name->u.rdnSequence.val[1], 553 &name->u.rdnSequence.val[0], 554 name->u.rdnSequence.len * 555 sizeof(name->u.rdnSequence.val[0])); 556 557 rdn = &name->u.rdnSequence.val[0]; 558 } 559 rdn->val = malloc(sizeof(rdn->val[0])); 560 if (rdn->val == NULL) 561 return ENOMEM; 562 rdn->len = 1; 563 ret = der_copy_oid(oid, &rdn->val[0].type); 564 if (ret) 565 return ret; 566 rdn->val[0].value.element = choice_DirectoryString_utf8String; 567 rdn->val[0].value.u.utf8String = strdup(str); 568 if (rdn->val[0].value.u.utf8String == NULL) 569 return ENOMEM; 570 name->u.rdnSequence.len += 1; 571 572 return 0; 573 } 574 575 /** 576 * Parse a string into a hx509 name object. 577 * 578 * @param context A hx509 context. 579 * @param str a string to parse. 580 * @param name the resulting object, NULL in case of error. 581 * 582 * @return An hx509 error code, see hx509_get_error_string(). 583 * 584 * @ingroup hx509_name 585 */ 586 587 int 588 hx509_parse_name(hx509_context context, const char *str, hx509_name *name) 589 { 590 const char *p, *q; 591 size_t len; 592 hx509_name n; 593 int ret; 594 595 *name = NULL; 596 597 n = calloc(1, sizeof(*n)); 598 if (n == NULL) { 599 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 600 return ENOMEM; 601 } 602 603 n->der_name.element = choice_Name_rdnSequence; 604 605 p = str; 606 607 while (p != NULL && *p != '\0') { 608 heim_oid oid; 609 int last; 610 611 q = strchr(p, ','); 612 if (q) { 613 len = (q - p); 614 last = 1; 615 } else { 616 len = strlen(p); 617 last = 0; 618 } 619 620 q = strchr(p, '='); 621 if (q == NULL) { 622 ret = HX509_PARSING_NAME_FAILED; 623 hx509_set_error_string(context, 0, ret, "missing = in %s", p); 624 goto out; 625 } 626 if (q == p) { 627 ret = HX509_PARSING_NAME_FAILED; 628 hx509_set_error_string(context, 0, ret, 629 "missing name before = in %s", p); 630 goto out; 631 } 632 633 if ((size_t)(q - p) > len) { 634 ret = HX509_PARSING_NAME_FAILED; 635 hx509_set_error_string(context, 0, ret, " = after , in %s", p); 636 goto out; 637 } 638 639 ret = stringtooid(p, q - p, &oid); 640 if (ret) { 641 ret = HX509_PARSING_NAME_FAILED; 642 hx509_set_error_string(context, 0, ret, 643 "unknown type: %.*s", (int)(q - p), p); 644 goto out; 645 } 646 647 { 648 size_t pstr_len = len - (q - p) - 1; 649 const char *pstr = p + (q - p) + 1; 650 char *r; 651 652 r = malloc(pstr_len + 1); 653 if (r == NULL) { 654 der_free_oid(&oid); 655 ret = ENOMEM; 656 hx509_set_error_string(context, 0, ret, "out of memory"); 657 goto out; 658 } 659 memcpy(r, pstr, pstr_len); 660 r[pstr_len] = '\0'; 661 662 ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r); 663 free(r); 664 der_free_oid(&oid); 665 if(ret) 666 goto out; 667 } 668 p += len + last; 669 } 670 671 *name = n; 672 673 return 0; 674 out: 675 hx509_name_free(&n); 676 return HX509_NAME_MALFORMED; 677 } 678 679 /** 680 * Copy a hx509 name object. 681 * 682 * @param context A hx509 cotext. 683 * @param from the name to copy from 684 * @param to the name to copy to 685 * 686 * @return An hx509 error code, see hx509_get_error_string(). 687 * 688 * @ingroup hx509_name 689 */ 690 691 int 692 hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) 693 { 694 int ret; 695 696 *to = calloc(1, sizeof(**to)); 697 if (*to == NULL) 698 return ENOMEM; 699 ret = copy_Name(&from->der_name, &(*to)->der_name); 700 if (ret) { 701 free(*to); 702 *to = NULL; 703 return ENOMEM; 704 } 705 return 0; 706 } 707 708 /** 709 * Convert a hx509_name into a Name. 710 * 711 * @param from the name to copy from 712 * @param to the name to copy to 713 * 714 * @return An hx509 error code, see hx509_get_error_string(). 715 * 716 * @ingroup hx509_name 717 */ 718 719 int 720 hx509_name_to_Name(const hx509_name from, Name *to) 721 { 722 return copy_Name(&from->der_name, to); 723 } 724 725 int 726 hx509_name_normalize(hx509_context context, hx509_name name) 727 { 728 return 0; 729 } 730 731 /** 732 * Expands variables in the name using env. Variables are on the form 733 * ${name}. Useful when dealing with certificate templates. 734 * 735 * @param context A hx509 cotext. 736 * @param name the name to expand. 737 * @param env environment variable to expand. 738 * 739 * @return An hx509 error code, see hx509_get_error_string(). 740 * 741 * @ingroup hx509_name 742 */ 743 744 int 745 hx509_name_expand(hx509_context context, 746 hx509_name name, 747 hx509_env env) 748 { 749 Name *n = &name->der_name; 750 size_t i, j; 751 752 if (env == NULL) 753 return 0; 754 755 if (n->element != choice_Name_rdnSequence) { 756 hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type"); 757 return EINVAL; 758 } 759 760 for (i = 0 ; i < n->u.rdnSequence.len; i++) { 761 for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { 762 /** Only UTF8String rdnSequence names are allowed */ 763 /* 764 THIS SHOULD REALLY BE: 765 COMP = n->u.rdnSequence.val[i].val[j]; 766 normalize COMP to utf8 767 check if there are variables 768 expand variables 769 convert back to orignal format, store in COMP 770 free normalized utf8 string 771 */ 772 DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; 773 char *p, *p2; 774 struct rk_strpool *strpool = NULL; 775 776 if (ds->element != choice_DirectoryString_utf8String) { 777 hx509_set_error_string(context, 0, EINVAL, "unsupported type"); 778 return EINVAL; 779 } 780 p = strstr(ds->u.utf8String, "${"); 781 if (p) { 782 strpool = rk_strpoolprintf(strpool, "%.*s", 783 (int)(p - ds->u.utf8String), 784 ds->u.utf8String); 785 if (strpool == NULL) { 786 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 787 return ENOMEM; 788 } 789 } 790 while (p != NULL) { 791 /* expand variables */ 792 const char *value; 793 p2 = strchr(p, '}'); 794 if (p2 == NULL) { 795 hx509_set_error_string(context, 0, EINVAL, "missing }"); 796 rk_strpoolfree(strpool); 797 return EINVAL; 798 } 799 p += 2; 800 value = hx509_env_lfind(context, env, p, p2 - p); 801 if (value == NULL) { 802 hx509_set_error_string(context, 0, EINVAL, 803 "variable %.*s missing", 804 (int)(p2 - p), p); 805 rk_strpoolfree(strpool); 806 return EINVAL; 807 } 808 strpool = rk_strpoolprintf(strpool, "%s", value); 809 if (strpool == NULL) { 810 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 811 return ENOMEM; 812 } 813 p2++; 814 815 p = strstr(p2, "${"); 816 if (p) 817 strpool = rk_strpoolprintf(strpool, "%.*s", 818 (int)(p - p2), p2); 819 else 820 strpool = rk_strpoolprintf(strpool, "%s", p2); 821 if (strpool == NULL) { 822 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 823 return ENOMEM; 824 } 825 } 826 if (strpool) { 827 free(ds->u.utf8String); 828 ds->u.utf8String = rk_strpoolcollect(strpool); 829 if (ds->u.utf8String == NULL) { 830 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 831 return ENOMEM; 832 } 833 } 834 } 835 } 836 return 0; 837 } 838 839 /** 840 * Free a hx509 name object, upond return *name will be NULL. 841 * 842 * @param name a hx509 name object to be freed. 843 * 844 * @ingroup hx509_name 845 */ 846 847 void 848 hx509_name_free(hx509_name *name) 849 { 850 free_Name(&(*name)->der_name); 851 memset(*name, 0, sizeof(**name)); 852 free(*name); 853 *name = NULL; 854 } 855 856 /** 857 * Convert a DER encoded name info a string. 858 * 859 * @param data data to a DER/BER encoded name 860 * @param length length of data 861 * @param str the resulting string, is NULL on failure. 862 * 863 * @return An hx509 error code, see hx509_get_error_string(). 864 * 865 * @ingroup hx509_name 866 */ 867 868 int 869 hx509_unparse_der_name(const void *data, size_t length, char **str) 870 { 871 Name name; 872 int ret; 873 874 *str = NULL; 875 876 ret = decode_Name(data, length, &name, NULL); 877 if (ret) 878 return ret; 879 ret = _hx509_Name_to_string(&name, str); 880 free_Name(&name); 881 return ret; 882 } 883 884 /** 885 * Convert a hx509_name object to DER encoded name. 886 * 887 * @param name name to concert 888 * @param os data to a DER encoded name, free the resulting octet 889 * string with hx509_xfree(os->data). 890 * 891 * @return An hx509 error code, see hx509_get_error_string(). 892 * 893 * @ingroup hx509_name 894 */ 895 896 int 897 hx509_name_binary(const hx509_name name, heim_octet_string *os) 898 { 899 size_t size; 900 int ret; 901 902 ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret); 903 if (ret) 904 return ret; 905 if (os->length != size) 906 _hx509_abort("internal ASN.1 encoder error"); 907 908 return 0; 909 } 910 911 int 912 _hx509_unparse_Name(const Name *aname, char **str) 913 { 914 hx509_name name; 915 int ret; 916 917 ret = _hx509_name_from_Name(aname, &name); 918 if (ret) 919 return ret; 920 921 ret = hx509_name_to_string(name, str); 922 hx509_name_free(&name); 923 return ret; 924 } 925 926 /** 927 * Unparse the hx509 name in name into a string. 928 * 929 * @param name the name to check if its empty/null. 930 * 931 * @return non zero if the name is empty/null. 932 * 933 * @ingroup hx509_name 934 */ 935 936 int 937 hx509_name_is_null_p(const hx509_name name) 938 { 939 return name->der_name.u.rdnSequence.len == 0; 940 } 941 942 /** 943 * Unparse the hx509 name in name into a string. 944 * 945 * @param name the name to print 946 * @param str an allocated string returns the name in string form 947 * 948 * @return An hx509 error code, see hx509_get_error_string(). 949 * 950 * @ingroup hx509_name 951 */ 952 953 int 954 hx509_general_name_unparse(GeneralName *name, char **str) 955 { 956 struct rk_strpool *strpool = NULL; 957 int ret = 0; 958 959 *str = NULL; 960 961 switch (name->element) { 962 case choice_GeneralName_otherName: { 963 char *oid; 964 hx509_oid_sprint(&name->u.otherName.type_id, &oid); 965 if (oid == NULL) 966 return ENOMEM; 967 strpool = rk_strpoolprintf(strpool, "otherName: %s", oid); 968 free(oid); 969 break; 970 } 971 case choice_GeneralName_rfc822Name: 972 strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s\n", 973 (int)name->u.rfc822Name.length, 974 (char *)name->u.rfc822Name.data); 975 break; 976 case choice_GeneralName_dNSName: 977 strpool = rk_strpoolprintf(strpool, "dNSName: %.*s\n", 978 (int)name->u.dNSName.length, 979 (char *)name->u.dNSName.data); 980 break; 981 case choice_GeneralName_directoryName: { 982 Name dir; 983 char *s; 984 memset(&dir, 0, sizeof(dir)); 985 dir.element = (enum Name_enum)name->u.directoryName.element; 986 dir.u.rdnSequence = name->u.directoryName.u.rdnSequence; 987 ret = _hx509_unparse_Name(&dir, &s); 988 if (ret) 989 return ret; 990 strpool = rk_strpoolprintf(strpool, "directoryName: %s", s); 991 free(s); 992 break; 993 } 994 case choice_GeneralName_uniformResourceIdentifier: 995 strpool = rk_strpoolprintf(strpool, "URI: %.*s", 996 (int)name->u.uniformResourceIdentifier.length, 997 (char *)name->u.uniformResourceIdentifier.data); 998 break; 999 case choice_GeneralName_iPAddress: { 1000 unsigned char *a = name->u.iPAddress.data; 1001 1002 strpool = rk_strpoolprintf(strpool, "IPAddress: "); 1003 if (strpool == NULL) 1004 break; 1005 if (name->u.iPAddress.length == 4) 1006 strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d", 1007 a[0], a[1], a[2], a[3]); 1008 else if (name->u.iPAddress.length == 16) 1009 strpool = rk_strpoolprintf(strpool, 1010 "%02X:%02X:%02X:%02X:" 1011 "%02X:%02X:%02X:%02X:" 1012 "%02X:%02X:%02X:%02X:" 1013 "%02X:%02X:%02X:%02X", 1014 a[0], a[1], a[2], a[3], 1015 a[4], a[5], a[6], a[7], 1016 a[8], a[9], a[10], a[11], 1017 a[12], a[13], a[14], a[15]); 1018 else 1019 strpool = rk_strpoolprintf(strpool, 1020 "unknown IP address of length %lu", 1021 (unsigned long)name->u.iPAddress.length); 1022 break; 1023 } 1024 case choice_GeneralName_registeredID: { 1025 char *oid; 1026 hx509_oid_sprint(&name->u.registeredID, &oid); 1027 if (oid == NULL) 1028 return ENOMEM; 1029 strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid); 1030 free(oid); 1031 break; 1032 } 1033 default: 1034 return EINVAL; 1035 } 1036 if (ret) 1037 rk_strpoolfree(strpool); 1038 else if (strpool == NULL || (*str = rk_strpoolcollect(strpool)) == NULL) 1039 return ENOMEM; 1040 return ret; 1041 } 1042