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