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_string (const char *string
)
155 log_printf ("[error]");
158 const unsigned char *s
;
160 for (s
=(const unsigned char*)string
; *s
; s
++)
162 if (*s
< ' ' || (*s
>= 0x7f && *s
<= 0xa0))
165 if (!*s
&& *string
!= '[')
166 log_printf ("%s", string
);
170 log_printhex (NULL
, string
, strlen (string
));
177 /* This simple dump function is mainly used for debugging purposes. */
179 gpgsm_dump_cert (const char *text
, ksba_cert_t cert
)
186 log_debug ("BEGIN Certificate `%s':\n", text
? text
:"");
189 sexp
= ksba_cert_get_serial (cert
);
190 log_debug (" serial: ");
191 gpgsm_dump_serial (sexp
);
195 ksba_cert_get_validity (cert
, 0, t
);
196 log_debug (" notBefore: ");
199 ksba_cert_get_validity (cert
, 1, t
);
200 log_debug (" notAfter: ");
204 dn
= ksba_cert_get_issuer (cert
, 0);
205 log_debug (" issuer: ");
206 gpgsm_dump_string (dn
);
210 dn
= ksba_cert_get_subject (cert
, 0);
211 log_debug (" subject: ");
212 gpgsm_dump_string (dn
);
216 log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert
));
218 p
= gpgsm_get_fingerprint_string (cert
, 0);
219 log_debug (" SHA1 Fingerprint: %s\n", p
);
222 log_debug ("END Certificate\n");
226 /* Return a new string holding the format serial number and issuer
227 ("#SN/issuer"). No filtering on invalid characters is done.
228 Caller must release the string. On memory failure NULL is
231 gpgsm_format_sn_issuer (ksba_sexp_t sn
, const char *issuer
)
237 p1
= gpgsm_format_serial (sn
);
239 p
= xtrystrdup ("[invalid SN]");
242 p
= xtrymalloc (strlen (p1
) + strlen (issuer
) + 2 + 1);
246 strcpy (stpcpy (stpcpy (p
+1, p1
),"/"), issuer
);
252 p
= xtrystrdup ("[invalid SN/issuer]");
257 /* Log the certificate's name in "#SN/ISSUERDN" format along with
260 gpgsm_cert_log_name (const char *text
, ksba_cert_t cert
)
262 log_info ("%s", text
? text
:"certificate" );
268 p
= ksba_cert_get_issuer (cert
, 0);
269 sn
= ksba_cert_get_serial (cert
);
273 gpgsm_dump_serial (sn
);
275 gpgsm_dump_string (p
);
278 log_printf (" [invalid]");
290 /* helper for the rfc2253 string parser */
291 static const unsigned char *
292 parse_dn_part (struct dn_array_s
*array
, const unsigned char *string
)
298 /* Warning: When adding new labels, make sure that the buffer
299 below we be allocated large enough. */
300 {"EMail", "1.2.840.113549.1.9.1" },
304 {"NameDistinguisher", "0.2.262.1.10.7.20"},
305 {"ADDR", "2.5.4.16" },
308 {"PostalCode", "2.5.4.17" },
309 {"Pseudo", "2.5.4.65" },
310 {"SerialNumber", "2.5.4.5" },
313 const unsigned char *s
, *s1
;
318 /* Parse attributeType */
319 for (s
= string
+1; *s
&& *s
!= '='; s
++)
322 return NULL
; /* error */
325 return NULL
; /* empty key */
327 /* We need to allocate a few bytes more due to the possible mapping
328 from the shorter OID to the longer label. */
329 array
->key
= p
= xtrymalloc (n
+10);
332 memcpy (p
, string
, n
);
334 trim_trailing_spaces (p
);
338 for (i
=0; label_map
[i
].label
; i
++ )
339 if ( !strcmp (p
, label_map
[i
].oid
) )
341 strcpy (p
, label_map
[i
].label
);
350 for (s
=string
; hexdigitp (s
); s
++)
354 return NULL
; /* Empty or odd number of digits. */
356 array
->value
= p
= xtrymalloc (n
+1);
359 for (s1
=string
; n
; s1
+= 2, n
--, p
++)
361 *(unsigned char *)p
= xtoi_2 (s1
);
363 *p
= 0x01; /* Better print a wrong value than truncating
369 { /* regular v3 quoted string */
370 for (n
=0, s
=string
; *s
; s
++)
375 if (*s
== ',' || *s
== '=' || *s
== '+'
376 || *s
== '<' || *s
== '>' || *s
== '#' || *s
== ';'
377 || *s
== '\\' || *s
== '\"' || *s
== ' ')
379 else if (hexdigitp (s
) && hexdigitp (s
+1))
385 return NULL
; /* invalid escape sequence */
388 return NULL
; /* invalid encoding */
389 else if (*s
== ',' || *s
== '=' || *s
== '+'
390 || *s
== '<' || *s
== '>' || *s
== ';' )
396 array
->value
= p
= xtrymalloc (n
+1);
399 for (s
=string
; n
; s
++, n
--)
406 *(unsigned char *)p
++ = xtoi_2 (s
);
421 /* Parse a DN and return an array-ized one. This is not a validating
422 parser and it does not support any old-stylish syntax; KSBA is
423 expected to return only rfc2253 compatible strings. */
424 static struct dn_array_s
*
425 parse_dn (const unsigned char *string
)
427 struct dn_array_s
*array
;
428 size_t arrayidx
, arraysize
;
431 arraysize
= 7; /* C,ST,L,O,OU,CN,email */
433 array
= xtrymalloc ((arraysize
+1) * sizeof *array
);
438 while (*string
== ' ')
442 if (arrayidx
>= arraysize
)
444 struct dn_array_s
*a2
;
447 a2
= xtryrealloc (array
, (arraysize
+1) * sizeof *array
);
452 array
[arrayidx
].key
= NULL
;
453 array
[arrayidx
].value
= NULL
;
454 string
= parse_dn_part (array
+arrayidx
, string
);
457 while (*string
== ' ')
459 array
[arrayidx
].multivalued
= (*string
== '+');
460 array
[arrayidx
].done
= 0;
462 if (*string
&& *string
!= ',' && *string
!= ';' && *string
!= '+')
463 goto failure
; /* invalid delimiter */
467 array
[arrayidx
].key
= NULL
;
468 array
[arrayidx
].value
= NULL
;
472 for (i
=0; i
< arrayidx
; i
++)
474 xfree (array
[i
].key
);
475 xfree (array
[i
].value
);
482 /* Print a DN part to STREAM or if STREAM is NULL to FP. */
484 print_dn_part (FILE *fp
, estream_t stream
,
485 struct dn_array_s
*dn
, const char *key
, int translate
)
487 struct dn_array_s
*first_dn
= dn
;
489 for (; dn
->key
; dn
++)
491 if (!dn
->done
&& !strcmp (dn
->key
, key
))
493 /* Forward to the last multi-valued RDN, so that we can
494 print them all in reverse in the correct order. Note
495 that this overrides the the standard sequence but that
496 seems to a reasonable thing to do with multi-valued
498 while (dn
->multivalued
&& dn
[1].key
)
501 if (!dn
->done
&& dn
->value
&& *dn
->value
)
505 es_fprintf (stream
, "/%s=", dn
->key
);
507 es_write_sanitized_utf8_buffer (stream
, dn
->value
,
511 es_write_sanitized (stream
, dn
->value
, strlen (dn
->value
),
516 fprintf (fp
, "/%s=", dn
->key
);
518 print_sanitized_utf8_string (fp
, dn
->value
, '/');
520 print_sanitized_string (fp
, dn
->value
, '/');
524 if (dn
> first_dn
&& dn
[-1].multivalued
)
533 /* Print all parts of a DN in a "standard" sequence. We first print
534 all the known parts, followed by the uncommon ones */
536 print_dn_parts (FILE *fp
, estream_t stream
,
537 struct dn_array_s
*dn
, int translate
)
539 const char *stdpart
[] = {
540 "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL
544 for (i
=0; stdpart
[i
]; i
++)
545 print_dn_part (fp
, stream
, dn
, stdpart
[i
], translate
);
547 /* Now print the rest without any specific ordering */
548 for (; dn
->key
; dn
++)
549 print_dn_part (fp
, stream
, dn
, dn
->key
, translate
);
553 /* Print the S-Expression in BUF, which has a valid length of BUFLEN,
554 as a human readable string in one line to FP. */
556 pretty_print_sexp (FILE *fp
, const unsigned char *buf
, size_t buflen
)
562 if ( gcry_sexp_sscan (&sexp
, NULL
, (const char*)buf
, buflen
) )
564 fputs (_("[Error - invalid encoding]"), fp
);
567 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, NULL
, 0);
569 result
= xtrymalloc (len
);
572 fputs (_("[Error - out of core]"), fp
);
573 gcry_sexp_release (sexp
);
576 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, result
, len
);
578 for (p
= result
; len
; len
--, p
++)
582 if (len
> 1) /* Avoid printing the trailing LF. */
595 gcry_sexp_release (sexp
);
598 /* Print the S-Expression in BUF to extended STREAM, which has a valid
599 length of BUFLEN, as a human readable string in one line to FP. */
601 pretty_es_print_sexp (estream_t fp
, const unsigned char *buf
, size_t buflen
)
607 if ( gcry_sexp_sscan (&sexp
, NULL
, (const char*)buf
, buflen
) )
609 es_fputs (_("[Error - invalid encoding]"), fp
);
612 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, NULL
, 0);
614 result
= xtrymalloc (len
);
617 es_fputs (_("[Error - out of core]"), fp
);
618 gcry_sexp_release (sexp
);
621 len
= gcry_sexp_sprint (sexp
, GCRYSEXP_FMT_ADVANCED
, result
, len
);
623 for (p
= result
; len
; len
--, p
++)
627 if (len
> 1) /* Avoid printing the trailing LF. */
628 es_fputs ("\\n", fp
);
631 es_fputs ("\\r", fp
);
633 es_fputs ("\\v", fp
);
635 es_fputs ("\\t", fp
);
640 gcry_sexp_release (sexp
);
647 gpgsm_print_name2 (FILE *fp
, const char *name
, int translate
)
649 const unsigned char *s
= (const unsigned char *)name
;
654 fputs (_("[Error - No name]"), fp
);
658 const char *s2
= strchr ( (char*)s
+1, '>');
662 print_sanitized_utf8_buffer (fp
, s
+ 1, s2
- (char*)s
- 1, 0);
664 print_sanitized_buffer (fp
, s
+ 1, s2
- (char*)s
- 1, 0);
669 pretty_print_sexp (fp
, s
, gcry_sexp_canon_len (s
, 0, NULL
, NULL
));
671 else if (!((*s
>= '0' && *s
< '9')
672 || (*s
>= 'A' && *s
<= 'Z')
673 || (*s
>= 'a' && *s
<= 'z')))
674 fputs (_("[Error - invalid encoding]"), fp
);
677 struct dn_array_s
*dn
= parse_dn (s
);
679 fputs (_("[Error - invalid DN]"), fp
);
682 print_dn_parts (fp
, NULL
, dn
, translate
);
683 for (i
=0; dn
[i
].key
; i
++)
695 gpgsm_print_name (FILE *fp
, const char *name
)
697 gpgsm_print_name2 (fp
, name
, 1);
701 /* This is a variant of gpgsm_print_name sending it output to an estream. */
703 gpgsm_es_print_name2 (estream_t fp
, const char *name
, int translate
)
705 const unsigned char *s
= (const unsigned char *)name
;
710 es_fputs (_("[Error - No name]"), fp
);
714 const char *s2
= strchr ( (char*)s
+1, '>');
719 es_write_sanitized_utf8_buffer (fp
, s
+ 1, s2
- (char*)s
- 1,
722 es_write_sanitized (fp
, s
+ 1, s2
- (char*)s
- 1, NULL
, NULL
);
727 pretty_es_print_sexp (fp
, s
, gcry_sexp_canon_len (s
, 0, NULL
, NULL
));
729 else if (!((*s
>= '0' && *s
< '9')
730 || (*s
>= 'A' && *s
<= 'Z')
731 || (*s
>= 'a' && *s
<= 'z')))
732 es_fputs (_("[Error - invalid encoding]"), fp
);
735 struct dn_array_s
*dn
= parse_dn (s
);
738 es_fputs (_("[Error - invalid DN]"), fp
);
741 print_dn_parts (NULL
, fp
, dn
, translate
);
742 for (i
=0; dn
[i
].key
; i
++)
754 gpgsm_es_print_name (estream_t fp
, const char *name
)
756 gpgsm_es_print_name2 (fp
, name
, 1);
760 /* A cookie structure used for the memory stream. */
761 struct format_name_cookie
763 char *buffer
; /* Malloced buffer with the data to deliver. */
764 size_t size
; /* Allocated size of this buffer. */
765 size_t len
; /* strlen (buffer). */
766 int error
; /* system error code if any. */
769 /* The writer function for the memory stream. */
771 format_name_writer (void *cookie
, const void *buffer
, size_t size
)
773 struct format_name_cookie
*c
= cookie
;
778 p
= xtrymalloc (size
+ 1 + 1);
786 else if (c
->len
+ size
< c
->len
)
791 else if (c
->size
< c
->len
+ size
)
793 p
= xtryrealloc (c
->buffer
, c
->len
+ size
+ 1);
796 c
->size
= c
->len
+ size
;
810 memcpy (p
+ c
->len
, buffer
, size
);
812 p
[c
->len
] = 0; /* Terminate string. */
814 return (ssize_t
)size
;
818 /* Format NAME which is expected to be in rfc2253 format into a better
819 human readable format. Caller must free the returned string. NULL
820 is returned in case of an error. With TRANSLATE set to true the
821 name will be translated to the native encoding. Note that NAME is
822 internally always UTF-8 encoded. */
824 gpgsm_format_name2 (const char *name
, int translate
)
827 struct format_name_cookie cookie
;
828 es_cookie_io_functions_t io
= { NULL
};
830 memset (&cookie
, 0, sizeof cookie
);
832 io
.func_write
= format_name_writer
;
833 fp
= es_fopencookie (&cookie
, "w", io
);
836 int save_errno
= errno
;
837 log_error ("error creating memory stream: %s\n", strerror (errno
));
841 gpgsm_es_print_name2 (fp
, name
, translate
);
843 if (cookie
.error
|| !cookie
.buffer
)
845 xfree (cookie
.buffer
);
846 errno
= cookie
.error
;
849 return cookie
.buffer
;
854 gpgsm_format_name (const char *name
)
856 return gpgsm_format_name2 (name
, 1);
860 /* Return fingerprint and a percent escaped name in a human readable
861 format suitable for status messages like GOODSIG. May return NULL
862 on error (out of core). */
864 gpgsm_fpr_and_name_for_status (ksba_cert_t cert
)
866 char *fpr
, *name
, *p
;
869 fpr
= gpgsm_get_fingerprint_hexstring (cert
, GCRY_MD_SHA1
);
873 name
= ksba_cert_get_subject (cert
, 0);
880 p
= gpgsm_format_name2 (name
, 0);
889 buffer
= xtrymalloc (strlen (fpr
) + 1 + 3*strlen (name
) + 1);
894 p
= stpcpy (stpcpy (buffer
, fpr
), " ");
895 for (s
= name
; *s
; s
++)
899 sprintf (p
, "%%%02X", *(const unsigned char*)s
);
913 /* Create a key description for the CERT, this may be passed to the
914 pinentry. The caller must free the returned string. NULL may be
915 returned on error. */
917 gpgsm_format_keydesc (ksba_cert_t cert
)
919 char *name
, *subject
, *buffer
;
927 name
= ksba_cert_get_subject (cert
, 0);
928 subject
= name
? gpgsm_format_name2 (name
, 0) : NULL
;
929 ksba_free (name
); name
= NULL
;
931 sexp
= ksba_cert_get_serial (cert
);
932 sn
= sexp
? gpgsm_format_serial (sexp
) : NULL
;
935 ksba_cert_get_validity (cert
, 0, t
);
937 sprintf (created
, "%.4s-%.2s-%.2s", t
, t
+4, t
+6);
940 ksba_cert_get_validity (cert
, 1, t
);
942 sprintf (expires
, "%.4s-%.2s-%.2s", t
, t
+4, t
+6);
946 orig_codeset
= i18n_switchto_utf8 ();
948 name
= xtryasprintf (_("Please enter the passphrase to unlock the"
949 " secret key for the X.509 certificate:\n"
951 "S/N %s, ID 0x%08lX,\n"
952 "created %s, expires %s.\n" ),
953 subject
? subject
:"?",
955 gpgsm_get_short_fingerprint (cert
, NULL
),
958 i18n_switchback (orig_codeset
);
970 buffer
= percent_plus_escape (name
);