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