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