Line data Source code
1 : /* dn.c - Distinguished Name helper functions
2 : * Copyright (C) 2001, 2006, 2012 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * KSBA is distributed in the hope that it will be useful, but WITHOUT
22 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 : * License for more details.
25 : *
26 : * You should have received a copies of the GNU General Public License
27 : * and the GNU Lesser General Public License along with this program;
28 : * if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : /* Reference is RFC-2253 */
32 :
33 : #include <config.h>
34 : #include <stdio.h>
35 : #include <stdlib.h>
36 : #include <string.h>
37 : #include <assert.h>
38 :
39 : #include "util.h"
40 : #include "asn1-func.h"
41 : #include "ber-help.h"
42 : #include "ber-decoder.h"
43 :
44 : static const struct {
45 : const char *name;
46 : int source; /* 0 = unknown
47 : 1 = rfc2253
48 : 2 = David Chadwick, July 2003
49 : <draft-ietf-pkix-dnstrings-02.txt>
50 : 3 = Peter Gutmann
51 : */
52 : const char *description;
53 : size_t oidlen;
54 : const unsigned char *oid; /* DER encoded OID. */
55 : const char *oidstr; /* OID as dotted string. */
56 : } oid_name_tbl[] = {
57 : {"CN", 1, "CommonName", 3, "\x55\x04\x03", "2.5.4.3" },
58 : {"SN", 2, "Surname", 3, "\x55\x04\x04", "2.5.4.4" },
59 : {"SERIALNUMBER", 2, "SerialNumber",3, "\x55\x04\x05", "2.5.4.5" },
60 : {"C", 1, "CountryName", 3, "\x55\x04\x06", "2.5.4.6" },
61 : {"L" , 1, "LocalityName", 3, "\x55\x04\x07", "2.5.4.7" },
62 : {"ST", 1, "StateOrProvince", 3, "\x55\x04\x08", "2.5.4.8" },
63 : {"STREET", 1, "StreetAddress", 3, "\x55\x04\x09", "2.5.4.9" },
64 : {"O", 1, "OrganizationName", 3, "\x55\x04\x0a", "2.5.4.10" },
65 : {"OU", 1, "OrganizationalUnit", 3, "\x55\x04\x0b", "2.5.4.11" },
66 : {"T", 2, "Title", 3, "\x55\x04\x0c", "2.5.4.12" },
67 : {"D", 3, "Description", 3, "\x55\x04\x0d", "2.5.4.13" },
68 : {"BC", 3, "BusinessCategory", 3, "\x55\x04\x0f", "2.5.4.15" },
69 : {"ADDR", 2, "PostalAddress", 3, "\x55\x04\x11", "2.5.4.16" },
70 : {"POSTALCODE" , 0, "PostalCode", 3, "\x55\x04\x11", "2.5.4.17" },
71 : {"GN", 2, "GivenName", 3, "\x55\x04\x2a", "2.5.4.42" },
72 : {"PSEUDO", 2, "Pseudonym", 3, "\x55\x04\x41", "2.5.4.65" },
73 : {"DC", 1, "domainComponent", 10,
74 : "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19", "0.9.2342.19200300.100.1.25" },
75 : {"UID", 1, "userid", 10,
76 : "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01", "0.9.2342.19200300.100.1.1 " },
77 : {"EMAIL", 3, "emailAddress", 9,
78 : "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01", "1.2.840.113549.1.9.1" },
79 : { NULL }
80 : };
81 :
82 :
83 : #define N 0x00
84 : #define P 0x01
85 : static unsigned char charclasses[128] = {
86 : N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
87 : N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
88 : P, N, N, N, N, N, N, P, P, P, N, P, P, P, P, P,
89 : P, P, P, P, P, P, P, P, P, P, P, N, N, P, N, P,
90 : N, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
91 : P, P, P, P, P, P, P, P, P, P, P, N, N, N, N, N,
92 : N, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P,
93 : P, P, P, P, P, P, P, P, P, P, P, N, N, N, N, N
94 : };
95 : #undef N
96 : #undef P
97 :
98 : struct stringbuf {
99 : size_t len;
100 : size_t size;
101 : char *buf;
102 : int out_of_core;
103 : };
104 :
105 :
106 :
107 : static void
108 9 : init_stringbuf (struct stringbuf *sb, int initiallen)
109 : {
110 9 : sb->len = 0;
111 9 : sb->size = initiallen;
112 9 : sb->out_of_core = 0;
113 : /* allocate one more, so that get_stringbuf can append a nul */
114 9 : sb->buf = xtrymalloc (initiallen+1);
115 9 : if (!sb->buf)
116 0 : sb->out_of_core = 1;
117 9 : }
118 :
119 : static void
120 9 : deinit_stringbuf (struct stringbuf *sb)
121 : {
122 9 : xfree (sb->buf);
123 9 : sb->buf = NULL;
124 9 : sb->out_of_core = 1; /* make sure the caller does an init before reuse */
125 9 : }
126 :
127 :
128 : static void
129 190 : put_stringbuf (struct stringbuf *sb, const char *text)
130 : {
131 190 : size_t n = strlen (text);
132 :
133 190 : if (sb->out_of_core)
134 0 : return;
135 :
136 190 : if (sb->len + n >= sb->size)
137 : {
138 : char *p;
139 :
140 4 : sb->size += n + 100;
141 4 : p = xtryrealloc (sb->buf, sb->size);
142 4 : if ( !p)
143 : {
144 0 : sb->out_of_core = 1;
145 0 : return;
146 : }
147 4 : sb->buf = p;
148 : }
149 190 : memcpy (sb->buf+sb->len, text, n);
150 190 : sb->len += n;
151 : }
152 :
153 : static void
154 43 : put_stringbuf_mem (struct stringbuf *sb, const char *text, size_t n)
155 : {
156 43 : if (sb->out_of_core)
157 0 : return;
158 :
159 43 : if (sb->len + n >= sb->size)
160 : {
161 : char *p;
162 :
163 0 : sb->size += n + 100;
164 0 : p = xtryrealloc (sb->buf, sb->size);
165 0 : if ( !p)
166 : {
167 0 : sb->out_of_core = 1;
168 0 : return;
169 : }
170 0 : sb->buf = p;
171 : }
172 43 : memcpy (sb->buf+sb->len, text, n);
173 43 : sb->len += n;
174 : }
175 :
176 : static void
177 40 : put_stringbuf_mem_skip (struct stringbuf *sb, const char *text, size_t n,
178 : int skip)
179 : {
180 : char *p;
181 :
182 40 : if (!skip)
183 : {
184 40 : put_stringbuf_mem (sb, text, n);
185 40 : return;
186 : }
187 0 : if (sb->out_of_core)
188 0 : return;
189 :
190 0 : if (sb->len + n >= sb->size)
191 : {
192 : /* Note: we allocate too much here, but we don't care. */
193 0 : sb->size += n + 100;
194 0 : p = xtryrealloc (sb->buf, sb->size);
195 0 : if ( !p)
196 : {
197 0 : sb->out_of_core = 1;
198 0 : return;
199 : }
200 0 : sb->buf = p;
201 : }
202 0 : p = sb->buf+sb->len;
203 0 : while (n > skip)
204 : {
205 0 : text += skip;
206 0 : n -= skip;
207 0 : *p++ = *text++;
208 0 : n--;
209 0 : sb->len++;
210 : }
211 : }
212 :
213 : static char *
214 9 : get_stringbuf (struct stringbuf *sb)
215 : {
216 : char *p;
217 :
218 9 : if (sb->out_of_core)
219 : {
220 0 : xfree (sb->buf); sb->buf = NULL;
221 0 : return NULL;
222 : }
223 :
224 9 : sb->buf[sb->len] = 0;
225 9 : p = sb->buf;
226 9 : sb->buf = NULL;
227 9 : sb->out_of_core = 1; /* make sure the caller does an init before reuse */
228 9 : return p;
229 : }
230 :
231 :
232 : /* This function is used for 1 byte encodings to insert any required
233 : quoting. It does not do the quoting for a space or hash mark at
234 : the beginning of a string or a space as the last character of a
235 : string. It will do steps of SKIP+1 characters, assuming that these
236 : SKIP characters are null octets. */
237 : static void
238 40 : append_quoted (struct stringbuf *sb, const unsigned char *value, size_t length,
239 : int skip)
240 : {
241 : unsigned char tmp[4];
242 40 : const unsigned char *s = value;
243 40 : size_t n = 0;
244 :
245 : for (;;)
246 : {
247 506 : for (value = s; n+skip < length; n++, s++)
248 : {
249 466 : s += skip;
250 466 : n += skip;
251 466 : if (*s < ' ' || *s > 126 || strchr (",+\"\\<>;", *s) )
252 : break;
253 : }
254 :
255 40 : if (s != value)
256 40 : put_stringbuf_mem_skip (sb, value, s-value, skip);
257 40 : if (n+skip >= length)
258 80 : return; /* ready */
259 0 : s += skip;
260 0 : n += skip;
261 0 : if ( *s < ' ' || *s > 126 )
262 : {
263 0 : snprintf (tmp, sizeof tmp, "\\%02X", *s);
264 0 : put_stringbuf_mem (sb, tmp, 3);
265 : }
266 : else
267 : {
268 0 : tmp[0] = '\\';
269 0 : tmp[1] = *s;
270 0 : put_stringbuf_mem (sb, tmp, 2);
271 : }
272 0 : n++; s++;
273 0 : }
274 : }
275 :
276 :
277 : /* Append VALUE of LENGTH and TYPE to SB. Do the required quoting. */
278 : static void
279 0 : append_utf8_value (const unsigned char *value, size_t length,
280 : struct stringbuf *sb)
281 : {
282 : unsigned char tmp[6];
283 : const unsigned char *s;
284 : size_t n;
285 : int i, nmore;
286 :
287 0 : if (length && (*value == ' ' || *value == '#'))
288 : {
289 0 : tmp[0] = '\\';
290 0 : tmp[1] = *value;
291 0 : put_stringbuf_mem (sb, tmp, 2);
292 0 : value++;
293 0 : length--;
294 : }
295 0 : if (length && value[length-1] == ' ')
296 : {
297 0 : tmp[0] = '\\';
298 0 : tmp[1] = ' ';
299 0 : put_stringbuf_mem (sb, tmp, 2);
300 0 : length--;
301 : }
302 :
303 0 : for (s=value, n=0;;)
304 : {
305 0 : for (value = s; n < length && !(*s & 0x80); n++, s++)
306 : ;
307 0 : if (s != value)
308 0 : append_quoted (sb, value, s-value, 0);
309 0 : if (n==length)
310 0 : return; /* ready */
311 0 : if (!(*s & 0x80))
312 0 : nmore = 0; /* Not expected here: high bit not set. */
313 0 : else if ( (*s & 0xe0) == 0xc0 ) /* 110x xxxx */
314 0 : nmore = 1;
315 0 : else if ( (*s & 0xf0) == 0xe0 ) /* 1110 xxxx */
316 0 : nmore = 2;
317 0 : else if ( (*s & 0xf8) == 0xf0 ) /* 1111 0xxx */
318 0 : nmore = 3;
319 0 : else if ( (*s & 0xfc) == 0xf8 ) /* 1111 10xx */
320 0 : nmore = 4;
321 0 : else if ( (*s & 0xfe) == 0xfc ) /* 1111 110x */
322 0 : nmore = 5;
323 : else /* Invalid encoding */
324 0 : nmore = 0;
325 :
326 0 : if (!nmore)
327 : {
328 : /* Encoding error: We quote the bad byte. */
329 0 : snprintf (tmp, sizeof tmp, "\\%02X", *s);
330 0 : put_stringbuf_mem (sb, tmp, 3);
331 0 : s++; n++;
332 : }
333 : else
334 : {
335 0 : if (n+nmore > length)
336 0 : nmore = length - n; /* Oops, encoding to short */
337 :
338 0 : tmp[0] = *s++; n++;
339 0 : for (i=1; i <= nmore; i++)
340 : {
341 0 : if ( (*s & 0xc0) != 0x80)
342 0 : break; /* Invalid encoding - let the next cycle detect this. */
343 0 : tmp[i] = *s++;
344 0 : n++;
345 : }
346 0 : put_stringbuf_mem (sb, tmp, i);
347 : }
348 0 : }
349 : }
350 :
351 : /* Append VALUE of LENGTH and TYPE to SB. Do character set conversion
352 : and quoting */
353 : static void
354 37 : append_latin1_value (const unsigned char *value, size_t length,
355 : struct stringbuf *sb)
356 : {
357 : unsigned char tmp[2];
358 : const unsigned char *s;
359 : size_t n;
360 :
361 37 : if (length && (*value == ' ' || *value == '#'))
362 : {
363 0 : tmp[0] = '\\';
364 0 : tmp[1] = *value;
365 0 : put_stringbuf_mem (sb, tmp, 2);
366 0 : value++;
367 0 : length--;
368 : }
369 37 : if (length && value[length-1] == ' ')
370 : {
371 0 : tmp[0] = '\\';
372 0 : tmp[1] = ' ';
373 0 : put_stringbuf_mem (sb, tmp, 2);
374 0 : length--;
375 : }
376 :
377 37 : for (s=value, n=0;;)
378 : {
379 40 : for (value = s; n < length && !(*s & 0x80); n++, s++)
380 : ;
381 40 : if (s != value)
382 40 : append_quoted (sb, value, s-value, 0);
383 40 : if (n==length)
384 74 : return; /* ready */
385 3 : assert ((*s & 0x80));
386 3 : tmp[0] = 0xc0 | ((*s >> 6) & 3);
387 3 : tmp[1] = 0x80 | ( *s & 0x3f );
388 3 : put_stringbuf_mem (sb, tmp, 2);
389 3 : n++; s++;
390 3 : }
391 : }
392 :
393 : /* Append VALUE of LENGTH and TYPE to SB. Do UCS-4 to utf conversion
394 : and and quoting */
395 : static void
396 0 : append_ucs4_value (const unsigned char *value, size_t length,
397 : struct stringbuf *sb)
398 : {
399 : unsigned char tmp[7];
400 : const unsigned char *s;
401 : size_t n;
402 : unsigned int c;
403 : int i;
404 :
405 0 : if (length>3 && !value[0] && !value[1] && !value[2]
406 0 : && (value[3] == ' ' || value[3] == '#'))
407 : {
408 0 : tmp[0] = '\\';
409 0 : tmp[1] = *value;
410 0 : put_stringbuf_mem (sb, tmp, 2);
411 0 : value += 4;
412 0 : length -= 4;
413 : }
414 0 : if (length>3 && !value[0] && !value[1] && !value[2] && value[3] == ' ')
415 : {
416 0 : tmp[0] = '\\';
417 0 : tmp[1] = ' ';
418 0 : put_stringbuf_mem (sb, tmp, 2);
419 0 : length -= 4;
420 : }
421 :
422 0 : for (s=value, n=0;;)
423 : {
424 0 : for (value = s; n+3 < length
425 0 : && !s[0] && !s[1] && !s[2] && !(s[3] & 0x80); n += 4, s += 4)
426 : ;
427 0 : if (s != value)
428 0 : append_quoted (sb, value, s-value, 3);
429 0 : if (n>=length)
430 0 : return; /* ready */
431 0 : if (n < 4)
432 : { /* This is an invalid encoding - better stop after adding
433 : one impossible characater */
434 0 : put_stringbuf_mem (sb, "\xff", 1);
435 0 : return;
436 : }
437 0 : c = *s++ << 24;
438 0 : c |= *s++ << 16;
439 0 : c |= *s++ << 8;
440 0 : c |= *s++;
441 0 : n += 4;
442 0 : i=0;
443 0 : if (c < (1<<11))
444 : {
445 0 : tmp[i++] = 0xc0 | ( c >> 6);
446 0 : tmp[i++] = 0x80 | ( c & 0x3f);
447 : }
448 0 : else if (c < (1<<16))
449 : {
450 0 : tmp[i++] = 0xe0 | ( c >> 12);
451 0 : tmp[i++] = 0x80 | ((c >> 6) & 0x3f);
452 0 : tmp[i++] = 0x80 | ( c & 0x3f);
453 : }
454 0 : else if (c < (1<<21))
455 : {
456 0 : tmp[i++] = 0xf0 | ( c >> 18);
457 0 : tmp[i++] = 0x80 | ((c >> 12) & 0x3f);
458 0 : tmp[i++] = 0x80 | ((c >> 6) & 0x3f);
459 0 : tmp[i++] = 0x80 | ( c & 0x3f);
460 : }
461 0 : else if (c < (1<<26))
462 : {
463 0 : tmp[i++] = 0xf8 | ( c >> 24);
464 0 : tmp[i++] = 0x80 | ((c >> 18) & 0x3f);
465 0 : tmp[i++] = 0x80 | ((c >> 12) & 0x3f);
466 0 : tmp[i++] = 0x80 | ((c >> 6) & 0x3f);
467 0 : tmp[i++] = 0x80 | ( c & 0x3f);
468 : }
469 : else
470 : {
471 0 : tmp[i++] = 0xfc | ( c >> 30);
472 0 : tmp[i++] = 0x80 | ((c >> 24) & 0x3f);
473 0 : tmp[i++] = 0x80 | ((c >> 18) & 0x3f);
474 0 : tmp[i++] = 0x80 | ((c >> 12) & 0x3f);
475 0 : tmp[i++] = 0x80 | ((c >> 6) & 0x3f);
476 0 : tmp[i++] = 0x80 | ( c & 0x3f);
477 : }
478 0 : put_stringbuf_mem (sb, tmp, i);
479 0 : }
480 : }
481 :
482 : /* Append VALUE of LENGTH and TYPE to SB. Do UCS-2 to utf conversion
483 : and and quoting */
484 : static void
485 0 : append_ucs2_value (const unsigned char *value, size_t length,
486 : struct stringbuf *sb)
487 : {
488 : unsigned char tmp[3];
489 : const unsigned char *s;
490 : size_t n;
491 : unsigned int c;
492 : int i;
493 :
494 0 : if (length>1 && !value[0] && (value[1] == ' ' || value[1] == '#'))
495 : {
496 0 : tmp[0] = '\\';
497 0 : tmp[1] = *value;
498 0 : put_stringbuf_mem (sb, tmp, 2);
499 0 : value += 2;
500 0 : length -= 2;
501 : }
502 0 : if (length>1 && !value[0] && value[1] == ' ')
503 : {
504 0 : tmp[0] = '\\';
505 0 : tmp[1] = ' ';
506 0 : put_stringbuf_mem (sb, tmp, 2);
507 0 : length -=2;
508 : }
509 :
510 0 : for (s=value, n=0;;)
511 : {
512 0 : for (value = s; n+1 < length && !s[0] && !(s[1] & 0x80); n += 2, s += 2)
513 : ;
514 0 : if (s != value)
515 0 : append_quoted (sb, value, s-value, 1);
516 0 : if (n>=length)
517 0 : return; /* ready */
518 0 : if (n < 2)
519 : { /* This is an invalid encoding - better stop after adding
520 : one impossible characater */
521 0 : put_stringbuf_mem (sb, "\xff", 1);
522 0 : return;
523 : }
524 0 : c = *s++ << 8;
525 0 : c |= *s++;
526 0 : n += 2;
527 0 : i=0;
528 0 : if (c < (1<<11))
529 : {
530 0 : tmp[i++] = 0xc0 | ( c >> 6);
531 0 : tmp[i++] = 0x80 | ( c & 0x3f);
532 : }
533 : else
534 : {
535 0 : tmp[i++] = 0xe0 | ( c >> 12);
536 0 : tmp[i++] = 0x80 | ((c >> 6) & 0x3f);
537 0 : tmp[i++] = 0x80 | ( c & 0x3f);
538 : }
539 0 : put_stringbuf_mem (sb, tmp, i);
540 0 : }
541 : }
542 :
543 :
544 : /* Append attribute and value. ROOT is the sequence */
545 : static gpg_error_t
546 41 : append_atv (const unsigned char *image, AsnNode root, struct stringbuf *sb)
547 : {
548 41 : AsnNode node = root->down;
549 : const char *name;
550 41 : int use_hex = 0;
551 : int i;
552 :
553 41 : if (!node || node->type != TYPE_OBJECT_ID)
554 0 : return gpg_error (GPG_ERR_UNEXPECTED_TAG);
555 41 : if (node->off == -1)
556 0 : return gpg_error (GPG_ERR_NO_VALUE); /* Hmmm, this might lead to misunderstandings */
557 :
558 41 : name = NULL;
559 275 : for (i=0; oid_name_tbl[i].name; i++)
560 : {
561 271 : if (oid_name_tbl[i].source == 1
562 175 : && node->len == oid_name_tbl[i].oidlen
563 278 : && !memcmp (image+node->off+node->nhdr,
564 278 : oid_name_tbl[i].oid, node->len))
565 : {
566 37 : name = oid_name_tbl[i].name;
567 37 : break;
568 : }
569 : }
570 41 : if (name)
571 37 : put_stringbuf (sb, name);
572 : else
573 : { /* No name for the OID in the table; at least not DER encoded.
574 : Now convert the OID to a string, try to find it in the table
575 : again and use the string as last resort. */
576 : char *p;
577 :
578 4 : p = ksba_oid_to_str (image+node->off+node->nhdr, node->len);
579 4 : if (!p)
580 0 : return gpg_error (GPG_ERR_ENOMEM);
581 :
582 80 : for (i=0; *p && oid_name_tbl[i].name; i++)
583 : {
584 76 : if (oid_name_tbl[i].source == 1
585 36 : && !strcmp (p, oid_name_tbl[i].oidstr))
586 : {
587 0 : name = oid_name_tbl[i].name;
588 0 : break;
589 : }
590 : }
591 4 : if (name)
592 0 : put_stringbuf (sb, name);
593 : else
594 : {
595 4 : put_stringbuf (sb, p);
596 4 : use_hex = 1;
597 : }
598 4 : xfree (p);
599 : }
600 41 : put_stringbuf (sb, "=");
601 41 : node = node->right;
602 41 : if (!node || node->off == -1)
603 0 : return gpg_error (GPG_ERR_NO_VALUE);
604 :
605 41 : switch (use_hex? 0 : node->type)
606 : {
607 : case TYPE_UTF8_STRING:
608 0 : append_utf8_value (image+node->off+node->nhdr, node->len, sb);
609 0 : break;
610 : case TYPE_PRINTABLE_STRING:
611 : case TYPE_IA5_STRING:
612 : /* we assume that wrong encodings are latin-1 */
613 : case TYPE_TELETEX_STRING: /* Not correct, but mostly used as latin-1 */
614 37 : append_latin1_value (image+node->off+node->nhdr, node->len, sb);
615 37 : break;
616 :
617 : case TYPE_UNIVERSAL_STRING:
618 0 : append_ucs4_value (image+node->off+node->nhdr, node->len, sb);
619 0 : break;
620 :
621 : case TYPE_BMP_STRING:
622 0 : append_ucs2_value (image+node->off+node->nhdr, node->len, sb);
623 0 : break;
624 :
625 : case 0: /* forced usage of hex */
626 : default:
627 4 : put_stringbuf (sb, "#");
628 76 : for (i=0; i < node->len; i++)
629 : {
630 : char tmp[3];
631 72 : snprintf (tmp, sizeof tmp, "%02X", image[node->off+node->nhdr+i]);
632 72 : put_stringbuf (sb, tmp);
633 : }
634 4 : break;
635 : }
636 :
637 41 : return 0;
638 : }
639 :
640 : static gpg_error_t
641 9 : dn_to_str (const unsigned char *image, AsnNode root, struct stringbuf *sb)
642 : {
643 : gpg_error_t err;
644 : AsnNode nset;
645 :
646 9 : if (!root )
647 0 : return 0; /* empty DN */
648 9 : nset = root->down;
649 9 : if (!nset)
650 0 : return 0; /* consider this as empty */
651 9 : if (nset->type != TYPE_SET_OF)
652 0 : return gpg_error (GPG_ERR_UNEXPECTED_TAG);
653 :
654 : /* output in reverse order */
655 50 : while (nset->right)
656 32 : nset = nset->right;
657 :
658 : for (;;)
659 : {
660 : AsnNode nseq;
661 :
662 41 : if (nset->type != TYPE_SET_OF)
663 0 : return gpg_error (GPG_ERR_UNEXPECTED_TAG);
664 82 : for (nseq = nset->down; nseq; nseq = nseq->right)
665 : {
666 41 : if (nseq->type != TYPE_SEQUENCE)
667 0 : return gpg_error (GPG_ERR_UNEXPECTED_TAG);
668 41 : if (nseq != nset->down)
669 0 : put_stringbuf (sb, "+");
670 41 : err = append_atv (image, nseq, sb);
671 41 : if (err)
672 0 : return err;
673 : }
674 41 : if (nset == root->down)
675 9 : break;
676 32 : put_stringbuf (sb, ",");
677 32 : nset = nset->left;
678 32 : }
679 :
680 9 : return 0;
681 : }
682 :
683 :
684 : gpg_error_t
685 9 : _ksba_dn_to_str (const unsigned char *image, AsnNode node, char **r_string)
686 : {
687 : gpg_error_t err;
688 : struct stringbuf sb;
689 :
690 9 : *r_string = NULL;
691 9 : if (!node || node->type != TYPE_SEQUENCE_OF)
692 0 : return gpg_error (GPG_ERR_INV_VALUE);
693 :
694 9 : init_stringbuf (&sb, 100);
695 9 : err = dn_to_str (image, node, &sb);
696 9 : if (!err)
697 : {
698 9 : *r_string = get_stringbuf (&sb);
699 9 : if (!*r_string)
700 0 : err = gpg_error (GPG_ERR_ENOMEM);
701 : }
702 9 : deinit_stringbuf (&sb);
703 :
704 9 : return err;
705 : }
706 :
707 :
708 : /* Create a new decoder and run it for the given element */
709 : /* Fixme: this code is duplicated from cms-parser.c */
710 : static gpg_error_t
711 2 : create_and_run_decoder (ksba_reader_t reader, const char *elem_name,
712 : AsnNode *r_root,
713 : unsigned char **r_image, size_t *r_imagelen)
714 : {
715 : gpg_error_t err;
716 : ksba_asn_tree_t crl_tree;
717 : BerDecoder decoder;
718 :
719 2 : err = ksba_asn_create_tree ("tmttv2", &crl_tree);
720 2 : if (err)
721 0 : return err;
722 :
723 2 : decoder = _ksba_ber_decoder_new ();
724 2 : if (!decoder)
725 : {
726 0 : ksba_asn_tree_release (crl_tree);
727 0 : return gpg_error (GPG_ERR_ENOMEM);
728 : }
729 :
730 2 : err = _ksba_ber_decoder_set_reader (decoder, reader);
731 2 : if (err)
732 : {
733 0 : ksba_asn_tree_release (crl_tree);
734 0 : _ksba_ber_decoder_release (decoder);
735 0 : return err;
736 : }
737 :
738 2 : err = _ksba_ber_decoder_set_module (decoder, crl_tree);
739 2 : if (err)
740 : {
741 0 : ksba_asn_tree_release (crl_tree);
742 0 : _ksba_ber_decoder_release (decoder);
743 0 : return err;
744 : }
745 :
746 2 : err = _ksba_ber_decoder_decode (decoder, elem_name, 0,
747 : r_root, r_image, r_imagelen);
748 :
749 2 : _ksba_ber_decoder_release (decoder);
750 2 : ksba_asn_tree_release (crl_tree);
751 2 : return err;
752 : }
753 :
754 :
755 : gpg_error_t
756 2 : _ksba_derdn_to_str (const unsigned char *der, size_t derlen, char **r_string)
757 : {
758 : gpg_error_t err;
759 : AsnNode root;
760 : unsigned char *image;
761 : size_t imagelen;
762 : ksba_reader_t reader;
763 :
764 2 : err = ksba_reader_new (&reader);
765 2 : if (err)
766 0 : return err;
767 2 : err = ksba_reader_set_mem (reader, der, derlen);
768 2 : if (err)
769 : {
770 0 : ksba_reader_release (reader);
771 0 : return err;
772 : }
773 2 : err = create_and_run_decoder (reader,
774 : "TMTTv2.CertificateList.tbsCertList.issuer",
775 : &root, &image, &imagelen);
776 2 : ksba_reader_release (reader);
777 2 : if (!err)
778 : {
779 2 : err = _ksba_dn_to_str (image, root->down, r_string);
780 2 : _ksba_asn_release_nodes (root);
781 2 : xfree (image);
782 : }
783 2 : return err;
784 : }
785 :
786 :
787 : /*
788 : Convert a string back to DN
789 : */
790 :
791 : /* Count the number of bytes in a quoted string, return a pointer to
792 : the character after the string or NULL in case of an paring error.
793 : The number of bytes needed to store the string verbatim will be
794 : return as RESULT. With V2COMAP true, the string is assumed to be
795 : in v2 quoting (but w/o the leading quote character)
796 : */
797 : static const char *
798 74 : count_quoted_string (const char *string, size_t *result,
799 : int v2compat, int *stringtype)
800 : {
801 : const unsigned char *s;
802 74 : int nbytes = 0;
803 74 : int highbit = 0;
804 74 : int nonprint = 0;
805 74 : int atsign = 0;
806 :
807 74 : *stringtype = 0;
808 497 : for (s=string; *s; s++)
809 : {
810 482 : if (*s == '\\')
811 : { /* pair */
812 0 : s++;
813 0 : if (*s == ',' || *s == '=' || *s == '+'
814 0 : || *s == '<' || *s == '>' || *s == '#' || *s == ';'
815 0 : || *s == '\\' || *s == '\"' || *s == ' ')
816 : {
817 0 : if (!charclasses[*s])
818 0 : nonprint = 1;
819 0 : nbytes++;
820 : }
821 0 : else if (hexdigitp (s) && hexdigitp (s+1))
822 0 : {
823 0 : int c = xtoi_2 (s);
824 0 : if ((c & 0x80))
825 0 : highbit = 1;
826 0 : else if (c == '@')
827 0 : atsign = 1;
828 0 : else if (!charclasses[c])
829 0 : nonprint = 1;
830 :
831 0 : s++;
832 0 : nbytes++;
833 : }
834 : else
835 0 : return NULL; /* invalid escape sequence */
836 : }
837 482 : else if (*s == '\"')
838 : {
839 2 : if (v2compat)
840 2 : break;
841 0 : return NULL; /* invalid encoding */
842 : }
843 480 : else if (!v2compat
844 480 : && (*s == ',' || *s == '=' || *s == '+'
845 423 : || *s == '<' || *s == '>' || *s == '#' || *s == ';') )
846 : {
847 : break;
848 : }
849 : else
850 : {
851 423 : nbytes++;
852 423 : if ((*s & 0x80))
853 24 : highbit = 1;
854 399 : else if (*s == '@')
855 3 : atsign = 1;
856 396 : else if (!charclasses[*s])
857 0 : nonprint = 1;
858 : }
859 : }
860 :
861 : /* Fixme: Should be remove spaces or white spces from the end unless
862 : they are not escaped or we are in v2compat mode? See TODO */
863 :
864 74 : if (highbit || nonprint)
865 6 : *stringtype = TYPE_UTF8_STRING;
866 68 : else if (atsign)
867 3 : *stringtype = TYPE_IA5_STRING;
868 : else
869 65 : *stringtype = TYPE_PRINTABLE_STRING;
870 :
871 74 : *result = nbytes;
872 74 : return s;
873 : }
874 :
875 :
876 : /* Write out the data to W and do the required escaping. Note that
877 : NBYTES is the number of bytes actually to be written, i.e. it is
878 : the result from count_quoted_string */
879 : static gpg_error_t
880 14 : write_escaped (ksba_writer_t w, const unsigned char *buffer, size_t nbytes)
881 : {
882 : const unsigned char *s;
883 : gpg_error_t err;
884 :
885 137 : for (s=buffer; nbytes; s++)
886 : {
887 123 : if (*s == '\\')
888 : {
889 0 : s++;
890 0 : if (hexdigitp (s) && hexdigitp (s+1))
891 0 : {
892 0 : unsigned char buf = xtoi_2 (s);
893 0 : err = ksba_writer_write (w, &buf, 1);
894 0 : if (err)
895 0 : return err;
896 0 : s++;
897 0 : nbytes--;
898 : }
899 : else
900 : {
901 0 : err = ksba_writer_write (w, s, 1);
902 0 : if (err)
903 0 : return err;
904 0 : nbytes--;
905 : }
906 : }
907 : else
908 : {
909 123 : err = ksba_writer_write (w, s, 1);
910 123 : if (err)
911 0 : return err;
912 123 : nbytes--;
913 : }
914 : }
915 :
916 14 : return 0;
917 : }
918 :
919 :
920 : /* Parse one RDN, and write it to WRITER. Returns a pointer to the
921 : next RDN part where the comma has already been skipped or NULL in
922 : case of an error. When NULL is passed as WRITER, the function does
923 : not allocate any memory but just parses the string and returns the
924 : ENDP. If ROFF or RLEN are not NULL, they will receive informaion
925 : useful for error reporting. */
926 : static gpg_error_t
927 84 : parse_rdn (const unsigned char *string, const char **endp,
928 : ksba_writer_t writer, size_t *roff, size_t *rlen)
929 : {
930 84 : const unsigned char *orig_string = string;
931 : const unsigned char *s, *s1;
932 : size_t n, n1;
933 : int i;
934 : unsigned char *p;
935 84 : unsigned char *oidbuf = NULL;
936 84 : unsigned char *valuebuf = NULL;
937 84 : const unsigned char *oid = NULL;
938 : size_t oidlen;
939 84 : const unsigned char *value = NULL;
940 : int valuelen;
941 : int valuetype;
942 84 : int need_escaping = 0;
943 84 : gpg_error_t err = 0;
944 : size_t dummy_roff, dummy_rlen;
945 :
946 84 : if (!roff)
947 49 : roff = &dummy_roff;
948 84 : if (!rlen)
949 49 : rlen = &dummy_rlen;
950 :
951 84 : *roff = *rlen = 0;
952 :
953 84 : if (!string)
954 0 : return gpg_error (GPG_ERR_INV_VALUE);
955 192 : while (*string == ' ')
956 24 : string++;
957 84 : *roff = string - orig_string;
958 84 : if (!*string)
959 0 : return gpg_error (GPG_ERR_SYNTAX); /* empty elements are not allowed */
960 84 : s = string;
961 :
962 84 : if ( ((*s == 'o' && s[1] == 'i' && s[2] == 'd')
963 84 : ||(*s == 'O' && s[1] == 'I' && s[2] == 'D'))
964 0 : && s[3] == '.' && digitp (s+4))
965 0 : s += 3; /* skip a prefixed oid */
966 :
967 : /* parse attributeType */
968 84 : string = s;
969 84 : *roff = string - orig_string;
970 84 : if (digitp (s))
971 : { /* oid */
972 0 : for (s++; digitp (s) || (*s == '.' && s[1] != '.'); s++)
973 : ;
974 0 : n = s - string;
975 0 : while (*s == ' ')
976 0 : s++;
977 0 : if (*s != '=')
978 0 : return gpg_error (GPG_ERR_SYNTAX);
979 :
980 0 : if (writer)
981 : {
982 0 : p = xtrymalloc (n+1);
983 0 : if (!p)
984 0 : return gpg_error (GPG_ERR_ENOMEM);
985 0 : memcpy (p, string, n);
986 0 : p[n] = 0;
987 0 : err = ksba_oid_from_str (p, &oidbuf, &oidlen);
988 0 : xfree (p);
989 0 : if (err)
990 0 : return err;
991 0 : oid = oidbuf;
992 : }
993 : }
994 84 : else if ((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') )
995 : { /* name */
996 215 : for (s++; ((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')
997 131 : || digitp (s) || *s == '-'); s++)
998 : ;
999 84 : n = s - string;
1000 170 : while (*s == ' ')
1001 2 : s++;
1002 84 : if (*s != '=')
1003 0 : return gpg_error (GPG_ERR_SYNTAX);
1004 :
1005 547 : for (i=0; oid_name_tbl[i].name; i++)
1006 : {
1007 543 : if ( n == strlen (oid_name_tbl[i].name)
1008 175 : && !ascii_memcasecmp (string, oid_name_tbl[i].name, n))
1009 80 : break;
1010 : }
1011 84 : if (!oid_name_tbl[i].name)
1012 : {
1013 4 : *roff = string - orig_string;
1014 4 : *rlen = n;
1015 4 : return gpg_error (GPG_ERR_UNKNOWN_NAME);
1016 : }
1017 80 : oid = oid_name_tbl[i].oid;
1018 80 : oidlen = oid_name_tbl[i].oidlen;
1019 : }
1020 80 : s++;
1021 169 : while (*s == ' ')
1022 9 : s++;
1023 80 : string = s;
1024 :
1025 80 : *roff = string - orig_string;
1026 :
1027 : /* parse attributeValue */
1028 80 : if (!*s)
1029 : {
1030 6 : err = gpg_error (GPG_ERR_SYNTAX); /* missing value */
1031 6 : goto leave;
1032 : }
1033 :
1034 74 : if (*s == '#')
1035 : { /* hexstring */
1036 0 : int need_utf8 = 0;
1037 0 : int need_ia5 = 0;
1038 :
1039 0 : string = ++s;
1040 0 : for (; hexdigitp (s); s++)
1041 0 : s++;
1042 0 : n = s - string;
1043 0 : if (!n || (n & 1))
1044 : {
1045 0 : *rlen = n;
1046 0 : err = gpg_error (GPG_ERR_SYNTAX); /* no hex digits or odd number */
1047 0 : goto leave;
1048 : }
1049 0 : while (*s == ' ')
1050 0 : s++;
1051 0 : n /= 2;
1052 0 : valuelen = n;
1053 0 : if (writer)
1054 : {
1055 0 : valuebuf = xtrymalloc (valuelen);
1056 0 : if (!valuebuf)
1057 : {
1058 0 : err = gpg_error (GPG_ERR_ENOMEM);
1059 0 : goto leave;
1060 : }
1061 0 : for (p=valuebuf, s1=string; n; p++, s1 += 2, n--)
1062 : {
1063 0 : *p = xtoi_2 (s1);
1064 0 : if (*p == '@')
1065 0 : need_ia5 = 1;
1066 0 : else if ((*p & 0x80) || !charclasses[*p])
1067 0 : need_utf8 = 1;
1068 : }
1069 0 : value = valuebuf;
1070 : }
1071 : else
1072 : {
1073 0 : for (s1=string; n; s1 += 2, n--)
1074 : {
1075 : unsigned int c;
1076 :
1077 0 : c = xtoi_2 (s1);
1078 0 : if (c == '@')
1079 0 : need_ia5 = 1;
1080 0 : else if ((c & 0x80) || !charclasses[c])
1081 0 : need_utf8 = 1;
1082 : }
1083 : }
1084 0 : valuetype = need_utf8? TYPE_UTF8_STRING :
1085 0 : need_ia5 ? TYPE_IA5_STRING : TYPE_PRINTABLE_STRING;
1086 : }
1087 74 : else if (*s == '\"')
1088 : { /* old style quotation */
1089 2 : string = s+1;
1090 2 : s = count_quoted_string (string, &n, 1, &valuetype);
1091 2 : if (!s || *s != '\"')
1092 : {
1093 0 : *rlen = s - orig_string;
1094 0 : err = gpg_error (GPG_ERR_SYNTAX); /* error or quote not closed */
1095 0 : goto leave;
1096 : }
1097 2 : s++;
1098 6 : while (*s == ' ')
1099 2 : s++;
1100 2 : value = string;
1101 2 : valuelen = n;
1102 2 : need_escaping = 1;
1103 : }
1104 : else
1105 : { /* regular v3 quoted string */
1106 72 : s = count_quoted_string (string, &n, 0, &valuetype);
1107 72 : if (!s)
1108 : {
1109 0 : err = gpg_error (GPG_ERR_SYNTAX); /* error */
1110 0 : goto leave;
1111 : }
1112 144 : while (*s == ' ')
1113 0 : s++;
1114 72 : value = string;
1115 72 : valuelen = n;
1116 72 : need_escaping = 1;
1117 : }
1118 :
1119 74 : if (!valuelen)
1120 : {
1121 10 : err = gpg_error (GPG_ERR_SYNTAX); /* empty elements are not allowed */
1122 10 : goto leave;
1123 : }
1124 64 : if ( *s && *s != ',' && *s != ';' && *s != '+')
1125 : {
1126 0 : *roff = s - orig_string;
1127 0 : err = gpg_error (GPG_ERR_SYNTAX); /* invalid delimiter */
1128 0 : goto leave;
1129 : }
1130 64 : if (*s == '+') /* fixme: implement this */
1131 : {
1132 0 : *roff = s - orig_string;
1133 0 : *rlen = 1;
1134 0 : err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1135 0 : goto leave;
1136 : }
1137 64 : *endp = *s? (s+1):s;
1138 :
1139 64 : if (writer)
1140 : { /* write out the data */
1141 :
1142 : /* need to calculate the length in advance */
1143 14 : n1 = _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, oidlen);
1144 14 : n1 += oidlen;
1145 14 : n1 += _ksba_ber_count_tl (valuetype, CLASS_UNIVERSAL, 0, valuelen);
1146 14 : n1 += valuelen;
1147 :
1148 : /* The SET tag */
1149 14 : n = _ksba_ber_count_tl (TYPE_SET, CLASS_UNIVERSAL, 1, n);
1150 14 : n += n1;
1151 14 : err = _ksba_ber_write_tl (writer, TYPE_SET, CLASS_UNIVERSAL, 1, n);
1152 :
1153 : /* The sequence tag */
1154 14 : n = n1;
1155 14 : err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
1156 :
1157 : /* the OBJECT ID */
1158 14 : err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID, CLASS_UNIVERSAL,
1159 : 0, oidlen);
1160 14 : if (!err)
1161 14 : err = ksba_writer_write (writer, oid, oidlen);
1162 14 : if (err)
1163 0 : goto leave;
1164 :
1165 : /* the value. Note that we don't need any conversion to the target
1166 : characters set because the input is expected to be utf8 and the
1167 : target type is either utf8, IA5 or printable string where the last
1168 : two are subsets of utf8 */
1169 14 : err = _ksba_ber_write_tl (writer, valuetype,
1170 : CLASS_UNIVERSAL, 0, valuelen);
1171 14 : if (!err)
1172 28 : err = need_escaping? write_escaped (writer, value, valuelen)
1173 28 : : ksba_writer_write (writer, value, valuelen);
1174 : }
1175 :
1176 : leave:
1177 80 : xfree (oidbuf);
1178 80 : xfree (valuebuf);
1179 80 : return err;
1180 : }
1181 :
1182 :
1183 :
1184 : gpg_error_t
1185 15 : _ksba_dn_from_str (const char *string, char **rbuf, size_t *rlength)
1186 : {
1187 : gpg_error_t err;
1188 : ksba_writer_t writer;
1189 : const char *s, *endp;
1190 15 : void *buf = NULL;
1191 : size_t buflen;
1192 15 : char const **part_array = NULL;
1193 : int part_array_size, nparts;
1194 :
1195 15 : *rbuf = NULL; *rlength = 0;
1196 : /* We are going to build the object using a writer object. */
1197 15 : err = ksba_writer_new (&writer);
1198 15 : if (!err)
1199 15 : err = ksba_writer_set_mem (writer, 1024);
1200 15 : if (err)
1201 0 : return err;
1202 :
1203 : /* We must assign it in reverse order so we do it in 2 passes. */
1204 15 : part_array_size = 0;
1205 55 : for (nparts=0, s=string; s && *s;)
1206 : {
1207 35 : err = parse_rdn (s, &endp, NULL, NULL, NULL);
1208 35 : if (err)
1209 10 : goto leave;
1210 25 : if (nparts >= part_array_size)
1211 : {
1212 : char const **tmp;
1213 :
1214 14 : part_array_size += 2;
1215 14 : tmp = part_array_size? xtryrealloc (part_array,
1216 : part_array_size * sizeof *tmp)
1217 0 : : xtrymalloc (part_array_size * sizeof *tmp);
1218 14 : if (!tmp)
1219 : {
1220 0 : err = gpg_error (GPG_ERR_ENOMEM);
1221 0 : goto leave;
1222 : }
1223 14 : part_array = tmp;
1224 : }
1225 25 : part_array[nparts++] = s;
1226 25 : s = endp;
1227 : }
1228 5 : if (!nparts)
1229 : {
1230 0 : err = gpg_error (GPG_ERR_SYNTAX);
1231 0 : goto leave;
1232 : }
1233 :
1234 24 : while (--nparts >= 0)
1235 : {
1236 14 : err = parse_rdn (part_array[nparts], &endp, writer, NULL, NULL);
1237 14 : if (err)
1238 0 : goto leave;
1239 : }
1240 :
1241 : /* Now get the memory. */
1242 5 : buf = ksba_writer_snatch_mem (writer, &buflen);
1243 5 : if (!buf)
1244 : {
1245 0 : err = gpg_error (GPG_ERR_ENOMEM);
1246 0 : goto leave;
1247 : }
1248 : /* Reinitialize the buffer to create the outer sequence. */
1249 5 : err = ksba_writer_set_mem (writer, buflen + 10);
1250 5 : if (err)
1251 0 : goto leave;
1252 :
1253 : /* write the outer sequence */
1254 5 : err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE,
1255 : CLASS_UNIVERSAL, 1, buflen);
1256 5 : if (err)
1257 0 : goto leave;
1258 : /* write the collected sets */
1259 5 : err = ksba_writer_write (writer, buf, buflen);
1260 5 : if (err)
1261 0 : goto leave;
1262 :
1263 : /* and get the result */
1264 5 : *rbuf = ksba_writer_snatch_mem (writer, rlength);
1265 5 : if (!*rbuf)
1266 : {
1267 0 : err = gpg_error (GPG_ERR_ENOMEM);
1268 0 : goto leave;
1269 : }
1270 :
1271 : leave:
1272 15 : xfree (part_array);
1273 15 : ksba_writer_release (writer);
1274 15 : xfree (buf);
1275 15 : return err;
1276 : }
1277 :
1278 :
1279 :
1280 : gpg_error_t
1281 0 : ksba_dn_der2str (const void *der, size_t derlen, char **rstring)
1282 : {
1283 0 : return _ksba_derdn_to_str (der, derlen, rstring);
1284 : }
1285 :
1286 :
1287 : gpg_error_t
1288 15 : ksba_dn_str2der (const char *string, unsigned char **rder, size_t *rderlen)
1289 : {
1290 15 : return _ksba_dn_from_str (string, (char**)rder, rderlen);
1291 : }
1292 :
1293 :
1294 :
1295 : /* Assuming that STRING contains an rfc2253 encoded string, test
1296 : whether this string may be passed as a valid DN to libksba. On
1297 : success the functions returns 0. On error the function returns an
1298 : error code and stores the offset within STRING of the erroneous
1299 : part at RERROFF. RERRLEN will then receive the length of the
1300 : erroneous part. This function is most useful to test whether a
1301 : symbolic name (like SN) is supported. SEQ should be passed as 0 for
1302 : now. RERROFF and RERRLEN may be passed as NULL if the caller is
1303 : not interested at this value. */
1304 : gpg_error_t
1305 15 : ksba_dn_teststr (const char *string, int seq,
1306 : size_t *rerroff, size_t *rerrlen)
1307 : {
1308 : size_t dummy_erroff, dummy_errlen;
1309 : gpg_error_t err;
1310 : int nparts;
1311 : const char *s, *endp;
1312 : size_t off, len;
1313 :
1314 15 : if (!rerroff)
1315 0 : rerroff = &dummy_erroff;
1316 15 : if (!rerrlen)
1317 0 : rerrlen = &dummy_errlen;
1318 :
1319 15 : *rerrlen = *rerroff = 0;
1320 :
1321 40 : for (nparts=0, s=string; s && *s; nparts++)
1322 : {
1323 35 : err = parse_rdn (s, &endp, NULL, &off, &len);
1324 35 : if (err && !seq--)
1325 : {
1326 10 : *rerroff = s - string + off;
1327 10 : *rerrlen = len? len : strlen (s);
1328 10 : return err;
1329 : }
1330 25 : s = endp;
1331 : }
1332 5 : if (!nparts)
1333 0 : return gpg_error (GPG_ERR_SYNTAX);
1334 5 : return 0;
1335 : }
|