1 /* certdump.c - Dump a certificate for debugging
2 * Copyright (C) 2001, 2004, 2007 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 3 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, see <http://www.gnu.org/licenses/>.
31 #ifdef HAVE_LANGINFO_CODESET
51 /* Print the first element of an S-Expression. */
53 gpgsm_print_serial (estream_t fp
, ksba_const_sexp_t sn
)
55 const char *p
= (const char *)sn
;
60 es_fputs (_("none"), fp
);
62 es_fputs ("[Internal error - not an S-expression]", fp
);
66 n
= strtoul (p
, &endp
, 10);
69 es_fputs ("[Internal Error - invalid S-expression]", fp
);
71 es_write_hexstring (fp
, p
, n
, 0, NULL
);
76 /* Dump the serial number or any other simple S-expression. */
78 gpgsm_dump_serial (ksba_const_sexp_t sn
)
80 const char *p
= (const char *)sn
;
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", *(const unsigned char *)p
);
105 gpgsm_format_serial (ksba_const_sexp_t sn
)
107 const char *p
= (const char *)sn
;
117 BUG (); /* Not a valid S-expression. */
120 n
= strtoul (p
, &endp
, 10);
123 BUG (); /* Not a valid S-expression. */
126 buffer
= xtrymalloc (n
*2+1);
129 for (i
=0; n
; n
--, p
++, i
+=2)
130 sprintf (buffer
+i
, "%02X", *(unsigned char *)p
);
140 gpgsm_print_time (estream_t fp
, ksba_isotime_t t
)
143 es_fputs (_("none"), fp
);
145 es_fprintf (fp
, "%.4s-%.2s-%.2s %.2s:%.2s:%s",
146 t
, t
+4, t
+6, t
+9, t
+11, t
+13);
151 gpgsm_dump_time (ksba_isotime_t t
)
154 log_printf (_("[none]"));
156 log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
157 t
, t
+4, t
+6, t
+9, t
+11, t
+13);
164 gpgsm_dump_string (const char *string
)
168 log_printf ("[error]");
171 const unsigned char *s
;
173 for (s
=(const unsigned char*)string
; *s
; s
++)
175 if (*s
< ' ' || (*s
>= 0x7f && *s
<= 0xa0))
178 if (!*s
&& *string
!= '[')
179 log_printf ("%s", string
);
183 log_printhex (NULL
, string
, strlen (string
));
190 /* This simple dump function is mainly used for debugging purposes. */
192 gpgsm_dump_cert (const char *text
, ksba_cert_t cert
)
199 log_debug ("BEGIN Certificate `%s':\n", text
? text
:"");
202 sexp
= ksba_cert_get_serial (cert
);
203 log_debug (" serial: ");
204 gpgsm_dump_serial (sexp
);
208 ksba_cert_get_validity (cert
, 0, t
);
209 log_debug (" notBefore: ");
212 ksba_cert_get_validity (cert
, 1, t
);
213 log_debug (" notAfter: ");
217 dn
= ksba_cert_get_issuer (cert
, 0);
218 log_debug (" issuer: ");
219 gpgsm_dump_string (dn
);
223 dn
= ksba_cert_get_subject (cert
, 0);
224 log_debug (" subject: ");
225 gpgsm_dump_string (dn
);
229 log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert
));
231 p
= gpgsm_get_fingerprint_string (cert
, 0);
232 log_debug (" SHA1 Fingerprint: %s\n", p
);
235 log_debug ("END Certificate\n");
239 /* Return a new string holding the format serial number and issuer
240 ("#SN/issuer"). No filtering on invalid characters is done.
241 Caller must release the string. On memory failure NULL is
244 gpgsm_format_sn_issuer (ksba_sexp_t sn
, const char *issuer
)
250 p1
= gpgsm_format_serial (sn
);
252 p
= xtrystrdup ("[invalid SN]");
255 p
= xtrymalloc (strlen (p1
) + strlen (issuer
) + 2 + 1);
259 strcpy (stpcpy (stpcpy (p
+1, p1
),"/"), issuer
);
265 p
= xtrystrdup ("[invalid SN/issuer]");
270 /* Log the certificate's name in "#SN/ISSUERDN" format along with
273 gpgsm_cert_log_name (const char *text
, ksba_cert_t cert
)
275 log_info ("%s", text
? text
:"certificate" );
281 p
= ksba_cert_get_issuer (cert
, 0);
282 sn
= ksba_cert_get_serial (cert
);
286 gpgsm_dump_serial (sn
);
288 gpgsm_dump_string (p
);
291 log_printf (" [invalid]");
303 /* helper for the rfc2253 string parser */
304 static const unsigned char *
305 parse_dn_part (struct dn_array_s
*array
, const unsigned char *string
)
311 /* Warning: When adding new labels, make sure that the buffer
312 below we be allocated large enough. */
313 {"EMail", "1.2.840.113549.1.9.1" },
317 {"NameDistinguisher", "0.2.262.1.10.7.20"},
318 {"ADDR", "2.5.4.16" },
321 {"PostalCode", "2.5.4.17" },
322 {"Pseudo", "2.5.4.65" },
323 {"SerialNumber", "2.5.4.5" },
326 const unsigned char *s
, *s1
;
331 /* Parse attributeType */
332 for (s
= string
+1; *s
&& *s
!= '='; s
++)
335 return NULL
; /* error */
338 return NULL
; /* empty key */
340 /* We need to allocate a few bytes more due to the possible mapping
341 from the shorter OID to the longer label. */
342 array
->key
= p
= xtrymalloc (n
+10);
345 memcpy (p
, string
, n
);
347 trim_trailing_spaces (p
);
351 for (i
=0; label_map
[i
].label
; i
++ )
352 if ( !strcmp (p
, label_map
[i
].oid
) )
354 strcpy (p
, label_map
[i
].label
);
363 for (s
=string
; hexdigitp (s
); s
++)
367 return NULL
; /* Empty or odd number of digits. */
369 array
->value
= p
= xtrymalloc (n
+1);
372 for (s1
=string
; n
; s1
+= 2, n
--, p
++)
374 *(unsigned char *)p
= xtoi_2 (s1
);
376 *p
= 0x01; /* Better print a wrong value than truncating
382 { /* regular v3 quoted string */
383 for (n
=0, s
=string
; *s
; s
++)
388 if (*s
== ',' || *s
== '=' || *s
== '+'
389 || *s
== '<' || *s
== '>' || *s
== '#' || *s
== ';'
390 || *s
== '\\' || *s
== '\"' || *s
== ' ')
392 else if (hexdigitp (s
) && hexdigitp (s
+1))
398 return NULL
; /* invalid escape sequence */
401 return NULL
; /* invalid encoding */
402 else if (*s
== ',' || *s
== '=' || *s
== '+'
403 || *s
== '<' || *s
== '>' || *s
== ';' )
409 array
->value
= p
= xtrymalloc (n
+1);
412 for (s
=string
; n
; s
++, n
--)
419 *(unsigned char *)p
++ = xtoi_2 (s
);
434 /* Parse a DN and return an array-ized one. This is not a validating
435 parser and it does not support any old-stylish syntax; KSBA is
436 expected to return only rfc2253 compatible strings. */
437 static struct dn_array_s
*
438 parse_dn (const unsigned char *string
)
440 struct dn_array_s
*array
;
441 size_t arrayidx
, arraysize
;
444 arraysize
= 7; /* C,ST,L,O,OU,CN,email */
446 array
= xtrymalloc ((arraysize
+1) * sizeof *array
);
451 while (*string
== ' ')
455 if (arrayidx
>= arraysize
)
457 struct dn_array_s
*a2
;
460 a2
= xtryrealloc (array
, (arraysize
+1) * sizeof *array
);
465 array
[arrayidx
].key
= NULL
;
466 array
[arrayidx
].value
= NULL
;
467 string
= parse_dn_part (array
+arrayidx
, string
);
470 while (*string
== ' ')
472 array
[arrayidx
].multivalued
= (*string
== '+');
473 array
[arrayidx
].done
= 0;
475 if (*string
&& *string
!= ',' && *string
!= ';' && *string
!= '+')
476 goto failure
; /* invalid delimiter */
480 array
[arrayidx
].key
= NULL
;
481 array
[arrayidx
].value
= NULL
;
485 for (i
=0; i
< arrayidx
; i
++)
487 xfree (array
[i
].key
);
488 xfree (array
[i
].value
);
495 /* Print a DN part to STREAM or if STREAM is NULL to FP. */
497 print_dn_part (FILE *fp
, estream_t stream
,
498 struct dn_array_s
*dn
, const char *key
, int translate
)
500 struct dn_array_s
*first_dn
= dn
;
502 for (; dn
->key
; dn
++)
504 if (!dn
->done
&& !strcmp (dn
->key
, key
))
506 /* Forward to the last multi-valued RDN, so that we can
507 print them all in reverse in the correct order. Note
508 that this overrides the the standard sequence but that
509 seems to a reasonable thing to do with multi-valued
511 while (dn
->multivalued
&& dn
[1].key
)
514 if (!dn
->done
&& dn
->value
&& *dn
->value
)
518 es_fprintf (stream
, "/%s=", dn
->key
);
520 es_write_sanitized_utf8_buffer (stream
, dn
->value
,
524 es_write_sanitized (stream
, dn
->value
, strlen (dn
->value
),
529 fprintf (fp
, "/%s=", dn
->key
);
531 print_sanitized_utf8_string (fp
, dn
->value
, '/');
533 print_sanitized_string (fp
, dn
->value
, '/');
537 if (dn
> first_dn
&& dn
[-1].multivalued
)
546 /* Print all parts of a DN in a "standard" sequence. We first print
547 all the known parts, followed by the uncommon ones */
549 print_dn_parts (FILE *fp
, estream_t stream
,
550 struct dn_array_s
*dn
, int translate
)
552 const char *stdpart
[] = {
553 "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL
557 for (i
=0; stdpart
[i
]; i
++)
558 print_dn_part (fp
, stream
, dn
, stdpart
[i
], translate
);
560 /* Now print the rest without any specific ordering */
561 for (; dn
->key
; dn
++)
562 print_dn_part (fp
, stream
, dn
, dn
->key
, translate
);
566 /* Print the S-Expression in BUF, which has a valid length of BUFLEN,
567 as a human readable string in one line to FP. */
569 pretty_print_sexp (FILE *fp
, const unsigned char *buf
, size_t buflen
)
575 if ( gcry_sexp_sscan (&sexp
, NULL
, (const char*)buf
, buflen
) )
577 fputs (_("[Error - invalid encoding]"), fp
);
580 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, NULL
, 0);
582 result
= xtrymalloc (len
);
585 fputs (_("[Error - out of core]"), fp
);
586 gcry_sexp_release (sexp
);
589 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, result
, len
);
591 for (p
= result
; len
; len
--, p
++)
595 if (len
> 1) /* Avoid printing the trailing LF. */
608 gcry_sexp_release (sexp
);
611 /* Print the S-Expression in BUF to extended STREAM, which has a valid
612 length of BUFLEN, as a human readable string in one line to FP. */
614 pretty_es_print_sexp (estream_t fp
, const unsigned char *buf
, size_t buflen
)
620 if ( gcry_sexp_sscan (&sexp
, NULL
, (const char*)buf
, buflen
) )
622 es_fputs (_("[Error - invalid encoding]"), fp
);
625 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, NULL
, 0);
627 result
= xtrymalloc (len
);
630 es_fputs (_("[Error - out of core]"), fp
);
631 gcry_sexp_release (sexp
);
634 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, result
, len
);
636 for (p
= result
; len
; len
--, p
++)
640 if (len
> 1) /* Avoid printing the trailing LF. */
641 es_fputs ("\\n", fp
);
644 es_fputs ("\\r", fp
);
646 es_fputs ("\\v", fp
);
648 es_fputs ("\\t", fp
);
653 gcry_sexp_release (sexp
);
660 gpgsm_print_name2 (FILE *fp
, const char *name
, int translate
)
662 const unsigned char *s
= (const unsigned char *)name
;
667 fputs (_("[Error - No name]"), fp
);
671 const char *s2
= strchr ( (char*)s
+1, '>');
675 print_sanitized_utf8_buffer (fp
, s
+ 1, s2
- (char*)s
- 1, 0);
677 print_sanitized_buffer (fp
, s
+ 1, s2
- (char*)s
- 1, 0);
682 pretty_print_sexp (fp
, s
, gcry_sexp_canon_len (s
, 0, NULL
, NULL
));
684 else if (!((*s
>= '0' && *s
< '9')
685 || (*s
>= 'A' && *s
<= 'Z')
686 || (*s
>= 'a' && *s
<= 'z')))
687 fputs (_("[Error - invalid encoding]"), fp
);
690 struct dn_array_s
*dn
= parse_dn (s
);
692 fputs (_("[Error - invalid DN]"), fp
);
695 print_dn_parts (fp
, NULL
, dn
, translate
);
696 for (i
=0; dn
[i
].key
; i
++)
708 gpgsm_print_name (FILE *fp
, const char *name
)
710 gpgsm_print_name2 (fp
, name
, 1);
714 /* This is a variant of gpgsm_print_name sending it output to an estream. */
716 gpgsm_es_print_name2 (estream_t fp
, const char *name
, int translate
)
718 const unsigned char *s
= (const unsigned char *)name
;
723 es_fputs (_("[Error - No name]"), fp
);
727 const char *s2
= strchr ( (char*)s
+1, '>');
732 es_write_sanitized_utf8_buffer (fp
, s
+ 1, s2
- (char*)s
- 1,
735 es_write_sanitized (fp
, s
+ 1, s2
- (char*)s
- 1, NULL
, NULL
);
740 pretty_es_print_sexp (fp
, s
, gcry_sexp_canon_len (s
, 0, NULL
, NULL
));
742 else if (!((*s
>= '0' && *s
< '9')
743 || (*s
>= 'A' && *s
<= 'Z')
744 || (*s
>= 'a' && *s
<= 'z')))
745 es_fputs (_("[Error - invalid encoding]"), fp
);
748 struct dn_array_s
*dn
= parse_dn (s
);
751 es_fputs (_("[Error - invalid DN]"), fp
);
754 print_dn_parts (NULL
, fp
, dn
, translate
);
755 for (i
=0; dn
[i
].key
; i
++)
767 gpgsm_es_print_name (estream_t fp
, const char *name
)
769 gpgsm_es_print_name2 (fp
, name
, 1);
773 /* A cookie structure used for the memory stream. */
774 struct format_name_cookie
776 char *buffer
; /* Malloced buffer with the data to deliver. */
777 size_t size
; /* Allocated size of this buffer. */
778 size_t len
; /* strlen (buffer). */
779 int error
; /* system error code if any. */
782 /* The writer function for the memory stream. */
784 format_name_writer (void *cookie
, const void *buffer
, size_t size
)
786 struct format_name_cookie
*c
= cookie
;
791 p
= xtrymalloc (size
+ 1 + 1);
799 else if (c
->len
+ size
< c
->len
)
804 else if (c
->size
< c
->len
+ size
)
806 p
= xtryrealloc (c
->buffer
, c
->len
+ size
+ 1);
809 c
->size
= c
->len
+ size
;
823 memcpy (p
+ c
->len
, buffer
, size
);
825 p
[c
->len
] = 0; /* Terminate string. */
827 return (ssize_t
)size
;
831 /* Format NAME which is expected to be in rfc2253 format into a better
832 human readable format. Caller must free the returned string. NULL
833 is returned in case of an error. With TRANSLATE set to true the
834 name will be translated to the native encoding. Note that NAME is
835 internally always UTF-8 encoded. */
837 gpgsm_format_name2 (const char *name
, int translate
)
840 struct format_name_cookie cookie
;
841 es_cookie_io_functions_t io
= { NULL
};
843 memset (&cookie
, 0, sizeof cookie
);
845 io
.func_write
= format_name_writer
;
846 fp
= es_fopencookie (&cookie
, "w", io
);
849 int save_errno
= errno
;
850 log_error ("error creating memory stream: %s\n", strerror (errno
));
854 gpgsm_es_print_name2 (fp
, name
, translate
);
856 if (cookie
.error
|| !cookie
.buffer
)
858 xfree (cookie
.buffer
);
859 errno
= cookie
.error
;
862 return cookie
.buffer
;
867 gpgsm_format_name (const char *name
)
869 return gpgsm_format_name2 (name
, 1);
873 /* Return fingerprint and a percent escaped name in a human readable
874 format suitable for status messages like GOODSIG. May return NULL
875 on error (out of core). */
877 gpgsm_fpr_and_name_for_status (ksba_cert_t cert
)
879 char *fpr
, *name
, *p
;
882 fpr
= gpgsm_get_fingerprint_hexstring (cert
, GCRY_MD_SHA1
);
886 name
= ksba_cert_get_subject (cert
, 0);
893 p
= gpgsm_format_name2 (name
, 0);
902 buffer
= xtrymalloc (strlen (fpr
) + 1 + 3*strlen (name
) + 1);
907 p
= stpcpy (stpcpy (buffer
, fpr
), " ");
908 for (s
= name
; *s
; s
++)
912 sprintf (p
, "%%%02X", *(const unsigned char*)s
);
926 /* Create a key description for the CERT, this may be passed to the
927 pinentry. The caller must free the returned string. NULL may be
928 returned on error. */
930 gpgsm_format_keydesc (ksba_cert_t cert
)
932 char *name
, *subject
, *buffer
;
940 name
= ksba_cert_get_subject (cert
, 0);
941 subject
= name
? gpgsm_format_name2 (name
, 0) : NULL
;
942 ksba_free (name
); name
= NULL
;
944 sexp
= ksba_cert_get_serial (cert
);
945 sn
= sexp
? gpgsm_format_serial (sexp
) : NULL
;
948 ksba_cert_get_validity (cert
, 0, t
);
950 sprintf (created
, "%.4s-%.2s-%.2s", t
, t
+4, t
+6);
953 ksba_cert_get_validity (cert
, 1, t
);
955 sprintf (expires
, "%.4s-%.2s-%.2s", t
, t
+4, t
+6);
959 orig_codeset
= i18n_switchto_utf8 ();
961 name
= xtryasprintf (_("Please enter the passphrase to unlock the"
962 " secret key for the X.509 certificate:\n"
964 "S/N %s, ID 0x%08lX,\n"
965 "created %s, expires %s.\n" ),
966 subject
? subject
:"?",
968 gpgsm_get_short_fingerprint (cert
),
971 i18n_switchback (orig_codeset
);
983 buffer
= percent_plus_escape (name
);