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