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