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