root/source4/heimdal/lib/hx509/name.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. quote_string
  2. append_string
  3. oidtostring
  4. stringtooid
  5. hx509_name_to_string
  6. _hx509_Name_to_string
  7. dsstringprep
  8. _hx509_name_ds_cmp
  9. _hx509_name_cmp
  10. hx509_name_cmp
  11. _hx509_name_from_Name
  12. _hx509_name_modify
  13. hx509_parse_name
  14. hx509_name_copy
  15. hx509_name_to_Name
  16. hx509_name_normalize
  17. hx509_name_expand
  18. hx509_name_free
  19. hx509_unparse_der_name
  20. hx509_name_binary
  21. _hx509_unparse_Name
  22. hx509_name_is_null_p
  23. hx509_general_name_unparse

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

/* [<][>][^][v][top][bottom][index][help] */