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