1 /* certdump.c - Dump a certificate for debugging
2 * Copyright (C) 2001, 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
32 #ifdef HAVE_LANGINFO_CODESET
51 /* print the first element of an S-Expression */
53 gpgsm_print_serial (FILE *fp
, ksba_const_sexp_t p
)
59 fputs (_("none"), fp
);
61 fputs ("[Internal error - not an S-expression]", fp
);
65 n
= strtoul (p
, &endp
, 10);
68 fputs ("[Internal Error - invalid S-expression]", fp
);
71 for (p
++; n
; n
--, p
++)
72 fprintf (fp
, "%02X", *p
);
79 gpgsm_dump_serial (ksba_const_sexp_t p
)
87 log_printf ("ERROR - not an S-expression");
91 n
= strtoul (p
, &endp
, 10);
94 log_printf ("ERROR - invalid S-expression");
97 for (p
++; n
; n
--, p
++)
98 log_printf ("%02X", *p
);
105 gpgsm_format_serial (ksba_const_sexp_t p
)
116 BUG (); /* Not a valid S-expression. */
119 n
= strtoul (p
, &endp
, 10);
122 BUG (); /* Not a valid S-expression. */
125 buffer
= xtrymalloc (n
*2+1);
128 for (i
=0; n
; n
--, p
++, i
+=2)
129 sprintf (buffer
+i
, "%02X", *(unsigned char *)p
);
139 gpgsm_print_time (FILE *fp
, ksba_isotime_t t
)
142 fputs (_("none"), fp
);
144 fprintf (fp
, "%.4s-%.2s-%.2s %.2s:%.2s:%s", t
, t
+4, t
+6, t
+9, t
+11, t
+13);
148 gpgsm_dump_time (ksba_isotime_t t
)
151 log_printf (_("[none]"));
153 log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
154 t
, t
+4, t
+6, t
+9, t
+11, t
+13);
161 gpgsm_dump_string (const char *string
)
165 log_printf ("[error]");
168 const unsigned char *s
;
170 for (s
=string
; *s
; s
++)
172 if (*s
< ' ' || (*s
>= 0x7f && *s
<= 0xa0))
175 if (!*s
&& *string
!= '[')
176 log_printf ("%s", string
);
180 log_printhex (NULL
, string
, strlen (string
));
187 /* This simple dump function is mainly used for debugging purposes. */
189 gpgsm_dump_cert (const char *text
, ksba_cert_t cert
)
196 log_debug ("BEGIN Certificate `%s':\n", text
? text
:"");
199 sexp
= ksba_cert_get_serial (cert
);
200 log_debug (" serial: ");
201 gpgsm_dump_serial (sexp
);
205 ksba_cert_get_validity (cert
, 0, t
);
206 log_debug (" notBefore: ");
209 ksba_cert_get_validity (cert
, 1, t
);
210 log_debug (" notAfter: ");
214 dn
= ksba_cert_get_issuer (cert
, 0);
215 log_debug (" issuer: ");
216 gpgsm_dump_string (dn
);
220 dn
= ksba_cert_get_subject (cert
, 0);
221 log_debug (" subject: ");
222 gpgsm_dump_string (dn
);
226 log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert
));
228 p
= gpgsm_get_fingerprint_string (cert
, 0);
229 log_debug (" SHA1 Fingerprint: %s\n", p
);
232 log_debug ("END Certificate\n");
237 /* helper for the rfc2253 string parser */
238 static const unsigned char *
239 parse_dn_part (struct dn_array_s
*array
, const unsigned char *string
)
245 /* Warning: When adding new labels, make sure that the buffer
246 below we be allocated large enough. */
247 {"EMail", "1.2.840.113549.1.9.1" },
251 {"NameDistinguisher", "0.2.262.1.10.7.20"},
252 {"ADDR", "2.5.4.16" },
255 {"PostalCode", "2.5.4.17" },
256 {"Pseudo", "2.5.4.65" },
257 {"SerialNumber", "2.5.4.5" },
260 const unsigned char *s
, *s1
;
265 /* Parse attributeType */
266 for (s
= string
+1; *s
&& *s
!= '='; s
++)
269 return NULL
; /* error */
272 return NULL
; /* empty key */
274 /* We need to allocate a few bytes more due to the possible mapping
275 from the shorter OID to the longer label. */
276 array
->key
= p
= xtrymalloc (n
+10);
279 memcpy (p
, string
, n
);
281 trim_trailing_spaces (p
);
285 for (i
=0; label_map
[i
].label
; i
++ )
286 if ( !strcmp (p
, label_map
[i
].oid
) )
288 strcpy (p
, label_map
[i
].label
);
297 for (s
=string
; hexdigitp (s
); s
++)
301 return NULL
; /* Empty or odd number of digits. */
303 array
->value
= p
= xtrymalloc (n
+1);
306 for (s1
=string
; n
; s1
+= 2, n
--, p
++)
310 *p
= 0x01; /* Better print a wrong value than truncating
316 { /* regular v3 quoted string */
317 for (n
=0, s
=string
; *s
; s
++)
322 if (*s
== ',' || *s
== '=' || *s
== '+'
323 || *s
== '<' || *s
== '>' || *s
== '#' || *s
== ';'
324 || *s
== '\\' || *s
== '\"' || *s
== ' ')
326 else if (hexdigitp (s
) && hexdigitp (s
+1))
332 return NULL
; /* invalid escape sequence */
335 return NULL
; /* invalid encoding */
336 else if (*s
== ',' || *s
== '=' || *s
== '+'
337 || *s
== '<' || *s
== '>' || *s
== '#' || *s
== ';' )
343 array
->value
= p
= xtrymalloc (n
+1);
346 for (s
=string
; n
; s
++, n
--)
368 /* Parse a DN and return an array-ized one. This is not a validating
369 parser and it does not support any old-stylish syntax; KSBA is
370 expected to return only rfc2253 compatible strings. */
371 static struct dn_array_s
*
372 parse_dn (const unsigned char *string
)
374 struct dn_array_s
*array
;
375 size_t arrayidx
, arraysize
;
378 arraysize
= 7; /* C,ST,L,O,OU,CN,email */
380 array
= xtrymalloc ((arraysize
+1) * sizeof *array
);
385 while (*string
== ' ')
389 if (arrayidx
>= arraysize
)
391 struct dn_array_s
*a2
;
394 a2
= xtryrealloc (array
, (arraysize
+1) * sizeof *array
);
399 array
[arrayidx
].key
= NULL
;
400 array
[arrayidx
].value
= NULL
;
401 string
= parse_dn_part (array
+arrayidx
, string
);
404 while (*string
== ' ')
406 array
[arrayidx
].multivalued
= (*string
== '+');
407 array
[arrayidx
].done
= 0;
409 if (*string
&& *string
!= ',' && *string
!= ';' && *string
!= '+')
410 goto failure
; /* invalid delimiter */
414 array
[arrayidx
].key
= NULL
;
415 array
[arrayidx
].value
= NULL
;
419 for (i
=0; i
< arrayidx
; i
++)
421 xfree (array
[i
].key
);
422 xfree (array
[i
].value
);
430 print_dn_part (FILE *fp
, struct dn_array_s
*dn
, const char *key
, int translate
)
432 struct dn_array_s
*first_dn
= dn
;
434 for (; dn
->key
; dn
++)
436 if (!dn
->done
&& !strcmp (dn
->key
, key
))
438 /* Forward to the last multi-valued RDN, so that we can
439 print them all in reverse in the correct order. Note
440 that this overrides the the standard sequence but that
441 seems to a reasonable thing to do with multi-valued
443 while (dn
->multivalued
&& dn
[1].key
)
446 if (!dn
->done
&& dn
->value
&& *dn
->value
)
448 fprintf (fp
, "/%s=", dn
->key
);
450 print_sanitized_utf8_string (fp
, dn
->value
, '/');
452 print_sanitized_string (fp
, dn
->value
, '/');
455 if (dn
> first_dn
&& dn
[-1].multivalued
)
464 /* Print all parts of a DN in a "standard" sequence. We first print
465 all the known parts, followed by the uncommon ones */
467 print_dn_parts (FILE *fp
, struct dn_array_s
*dn
, int translate
)
469 const char *stdpart
[] = {
470 "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL
474 for (i
=0; stdpart
[i
]; i
++)
475 print_dn_part (fp
, dn
, stdpart
[i
], translate
);
477 /* Now print the rest without any specific ordering */
478 for (; dn
->key
; dn
++)
479 print_dn_part (fp
, dn
, dn
->key
, translate
);
485 gpgsm_print_name2 (FILE *fp
, const char *name
, int translate
)
487 const unsigned char *s
;
493 fputs (_("[Error - No name]"), fp
);
497 const unsigned char *s2
= strchr (s
+1, '>');
501 print_sanitized_utf8_buffer (fp
, s
+ 1, s2
- s
- 1, 0);
503 print_sanitized_buffer (fp
, s
+ 1, s2
- s
- 1, 0);
507 fputs (_("[Error - unknown encoding]"), fp
);
508 else if (!((*s
>= '0' && *s
< '9')
509 || (*s
>= 'A' && *s
<= 'Z')
510 || (*s
>= 'a' && *s
<= 'z')))
511 fputs (_("[Error - invalid encoding]"), fp
);
514 struct dn_array_s
*dn
= parse_dn (s
);
516 fputs (_("[Error - invalid DN]"), fp
);
519 print_dn_parts (fp
, dn
, translate
);
520 for (i
=0; dn
[i
].key
; i
++)
532 gpgsm_print_name (FILE *fp
, const char *name
)
534 gpgsm_print_name2 (fp
, name
, 1);
538 /* A cookie structure used for the memory stream. */
539 struct format_name_cookie
541 char *buffer
; /* Malloced buffer with the data to deliver. */
542 size_t size
; /* Allocated size of this buffer. */
543 size_t len
; /* strlen (buffer). */
544 int error
; /* system error code if any. */
547 /* The writer function for the memory stream. */
549 format_name_writer (void *cookie
, const char *buffer
, size_t size
)
551 struct format_name_cookie
*c
= cookie
;
555 p
= xtryrealloc (c
->buffer
, c
->size
+ size
+ 1);
557 p
= xtrymalloc (size
+ 1);
566 memcpy (p
+ c
->len
, buffer
, size
);
568 p
[c
->len
] = 0; /* Terminate string. */
573 /* Format NAME which is expected to be in rfc2253 format into a better
574 human readable format. Caller must free the returned string. NULL
575 is returned in case of an error. With TRANSLATE set to true the
576 name will be translated to the native encodig. Note that NAME is
577 internally always UTF-8 encoded. */
579 gpgsm_format_name2 (const char *name
, int translate
)
581 #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
583 struct format_name_cookie cookie
;
585 memset (&cookie
, 0, sizeof cookie
);
587 #ifdef HAVE_FOPENCOOKIE
589 cookie_io_functions_t io
= { NULL
};
590 io
.write
= format_name_writer
;
592 fp
= fopencookie (&cookie
, "w", io
);
594 #else /*!HAVE_FOPENCOOKIE*/
596 fp
= funopen (&cookie
, NULL
, format_name_writer
, NULL
, NULL
);
598 #endif /*!HAVE_FOPENCOOKIE*/
601 int save_errno
= errno
;
602 log_error ("error creating memory stream: %s\n", strerror (errno
));
606 gpgsm_print_name2 (fp
, name
, translate
);
608 if (cookie
.error
|| !cookie
.buffer
)
610 xfree (cookie
.buffer
);
611 errno
= cookie
.error
;
614 return cookie
.buffer
;
615 #else /* No fun - use the name verbatim. */
616 return xtrystrdup (name
);
621 gpgsm_format_name (const char *name
)
623 return gpgsm_format_name2 (name
, 1);
627 /* Create a key description for the CERT, this may be passed to the
628 pinentry. The caller must free the returned string. NULL may be
629 returned on error. */
631 gpgsm_format_keydesc (ksba_cert_t cert
)
634 char *name
, *subject
, *buffer
, *p
;
640 char *orig_codeset
= NULL
;
642 name
= ksba_cert_get_subject (cert
, 0);
643 subject
= name
? gpgsm_format_name2 (name
, 0) : NULL
;
644 ksba_free (name
); name
= NULL
;
646 sexp
= ksba_cert_get_serial (cert
);
647 sn
= sexp
? gpgsm_format_serial (sexp
) : NULL
;
650 ksba_cert_get_validity (cert
, 0, t
);
652 sprintf (created
, "%.4s-%.2s-%.2s", t
, t
+4, t
+6);
658 /* The Assuan agent protol requires us to transmit utf-8 strings */
659 orig_codeset
= bind_textdomain_codeset (PACKAGE_GT
, NULL
);
660 #ifdef HAVE_LANGINFO_CODESET
662 orig_codeset
= nl_langinfo (CODESET
);
665 { /* We only switch when we are able to restore the codeset later.
666 Note that bind_textdomain_codeset does only return on memory
667 errors but not if a codeset is not available. Thus we don't
668 bother printing a diagnostic here. */
669 orig_codeset
= xstrdup (orig_codeset
);
670 if (!bind_textdomain_codeset (PACKAGE_GT
, "utf-8"))
676 rc
= asprintf (&name
,
677 _("Please enter the passphrase to unlock the"
680 "S/N %s, ID %08lX, created %s" ),
681 subject
? subject
:"?",
683 gpgsm_get_short_fingerprint (cert
),
688 bind_textdomain_codeset (PACKAGE_GT
, orig_codeset
);
690 xfree (orig_codeset
);
694 int save_errno
= errno
;
704 buffer
= p
= xtrymalloc (strlen (name
) * 3 + 1);
705 for (s
=name
; *s
; s
++)
707 if (*s
< ' ' || *s
== '+')
709 sprintf (p
, "%%%02X", *(unsigned char *)s
);