1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 *
33 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
35 *
36 * Copyright 2018, Joyent, Inc.
37 *
38 * File: rdn_parser.c
39 */
40
41 #include <strings.h>
42 #include <stdlib.h>
43 #include <kmfapi.h>
44 #include <kmfapiP.h>
45 #include <ber_der.h>
46 #include <rdn_parser.h>
47 #include <stdio.h>
48 #include <values.h>
49 #include <libcustr.h>
50
51 /*
52 * The order here is important. The OIDs are arranged in order of
53 * significance. The CN is the most specific value, the C (country)
54 * is less specific, etc. Add to this list with care.
55 */
56 static const struct NameToKind name2kinds[] = {
57 { "CN", OID_AVA_COMMON_NAME, (KMF_OID *)&KMFOID_CommonName},
58 { "SN", OID_AVA_SURNAME, (KMF_OID *)&KMFOID_Surname},
59 { "GN", OID_AVA_GIVEN_NAME, (KMF_OID *)&KMFOID_GivenName},
60 { "emailAddress", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
61 { "E", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
62 { "MAIL", OID_RFC1274_MAIL, (KMF_OID *)&KMFOID_RFC822mailbox},
63 { "STREET", OID_AVA_STREET_ADDRESS, (KMF_OID *)&KMFOID_StreetAddress},
64 { "UID", OID_RFC1274_UID, (KMF_OID *)&KMFOID_userid},
65 { "OU", OID_AVA_ORGANIZATIONAL_UNIT_NAME,
66 (KMF_OID *)&KMFOID_OrganizationalUnitName},
67 { "O", OID_AVA_ORGANIZATION_NAME, (KMF_OID *)&KMFOID_OrganizationName},
68 { "L", OID_AVA_LOCALITY, (KMF_OID *)&KMFOID_LocalityName},
69 { "ST", OID_AVA_STATE_OR_PROVINCE,
70 (KMF_OID *)&KMFOID_StateProvinceName},
71 { "C", OID_AVA_COUNTRY_NAME, (KMF_OID *)&KMFOID_CountryName},
72 { "DC", OID_AVA_DC, (KMF_OID *)&KMFOID_domainComponent},
73 { 0, OID_UNKNOWN, NULL}
74 };
75
76 static KMF_BOOL
IsPrintable(unsigned char * data,unsigned len)77 IsPrintable(unsigned char *data, unsigned len)
78 {
79 unsigned char ch, *end;
80
81 end = data + len;
82 while (data < end) {
83 ch = *data++;
84 if (!IS_PRINTABLE(ch)) {
85 return (B_FALSE);
86 }
87 }
88 return (B_TRUE);
89 }
90
91 static KMF_BOOL
Is7Bit(unsigned char * data,unsigned len)92 Is7Bit(unsigned char *data, unsigned len)
93 {
94 unsigned char ch, *end;
95
96 end = data + len;
97 while (data < end) {
98 ch = *data++;
99 if ((ch & 0x80)) {
100 return (B_FALSE);
101 }
102 }
103 return (B_TRUE);
104 }
105
106 static void
skipSpace(char ** pbp,char * endptr)107 skipSpace(char **pbp, char *endptr)
108 {
109 char *bp = *pbp;
110 while (bp < endptr && OPTIONAL_SPACE(*bp)) {
111 bp++;
112 }
113 *pbp = bp;
114 }
115
116 static KMF_RETURN
scanTag(char ** pbp,char * endptr,char * tagBuf,int tagBufSize)117 scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize)
118 {
119 char *bp, *tagBufp;
120 int taglen;
121
122 if (tagBufSize <= 0)
123 return (KMF_ERR_INTERNAL);
124
125 /* skip optional leading space */
126 skipSpace(pbp, endptr);
127 if (*pbp == endptr) {
128 /* nothing left */
129 return (KMF_ERR_RDN_PARSER);
130 }
131
132 /* fill tagBuf */
133 taglen = 0;
134 bp = *pbp;
135 tagBufp = tagBuf;
136 while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
137 if (++taglen >= tagBufSize) {
138 *pbp = bp;
139 return (KMF_ERR_RDN_PARSER);
140 }
141 *tagBufp++ = *bp++;
142 }
143 /* null-terminate tagBuf -- guaranteed at least one space left */
144 *tagBufp++ = 0;
145 *pbp = bp;
146
147 /*
148 * skip trailing spaces till we hit something - should be
149 * an equal sign
150 */
151 skipSpace(pbp, endptr);
152 if (*pbp == endptr) {
153 /* nothing left */
154 return (KMF_ERR_RDN_PARSER);
155 }
156 if (**pbp != C_EQUAL) {
157 /* should be an equal sign */
158 return (KMF_ERR_RDN_PARSER);
159 }
160 /* skip over the equal sign */
161 (*pbp)++;
162
163 return (KMF_OK);
164 }
165
166 static KMF_RETURN
scanVal(char ** pbp,char * endptr,char * valBuf,int valBufSize)167 scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)
168 {
169 char *bp, *valBufp;
170 int vallen;
171 boolean_t isQuoted;
172
173 if (valBufSize <= 0)
174 return (KMF_ERR_INTERNAL);
175
176 /* skip optional leading space */
177 skipSpace(pbp, endptr);
178 if (*pbp == endptr) {
179 /* nothing left */
180 return (KMF_ERR_RDN_PARSER);
181 }
182
183 bp = *pbp;
184
185 /* quoted? */
186 if (*bp == C_DOUBLE_QUOTE) {
187 isQuoted = B_TRUE;
188 /* skip over it */
189 bp++;
190 } else {
191 isQuoted = B_FALSE;
192 }
193
194 valBufp = valBuf;
195 vallen = 0;
196 while (bp < endptr) {
197 char c = *bp;
198 if (c == C_BACKSLASH) {
199 /* escape character */
200 bp++;
201 if (bp >= endptr) {
202 /*
203 * escape charater must appear with paired char
204 */
205 *pbp = bp;
206 return (KMF_ERR_RDN_PARSER);
207 }
208 } else if (!isQuoted && SPECIAL_CHAR(c)) {
209 /* unescaped special and not within quoted value */
210 break;
211 } else if (c == C_DOUBLE_QUOTE) {
212 /* reached unescaped double quote */
213 break;
214 }
215 /* append character */
216 vallen++;
217 if (vallen >= valBufSize) {
218 *pbp = bp;
219 return (KMF_ERR_RDN_PARSER);
220 }
221 *valBufp++ = *bp++;
222 }
223
224 /* stip trailing spaces from unquoted values */
225 if (!isQuoted) {
226 if (valBufp > valBuf) {
227 valBufp--;
228 while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) {
229 valBufp--;
230 }
231 valBufp++;
232 }
233 }
234
235 if (isQuoted) {
236 /* insist that we stopped on a double quote */
237 if (*bp != C_DOUBLE_QUOTE) {
238 *pbp = bp;
239 return (KMF_ERR_RDN_PARSER);
240 }
241 /* skip over the quote and skip optional space */
242 bp++;
243 skipSpace(&bp, endptr);
244 }
245
246 *pbp = bp;
247
248 if (valBufp == valBuf) {
249 /* empty value -- not allowed */
250 return (KMF_ERR_RDN_PARSER);
251 }
252
253 /* null-terminate valBuf -- guaranteed at least one space left */
254 *valBufp++ = 0;
255
256 return (KMF_OK);
257 }
258
259 static KMF_RETURN
CreateRDN(KMF_X509_TYPE_VALUE_PAIR * ava,KMF_X509_RDN * newrdn)260 CreateRDN(KMF_X509_TYPE_VALUE_PAIR *ava, KMF_X509_RDN *newrdn)
261 {
262 /* Each RDN has 1 AttrTypeAndValue */
263 (void) memset(newrdn, 0, sizeof (KMF_X509_RDN));
264 newrdn->numberOfPairs = 1;
265 newrdn->AttributeTypeAndValue = ava;
266
267 return (KMF_OK);
268 }
269
270 static KMF_RETURN
copy_oid(KMF_OID * dst,KMF_OID * src)271 copy_oid(KMF_OID *dst, KMF_OID *src)
272 {
273 KMF_RETURN ret = KMF_OK;
274
275 if (dst == NULL || src == NULL)
276 return (KMF_ERR_BAD_PARAMETER);
277
278 dst->Data = malloc(src->Length);
279 if (dst->Data == NULL)
280 return (KMF_ERR_MEMORY);
281
282 dst->Length = src->Length;
283 (void) memcpy(dst->Data, src->Data, src->Length);
284
285 return (ret);
286 }
287
288 static KMF_RETURN
CreateAVA(KMF_OID * oid,int valueType,char * value,KMF_X509_TYPE_VALUE_PAIR ** newava)289 CreateAVA(KMF_OID *oid, int valueType, char *value,
290 KMF_X509_TYPE_VALUE_PAIR **newava)
291 {
292 int rv = KMF_OK;
293 KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
294
295 *newava = NULL;
296 ava = (KMF_X509_TYPE_VALUE_PAIR*) malloc(
297 sizeof (KMF_X509_TYPE_VALUE_PAIR));
298 if (ava == NULL) {
299 return (KMF_ERR_MEMORY);
300 } else {
301 (void) memset(ava, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR));
302 ava->valueType = valueType;
303 ava->value.Data = malloc(strlen(value));
304 if (ava->value.Data == NULL) {
305 free(ava);
306 return (KMF_ERR_MEMORY);
307 }
308 (void) memcpy(ava->value.Data, value, strlen(value));
309 ava->value.Length = strlen(value);
310
311 rv = copy_oid(&ava->type, oid);
312 if (rv != KMF_OK) {
313 /* Illegal AVA type */
314 free(ava->value.Data);
315 free(ava);
316 return (rv);
317 }
318 }
319 *newava = ava;
320
321 return (rv);
322 }
323
324 static KMF_RETURN
ParseRdnAttribute(char ** pbp,char * endptr,boolean_t singleAVA,KMF_X509_TYPE_VALUE_PAIR ** a)325 ParseRdnAttribute(char **pbp, char *endptr, boolean_t singleAVA,
326 KMF_X509_TYPE_VALUE_PAIR **a)
327 {
328 KMF_RETURN rv;
329 const struct NameToKind *n2k;
330 int vt;
331 int valLen;
332 char *bp;
333
334 char tagBuf[32];
335 char valBuf[384];
336
337 rv = scanTag(pbp, endptr, tagBuf, sizeof (tagBuf));
338 if (rv != KMF_OK)
339 return (rv);
340 rv = scanVal(pbp, endptr, valBuf, sizeof (valBuf));
341 if (rv != KMF_OK)
342 return (rv);
343
344 /* insist that if we haven't finished we've stopped on a separator */
345 bp = *pbp;
346 if (bp < endptr) {
347 if (singleAVA || (*bp != ',' && *bp != ';')) {
348 *pbp = bp;
349 return (KMF_ERR_RDN_ATTR);
350 }
351 /* ok, skip over separator */
352 bp++;
353 }
354 *pbp = bp;
355
356 for (n2k = name2kinds; n2k->name; n2k++) {
357 if (strcasecmp(n2k->name, tagBuf) == 0) {
358 valLen = strlen(valBuf);
359 if (n2k->kind == OID_AVA_COUNTRY_NAME) {
360 vt = BER_PRINTABLE_STRING;
361 if (valLen != 2) {
362 return (KMF_ERR_RDN_ATTR);
363 }
364 if (!IsPrintable((unsigned char *) valBuf, 2)) {
365 return (KMF_ERR_RDN_ATTR);
366 }
367 } else if ((n2k->kind == OID_PKCS9_EMAIL_ADDRESS) ||
368 (n2k->kind == OID_RFC1274_MAIL)) {
369 vt = BER_IA5STRING;
370 } else {
371 /*
372 * Hack -- for rationale see X.520
373 * DirectoryString defn
374 */
375 if (IsPrintable((unsigned char *)valBuf,
376 valLen)) {
377 vt = BER_PRINTABLE_STRING;
378 } else if (Is7Bit((unsigned char *)valBuf,
379 valLen)) {
380 vt = BER_T61STRING;
381 }
382 }
383 rv = CreateAVA(n2k->OID, vt, (char *)valBuf, a);
384 return (rv);
385 }
386 }
387 /* matched no kind -- invalid tag */
388 return (KMF_ERR_RDN_ATTR);
389 }
390
391 static int
rdnavcompare(const void * a,const void * b)392 rdnavcompare(const void *a, const void *b)
393 {
394 KMF_X509_RDN *r1, *r2;
395 KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
396 int i, p1, p2;
397 const struct NameToKind *n2k;
398 KMF_OID *oidrec;
399
400 r1 = (KMF_X509_RDN *)a;
401 r2 = (KMF_X509_RDN *)b;
402
403 av1 = r1->AttributeTypeAndValue;
404 av2 = r2->AttributeTypeAndValue;
405
406 p1 = p2 = MAXINT;
407 /*
408 * The "Name2Kinds" list is ordered by significance.
409 * Compare the "ranking" of each of the OIDs to determine
410 * the result.
411 */
412 for (n2k = name2kinds, i = 0;
413 n2k->name && (p1 == MAXINT || p2 == MAXINT);
414 n2k++, i++) {
415 oidrec = n2k->OID;
416 if (oidrec != NULL) {
417 if (IsEqualOid(&av1->type, oidrec))
418 p1 = i;
419 if (IsEqualOid(&av2->type, oidrec))
420 p2 = i;
421 }
422 }
423
424 if (p1 > p2)
425 return (-1);
426 else if (p1 < p2)
427 return (1);
428 else /* If equal, treat as if it is less than */
429 return (1);
430 }
431
432 static KMF_RETURN
ParseDistinguishedName(char * buf,int len,KMF_X509_NAME * name)433 ParseDistinguishedName(char *buf, int len, KMF_X509_NAME *name)
434 {
435 KMF_RETURN rv = KMF_OK;
436 char *bp, *e;
437 KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
438 KMF_X509_RDN rdn;
439
440 (void) memset(name, 0, sizeof (KMF_X509_NAME));
441 e = buf + len;
442 bp = buf;
443 while (bp < e) {
444 rv = ParseRdnAttribute(&bp, e, B_FALSE, &ava);
445 if (rv != KMF_OK) goto loser;
446 rv = CreateRDN(ava, &rdn);
447 if (rv != KMF_OK) goto loser;
448 if (AddRDN(name, &rdn) != KMF_OK) goto loser;
449 skipSpace(&bp, e);
450 }
451
452 /*
453 * Canonicalize the DN by sorting the elements
454 * in little-endian order, as per RFC 1485:
455 * "The name is presented/input in a little-endian
456 * order (most significant component last)."
457 */
458 qsort((void *)name->RelativeDistinguishedName,
459 name->numberOfRDNs, sizeof (KMF_X509_RDN), rdnavcompare);
460
461 /* return result */
462 return (rv);
463
464 loser:
465 kmf_free_dn(name);
466 return (rv);
467 }
468
469 static KMF_BOOL
IsEqualData(KMF_DATA * d1,KMF_DATA * d2)470 IsEqualData(KMF_DATA *d1, KMF_DATA *d2)
471 {
472 return ((d1->Length == d2->Length) &&
473 !memcmp(d1->Data, d2->Data, d1->Length));
474 }
475
476 /*
477 * Generic routine to compare 2 RDN structures.
478 *
479 * Because the ordering of the AV pairs may not be
480 * the same, we must compare each AV pair individually
481 *
482 * Return 0 if equal, 1 if not.
483 */
484 int
kmf_compare_rdns(KMF_X509_NAME * name1,KMF_X509_NAME * name2)485 kmf_compare_rdns(KMF_X509_NAME *name1, KMF_X509_NAME *name2)
486 {
487 int i, j;
488 boolean_t avfound;
489 KMF_X509_RDN *r1, *r2;
490 KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
491
492 if (name1 == NULL || name2 == NULL)
493 return (1);
494
495 if (name1->numberOfRDNs != name2->numberOfRDNs)
496 return (1);
497
498 for (i = 0; i < name1->numberOfRDNs; i++) {
499 r1 = (KMF_X509_RDN *)&name1->RelativeDistinguishedName[i];
500 av1 = (KMF_X509_TYPE_VALUE_PAIR *)r1->AttributeTypeAndValue;
501
502 avfound = FALSE;
503 for (j = 0; j < name2->numberOfRDNs && !avfound; j++) {
504 r2 = (KMF_X509_RDN *)
505 &name2->RelativeDistinguishedName[j];
506 av2 = (KMF_X509_TYPE_VALUE_PAIR *)
507 r2->AttributeTypeAndValue;
508
509 avfound = (IsEqualOid(&av1->type, &av2->type) &&
510 IsEqualData(&av1->value, &av2->value));
511 }
512 /*
513 * If the current AV from name1 was not found in name2,
514 * we are done.
515 */
516 if (!avfound)
517 return (1);
518 }
519
520 /* If we got this far, it must be a match */
521 return (0);
522 }
523
524 /*
525 * kmf_dn_parser
526 *
527 * Public interface for parsing a Distinguished name in
528 * human-readable format into a binary KMF_X509_NAME.
529 */
530 KMF_RETURN
kmf_dn_parser(char * string,KMF_X509_NAME * name)531 kmf_dn_parser(char *string, KMF_X509_NAME *name)
532 {
533 KMF_RETURN err;
534
535 if (string == NULL || name == NULL)
536 return (KMF_ERR_BAD_PARAMETER);
537
538 err = ParseDistinguishedName(string, (int)strlen(string), name);
539 return (err);
540 }
541
542 static const char hexdigits[] = "0123456789abcdef";
543
544 static KMF_RETURN
binvalue_to_string(KMF_DATA * data,custr_t * str)545 binvalue_to_string(KMF_DATA *data, custr_t *str)
546 {
547 size_t i;
548 uchar_t c;
549
550 if (custr_appendc(str, '#') != 0)
551 return (KMF_ERR_MEMORY);
552
553 for (i = 0; i < data->Length; i++) {
554 c = data->Data[i];
555 if (custr_appendc(str, hexdigits[(c >> 4) & 0xf]) != 0 ||
556 custr_appendc(str, hexdigits[(c & 0xf)]) != 0) {
557 return (KMF_ERR_MEMORY);
558 }
559 }
560
561 return (KMF_OK);
562 }
563
564 /*
565 * Convert an RDN value into a printable name with appropriate escaping.
566 * The rules are taken from RFC4514. While it is dealing with LDAP
567 * distinguished names, both LDAP and x509 certificates are based on the
568 * same underlying ITU standards, and as far as I can determine, the same
569 * rules apply (or at least the rules for LDAP DNs apply the same to x509
570 * DNs).
571 */
572 static KMF_RETURN
value_to_string(KMF_DATA * data,custr_t * str)573 value_to_string(KMF_DATA *data, custr_t *str)
574 {
575 size_t i;
576 uchar_t c;
577
578 for (i = 0; i < data->Length; i++) {
579 c = data->Data[i];
580
581 /*
582 * While technically not required, it is suggested that
583 * printable non-ascii characters (e.g. multi-byte UTF-8
584 * characters) are converted as escaped hex (as well as
585 * unprintable characters). AFAIK there is no one canonical
586 * string representation (e.g. attribute names are case
587 * insensitive, so 'CN=foo' and 'cn=foo' convert to the same
588 * binary representation, but there is nothing to say if
589 * either string form is canonical), so this shouldn't
590 * pose a problem.
591 */
592 if (c < ' ' || c >= 0x7f) {
593 /*
594 * RFC4514 specifies the hex form in a DN string as
595 * \{hex}{hex}. OpenSSL uses capitals for A-F so we
596 * do the same.
597 */
598 if (custr_append_printf(str, "\\%02hhX", c) != 0)
599 return (KMF_ERR_MEMORY);
600 continue;
601 }
602
603 switch (c) {
604 case '#':
605 /* Escape # if at the start of a value */
606 if (i != 0)
607 break;
608 /* FALLTHROUGH */
609 case ' ':
610 /* Escape ' ' if at the start or end of a value */
611 if (i != 0 && i + 1 != data->Length)
612 break;
613 /* FALLTHROUGH */
614 case '"':
615 case '+':
616 case ',':
617 case ';':
618 case '<':
619 case '>':
620 case '\\':
621 /* Escape these */
622 if (custr_appendc(str, '\\') != 0)
623 return (KMF_ERR_MEMORY);
624 }
625
626 if (custr_appendc(str, c) != 0)
627 return (KMF_ERR_MEMORY);
628 }
629
630 return (KMF_OK);
631 }
632
633 /*
634 * Translate an attribute/value pair into a string. If the attribute OID
635 * is a well known OID (in name2kinds) we use the name instead of the OID.
636 */
637 static KMF_RETURN
ava_to_string(KMF_X509_TYPE_VALUE_PAIR * tvp,custr_t * str)638 ava_to_string(KMF_X509_TYPE_VALUE_PAIR *tvp, custr_t *str)
639 {
640 KMF_OID *kind_oid;
641 KMF_OID *rdn_oid = &tvp->type;
642 const char *attr = NULL;
643 size_t i;
644 KMF_RETURN ret = KMF_OK;
645 boolean_t found = B_FALSE;
646
647 for (i = 0; name2kinds[i].name != NULL; i++) {
648 kind_oid = name2kinds[i].OID;
649
650 if (!IsEqualOid(kind_oid, rdn_oid))
651 continue;
652
653 attr = name2kinds[i].name;
654 found = B_TRUE;
655 break;
656 }
657
658 if (!found && (attr = kmf_oid_to_string(rdn_oid)) == NULL) {
659 ret = KMF_ERR_MEMORY;
660 goto done;
661 }
662 if (custr_append(str, attr) != 0) {
663 ret = KMF_ERR_MEMORY;
664 goto done;
665 }
666 if (custr_appendc(str, '=') != 0) {
667 ret = KMF_ERR_MEMORY;
668 goto done;
669 }
670
671 /*
672 * RFC4514 indicates that an oid=value pair should have the value
673 * printed as #xxxxxx. In addition, we also print as a binary
674 * value if the BER tag does not indicate the value is some sort
675 * of printable string.
676 */
677 switch (tvp->valueType) {
678 case BER_UTF8_STRING:
679 case BER_PRINTABLE_STRING:
680 case BER_T61STRING:
681 case BER_IA5STRING:
682 if (found) {
683 ret = value_to_string(&tvp->value, str);
684 break;
685 }
686 /*FALLTHROUGH*/
687 default:
688 ret = binvalue_to_string(&tvp->value, str);
689 break;
690 }
691
692 done:
693 if (!found)
694 free((void *)attr);
695
696 return (ret);
697 }
698
699 static KMF_RETURN
rdn_to_string(KMF_X509_RDN * rdn,custr_t * str)700 rdn_to_string(KMF_X509_RDN *rdn, custr_t *str)
701 {
702 KMF_RETURN ret;
703 size_t i;
704
705 for (i = 0; i < rdn->numberOfPairs; i++) {
706 if (i > 0 && custr_appendc(str, '+') != 0)
707 return (KMF_ERR_MEMORY);
708
709 ret = ava_to_string(&rdn->AttributeTypeAndValue[i], str);
710 if (ret != KMF_OK)
711 return (ret);
712 }
713
714 return (KMF_OK);
715 }
716
717 /*
718 * kmf_dn_to_string
719 *
720 * Take a binary KMF_X509_NAME and convert it into a human readable string.
721 */
722 KMF_RETURN
kmf_dn_to_string(KMF_X509_NAME * name,char ** string)723 kmf_dn_to_string(KMF_X509_NAME *name, char **string)
724 {
725 custr_t *str = NULL;
726 KMF_RETURN err = KMF_OK;
727 size_t i;
728
729 if (name == NULL || string == NULL)
730 return (KMF_ERR_BAD_PARAMETER);
731
732 *string = NULL;
733
734 if (custr_alloc(&str) != 0)
735 return (KMF_ERR_MEMORY);
736
737 for (i = 0; i < name->numberOfRDNs; i++) {
738 KMF_X509_RDN *rdn = &name->RelativeDistinguishedName[i];
739
740 if (i > 0 && custr_append(str, ", ") != 0) {
741 err = KMF_ERR_MEMORY;
742 goto done;
743 }
744
745 if ((err = rdn_to_string(rdn, str)) != KMF_OK)
746 goto done;
747 }
748
749 if ((*string = strdup(custr_cstr(str))) == NULL)
750 err = KMF_ERR_MEMORY;
751
752 done:
753 custr_free(str);
754 return (err);
755 }
756