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