1 /* $NetBSD: name.c,v 1.1.1.2 2014/04/24 12:45:42 pettai 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 return ret; 245 246 ss = malloc(k + 1); 247 if (ss == NULL) 248 _hx509_abort("allocation failure"); /* XXX */ 249 ret = wind_ucs2utf8(bmp, bmplen, ss, NULL); 250 if (ret) { 251 free(ss); 252 return ret; 253 } 254 ss[k] = '\0'; 255 len = k; 256 break; 257 } 258 case choice_DirectoryString_teletexString: 259 ss = ds->u.teletexString; 260 len = strlen(ss); 261 break; 262 case choice_DirectoryString_universalString: { 263 const uint32_t *uni = ds->u.universalString.data; 264 size_t unilen = ds->u.universalString.length; 265 size_t k; 266 267 ret = wind_ucs4utf8_length(uni, unilen, &k); 268 if (ret) 269 return ret; 270 271 ss = malloc(k + 1); 272 if (ss == NULL) 273 _hx509_abort("allocation failure"); /* XXX */ 274 ret = wind_ucs4utf8(uni, unilen, ss, NULL); 275 if (ret) { 276 free(ss); 277 return ret; 278 } 279 ss[k] = '\0'; 280 len = k; 281 break; 282 } 283 default: 284 _hx509_abort("unknown directory type: %d", ds->element); 285 exit(1); 286 } 287 append_string(str, &total_len, oidname, strlen(oidname), 0); 288 free(oidname); 289 append_string(str, &total_len, "=", 1, 0); 290 append_string(str, &total_len, ss, len, 1); 291 if (ds->element == choice_DirectoryString_bmpString || 292 ds->element == choice_DirectoryString_universalString) 293 { 294 free(ss); 295 } 296 if (j + 1 < n->u.rdnSequence.val[i].len) 297 append_string(str, &total_len, "+", 1, 0); 298 } 299 300 if (i > 0) 301 append_string(str, &total_len, ",", 1, 0); 302 } 303 return 0; 304 } 305 306 #define COPYCHARARRAY(_ds,_el,_l,_n) \ 307 (_l) = strlen(_ds->u._el); \ 308 (_n) = malloc((_l) * sizeof((_n)[0])); \ 309 if ((_n) == NULL) \ 310 return ENOMEM; \ 311 for (i = 0; i < (_l); i++) \ 312 (_n)[i] = _ds->u._el[i] 313 314 315 #define COPYVALARRAY(_ds,_el,_l,_n) \ 316 (_l) = _ds->u._el.length; \ 317 (_n) = malloc((_l) * sizeof((_n)[0])); \ 318 if ((_n) == NULL) \ 319 return ENOMEM; \ 320 for (i = 0; i < (_l); i++) \ 321 (_n)[i] = _ds->u._el.data[i] 322 323 #define COPYVOIDARRAY(_ds,_el,_l,_n) \ 324 (_l) = _ds->u._el.length; \ 325 (_n) = malloc((_l) * sizeof((_n)[0])); \ 326 if ((_n) == NULL) \ 327 return ENOMEM; \ 328 for (i = 0; i < (_l); i++) \ 329 (_n)[i] = ((unsigned char *)_ds->u._el.data)[i] 330 331 332 333 static int 334 dsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen) 335 { 336 wind_profile_flags flags; 337 size_t i, len; 338 int ret; 339 uint32_t *name; 340 341 *rname = NULL; 342 *rlen = 0; 343 344 switch(ds->element) { 345 case choice_DirectoryString_ia5String: 346 flags = WIND_PROFILE_LDAP; 347 COPYVOIDARRAY(ds, ia5String, len, name); 348 break; 349 case choice_DirectoryString_printableString: 350 flags = WIND_PROFILE_LDAP; 351 flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE; 352 COPYVOIDARRAY(ds, printableString, len, name); 353 break; 354 case choice_DirectoryString_teletexString: 355 flags = WIND_PROFILE_LDAP_CASE; 356 COPYCHARARRAY(ds, teletexString, len, name); 357 break; 358 case choice_DirectoryString_bmpString: 359 flags = WIND_PROFILE_LDAP; 360 COPYVALARRAY(ds, bmpString, len, name); 361 break; 362 case choice_DirectoryString_universalString: 363 flags = WIND_PROFILE_LDAP; 364 COPYVALARRAY(ds, universalString, len, name); 365 break; 366 case choice_DirectoryString_utf8String: 367 flags = WIND_PROFILE_LDAP; 368 ret = wind_utf8ucs4_length(ds->u.utf8String, &len); 369 if (ret) 370 return ret; 371 name = malloc(len * sizeof(name[0])); 372 if (name == NULL) 373 return ENOMEM; 374 ret = wind_utf8ucs4(ds->u.utf8String, name, &len); 375 if (ret) { 376 free(name); 377 return ret; 378 } 379 break; 380 default: 381 _hx509_abort("unknown directory type: %d", ds->element); 382 } 383 384 *rlen = len; 385 /* try a couple of times to get the length right, XXX gross */ 386 for (i = 0; i < 4; i++) { 387 *rlen = *rlen * 2; 388 *rname = malloc(*rlen * sizeof((*rname)[0])); 389 390 ret = wind_stringprep(name, len, *rname, rlen, flags); 391 if (ret == WIND_ERR_OVERRUN) { 392 free(*rname); 393 *rname = NULL; 394 continue; 395 } else 396 break; 397 } 398 free(name); 399 if (ret) { 400 if (*rname) 401 free(*rname); 402 *rname = NULL; 403 *rlen = 0; 404 return ret; 405 } 406 407 return 0; 408 } 409 410 int 411 _hx509_name_ds_cmp(const DirectoryString *ds1, 412 const DirectoryString *ds2, 413 int *diff) 414 { 415 uint32_t *ds1lp, *ds2lp; 416 size_t ds1len, ds2len, i; 417 int ret; 418 419 ret = dsstringprep(ds1, &ds1lp, &ds1len); 420 if (ret) 421 return ret; 422 ret = dsstringprep(ds2, &ds2lp, &ds2len); 423 if (ret) { 424 free(ds1lp); 425 return ret; 426 } 427 428 if (ds1len != ds2len) 429 *diff = ds1len - ds2len; 430 else { 431 for (i = 0; i < ds1len; i++) { 432 *diff = ds1lp[i] - ds2lp[i]; 433 if (*diff) 434 break; 435 } 436 } 437 free(ds1lp); 438 free(ds2lp); 439 440 return 0; 441 } 442 443 int 444 _hx509_name_cmp(const Name *n1, const Name *n2, int *c) 445 { 446 int ret; 447 size_t i, j; 448 449 *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len; 450 if (*c) 451 return 0; 452 453 for (i = 0 ; i < n1->u.rdnSequence.len; i++) { 454 *c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len; 455 if (*c) 456 return 0; 457 458 for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) { 459 *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type, 460 &n1->u.rdnSequence.val[i].val[j].type); 461 if (*c) 462 return 0; 463 464 ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value, 465 &n2->u.rdnSequence.val[i].val[j].value, 466 c); 467 if (ret) 468 return ret; 469 if (*c) 470 return 0; 471 } 472 } 473 *c = 0; 474 return 0; 475 } 476 477 /** 478 * Compare to hx509 name object, useful for sorting. 479 * 480 * @param n1 a hx509 name object. 481 * @param n2 a hx509 name object. 482 * 483 * @return 0 the objects are the same, returns > 0 is n2 is "larger" 484 * then n2, < 0 if n1 is "smaller" then n2. 485 * 486 * @ingroup hx509_name 487 */ 488 489 int 490 hx509_name_cmp(hx509_name n1, hx509_name n2) 491 { 492 int ret, diff; 493 ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff); 494 if (ret) 495 return ret; 496 return diff; 497 } 498 499 500 int 501 _hx509_name_from_Name(const Name *n, hx509_name *name) 502 { 503 int ret; 504 *name = calloc(1, sizeof(**name)); 505 if (*name == NULL) 506 return ENOMEM; 507 ret = copy_Name(n, &(*name)->der_name); 508 if (ret) { 509 free(*name); 510 *name = NULL; 511 } 512 return ret; 513 } 514 515 int 516 _hx509_name_modify(hx509_context context, 517 Name *name, 518 int append, 519 const heim_oid *oid, 520 const char *str) 521 { 522 RelativeDistinguishedName *rdn; 523 int ret; 524 void *ptr; 525 526 ptr = realloc(name->u.rdnSequence.val, 527 sizeof(name->u.rdnSequence.val[0]) * 528 (name->u.rdnSequence.len + 1)); 529 if (ptr == NULL) { 530 hx509_set_error_string(context, 0, ENOMEM, "Out of memory"); 531 return ENOMEM; 532 } 533 name->u.rdnSequence.val = ptr; 534 535 if (append) { 536 rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len]; 537 } else { 538 memmove(&name->u.rdnSequence.val[1], 539 &name->u.rdnSequence.val[0], 540 name->u.rdnSequence.len * 541 sizeof(name->u.rdnSequence.val[0])); 542 543 rdn = &name->u.rdnSequence.val[0]; 544 } 545 rdn->val = malloc(sizeof(rdn->val[0])); 546 if (rdn->val == NULL) 547 return ENOMEM; 548 rdn->len = 1; 549 ret = der_copy_oid(oid, &rdn->val[0].type); 550 if (ret) 551 return ret; 552 rdn->val[0].value.element = choice_DirectoryString_utf8String; 553 rdn->val[0].value.u.utf8String = strdup(str); 554 if (rdn->val[0].value.u.utf8String == NULL) 555 return ENOMEM; 556 name->u.rdnSequence.len += 1; 557 558 return 0; 559 } 560 561 /** 562 * Parse a string into a hx509 name object. 563 * 564 * @param context A hx509 context. 565 * @param str a string to parse. 566 * @param name the resulting object, NULL in case of error. 567 * 568 * @return An hx509 error code, see hx509_get_error_string(). 569 * 570 * @ingroup hx509_name 571 */ 572 573 int 574 hx509_parse_name(hx509_context context, const char *str, hx509_name *name) 575 { 576 const char *p, *q; 577 size_t len; 578 hx509_name n; 579 int ret; 580 581 *name = NULL; 582 583 n = calloc(1, sizeof(*n)); 584 if (n == NULL) { 585 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 586 return ENOMEM; 587 } 588 589 n->der_name.element = choice_Name_rdnSequence; 590 591 p = str; 592 593 while (p != NULL && *p != '\0') { 594 heim_oid oid; 595 int last; 596 597 q = strchr(p, ','); 598 if (q) { 599 len = (q - p); 600 last = 1; 601 } else { 602 len = strlen(p); 603 last = 0; 604 } 605 606 q = strchr(p, '='); 607 if (q == NULL) { 608 ret = HX509_PARSING_NAME_FAILED; 609 hx509_set_error_string(context, 0, ret, "missing = in %s", p); 610 goto out; 611 } 612 if (q == p) { 613 ret = HX509_PARSING_NAME_FAILED; 614 hx509_set_error_string(context, 0, ret, 615 "missing name before = in %s", p); 616 goto out; 617 } 618 619 if ((size_t)(q - p) > len) { 620 ret = HX509_PARSING_NAME_FAILED; 621 hx509_set_error_string(context, 0, ret, " = after , in %s", p); 622 goto out; 623 } 624 625 ret = stringtooid(p, q - p, &oid); 626 if (ret) { 627 ret = HX509_PARSING_NAME_FAILED; 628 hx509_set_error_string(context, 0, ret, 629 "unknown type: %.*s", (int)(q - p), p); 630 goto out; 631 } 632 633 { 634 size_t pstr_len = len - (q - p) - 1; 635 const char *pstr = p + (q - p) + 1; 636 char *r; 637 638 r = malloc(pstr_len + 1); 639 if (r == NULL) { 640 der_free_oid(&oid); 641 ret = ENOMEM; 642 hx509_set_error_string(context, 0, ret, "out of memory"); 643 goto out; 644 } 645 memcpy(r, pstr, pstr_len); 646 r[pstr_len] = '\0'; 647 648 ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r); 649 free(r); 650 der_free_oid(&oid); 651 if(ret) 652 goto out; 653 } 654 p += len + last; 655 } 656 657 *name = n; 658 659 return 0; 660 out: 661 hx509_name_free(&n); 662 return HX509_NAME_MALFORMED; 663 } 664 665 /** 666 * Copy a hx509 name object. 667 * 668 * @param context A hx509 cotext. 669 * @param from the name to copy from 670 * @param to the name to copy to 671 * 672 * @return An hx509 error code, see hx509_get_error_string(). 673 * 674 * @ingroup hx509_name 675 */ 676 677 int 678 hx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to) 679 { 680 int ret; 681 682 *to = calloc(1, sizeof(**to)); 683 if (*to == NULL) 684 return ENOMEM; 685 ret = copy_Name(&from->der_name, &(*to)->der_name); 686 if (ret) { 687 free(*to); 688 *to = NULL; 689 return ENOMEM; 690 } 691 return 0; 692 } 693 694 /** 695 * Convert a hx509_name into a Name. 696 * 697 * @param from the name to copy from 698 * @param to the name to copy to 699 * 700 * @return An hx509 error code, see hx509_get_error_string(). 701 * 702 * @ingroup hx509_name 703 */ 704 705 int 706 hx509_name_to_Name(const hx509_name from, Name *to) 707 { 708 return copy_Name(&from->der_name, to); 709 } 710 711 int 712 hx509_name_normalize(hx509_context context, hx509_name name) 713 { 714 return 0; 715 } 716 717 /** 718 * Expands variables in the name using env. Variables are on the form 719 * ${name}. Useful when dealing with certificate templates. 720 * 721 * @param context A hx509 cotext. 722 * @param name the name to expand. 723 * @param env environment variable to expand. 724 * 725 * @return An hx509 error code, see hx509_get_error_string(). 726 * 727 * @ingroup hx509_name 728 */ 729 730 int 731 hx509_name_expand(hx509_context context, 732 hx509_name name, 733 hx509_env env) 734 { 735 Name *n = &name->der_name; 736 size_t i, j; 737 738 if (env == NULL) 739 return 0; 740 741 if (n->element != choice_Name_rdnSequence) { 742 hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type"); 743 return EINVAL; 744 } 745 746 for (i = 0 ; i < n->u.rdnSequence.len; i++) { 747 for (j = 0; j < n->u.rdnSequence.val[i].len; j++) { 748 /** Only UTF8String rdnSequence names are allowed */ 749 /* 750 THIS SHOULD REALLY BE: 751 COMP = n->u.rdnSequence.val[i].val[j]; 752 normalize COMP to utf8 753 check if there are variables 754 expand variables 755 convert back to orignal format, store in COMP 756 free normalized utf8 string 757 */ 758 DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value; 759 char *p, *p2; 760 struct rk_strpool *strpool = NULL; 761 762 if (ds->element != choice_DirectoryString_utf8String) { 763 hx509_set_error_string(context, 0, EINVAL, "unsupported type"); 764 return EINVAL; 765 } 766 p = strstr(ds->u.utf8String, "${"); 767 if (p) { 768 strpool = rk_strpoolprintf(strpool, "%.*s", 769 (int)(p - ds->u.utf8String), 770 ds->u.utf8String); 771 if (strpool == NULL) { 772 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 773 return ENOMEM; 774 } 775 } 776 while (p != NULL) { 777 /* expand variables */ 778 const char *value; 779 p2 = strchr(p, '}'); 780 if (p2 == NULL) { 781 hx509_set_error_string(context, 0, EINVAL, "missing }"); 782 rk_strpoolfree(strpool); 783 return EINVAL; 784 } 785 p += 2; 786 value = hx509_env_lfind(context, env, p, p2 - p); 787 if (value == NULL) { 788 hx509_set_error_string(context, 0, EINVAL, 789 "variable %.*s missing", 790 (int)(p2 - p), p); 791 rk_strpoolfree(strpool); 792 return EINVAL; 793 } 794 strpool = rk_strpoolprintf(strpool, "%s", value); 795 if (strpool == NULL) { 796 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 797 return ENOMEM; 798 } 799 p2++; 800 801 p = strstr(p2, "${"); 802 if (p) 803 strpool = rk_strpoolprintf(strpool, "%.*s", 804 (int)(p - p2), p2); 805 else 806 strpool = rk_strpoolprintf(strpool, "%s", p2); 807 if (strpool == NULL) { 808 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 809 return ENOMEM; 810 } 811 } 812 if (strpool) { 813 free(ds->u.utf8String); 814 ds->u.utf8String = rk_strpoolcollect(strpool); 815 if (ds->u.utf8String == NULL) { 816 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 817 return ENOMEM; 818 } 819 } 820 } 821 } 822 return 0; 823 } 824 825 /** 826 * Free a hx509 name object, upond return *name will be NULL. 827 * 828 * @param name a hx509 name object to be freed. 829 * 830 * @ingroup hx509_name 831 */ 832 833 void 834 hx509_name_free(hx509_name *name) 835 { 836 free_Name(&(*name)->der_name); 837 memset(*name, 0, sizeof(**name)); 838 free(*name); 839 *name = NULL; 840 } 841 842 /** 843 * Convert a DER encoded name info a string. 844 * 845 * @param data data to a DER/BER encoded name 846 * @param length length of data 847 * @param str the resulting string, is NULL on failure. 848 * 849 * @return An hx509 error code, see hx509_get_error_string(). 850 * 851 * @ingroup hx509_name 852 */ 853 854 int 855 hx509_unparse_der_name(const void *data, size_t length, char **str) 856 { 857 Name name; 858 int ret; 859 860 *str = NULL; 861 862 ret = decode_Name(data, length, &name, NULL); 863 if (ret) 864 return ret; 865 ret = _hx509_Name_to_string(&name, str); 866 free_Name(&name); 867 return ret; 868 } 869 870 /** 871 * Convert a hx509_name object to DER encoded name. 872 * 873 * @param name name to concert 874 * @param os data to a DER encoded name, free the resulting octet 875 * string with hx509_xfree(os->data). 876 * 877 * @return An hx509 error code, see hx509_get_error_string(). 878 * 879 * @ingroup hx509_name 880 */ 881 882 int 883 hx509_name_binary(const hx509_name name, heim_octet_string *os) 884 { 885 size_t size; 886 int ret; 887 888 ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret); 889 if (ret) 890 return ret; 891 if (os->length != size) 892 _hx509_abort("internal ASN.1 encoder error"); 893 894 return 0; 895 } 896 897 int 898 _hx509_unparse_Name(const Name *aname, char **str) 899 { 900 hx509_name name; 901 int ret; 902 903 ret = _hx509_name_from_Name(aname, &name); 904 if (ret) 905 return ret; 906 907 ret = hx509_name_to_string(name, str); 908 hx509_name_free(&name); 909 return ret; 910 } 911 912 /** 913 * Unparse the hx509 name in name into a string. 914 * 915 * @param name the name to check if its empty/null. 916 * 917 * @return non zero if the name is empty/null. 918 * 919 * @ingroup hx509_name 920 */ 921 922 int 923 hx509_name_is_null_p(const hx509_name name) 924 { 925 return name->der_name.u.rdnSequence.len == 0; 926 } 927 928 /** 929 * Unparse the hx509 name in name into a string. 930 * 931 * @param name the name to print 932 * @param str an allocated string returns the name in string form 933 * 934 * @return An hx509 error code, see hx509_get_error_string(). 935 * 936 * @ingroup hx509_name 937 */ 938 939 int 940 hx509_general_name_unparse(GeneralName *name, char **str) 941 { 942 struct rk_strpool *strpool = NULL; 943 944 *str = NULL; 945 946 switch (name->element) { 947 case choice_GeneralName_otherName: { 948 char *oid; 949 hx509_oid_sprint(&name->u.otherName.type_id, &oid); 950 if (oid == NULL) 951 return ENOMEM; 952 strpool = rk_strpoolprintf(strpool, "otherName: %s", oid); 953 free(oid); 954 break; 955 } 956 case choice_GeneralName_rfc822Name: 957 strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s\n", 958 (int)name->u.rfc822Name.length, 959 (char *)name->u.rfc822Name.data); 960 break; 961 case choice_GeneralName_dNSName: 962 strpool = rk_strpoolprintf(strpool, "dNSName: %.*s\n", 963 (int)name->u.dNSName.length, 964 (char *)name->u.dNSName.data); 965 break; 966 case choice_GeneralName_directoryName: { 967 Name dir; 968 char *s; 969 int ret; 970 memset(&dir, 0, sizeof(dir)); 971 dir.element = name->u.directoryName.element; 972 dir.u.rdnSequence = name->u.directoryName.u.rdnSequence; 973 ret = _hx509_unparse_Name(&dir, &s); 974 if (ret) 975 return ret; 976 strpool = rk_strpoolprintf(strpool, "directoryName: %s", s); 977 free(s); 978 break; 979 } 980 case choice_GeneralName_uniformResourceIdentifier: 981 strpool = rk_strpoolprintf(strpool, "URI: %.*s", 982 (int)name->u.uniformResourceIdentifier.length, 983 (char *)name->u.uniformResourceIdentifier.data); 984 break; 985 case choice_GeneralName_iPAddress: { 986 unsigned char *a = name->u.iPAddress.data; 987 988 strpool = rk_strpoolprintf(strpool, "IPAddress: "); 989 if (strpool == NULL) 990 break; 991 if (name->u.iPAddress.length == 4) 992 strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d", 993 a[0], a[1], a[2], a[3]); 994 else if (name->u.iPAddress.length == 16) 995 strpool = rk_strpoolprintf(strpool, 996 "%02X:%02X:%02X:%02X:" 997 "%02X:%02X:%02X:%02X:" 998 "%02X:%02X:%02X:%02X:" 999 "%02X:%02X:%02X:%02X", 1000 a[0], a[1], a[2], a[3], 1001 a[4], a[5], a[6], a[7], 1002 a[8], a[9], a[10], a[11], 1003 a[12], a[13], a[14], a[15]); 1004 else 1005 strpool = rk_strpoolprintf(strpool, 1006 "unknown IP address of length %lu", 1007 (unsigned long)name->u.iPAddress.length); 1008 break; 1009 } 1010 case choice_GeneralName_registeredID: { 1011 char *oid; 1012 hx509_oid_sprint(&name->u.registeredID, &oid); 1013 if (oid == NULL) 1014 return ENOMEM; 1015 strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid); 1016 free(oid); 1017 break; 1018 } 1019 default: 1020 return EINVAL; 1021 } 1022 if (strpool == NULL) 1023 return ENOMEM; 1024 1025 *str = rk_strpoolcollect(strpool); 1026 1027 return 0; 1028 } 1029