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