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