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