1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2009 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35233294Sstas#include <wind.h>
36233294Sstas#include "char_map.h"
37178825Sdfr
38178825Sdfr/**
39178825Sdfr * @page page_name PKIX/X.509 Names
40178825Sdfr *
41178825Sdfr * There are several names in PKIX/X.509, GeneralName and Name.
42178825Sdfr *
43178825Sdfr * A Name consists of an ordered list of Relative Distinguished Names
44178825Sdfr * (RDN). Each RDN consists of an unordered list of typed strings. The
45178825Sdfr * types are defined by OID and have long and short description. For
46178825Sdfr * example id-at-commonName (2.5.4.3) have the long name CommonName
47233294Sstas * and short name CN. The string itself can be of several encoding,
48178825Sdfr * UTF8, UTF16, Teltex string, etc. The type limit what encoding
49178825Sdfr * should be used.
50178825Sdfr *
51178825Sdfr * GeneralName is a broader nametype that can contains al kind of
52178825Sdfr * stuff like Name, IP addresses, partial Name, etc.
53178825Sdfr *
54178825Sdfr * Name is mapped into a hx509_name object.
55178825Sdfr *
56178825Sdfr * Parse and string name into a hx509_name object with hx509_parse_name(),
57178825Sdfr * make it back into string representation with hx509_name_to_string().
58178825Sdfr *
59178825Sdfr * Name string are defined rfc2253, rfc1779 and X.501.
60178825Sdfr *
61178825Sdfr * See the library functions here: @ref hx509_name
62178825Sdfr */
63178825Sdfr
64178825Sdfrstatic const struct {
65178825Sdfr    const char *n;
66233294Sstas    const heim_oid *o;
67233294Sstas    wind_profile_flags flags;
68178825Sdfr} no[] = {
69233294Sstas    { "C", &asn1_oid_id_at_countryName, 0 },
70233294Sstas    { "CN", &asn1_oid_id_at_commonName, 0 },
71233294Sstas    { "DC", &asn1_oid_id_domainComponent, 0 },
72233294Sstas    { "L", &asn1_oid_id_at_localityName, 0 },
73233294Sstas    { "O", &asn1_oid_id_at_organizationName, 0 },
74233294Sstas    { "OU", &asn1_oid_id_at_organizationalUnitName, 0 },
75233294Sstas    { "S", &asn1_oid_id_at_stateOrProvinceName, 0 },
76233294Sstas    { "STREET", &asn1_oid_id_at_streetAddress, 0 },
77233294Sstas    { "UID", &asn1_oid_id_Userid, 0 },
78233294Sstas    { "emailAddress", &asn1_oid_id_pkcs9_emailAddress, 0 },
79233294Sstas    { "serialNumber", &asn1_oid_id_at_serialNumber, 0 }
80178825Sdfr};
81178825Sdfr
82178825Sdfrstatic char *
83233294Sstasquote_string(const char *f, size_t len, int flags, size_t *rlen)
84178825Sdfr{
85178825Sdfr    size_t i, j, tolen;
86233294Sstas    const unsigned char *from = (const unsigned char *)f;
87233294Sstas    unsigned char *to;
88178825Sdfr
89178825Sdfr    tolen = len * 3 + 1;
90178825Sdfr    to = malloc(tolen);
91178825Sdfr    if (to == NULL)
92178825Sdfr	return NULL;
93178825Sdfr
94178825Sdfr    for (i = 0, j = 0; i < len; i++) {
95233294Sstas	unsigned char map = char_map[from[i]] & flags;
96233294Sstas	if (i == 0 && (map & Q_RFC2253_QUOTE_FIRST)) {
97233294Sstas	    to[j++] = '\\';
98178825Sdfr	    to[j++] = from[i];
99233294Sstas	} else if ((i + 1) == len && (map & Q_RFC2253_QUOTE_LAST)) {
100233294Sstas
101178825Sdfr	    to[j++] = '\\';
102178825Sdfr	    to[j++] = from[i];
103233294Sstas	} else if (map & Q_RFC2253_QUOTE) {
104233294Sstas	    to[j++] = '\\';
105178825Sdfr	    to[j++] = from[i];
106233294Sstas	} else if (map & Q_RFC2253_HEX) {
107233294Sstas	    int l = snprintf((char *)&to[j], tolen - j - 1,
108178825Sdfr			     "#%02x", (unsigned char)from[i]);
109178825Sdfr	    j += l;
110233294Sstas	} else {
111233294Sstas	    to[j++] = from[i];
112178825Sdfr	}
113178825Sdfr    }
114178825Sdfr    to[j] = '\0';
115178825Sdfr    assert(j < tolen);
116178825Sdfr    *rlen = j;
117233294Sstas    return (char *)to;
118178825Sdfr}
119178825Sdfr
120178825Sdfr
121178825Sdfrstatic int
122233294Sstasappend_string(char **str, size_t *total_len, const char *ss,
123178825Sdfr	      size_t len, int quote)
124178825Sdfr{
125178825Sdfr    char *s, *qs;
126178825Sdfr
127178825Sdfr    if (quote)
128233294Sstas	qs = quote_string(ss, len, Q_RFC2253, &len);
129178825Sdfr    else
130178825Sdfr	qs = rk_UNCONST(ss);
131178825Sdfr
132178825Sdfr    s = realloc(*str, len + *total_len + 1);
133178825Sdfr    if (s == NULL)
134178825Sdfr	_hx509_abort("allocation failure"); /* XXX */
135178825Sdfr    memcpy(s + *total_len, qs, len);
136178825Sdfr    if (qs != ss)
137178825Sdfr	free(qs);
138178825Sdfr    s[*total_len + len] = '\0';
139178825Sdfr    *str = s;
140178825Sdfr    *total_len += len;
141178825Sdfr    return 0;
142178825Sdfr}
143178825Sdfr
144178825Sdfrstatic char *
145178825Sdfroidtostring(const heim_oid *type)
146178825Sdfr{
147178825Sdfr    char *s;
148178825Sdfr    size_t i;
149233294Sstas
150178825Sdfr    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
151233294Sstas	if (der_heim_oid_cmp(no[i].o, type) == 0)
152178825Sdfr	    return strdup(no[i].n);
153178825Sdfr    }
154178825Sdfr    if (der_print_heim_oid(type, '.', &s) != 0)
155178825Sdfr	return NULL;
156178825Sdfr    return s;
157178825Sdfr}
158178825Sdfr
159178825Sdfrstatic int
160178825Sdfrstringtooid(const char *name, size_t len, heim_oid *oid)
161178825Sdfr{
162233294Sstas    int ret;
163233294Sstas    size_t i;
164178825Sdfr    char *s;
165233294Sstas
166178825Sdfr    memset(oid, 0, sizeof(*oid));
167178825Sdfr
168178825Sdfr    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) {
169178825Sdfr	if (strncasecmp(no[i].n, name, len) == 0)
170233294Sstas	    return der_copy_oid(no[i].o, oid);
171178825Sdfr    }
172178825Sdfr    s = malloc(len + 1);
173178825Sdfr    if (s == NULL)
174178825Sdfr	return ENOMEM;
175178825Sdfr    memcpy(s, name, len);
176178825Sdfr    s[len] = '\0';
177178825Sdfr    ret = der_parse_heim_oid(s, ".", oid);
178178825Sdfr    free(s);
179178825Sdfr    return ret;
180178825Sdfr}
181178825Sdfr
182178825Sdfr/**
183178825Sdfr * Convert the hx509 name object into a printable string.
184178825Sdfr * The resulting string should be freed with free().
185178825Sdfr *
186178825Sdfr * @param name name to print
187178825Sdfr * @param str the string to return
188178825Sdfr *
189178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
190178825Sdfr *
191178825Sdfr * @ingroup hx509_name
192178825Sdfr */
193178825Sdfr
194178825Sdfrint
195178825Sdfrhx509_name_to_string(const hx509_name name, char **str)
196178825Sdfr{
197178825Sdfr    return _hx509_Name_to_string(&name->der_name, str);
198178825Sdfr}
199178825Sdfr
200178825Sdfrint
201178825Sdfr_hx509_Name_to_string(const Name *n, char **str)
202178825Sdfr{
203178825Sdfr    size_t total_len = 0;
204233294Sstas    size_t i, j, m;
205233294Sstas    int ret;
206178825Sdfr
207178825Sdfr    *str = strdup("");
208178825Sdfr    if (*str == NULL)
209178825Sdfr	return ENOMEM;
210178825Sdfr
211233294Sstas    for (m = n->u.rdnSequence.len; m > 0; m--) {
212233294Sstas	size_t len;
213233294Sstas	i = m - 1;
214178825Sdfr
215178825Sdfr	for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
216178825Sdfr	    DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
217178825Sdfr	    char *oidname;
218178825Sdfr	    char *ss;
219233294Sstas
220178825Sdfr	    oidname = oidtostring(&n->u.rdnSequence.val[i].val[j].type);
221178825Sdfr
222178825Sdfr	    switch(ds->element) {
223178825Sdfr	    case choice_DirectoryString_ia5String:
224233294Sstas		ss = ds->u.ia5String.data;
225233294Sstas		len = ds->u.ia5String.length;
226178825Sdfr		break;
227178825Sdfr	    case choice_DirectoryString_printableString:
228233294Sstas		ss = ds->u.printableString.data;
229233294Sstas		len = ds->u.printableString.length;
230178825Sdfr		break;
231178825Sdfr	    case choice_DirectoryString_utf8String:
232178825Sdfr		ss = ds->u.utf8String;
233233294Sstas		len = strlen(ss);
234178825Sdfr		break;
235178825Sdfr	    case choice_DirectoryString_bmpString: {
236233294Sstas	        const uint16_t *bmp = ds->u.bmpString.data;
237178825Sdfr		size_t bmplen = ds->u.bmpString.length;
238178825Sdfr		size_t k;
239178825Sdfr
240233294Sstas		ret = wind_ucs2utf8_length(bmp, bmplen, &k);
241233294Sstas		if (ret)
242233294Sstas		    return ret;
243233294Sstas
244233294Sstas		ss = malloc(k + 1);
245178825Sdfr		if (ss == NULL)
246178825Sdfr		    _hx509_abort("allocation failure"); /* XXX */
247233294Sstas		ret = wind_ucs2utf8(bmp, bmplen, ss, NULL);
248233294Sstas		if (ret) {
249233294Sstas		    free(ss);
250233294Sstas		    return ret;
251233294Sstas		}
252178825Sdfr		ss[k] = '\0';
253233294Sstas		len = k;
254178825Sdfr		break;
255178825Sdfr	    }
256178825Sdfr	    case choice_DirectoryString_teletexString:
257233294Sstas		ss = ds->u.teletexString;
258233294Sstas		len = strlen(ss);
259178825Sdfr		break;
260178825Sdfr	    case choice_DirectoryString_universalString: {
261233294Sstas	        const uint32_t *uni = ds->u.universalString.data;
262178825Sdfr		size_t unilen = ds->u.universalString.length;
263178825Sdfr		size_t k;
264178825Sdfr
265233294Sstas		ret = wind_ucs4utf8_length(uni, unilen, &k);
266233294Sstas		if (ret)
267233294Sstas		    return ret;
268233294Sstas
269233294Sstas		ss = malloc(k + 1);
270178825Sdfr		if (ss == NULL)
271178825Sdfr		    _hx509_abort("allocation failure"); /* XXX */
272233294Sstas		ret = wind_ucs4utf8(uni, unilen, ss, NULL);
273233294Sstas		if (ret) {
274233294Sstas		    free(ss);
275233294Sstas		    return ret;
276233294Sstas		}
277178825Sdfr		ss[k] = '\0';
278233294Sstas		len = k;
279178825Sdfr		break;
280178825Sdfr	    }
281178825Sdfr	    default:
282178825Sdfr		_hx509_abort("unknown directory type: %d", ds->element);
283178825Sdfr		exit(1);
284178825Sdfr	    }
285178825Sdfr	    append_string(str, &total_len, oidname, strlen(oidname), 0);
286178825Sdfr	    free(oidname);
287178825Sdfr	    append_string(str, &total_len, "=", 1, 0);
288178825Sdfr	    append_string(str, &total_len, ss, len, 1);
289233294Sstas	    if (ds->element == choice_DirectoryString_bmpString ||
290233294Sstas		ds->element == choice_DirectoryString_universalString)
291178825Sdfr	    {
292178825Sdfr		free(ss);
293178825Sdfr	    }
294178825Sdfr	    if (j + 1 < n->u.rdnSequence.val[i].len)
295178825Sdfr		append_string(str, &total_len, "+", 1, 0);
296178825Sdfr	}
297178825Sdfr
298178825Sdfr	if (i > 0)
299178825Sdfr	    append_string(str, &total_len, ",", 1, 0);
300178825Sdfr    }
301178825Sdfr    return 0;
302178825Sdfr}
303178825Sdfr
304233294Sstas#define COPYCHARARRAY(_ds,_el,_l,_n)		\
305233294Sstas        (_l) = strlen(_ds->u._el);		\
306233294Sstas	(_n) = malloc((_l) * sizeof((_n)[0]));	\
307233294Sstas	if ((_n) == NULL)			\
308233294Sstas	    return ENOMEM;			\
309233294Sstas	for (i = 0; i < (_l); i++)		\
310233294Sstas	    (_n)[i] = _ds->u._el[i]
311178825Sdfr
312178825Sdfr
313233294Sstas#define COPYVALARRAY(_ds,_el,_l,_n)		\
314233294Sstas        (_l) = _ds->u._el.length;		\
315233294Sstas	(_n) = malloc((_l) * sizeof((_n)[0]));	\
316233294Sstas	if ((_n) == NULL)			\
317233294Sstas	    return ENOMEM;			\
318233294Sstas	for (i = 0; i < (_l); i++)		\
319233294Sstas	    (_n)[i] = _ds->u._el.data[i]
320233294Sstas
321233294Sstas#define COPYVOIDARRAY(_ds,_el,_l,_n)		\
322233294Sstas        (_l) = _ds->u._el.length;		\
323233294Sstas	(_n) = malloc((_l) * sizeof((_n)[0]));	\
324233294Sstas	if ((_n) == NULL)			\
325233294Sstas	    return ENOMEM;			\
326233294Sstas	for (i = 0; i < (_l); i++)		\
327233294Sstas	    (_n)[i] = ((unsigned char *)_ds->u._el.data)[i]
328233294Sstas
329233294Sstas
330233294Sstas
331233294Sstasstatic int
332233294Sstasdsstringprep(const DirectoryString *ds, uint32_t **rname, size_t *rlen)
333178825Sdfr{
334233294Sstas    wind_profile_flags flags;
335233294Sstas    size_t i, len;
336233294Sstas    int ret;
337233294Sstas    uint32_t *name;
338178825Sdfr
339233294Sstas    *rname = NULL;
340233294Sstas    *rlen = 0;
341178825Sdfr
342233294Sstas    switch(ds->element) {
343178825Sdfr    case choice_DirectoryString_ia5String:
344233294Sstas	flags = WIND_PROFILE_LDAP;
345233294Sstas	COPYVOIDARRAY(ds, ia5String, len, name);
346178825Sdfr	break;
347233294Sstas    case choice_DirectoryString_printableString:
348233294Sstas	flags = WIND_PROFILE_LDAP;
349233294Sstas	flags |= WIND_PROFILE_LDAP_CASE_EXACT_ATTRIBUTE;
350233294Sstas	COPYVOIDARRAY(ds, printableString, len, name);
351233294Sstas	break;
352178825Sdfr    case choice_DirectoryString_teletexString:
353233294Sstas	flags = WIND_PROFILE_LDAP_CASE;
354233294Sstas	COPYCHARARRAY(ds, teletexString, len, name);
355178825Sdfr	break;
356233294Sstas    case choice_DirectoryString_bmpString:
357233294Sstas	flags = WIND_PROFILE_LDAP;
358233294Sstas	COPYVALARRAY(ds, bmpString, len, name);
359178825Sdfr	break;
360178825Sdfr    case choice_DirectoryString_universalString:
361233294Sstas	flags = WIND_PROFILE_LDAP;
362233294Sstas	COPYVALARRAY(ds, universalString, len, name);
363178825Sdfr	break;
364233294Sstas    case choice_DirectoryString_utf8String:
365233294Sstas	flags = WIND_PROFILE_LDAP;
366233294Sstas	ret = wind_utf8ucs4_length(ds->u.utf8String, &len);
367233294Sstas	if (ret)
368233294Sstas	    return ret;
369233294Sstas	name = malloc(len * sizeof(name[0]));
370233294Sstas	if (name == NULL)
371233294Sstas	    return ENOMEM;
372233294Sstas	ret = wind_utf8ucs4(ds->u.utf8String, name, &len);
373233294Sstas	if (ret) {
374233294Sstas	    free(name);
375233294Sstas	    return ret;
376233294Sstas	}
377178825Sdfr	break;
378178825Sdfr    default:
379233294Sstas	_hx509_abort("unknown directory type: %d", ds->element);
380178825Sdfr    }
381233294Sstas
382233294Sstas    *rlen = len;
383233294Sstas    /* try a couple of times to get the length right, XXX gross */
384233294Sstas    for (i = 0; i < 4; i++) {
385233294Sstas	*rlen = *rlen * 2;
386233294Sstas	*rname = malloc(*rlen * sizeof((*rname)[0]));
387233294Sstas
388233294Sstas	ret = wind_stringprep(name, len, *rname, rlen, flags);
389233294Sstas	if (ret == WIND_ERR_OVERRUN) {
390233294Sstas	    free(*rname);
391233294Sstas	    *rname = NULL;
392233294Sstas	    continue;
393233294Sstas	} else
394233294Sstas	    break;
395233294Sstas    }
396233294Sstas    free(name);
397233294Sstas    if (ret) {
398233294Sstas	if (*rname)
399233294Sstas	    free(*rname);
400233294Sstas	*rname = NULL;
401233294Sstas	*rlen = 0;
402233294Sstas	return ret;
403233294Sstas    }
404233294Sstas
405233294Sstas    return 0;
406178825Sdfr}
407178825Sdfr
408178825Sdfrint
409233294Sstas_hx509_name_ds_cmp(const DirectoryString *ds1,
410233294Sstas		   const DirectoryString *ds2,
411233294Sstas		   int *diff)
412178825Sdfr{
413233294Sstas    uint32_t *ds1lp, *ds2lp;
414233294Sstas    size_t ds1len, ds2len, i;
415233294Sstas    int ret;
416178825Sdfr
417233294Sstas    ret = dsstringprep(ds1, &ds1lp, &ds1len);
418233294Sstas    if (ret)
419233294Sstas	return ret;
420233294Sstas    ret = dsstringprep(ds2, &ds2lp, &ds2len);
421233294Sstas    if (ret) {
422233294Sstas	free(ds1lp);
423233294Sstas	return ret;
424233294Sstas    }
425178825Sdfr
426233294Sstas    if (ds1len != ds2len)
427233294Sstas	*diff = ds1len - ds2len;
428233294Sstas    else {
429233294Sstas	for (i = 0; i < ds1len; i++) {
430233294Sstas	    *diff = ds1lp[i] - ds2lp[i];
431233294Sstas	    if (*diff)
432233294Sstas		break;
433233294Sstas	}
434233294Sstas    }
435233294Sstas    free(ds1lp);
436233294Sstas    free(ds2lp);
437233294Sstas
438233294Sstas    return 0;
439233294Sstas}
440233294Sstas
441233294Sstasint
442233294Sstas_hx509_name_cmp(const Name *n1, const Name *n2, int *c)
443233294Sstas{
444233294Sstas    int ret;
445233294Sstas    size_t i, j;
446233294Sstas
447233294Sstas    *c = n1->u.rdnSequence.len - n2->u.rdnSequence.len;
448233294Sstas    if (*c)
449233294Sstas	return 0;
450233294Sstas
451178825Sdfr    for (i = 0 ; i < n1->u.rdnSequence.len; i++) {
452233294Sstas	*c = n1->u.rdnSequence.val[i].len - n2->u.rdnSequence.val[i].len;
453233294Sstas	if (*c)
454233294Sstas	    return 0;
455178825Sdfr
456178825Sdfr	for (j = 0; j < n1->u.rdnSequence.val[i].len; j++) {
457233294Sstas	    *c = der_heim_oid_cmp(&n1->u.rdnSequence.val[i].val[j].type,
458233294Sstas				  &n1->u.rdnSequence.val[i].val[j].type);
459233294Sstas	    if (*c)
460233294Sstas		return 0;
461233294Sstas
462233294Sstas	    ret = _hx509_name_ds_cmp(&n1->u.rdnSequence.val[i].val[j].value,
463233294Sstas				     &n2->u.rdnSequence.val[i].val[j].value,
464233294Sstas				     c);
465233294Sstas	    if (ret)
466233294Sstas		return ret;
467233294Sstas	    if (*c)
468233294Sstas		return 0;
469178825Sdfr	}
470178825Sdfr    }
471233294Sstas    *c = 0;
472178825Sdfr    return 0;
473178825Sdfr}
474178825Sdfr
475178825Sdfr/**
476178825Sdfr * Compare to hx509 name object, useful for sorting.
477178825Sdfr *
478178825Sdfr * @param n1 a hx509 name object.
479178825Sdfr * @param n2 a hx509 name object.
480178825Sdfr *
481178825Sdfr * @return 0 the objects are the same, returns > 0 is n2 is "larger"
482178825Sdfr * then n2, < 0 if n1 is "smaller" then n2.
483178825Sdfr *
484178825Sdfr * @ingroup hx509_name
485178825Sdfr */
486178825Sdfr
487178825Sdfrint
488178825Sdfrhx509_name_cmp(hx509_name n1, hx509_name n2)
489178825Sdfr{
490233294Sstas    int ret, diff;
491233294Sstas    ret = _hx509_name_cmp(&n1->der_name, &n2->der_name, &diff);
492233294Sstas    if (ret)
493233294Sstas	return ret;
494233294Sstas    return diff;
495178825Sdfr}
496178825Sdfr
497178825Sdfr
498178825Sdfrint
499178825Sdfr_hx509_name_from_Name(const Name *n, hx509_name *name)
500178825Sdfr{
501178825Sdfr    int ret;
502178825Sdfr    *name = calloc(1, sizeof(**name));
503178825Sdfr    if (*name == NULL)
504178825Sdfr	return ENOMEM;
505178825Sdfr    ret = copy_Name(n, &(*name)->der_name);
506178825Sdfr    if (ret) {
507178825Sdfr	free(*name);
508178825Sdfr	*name = NULL;
509178825Sdfr    }
510178825Sdfr    return ret;
511178825Sdfr}
512178825Sdfr
513178825Sdfrint
514178825Sdfr_hx509_name_modify(hx509_context context,
515233294Sstas		   Name *name,
516178825Sdfr		   int append,
517233294Sstas		   const heim_oid *oid,
518178825Sdfr		   const char *str)
519178825Sdfr{
520178825Sdfr    RelativeDistinguishedName *rdn;
521178825Sdfr    int ret;
522178825Sdfr    void *ptr;
523178825Sdfr
524233294Sstas    ptr = realloc(name->u.rdnSequence.val,
525233294Sstas		  sizeof(name->u.rdnSequence.val[0]) *
526178825Sdfr		  (name->u.rdnSequence.len + 1));
527178825Sdfr    if (ptr == NULL) {
528178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
529178825Sdfr	return ENOMEM;
530178825Sdfr    }
531178825Sdfr    name->u.rdnSequence.val = ptr;
532178825Sdfr
533178825Sdfr    if (append) {
534178825Sdfr	rdn = &name->u.rdnSequence.val[name->u.rdnSequence.len];
535178825Sdfr    } else {
536178825Sdfr	memmove(&name->u.rdnSequence.val[1],
537178825Sdfr		&name->u.rdnSequence.val[0],
538233294Sstas		name->u.rdnSequence.len *
539178825Sdfr		sizeof(name->u.rdnSequence.val[0]));
540233294Sstas
541178825Sdfr	rdn = &name->u.rdnSequence.val[0];
542178825Sdfr    }
543178825Sdfr    rdn->val = malloc(sizeof(rdn->val[0]));
544178825Sdfr    if (rdn->val == NULL)
545178825Sdfr	return ENOMEM;
546178825Sdfr    rdn->len = 1;
547178825Sdfr    ret = der_copy_oid(oid, &rdn->val[0].type);
548178825Sdfr    if (ret)
549178825Sdfr	return ret;
550178825Sdfr    rdn->val[0].value.element = choice_DirectoryString_utf8String;
551178825Sdfr    rdn->val[0].value.u.utf8String = strdup(str);
552178825Sdfr    if (rdn->val[0].value.u.utf8String == NULL)
553178825Sdfr	return ENOMEM;
554178825Sdfr    name->u.rdnSequence.len += 1;
555178825Sdfr
556178825Sdfr    return 0;
557178825Sdfr}
558178825Sdfr
559178825Sdfr/**
560178825Sdfr * Parse a string into a hx509 name object.
561178825Sdfr *
562178825Sdfr * @param context A hx509 context.
563178825Sdfr * @param str a string to parse.
564178825Sdfr * @param name the resulting object, NULL in case of error.
565178825Sdfr *
566178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
567178825Sdfr *
568178825Sdfr * @ingroup hx509_name
569178825Sdfr */
570178825Sdfr
571178825Sdfrint
572178825Sdfrhx509_parse_name(hx509_context context, const char *str, hx509_name *name)
573178825Sdfr{
574178825Sdfr    const char *p, *q;
575178825Sdfr    size_t len;
576178825Sdfr    hx509_name n;
577178825Sdfr    int ret;
578178825Sdfr
579178825Sdfr    *name = NULL;
580178825Sdfr
581178825Sdfr    n = calloc(1, sizeof(*n));
582178825Sdfr    if (n == NULL) {
583178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
584178825Sdfr	return ENOMEM;
585178825Sdfr    }
586178825Sdfr
587178825Sdfr    n->der_name.element = choice_Name_rdnSequence;
588178825Sdfr
589178825Sdfr    p = str;
590178825Sdfr
591178825Sdfr    while (p != NULL && *p != '\0') {
592178825Sdfr	heim_oid oid;
593178825Sdfr	int last;
594178825Sdfr
595178825Sdfr	q = strchr(p, ',');
596178825Sdfr	if (q) {
597178825Sdfr	    len = (q - p);
598178825Sdfr	    last = 1;
599178825Sdfr	} else {
600178825Sdfr	    len = strlen(p);
601178825Sdfr	    last = 0;
602178825Sdfr	}
603178825Sdfr
604178825Sdfr	q = strchr(p, '=');
605178825Sdfr	if (q == NULL) {
606178825Sdfr	    ret = HX509_PARSING_NAME_FAILED;
607178825Sdfr	    hx509_set_error_string(context, 0, ret, "missing = in %s", p);
608178825Sdfr	    goto out;
609178825Sdfr	}
610178825Sdfr	if (q == p) {
611178825Sdfr	    ret = HX509_PARSING_NAME_FAILED;
612233294Sstas	    hx509_set_error_string(context, 0, ret,
613178825Sdfr				   "missing name before = in %s", p);
614178825Sdfr	    goto out;
615178825Sdfr	}
616233294Sstas
617233294Sstas	if ((size_t)(q - p) > len) {
618178825Sdfr	    ret = HX509_PARSING_NAME_FAILED;
619178825Sdfr	    hx509_set_error_string(context, 0, ret, " = after , in %s", p);
620178825Sdfr	    goto out;
621178825Sdfr	}
622178825Sdfr
623178825Sdfr	ret = stringtooid(p, q - p, &oid);
624178825Sdfr	if (ret) {
625178825Sdfr	    ret = HX509_PARSING_NAME_FAILED;
626233294Sstas	    hx509_set_error_string(context, 0, ret,
627178825Sdfr				   "unknown type: %.*s", (int)(q - p), p);
628178825Sdfr	    goto out;
629178825Sdfr	}
630233294Sstas
631178825Sdfr	{
632178825Sdfr	    size_t pstr_len = len - (q - p) - 1;
633178825Sdfr	    const char *pstr = p + (q - p) + 1;
634178825Sdfr	    char *r;
635233294Sstas
636178825Sdfr	    r = malloc(pstr_len + 1);
637178825Sdfr	    if (r == NULL) {
638178825Sdfr		der_free_oid(&oid);
639178825Sdfr		ret = ENOMEM;
640178825Sdfr		hx509_set_error_string(context, 0, ret, "out of memory");
641178825Sdfr		goto out;
642178825Sdfr	    }
643178825Sdfr	    memcpy(r, pstr, pstr_len);
644178825Sdfr	    r[pstr_len] = '\0';
645178825Sdfr
646178825Sdfr	    ret = _hx509_name_modify(context, &n->der_name, 0, &oid, r);
647178825Sdfr	    free(r);
648178825Sdfr	    der_free_oid(&oid);
649178825Sdfr	    if(ret)
650178825Sdfr		goto out;
651178825Sdfr	}
652178825Sdfr	p += len + last;
653178825Sdfr    }
654178825Sdfr
655178825Sdfr    *name = n;
656178825Sdfr
657178825Sdfr    return 0;
658178825Sdfrout:
659178825Sdfr    hx509_name_free(&n);
660178825Sdfr    return HX509_NAME_MALFORMED;
661178825Sdfr}
662178825Sdfr
663178825Sdfr/**
664178825Sdfr * Copy a hx509 name object.
665178825Sdfr *
666178825Sdfr * @param context A hx509 cotext.
667178825Sdfr * @param from the name to copy from
668178825Sdfr * @param to the name to copy to
669178825Sdfr *
670178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
671178825Sdfr *
672178825Sdfr * @ingroup hx509_name
673178825Sdfr */
674178825Sdfr
675178825Sdfrint
676178825Sdfrhx509_name_copy(hx509_context context, const hx509_name from, hx509_name *to)
677178825Sdfr{
678178825Sdfr    int ret;
679178825Sdfr
680178825Sdfr    *to = calloc(1, sizeof(**to));
681178825Sdfr    if (*to == NULL)
682178825Sdfr	return ENOMEM;
683178825Sdfr    ret = copy_Name(&from->der_name, &(*to)->der_name);
684178825Sdfr    if (ret) {
685178825Sdfr	free(*to);
686178825Sdfr	*to = NULL;
687178825Sdfr	return ENOMEM;
688178825Sdfr    }
689178825Sdfr    return 0;
690178825Sdfr}
691178825Sdfr
692178825Sdfr/**
693178825Sdfr * Convert a hx509_name into a Name.
694178825Sdfr *
695178825Sdfr * @param from the name to copy from
696178825Sdfr * @param to the name to copy to
697178825Sdfr *
698178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
699178825Sdfr *
700178825Sdfr * @ingroup hx509_name
701178825Sdfr */
702178825Sdfr
703178825Sdfrint
704178825Sdfrhx509_name_to_Name(const hx509_name from, Name *to)
705178825Sdfr{
706178825Sdfr    return copy_Name(&from->der_name, to);
707178825Sdfr}
708178825Sdfr
709178825Sdfrint
710178825Sdfrhx509_name_normalize(hx509_context context, hx509_name name)
711178825Sdfr{
712178825Sdfr    return 0;
713178825Sdfr}
714178825Sdfr
715178825Sdfr/**
716178825Sdfr * Expands variables in the name using env. Variables are on the form
717178825Sdfr * ${name}. Useful when dealing with certificate templates.
718178825Sdfr *
719178825Sdfr * @param context A hx509 cotext.
720178825Sdfr * @param name the name to expand.
721178825Sdfr * @param env environment variable to expand.
722178825Sdfr *
723178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
724178825Sdfr *
725178825Sdfr * @ingroup hx509_name
726178825Sdfr */
727178825Sdfr
728178825Sdfrint
729178825Sdfrhx509_name_expand(hx509_context context,
730178825Sdfr		  hx509_name name,
731178825Sdfr		  hx509_env env)
732178825Sdfr{
733178825Sdfr    Name *n = &name->der_name;
734233294Sstas    size_t i, j;
735178825Sdfr
736178825Sdfr    if (env == NULL)
737178825Sdfr	return 0;
738178825Sdfr
739178825Sdfr    if (n->element != choice_Name_rdnSequence) {
740178825Sdfr	hx509_set_error_string(context, 0, EINVAL, "RDN not of supported type");
741178825Sdfr	return EINVAL;
742178825Sdfr    }
743178825Sdfr
744178825Sdfr    for (i = 0 ; i < n->u.rdnSequence.len; i++) {
745178825Sdfr	for (j = 0; j < n->u.rdnSequence.val[i].len; j++) {
746178825Sdfr	    /** Only UTF8String rdnSequence names are allowed */
747178825Sdfr	    /*
748178825Sdfr	      THIS SHOULD REALLY BE:
749178825Sdfr	      COMP = n->u.rdnSequence.val[i].val[j];
750178825Sdfr	      normalize COMP to utf8
751178825Sdfr	      check if there are variables
752178825Sdfr	        expand variables
753178825Sdfr	        convert back to orignal format, store in COMP
754178825Sdfr	      free normalized utf8 string
755178825Sdfr	    */
756178825Sdfr	    DirectoryString *ds = &n->u.rdnSequence.val[i].val[j].value;
757178825Sdfr	    char *p, *p2;
758178825Sdfr	    struct rk_strpool *strpool = NULL;
759178825Sdfr
760178825Sdfr	    if (ds->element != choice_DirectoryString_utf8String) {
761178825Sdfr		hx509_set_error_string(context, 0, EINVAL, "unsupported type");
762178825Sdfr		return EINVAL;
763178825Sdfr	    }
764178825Sdfr	    p = strstr(ds->u.utf8String, "${");
765178825Sdfr	    if (p) {
766233294Sstas		strpool = rk_strpoolprintf(strpool, "%.*s",
767233294Sstas					   (int)(p - ds->u.utf8String),
768178825Sdfr					   ds->u.utf8String);
769178825Sdfr		if (strpool == NULL) {
770178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
771178825Sdfr		    return ENOMEM;
772178825Sdfr		}
773178825Sdfr	    }
774178825Sdfr	    while (p != NULL) {
775178825Sdfr		/* expand variables */
776178825Sdfr		const char *value;
777178825Sdfr		p2 = strchr(p, '}');
778178825Sdfr		if (p2 == NULL) {
779178825Sdfr		    hx509_set_error_string(context, 0, EINVAL, "missing }");
780178825Sdfr		    rk_strpoolfree(strpool);
781178825Sdfr		    return EINVAL;
782178825Sdfr		}
783178825Sdfr		p += 2;
784178825Sdfr		value = hx509_env_lfind(context, env, p, p2 - p);
785178825Sdfr		if (value == NULL) {
786233294Sstas		    hx509_set_error_string(context, 0, EINVAL,
787178825Sdfr					   "variable %.*s missing",
788178825Sdfr					   (int)(p2 - p), p);
789178825Sdfr		    rk_strpoolfree(strpool);
790178825Sdfr		    return EINVAL;
791178825Sdfr		}
792178825Sdfr		strpool = rk_strpoolprintf(strpool, "%s", value);
793178825Sdfr		if (strpool == NULL) {
794178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
795178825Sdfr		    return ENOMEM;
796178825Sdfr		}
797178825Sdfr		p2++;
798178825Sdfr
799178825Sdfr		p = strstr(p2, "${");
800178825Sdfr		if (p)
801233294Sstas		    strpool = rk_strpoolprintf(strpool, "%.*s",
802178825Sdfr					       (int)(p - p2), p2);
803178825Sdfr		else
804178825Sdfr		    strpool = rk_strpoolprintf(strpool, "%s", p2);
805178825Sdfr		if (strpool == NULL) {
806178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
807178825Sdfr		    return ENOMEM;
808178825Sdfr		}
809178825Sdfr	    }
810178825Sdfr	    if (strpool) {
811178825Sdfr		free(ds->u.utf8String);
812178825Sdfr		ds->u.utf8String = rk_strpoolcollect(strpool);
813178825Sdfr		if (ds->u.utf8String == NULL) {
814178825Sdfr		    hx509_set_error_string(context, 0, ENOMEM, "out of memory");
815178825Sdfr		    return ENOMEM;
816178825Sdfr		}
817178825Sdfr	    }
818178825Sdfr	}
819178825Sdfr    }
820178825Sdfr    return 0;
821178825Sdfr}
822178825Sdfr
823178825Sdfr/**
824178825Sdfr * Free a hx509 name object, upond return *name will be NULL.
825178825Sdfr *
826178825Sdfr * @param name a hx509 name object to be freed.
827178825Sdfr *
828178825Sdfr * @ingroup hx509_name
829178825Sdfr */
830178825Sdfr
831178825Sdfrvoid
832178825Sdfrhx509_name_free(hx509_name *name)
833178825Sdfr{
834178825Sdfr    free_Name(&(*name)->der_name);
835178825Sdfr    memset(*name, 0, sizeof(**name));
836178825Sdfr    free(*name);
837178825Sdfr    *name = NULL;
838178825Sdfr}
839178825Sdfr
840178825Sdfr/**
841178825Sdfr * Convert a DER encoded name info a string.
842178825Sdfr *
843178825Sdfr * @param data data to a DER/BER encoded name
844178825Sdfr * @param length length of data
845178825Sdfr * @param str the resulting string, is NULL on failure.
846178825Sdfr *
847178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
848178825Sdfr *
849178825Sdfr * @ingroup hx509_name
850178825Sdfr */
851178825Sdfr
852178825Sdfrint
853178825Sdfrhx509_unparse_der_name(const void *data, size_t length, char **str)
854178825Sdfr{
855178825Sdfr    Name name;
856178825Sdfr    int ret;
857178825Sdfr
858178825Sdfr    *str = NULL;
859178825Sdfr
860178825Sdfr    ret = decode_Name(data, length, &name, NULL);
861178825Sdfr    if (ret)
862178825Sdfr	return ret;
863178825Sdfr    ret = _hx509_Name_to_string(&name, str);
864178825Sdfr    free_Name(&name);
865178825Sdfr    return ret;
866178825Sdfr}
867178825Sdfr
868178825Sdfr/**
869178825Sdfr * Convert a hx509_name object to DER encoded name.
870178825Sdfr *
871178825Sdfr * @param name name to concert
872178825Sdfr * @param os data to a DER encoded name, free the resulting octet
873178825Sdfr * string with hx509_xfree(os->data).
874178825Sdfr *
875178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
876178825Sdfr *
877178825Sdfr * @ingroup hx509_name
878178825Sdfr */
879178825Sdfr
880178825Sdfrint
881178825Sdfrhx509_name_binary(const hx509_name name, heim_octet_string *os)
882178825Sdfr{
883178825Sdfr    size_t size;
884178825Sdfr    int ret;
885178825Sdfr
886178825Sdfr    ASN1_MALLOC_ENCODE(Name, os->data, os->length, &name->der_name, &size, ret);
887178825Sdfr    if (ret)
888178825Sdfr	return ret;
889178825Sdfr    if (os->length != size)
890178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
891178825Sdfr
892178825Sdfr    return 0;
893178825Sdfr}
894178825Sdfr
895178825Sdfrint
896178825Sdfr_hx509_unparse_Name(const Name *aname, char **str)
897178825Sdfr{
898178825Sdfr    hx509_name name;
899178825Sdfr    int ret;
900178825Sdfr
901178825Sdfr    ret = _hx509_name_from_Name(aname, &name);
902178825Sdfr    if (ret)
903178825Sdfr	return ret;
904178825Sdfr
905178825Sdfr    ret = hx509_name_to_string(name, str);
906178825Sdfr    hx509_name_free(&name);
907178825Sdfr    return ret;
908178825Sdfr}
909178825Sdfr
910178825Sdfr/**
911178825Sdfr * Unparse the hx509 name in name into a string.
912178825Sdfr *
913178825Sdfr * @param name the name to check if its empty/null.
914178825Sdfr *
915178825Sdfr * @return non zero if the name is empty/null.
916178825Sdfr *
917178825Sdfr * @ingroup hx509_name
918178825Sdfr */
919178825Sdfr
920178825Sdfrint
921178825Sdfrhx509_name_is_null_p(const hx509_name name)
922178825Sdfr{
923178825Sdfr    return name->der_name.u.rdnSequence.len == 0;
924178825Sdfr}
925178825Sdfr
926178825Sdfr/**
927178825Sdfr * Unparse the hx509 name in name into a string.
928178825Sdfr *
929178825Sdfr * @param name the name to print
930178825Sdfr * @param str an allocated string returns the name in string form
931178825Sdfr *
932233294Sstas * @return An hx509 error code, see hx509_get_error_string().
933178825Sdfr *
934178825Sdfr * @ingroup hx509_name
935178825Sdfr */
936178825Sdfr
937178825Sdfrint
938178825Sdfrhx509_general_name_unparse(GeneralName *name, char **str)
939178825Sdfr{
940178825Sdfr    struct rk_strpool *strpool = NULL;
941178825Sdfr
942178825Sdfr    *str = NULL;
943178825Sdfr
944178825Sdfr    switch (name->element) {
945178825Sdfr    case choice_GeneralName_otherName: {
946233294Sstas	char *oid;
947233294Sstas	hx509_oid_sprint(&name->u.otherName.type_id, &oid);
948233294Sstas	if (oid == NULL)
949178825Sdfr	    return ENOMEM;
950233294Sstas	strpool = rk_strpoolprintf(strpool, "otherName: %s", oid);
951233294Sstas	free(oid);
952178825Sdfr	break;
953178825Sdfr    }
954178825Sdfr    case choice_GeneralName_rfc822Name:
955233294Sstas	strpool = rk_strpoolprintf(strpool, "rfc822Name: %.*s\n",
956233294Sstas				   (int)name->u.rfc822Name.length,
957233294Sstas				   (char *)name->u.rfc822Name.data);
958178825Sdfr	break;
959178825Sdfr    case choice_GeneralName_dNSName:
960233294Sstas	strpool = rk_strpoolprintf(strpool, "dNSName: %.*s\n",
961233294Sstas				   (int)name->u.dNSName.length,
962233294Sstas				   (char *)name->u.dNSName.data);
963178825Sdfr	break;
964178825Sdfr    case choice_GeneralName_directoryName: {
965178825Sdfr	Name dir;
966178825Sdfr	char *s;
967178825Sdfr	int ret;
968178825Sdfr	memset(&dir, 0, sizeof(dir));
969178825Sdfr	dir.element = name->u.directoryName.element;
970178825Sdfr	dir.u.rdnSequence = name->u.directoryName.u.rdnSequence;
971178825Sdfr	ret = _hx509_unparse_Name(&dir, &s);
972178825Sdfr	if (ret)
973178825Sdfr	    return ret;
974178825Sdfr	strpool = rk_strpoolprintf(strpool, "directoryName: %s", s);
975178825Sdfr	free(s);
976178825Sdfr	break;
977178825Sdfr    }
978178825Sdfr    case choice_GeneralName_uniformResourceIdentifier:
979233294Sstas	strpool = rk_strpoolprintf(strpool, "URI: %.*s",
980233294Sstas				   (int)name->u.uniformResourceIdentifier.length,
981233294Sstas				   (char *)name->u.uniformResourceIdentifier.data);
982178825Sdfr	break;
983178825Sdfr    case choice_GeneralName_iPAddress: {
984178825Sdfr	unsigned char *a = name->u.iPAddress.data;
985178825Sdfr
986178825Sdfr	strpool = rk_strpoolprintf(strpool, "IPAddress: ");
987178825Sdfr	if (strpool == NULL)
988178825Sdfr	    break;
989178825Sdfr	if (name->u.iPAddress.length == 4)
990233294Sstas	    strpool = rk_strpoolprintf(strpool, "%d.%d.%d.%d",
991178825Sdfr				       a[0], a[1], a[2], a[3]);
992178825Sdfr	else if (name->u.iPAddress.length == 16)
993233294Sstas	    strpool = rk_strpoolprintf(strpool,
994178825Sdfr				       "%02X:%02X:%02X:%02X:"
995178825Sdfr				       "%02X:%02X:%02X:%02X:"
996178825Sdfr				       "%02X:%02X:%02X:%02X:"
997233294Sstas				       "%02X:%02X:%02X:%02X",
998178825Sdfr				       a[0], a[1], a[2], a[3],
999178825Sdfr				       a[4], a[5], a[6], a[7],
1000178825Sdfr				       a[8], a[9], a[10], a[11],
1001178825Sdfr				       a[12], a[13], a[14], a[15]);
1002178825Sdfr	else
1003233294Sstas	    strpool = rk_strpoolprintf(strpool,
1004178825Sdfr				       "unknown IP address of length %lu",
1005178825Sdfr				       (unsigned long)name->u.iPAddress.length);
1006178825Sdfr	break;
1007178825Sdfr    }
1008178825Sdfr    case choice_GeneralName_registeredID: {
1009233294Sstas	char *oid;
1010233294Sstas	hx509_oid_sprint(&name->u.registeredID, &oid);
1011233294Sstas	if (oid == NULL)
1012178825Sdfr	    return ENOMEM;
1013233294Sstas	strpool = rk_strpoolprintf(strpool, "registeredID: %s", oid);
1014233294Sstas	free(oid);
1015178825Sdfr	break;
1016178825Sdfr    }
1017178825Sdfr    default:
1018178825Sdfr	return EINVAL;
1019178825Sdfr    }
1020178825Sdfr    if (strpool == NULL)
1021178825Sdfr	return ENOMEM;
1022178825Sdfr
1023178825Sdfr    *str = rk_strpoolcollect(strpool);
1024178825Sdfr
1025178825Sdfr    return 0;
1026178825Sdfr}
1027