Line data Source code
1 : /* certdump.c - Dump a certificate for debugging
2 : * Copyright (C) 2001, 2004, 2007 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
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.
10 : *
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.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 : #include <errno.h>
25 : #include <unistd.h>
26 : #include <time.h>
27 : #include <assert.h>
28 : #ifdef HAVE_LOCALE_H
29 : #include <locale.h>
30 : #endif
31 : #ifdef HAVE_LANGINFO_CODESET
32 : #include <langinfo.h>
33 : #endif
34 :
35 : #include "gpgsm.h"
36 : #include <gcrypt.h>
37 : #include <ksba.h>
38 :
39 : #include "keydb.h"
40 : #include "i18n.h"
41 :
42 :
43 : struct dn_array_s {
44 : char *key;
45 : char *value;
46 : int multivalued;
47 : int done;
48 : };
49 :
50 :
51 : /* Print the first element of an S-Expression. */
52 : void
53 0 : gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn)
54 : {
55 0 : const char *p = (const char *)sn;
56 : unsigned long n;
57 : char *endp;
58 :
59 0 : if (!p)
60 0 : es_fputs (_("none"), fp);
61 0 : else if (*p != '(')
62 0 : es_fputs ("[Internal error - not an S-expression]", fp);
63 : else
64 : {
65 0 : p++;
66 0 : n = strtoul (p, &endp, 10);
67 0 : p = endp;
68 0 : if (*p++ != ':')
69 0 : es_fputs ("[Internal Error - invalid S-expression]", fp);
70 : else
71 0 : es_write_hexstring (fp, p, n, 0, NULL);
72 : }
73 0 : }
74 :
75 :
76 : /* Dump the serial number or any other simple S-expression. */
77 : void
78 0 : gpgsm_dump_serial (ksba_const_sexp_t sn)
79 : {
80 0 : const char *p = (const char *)sn;
81 : unsigned long n;
82 : char *endp;
83 :
84 0 : if (!p)
85 0 : log_printf ("none");
86 0 : else if (*p != '(')
87 0 : log_printf ("ERROR - not an S-expression");
88 : else
89 : {
90 0 : p++;
91 0 : n = strtoul (p, &endp, 10);
92 0 : p = endp;
93 0 : if (*p!=':')
94 0 : log_printf ("ERROR - invalid S-expression");
95 : else
96 : {
97 0 : for (p++; n; n--, p++)
98 0 : log_printf ("%02X", *(const unsigned char *)p);
99 : }
100 : }
101 0 : }
102 :
103 :
104 : char *
105 0 : gpgsm_format_serial (ksba_const_sexp_t sn)
106 : {
107 0 : const char *p = (const char *)sn;
108 : unsigned long n;
109 : char *endp;
110 : char *buffer;
111 : int i;
112 :
113 0 : if (!p)
114 0 : return NULL;
115 :
116 0 : if (*p != '(')
117 0 : BUG (); /* Not a valid S-expression. */
118 :
119 0 : p++;
120 0 : n = strtoul (p, &endp, 10);
121 0 : p = endp;
122 0 : if (*p!=':')
123 0 : BUG (); /* Not a valid S-expression. */
124 0 : p++;
125 :
126 0 : buffer = xtrymalloc (n*2+1);
127 0 : if (buffer)
128 : {
129 0 : for (i=0; n; n--, p++, i+=2)
130 0 : sprintf (buffer+i, "%02X", *(unsigned char *)p);
131 0 : buffer[i] = 0;
132 : }
133 0 : return buffer;
134 : }
135 :
136 :
137 :
138 :
139 : void
140 0 : gpgsm_print_time (estream_t fp, ksba_isotime_t t)
141 : {
142 0 : if (!t || !*t)
143 0 : es_fputs (_("none"), fp);
144 : else
145 0 : es_fprintf (fp, "%.4s-%.2s-%.2s %.2s:%.2s:%s",
146 : t, t+4, t+6, t+9, t+11, t+13);
147 0 : }
148 :
149 :
150 : void
151 0 : gpgsm_dump_string (const char *string)
152 : {
153 :
154 0 : if (!string)
155 0 : log_printf ("[error]");
156 : else
157 : {
158 : const unsigned char *s;
159 :
160 0 : for (s=(const unsigned char*)string; *s; s++)
161 : {
162 0 : if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
163 : break;
164 : }
165 0 : if (!*s && *string != '[')
166 0 : log_printf ("%s", string);
167 : else
168 : {
169 0 : log_printf ( "[ ");
170 0 : log_printhex (NULL, string, strlen (string));
171 0 : log_printf ( " ]");
172 : }
173 : }
174 0 : }
175 :
176 :
177 : /* This simple dump function is mainly used for debugging purposes. */
178 : void
179 0 : gpgsm_dump_cert (const char *text, ksba_cert_t cert)
180 : {
181 : ksba_sexp_t sexp;
182 : char *p;
183 : char *dn;
184 : ksba_isotime_t t;
185 :
186 0 : log_debug ("BEGIN Certificate '%s':\n", text? text:"");
187 0 : if (cert)
188 : {
189 0 : sexp = ksba_cert_get_serial (cert);
190 0 : log_debug (" serial: ");
191 0 : gpgsm_dump_serial (sexp);
192 0 : ksba_free (sexp);
193 0 : log_printf ("\n");
194 :
195 0 : ksba_cert_get_validity (cert, 0, t);
196 0 : log_debug (" notBefore: ");
197 0 : dump_isotime (t);
198 0 : log_printf ("\n");
199 0 : ksba_cert_get_validity (cert, 1, t);
200 0 : log_debug (" notAfter: ");
201 0 : dump_isotime (t);
202 0 : log_printf ("\n");
203 :
204 0 : dn = ksba_cert_get_issuer (cert, 0);
205 0 : log_debug (" issuer: ");
206 0 : gpgsm_dump_string (dn);
207 0 : ksba_free (dn);
208 0 : log_printf ("\n");
209 :
210 0 : dn = ksba_cert_get_subject (cert, 0);
211 0 : log_debug (" subject: ");
212 0 : gpgsm_dump_string (dn);
213 0 : ksba_free (dn);
214 0 : log_printf ("\n");
215 :
216 0 : log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert));
217 :
218 0 : p = gpgsm_get_fingerprint_string (cert, 0);
219 0 : log_debug (" SHA1 Fingerprint: %s\n", p);
220 0 : xfree (p);
221 : }
222 0 : log_debug ("END Certificate\n");
223 0 : }
224 :
225 :
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
229 : returned. */
230 : char *
231 0 : gpgsm_format_sn_issuer (ksba_sexp_t sn, const char *issuer)
232 : {
233 : char *p, *p1;
234 :
235 0 : if (sn && issuer)
236 : {
237 0 : p1 = gpgsm_format_serial (sn);
238 0 : if (!p1)
239 0 : p = xtrystrdup ("[invalid SN]");
240 : else
241 : {
242 0 : p = xtrymalloc (strlen (p1) + strlen (issuer) + 2 + 1);
243 0 : if (p)
244 : {
245 0 : *p = '#';
246 0 : strcpy (stpcpy (stpcpy (p+1, p1),"/"), issuer);
247 : }
248 0 : xfree (p1);
249 : }
250 : }
251 : else
252 0 : p = xtrystrdup ("[invalid SN/issuer]");
253 0 : return p;
254 : }
255 :
256 :
257 : /* Log the certificate's name in "#SN/ISSUERDN" format along with
258 : TEXT. */
259 : void
260 0 : gpgsm_cert_log_name (const char *text, ksba_cert_t cert)
261 : {
262 0 : log_info ("%s", text? text:"certificate" );
263 0 : if (cert)
264 : {
265 : ksba_sexp_t sn;
266 : char *p;
267 :
268 0 : p = ksba_cert_get_issuer (cert, 0);
269 0 : sn = ksba_cert_get_serial (cert);
270 0 : if (p && sn)
271 : {
272 0 : log_printf (" #");
273 0 : gpgsm_dump_serial (sn);
274 0 : log_printf ("/");
275 0 : gpgsm_dump_string (p);
276 : }
277 : else
278 0 : log_printf (" [invalid]");
279 0 : ksba_free (sn);
280 0 : xfree (p);
281 : }
282 0 : log_printf ("\n");
283 0 : }
284 :
285 :
286 :
287 :
288 :
289 :
290 : /* helper for the rfc2253 string parser */
291 : static const unsigned char *
292 0 : parse_dn_part (struct dn_array_s *array, const unsigned char *string)
293 : {
294 : static struct {
295 : const char *label;
296 : const char *oid;
297 : } label_map[] = {
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" },
301 : {"T", "2.5.4.12" },
302 : {"GN", "2.5.4.42" },
303 : {"SN", "2.5.4.4" },
304 : {"NameDistinguisher", "0.2.262.1.10.7.20"},
305 : {"ADDR", "2.5.4.16" },
306 : {"BC", "2.5.4.15" },
307 : {"D", "2.5.4.13" },
308 : {"PostalCode", "2.5.4.17" },
309 : {"Pseudo", "2.5.4.65" },
310 : {"SerialNumber", "2.5.4.5" },
311 : {NULL, NULL}
312 : };
313 : const unsigned char *s, *s1;
314 : size_t n;
315 : char *p;
316 : int i;
317 :
318 : /* Parse attributeType */
319 0 : for (s = string+1; *s && *s != '='; s++)
320 : ;
321 0 : if (!*s)
322 0 : return NULL; /* error */
323 0 : n = s - string;
324 0 : if (!n)
325 0 : return NULL; /* empty key */
326 :
327 : /* We need to allocate a few bytes more due to the possible mapping
328 : from the shorter OID to the longer label. */
329 0 : array->key = p = xtrymalloc (n+10);
330 0 : if (!array->key)
331 0 : return NULL;
332 0 : memcpy (p, string, n);
333 0 : p[n] = 0;
334 0 : trim_trailing_spaces (p);
335 :
336 0 : if (digitp (p))
337 : {
338 0 : for (i=0; label_map[i].label; i++ )
339 0 : if ( !strcmp (p, label_map[i].oid) )
340 : {
341 0 : strcpy (p, label_map[i].label);
342 0 : break;
343 : }
344 : }
345 0 : string = s + 1;
346 :
347 0 : if (*string == '#')
348 : { /* hexstring */
349 0 : string++;
350 0 : for (s=string; hexdigitp (s); s++)
351 0 : s++;
352 0 : n = s - string;
353 0 : if (!n || (n & 1))
354 0 : return NULL; /* Empty or odd number of digits. */
355 0 : n /= 2;
356 0 : array->value = p = xtrymalloc (n+1);
357 0 : if (!p)
358 0 : return NULL;
359 0 : for (s1=string; n; s1 += 2, n--, p++)
360 : {
361 0 : *(unsigned char *)p = xtoi_2 (s1);
362 0 : if (!*p)
363 0 : *p = 0x01; /* Better print a wrong value than truncating
364 : the string. */
365 : }
366 0 : *p = 0;
367 : }
368 : else
369 : { /* regular v3 quoted string */
370 0 : for (n=0, s=string; *s; s++)
371 : {
372 0 : if (*s == '\\')
373 : { /* pair */
374 0 : s++;
375 0 : if (*s == ',' || *s == '=' || *s == '+'
376 0 : || *s == '<' || *s == '>' || *s == '#' || *s == ';'
377 0 : || *s == '\\' || *s == '\"' || *s == ' ')
378 0 : n++;
379 0 : else if (hexdigitp (s) && hexdigitp (s+1))
380 : {
381 0 : s++;
382 0 : n++;
383 : }
384 : else
385 0 : return NULL; /* invalid escape sequence */
386 : }
387 0 : else if (*s == '\"')
388 0 : return NULL; /* invalid encoding */
389 0 : else if (*s == ',' || *s == '=' || *s == '+'
390 0 : || *s == '<' || *s == '>' || *s == ';' )
391 : break;
392 : else
393 0 : n++;
394 : }
395 :
396 0 : array->value = p = xtrymalloc (n+1);
397 0 : if (!p)
398 0 : return NULL;
399 0 : for (s=string; n; s++, n--)
400 : {
401 0 : if (*s == '\\')
402 : {
403 0 : s++;
404 0 : if (hexdigitp (s))
405 : {
406 0 : *(unsigned char *)p++ = xtoi_2 (s);
407 0 : s++;
408 : }
409 : else
410 0 : *p++ = *s;
411 : }
412 : else
413 0 : *p++ = *s;
414 : }
415 0 : *p = 0;
416 : }
417 0 : return s;
418 : }
419 :
420 :
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 0 : parse_dn (const unsigned char *string)
426 : {
427 : struct dn_array_s *array;
428 : size_t arrayidx, arraysize;
429 : int i;
430 :
431 0 : arraysize = 7; /* C,ST,L,O,OU,CN,email */
432 0 : arrayidx = 0;
433 0 : array = xtrymalloc ((arraysize+1) * sizeof *array);
434 0 : if (!array)
435 0 : return NULL;
436 0 : while (*string)
437 : {
438 0 : while (*string == ' ')
439 0 : string++;
440 0 : if (!*string)
441 0 : break; /* ready */
442 0 : if (arrayidx >= arraysize)
443 : {
444 : struct dn_array_s *a2;
445 :
446 0 : arraysize += 5;
447 0 : a2 = xtryrealloc (array, (arraysize+1) * sizeof *array);
448 0 : if (!a2)
449 0 : goto failure;
450 0 : array = a2;
451 : }
452 0 : array[arrayidx].key = NULL;
453 0 : array[arrayidx].value = NULL;
454 0 : string = parse_dn_part (array+arrayidx, string);
455 0 : if (!string)
456 0 : goto failure;
457 0 : while (*string == ' ')
458 0 : string++;
459 0 : array[arrayidx].multivalued = (*string == '+');
460 0 : array[arrayidx].done = 0;
461 0 : arrayidx++;
462 0 : if (*string && *string != ',' && *string != ';' && *string != '+')
463 0 : goto failure; /* invalid delimiter */
464 0 : if (*string)
465 0 : string++;
466 : }
467 0 : array[arrayidx].key = NULL;
468 0 : array[arrayidx].value = NULL;
469 0 : return array;
470 :
471 : failure:
472 0 : for (i=0; i < arrayidx; i++)
473 : {
474 0 : xfree (array[i].key);
475 0 : xfree (array[i].value);
476 : }
477 0 : xfree (array);
478 0 : return NULL;
479 : }
480 :
481 :
482 : /* Print a DN part to STREAM. */
483 : static void
484 0 : print_dn_part (estream_t stream,
485 : struct dn_array_s *dn, const char *key, int translate)
486 : {
487 0 : struct dn_array_s *first_dn = dn;
488 :
489 0 : for (; dn->key; dn++)
490 : {
491 0 : if (!dn->done && !strcmp (dn->key, key))
492 : {
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
497 : RDNs. */
498 0 : while (dn->multivalued && dn[1].key)
499 0 : dn++;
500 : next:
501 0 : if (!dn->done && dn->value && *dn->value)
502 : {
503 0 : es_fprintf (stream, "/%s=", dn->key);
504 0 : if (translate)
505 0 : print_utf8_buffer3 (stream, dn->value, strlen (dn->value),
506 : "/");
507 : else
508 0 : es_write_sanitized (stream, dn->value, strlen (dn->value),
509 : "/", NULL);
510 : }
511 0 : dn->done = 1;
512 0 : if (dn > first_dn && dn[-1].multivalued)
513 : {
514 0 : dn--;
515 0 : goto next;
516 : }
517 : }
518 : }
519 0 : }
520 :
521 : /* Print all parts of a DN in a "standard" sequence. We first print
522 : all the known parts, followed by the uncommon ones */
523 : static void
524 0 : print_dn_parts (estream_t stream,
525 : struct dn_array_s *dn, int translate)
526 : {
527 0 : const char *stdpart[] = {
528 : "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL
529 : };
530 : int i;
531 :
532 0 : for (i=0; stdpart[i]; i++)
533 0 : print_dn_part (stream, dn, stdpart[i], translate);
534 :
535 : /* Now print the rest without any specific ordering */
536 0 : for (; dn->key; dn++)
537 0 : print_dn_part (stream, dn, dn->key, translate);
538 0 : }
539 :
540 :
541 : /* Print the S-Expression in BUF to extended STREAM, which has a valid
542 : length of BUFLEN, as a human readable string in one line to FP. */
543 : static void
544 0 : pretty_es_print_sexp (estream_t fp, const unsigned char *buf, size_t buflen)
545 : {
546 : size_t len;
547 : gcry_sexp_t sexp;
548 : char *result, *p;
549 :
550 0 : if ( gcry_sexp_sscan (&sexp, NULL, (const char*)buf, buflen) )
551 : {
552 0 : es_fputs (_("[Error - invalid encoding]"), fp);
553 0 : return;
554 : }
555 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
556 0 : assert (len);
557 0 : result = xtrymalloc (len);
558 0 : if (!result)
559 : {
560 0 : es_fputs (_("[Error - out of core]"), fp);
561 0 : gcry_sexp_release (sexp);
562 0 : return;
563 : }
564 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
565 0 : assert (len);
566 0 : for (p = result; len; len--, p++)
567 : {
568 0 : if (*p == '\n')
569 : {
570 0 : if (len > 1) /* Avoid printing the trailing LF. */
571 0 : es_fputs ("\\n", fp);
572 : }
573 0 : else if (*p == '\r')
574 0 : es_fputs ("\\r", fp);
575 0 : else if (*p == '\v')
576 0 : es_fputs ("\\v", fp);
577 0 : else if (*p == '\t')
578 0 : es_fputs ("\\t", fp);
579 : else
580 0 : es_putc (*p, fp);
581 : }
582 0 : xfree (result);
583 0 : gcry_sexp_release (sexp);
584 : }
585 :
586 :
587 : /* This is a variant of gpgsm_print_name sending it output to an estream. */
588 : void
589 0 : gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
590 : {
591 0 : const unsigned char *s = (const unsigned char *)name;
592 : int i;
593 :
594 0 : if (!s)
595 : {
596 0 : es_fputs (_("[Error - No name]"), fp);
597 : }
598 0 : else if (*s == '<')
599 : {
600 0 : const char *s2 = strchr ( (char*)s+1, '>');
601 :
602 0 : if (s2)
603 : {
604 0 : if (translate)
605 0 : print_utf8_buffer (fp, s + 1, s2 - (char*)s - 1);
606 : else
607 0 : es_write_sanitized (fp, s + 1, s2 - (char*)s - 1, NULL, NULL);
608 : }
609 : }
610 0 : else if (*s == '(')
611 : {
612 0 : pretty_es_print_sexp (fp, s, gcry_sexp_canon_len (s, 0, NULL, NULL));
613 : }
614 0 : else if (!((*s >= '0' && *s < '9')
615 0 : || (*s >= 'A' && *s <= 'Z')
616 0 : || (*s >= 'a' && *s <= 'z')))
617 0 : es_fputs (_("[Error - invalid encoding]"), fp);
618 : else
619 : {
620 0 : struct dn_array_s *dn = parse_dn (s);
621 :
622 0 : if (!dn)
623 0 : es_fputs (_("[Error - invalid DN]"), fp);
624 : else
625 : {
626 0 : print_dn_parts (fp, dn, translate);
627 0 : for (i=0; dn[i].key; i++)
628 : {
629 0 : xfree (dn[i].key);
630 0 : xfree (dn[i].value);
631 : }
632 0 : xfree (dn);
633 : }
634 : }
635 0 : }
636 :
637 :
638 : void
639 0 : gpgsm_es_print_name (estream_t fp, const char *name)
640 : {
641 0 : gpgsm_es_print_name2 (fp, name, 1);
642 0 : }
643 :
644 :
645 : /* A cookie structure used for the memory stream. */
646 : struct format_name_cookie
647 : {
648 : char *buffer; /* Malloced buffer with the data to deliver. */
649 : size_t size; /* Allocated size of this buffer. */
650 : size_t len; /* strlen (buffer). */
651 : int error; /* system error code if any. */
652 : };
653 :
654 : /* The writer function for the memory stream. */
655 : static gpgrt_ssize_t
656 0 : format_name_writer (void *cookie, const void *buffer, size_t size)
657 : {
658 0 : struct format_name_cookie *c = cookie;
659 : char *p;
660 :
661 0 : if (!c->buffer)
662 : {
663 0 : p = xtrymalloc (size + 1 + 1);
664 0 : if (p)
665 : {
666 0 : c->size = size + 1;
667 0 : c->buffer = p;
668 0 : c->len = 0;
669 : }
670 : }
671 0 : else if (c->len + size < c->len)
672 : {
673 0 : p = NULL;
674 0 : gpg_err_set_errno (ENOMEM);
675 : }
676 0 : else if (c->size < c->len + size)
677 : {
678 0 : p = xtryrealloc (c->buffer, c->len + size + 1);
679 0 : if (p)
680 : {
681 0 : c->size = c->len + size;
682 0 : c->buffer = p;
683 : }
684 : }
685 : else
686 0 : p = c->buffer;
687 0 : if (!p)
688 : {
689 0 : c->error = errno;
690 0 : xfree (c->buffer);
691 0 : c->buffer = NULL;
692 0 : gpg_err_set_errno (c->error);
693 0 : return -1;
694 : }
695 0 : memcpy (p + c->len, buffer, size);
696 0 : c->len += size;
697 0 : p[c->len] = 0; /* Terminate string. */
698 :
699 0 : return (gpgrt_ssize_t)size;
700 : }
701 :
702 :
703 : /* Format NAME which is expected to be in rfc2253 format into a better
704 : human readable format. Caller must free the returned string. NULL
705 : is returned in case of an error. With TRANSLATE set to true the
706 : name will be translated to the native encoding. Note that NAME is
707 : internally always UTF-8 encoded. */
708 : char *
709 0 : gpgsm_format_name2 (const char *name, int translate)
710 : {
711 : estream_t fp;
712 : struct format_name_cookie cookie;
713 0 : es_cookie_io_functions_t io = { NULL };
714 :
715 0 : memset (&cookie, 0, sizeof cookie);
716 :
717 0 : io.func_write = format_name_writer;
718 0 : fp = es_fopencookie (&cookie, "w", io);
719 0 : if (!fp)
720 : {
721 0 : int save_errno = errno;
722 0 : log_error ("error creating memory stream: %s\n", strerror (save_errno));
723 0 : gpg_err_set_errno (save_errno);
724 0 : return NULL;
725 : }
726 0 : gpgsm_es_print_name2 (fp, name, translate);
727 0 : es_fclose (fp);
728 0 : if (cookie.error || !cookie.buffer)
729 : {
730 0 : xfree (cookie.buffer);
731 0 : gpg_err_set_errno (cookie.error);
732 0 : return NULL;
733 : }
734 0 : return cookie.buffer;
735 : }
736 :
737 :
738 : char *
739 0 : gpgsm_format_name (const char *name)
740 : {
741 0 : return gpgsm_format_name2 (name, 1);
742 : }
743 :
744 :
745 : /* Return fingerprint and a percent escaped name in a human readable
746 : format suitable for status messages like GOODSIG. May return NULL
747 : on error (out of core). */
748 : char *
749 0 : gpgsm_fpr_and_name_for_status (ksba_cert_t cert)
750 : {
751 : char *fpr, *name, *p;
752 : char *buffer;
753 :
754 0 : fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
755 0 : if (!fpr)
756 0 : return NULL;
757 :
758 0 : name = ksba_cert_get_subject (cert, 0);
759 0 : if (!name)
760 : {
761 0 : xfree (fpr);
762 0 : return NULL;
763 : }
764 :
765 0 : p = gpgsm_format_name2 (name, 0);
766 0 : ksba_free (name);
767 0 : name = p;
768 0 : if (!name)
769 : {
770 0 : xfree (fpr);
771 0 : return NULL;
772 : }
773 :
774 0 : buffer = xtrymalloc (strlen (fpr) + 1 + 3*strlen (name) + 1);
775 0 : if (buffer)
776 : {
777 : const char *s;
778 :
779 0 : p = stpcpy (stpcpy (buffer, fpr), " ");
780 0 : for (s = name; *s; s++)
781 : {
782 0 : if (*s < ' ')
783 : {
784 0 : sprintf (p, "%%%02X", *(const unsigned char*)s);
785 0 : p += 3;
786 : }
787 : else
788 0 : *p++ = *s;
789 : }
790 0 : *p = 0;
791 : }
792 0 : xfree (fpr);
793 0 : xfree (name);
794 0 : return buffer;
795 : }
796 :
797 :
798 : /* Create a key description for the CERT, this may be passed to the
799 : pinentry. The caller must free the returned string. NULL may be
800 : returned on error. */
801 : char *
802 0 : gpgsm_format_keydesc (ksba_cert_t cert)
803 : {
804 : char *name, *subject, *buffer;
805 : ksba_isotime_t t;
806 : char created[20];
807 : char expires[20];
808 : char *sn;
809 : ksba_sexp_t sexp;
810 : char *orig_codeset;
811 :
812 0 : name = ksba_cert_get_subject (cert, 0);
813 0 : subject = name? gpgsm_format_name2 (name, 0) : NULL;
814 0 : ksba_free (name); name = NULL;
815 :
816 0 : sexp = ksba_cert_get_serial (cert);
817 0 : sn = sexp? gpgsm_format_serial (sexp) : NULL;
818 0 : ksba_free (sexp);
819 :
820 0 : ksba_cert_get_validity (cert, 0, t);
821 0 : if (*t)
822 0 : sprintf (created, "%.4s-%.2s-%.2s", t, t+4, t+6);
823 : else
824 0 : *created = 0;
825 0 : ksba_cert_get_validity (cert, 1, t);
826 0 : if (*t)
827 0 : sprintf (expires, "%.4s-%.2s-%.2s", t, t+4, t+6);
828 : else
829 0 : *expires = 0;
830 :
831 0 : orig_codeset = i18n_switchto_utf8 ();
832 :
833 0 : name = xtryasprintf (_("Please enter the passphrase to unlock the"
834 : " secret key for the X.509 certificate:\n"
835 : "\"%s\"\n"
836 : "S/N %s, ID 0x%08lX,\n"
837 : "created %s, expires %s.\n" ),
838 : subject? subject:"?",
839 : sn? sn: "?",
840 : gpgsm_get_short_fingerprint (cert, NULL),
841 : created, expires);
842 :
843 0 : i18n_switchback (orig_codeset);
844 :
845 0 : if (!name)
846 : {
847 0 : xfree (subject);
848 0 : xfree (sn);
849 0 : return NULL;
850 : }
851 :
852 0 : xfree (subject);
853 0 : xfree (sn);
854 :
855 0 : buffer = percent_plus_escape (name);
856 0 : xfree (name);
857 0 : return buffer;
858 : }
|