agent/
[gnupg.git] / kbx / keybox-dump.c
blobb671089a0c5f919a481d9ae82bb0d15b51094b0e
1 /* keybox-dump.c - Debug helpers
2 * Copyright (C) 2001, 2003 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/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
26 #include "keybox-defs.h"
27 #include <gcrypt.h>
29 /* Argg, we can't include ../common/util.h */
30 char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
33 static ulong
34 get32 (const byte *buffer)
36 ulong a;
37 a = *buffer << 24;
38 a |= buffer[1] << 16;
39 a |= buffer[2] << 8;
40 a |= buffer[3];
41 return a;
44 static ulong
45 get16 (const byte *buffer)
47 ulong a;
48 a = *buffer << 8;
49 a |= buffer[1];
50 return a;
53 void
54 print_string (FILE *fp, const byte *p, size_t n, int delim)
56 for ( ; n; n--, p++ )
58 if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
60 putc('\\', fp);
61 if( *p == '\n' )
62 putc('n', fp);
63 else if( *p == '\r' )
64 putc('r', fp);
65 else if( *p == '\f' )
66 putc('f', fp);
67 else if( *p == '\v' )
68 putc('v', fp);
69 else if( *p == '\b' )
70 putc('b', fp);
71 else if( !*p )
72 putc('0', fp);
73 else
74 fprintf(fp, "x%02x", *p );
76 else
77 putc(*p, fp);
82 static int
83 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
85 unsigned long n;
87 if (length < 32)
89 fprintf (fp, "[blob too short]\n");
90 return -1;
92 fprintf (fp, "Version: %d\n", buffer[5]);
93 if ( memcmp (buffer+8, "KBXf", 4))
94 fprintf (fp, "[Error: invalid magic number]\n");
96 n = get32 (buffer+16);
97 fprintf( fp, "created-at: %lu\n", n );
98 n = get32 (buffer+20);
99 fprintf( fp, "last-maint: %lu\n", n );
101 return 0;
105 /* Dump one block to FP */
107 _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
109 const byte *buffer;
110 size_t length;
111 int type;
112 ulong n, nkeys, keyinfolen;
113 ulong nuids, uidinfolen;
114 ulong nsigs, siginfolen;
115 ulong rawdata_off, rawdata_len;
116 ulong nserial;
117 const byte *p;
119 buffer = _keybox_get_blob_image (blob, &length);
121 if (length < 32)
123 fprintf (fp, "[blob too short]\n");
124 return -1;
127 n = get32( buffer );
128 if (n > length)
129 fprintf (fp, "[blob larger than length - output truncated]\n");
130 else
131 length = n; /* ignore the rest */
133 fprintf (fp, "Length: %lu\n", n );
134 type = buffer[4];
135 switch (type)
137 case BLOBTYPE_EMPTY:
138 fprintf (fp, "Type: Empty\n");
139 return 0;
141 case BLOBTYPE_HEADER:
142 fprintf (fp, "Type: Header\n");
143 return dump_header_blob (buffer, length, fp);
144 case BLOBTYPE_PGP:
145 fprintf (fp, "Type: OpenPGP\n");
146 break;
147 case BLOBTYPE_X509:
148 fprintf (fp, "Type: X.509\n");
149 break;
150 default:
151 fprintf (fp, "Type: %d\n", type);
152 fprintf (fp, "[can't dump this blob type]\n");
153 return 0;
155 fprintf (fp, "Version: %d\n", buffer[5]);
157 if (length < 40)
159 fprintf (fp, "[blob too short]\n");
160 return -1;
163 n = get16 (buffer + 6);
164 fprintf( fp, "Blob-Flags: %04lX", n);
165 if (n)
167 int any = 0;
169 fputs (" (", fp);
170 if ((n & 1))
172 fputs ("secret", fp);
173 any++;
175 if ((n & 2))
177 if (any)
178 putc (',', fp);
179 fputs ("ephemeral", fp);
180 any++;
182 putc (')', fp);
184 putc ('\n', fp);
186 rawdata_off = get32 (buffer + 8);
187 rawdata_len = get32 (buffer + 12);
189 fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
190 fprintf( fp, "Data-Length: %lu\n", rawdata_len );
191 if (rawdata_off > length || rawdata_len > length
192 || rawdata_off+rawdata_off > length)
193 fprintf (fp, "[Error: raw data larger than blob]\n");
195 nkeys = get16 (buffer + 16);
196 fprintf (fp, "Key-Count: %lu\n", nkeys );
197 if (!nkeys)
198 fprintf (fp, "[Error: no keys]\n");
199 if (nkeys > 1 && type == BLOBTYPE_X509)
200 fprintf (fp, "[Error: only one key allowed for X509]\n");
202 keyinfolen = get16 (buffer + 18 );
203 fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
204 /* fixme: check bounds */
205 p = buffer + 20;
206 for (n=0; n < nkeys; n++, p += keyinfolen)
208 int i;
209 ulong kidoff, kflags;
211 fprintf (fp, "Key-Fpr[%lu]: ", n );
212 for (i=0; i < 20; i++ )
213 fprintf (fp, "%02X", p[i]);
214 kidoff = get32 (p + 20);
215 fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
216 fprintf (fp, "Key-Kid[%lu]: ", n );
217 /* fixme: check bounds */
218 for (i=0; i < 8; i++ )
219 fprintf (fp, "%02X", buffer[kidoff+i] );
220 kflags = get16 (p + 24 );
221 fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
224 /* serial number */
225 fputs ("Serial-No: ", fp);
226 nserial = get16 (p);
227 p += 2;
228 if (!nserial)
229 fputs ("none", fp);
230 else
232 for (; nserial; nserial--, p++)
233 fprintf (fp, "%02X", *p);
235 putc ('\n', fp);
237 /* user IDs */
238 nuids = get16 (p);
239 fprintf (fp, "Uid-Count: %lu\n", nuids );
240 uidinfolen = get16 (p + 2);
241 fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
242 /* fixme: check bounds */
243 p += 4;
244 for (n=0; n < nuids; n++, p += uidinfolen)
246 ulong uidoff, uidlen, uflags;
248 uidoff = get32( p );
249 uidlen = get32( p+4 );
250 if (type == BLOBTYPE_X509 && !n)
252 fprintf (fp, "Issuer-Off: %lu\n", uidoff );
253 fprintf (fp, "Issuer-Len: %lu\n", uidlen );
254 fprintf (fp, "Issuer: \"");
256 else if (type == BLOBTYPE_X509 && n == 1)
258 fprintf (fp, "Subject-Off: %lu\n", uidoff );
259 fprintf (fp, "Subject-Len: %lu\n", uidlen );
260 fprintf (fp, "Subject: \"");
262 else
264 fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
265 fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
266 fprintf (fp, "Uid[%lu]: \"", n );
268 print_string (fp, buffer+uidoff, uidlen, '\"');
269 fputs ("\"\n", fp);
270 uflags = get16 (p + 8);
271 if (type == BLOBTYPE_X509 && !n)
273 fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
274 fprintf (fp, "Issuer-Validity: %d\n", p[10] );
276 else if (type == BLOBTYPE_X509 && n == 1)
278 fprintf (fp, "Subject-Flags: %04lX\n", uflags );
279 fprintf (fp, "Subject-Validity: %d\n", p[10] );
281 else
283 fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
284 fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
288 nsigs = get16 (p);
289 fprintf (fp, "Sig-Count: %lu\n", nsigs );
290 siginfolen = get16 (p + 2);
291 fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
292 /* fixme: check bounds */
293 p += 4;
294 for (n=0; n < nsigs; n++, p += siginfolen)
296 ulong sflags;
298 sflags = get32 (p);
299 fprintf (fp, "Sig-Expire[%lu]: ", n );
300 if (!sflags)
301 fputs ("[not checked]", fp);
302 else if (sflags == 1 )
303 fputs ("[missing key]", fp);
304 else if (sflags == 2 )
305 fputs ("[bad signature]", fp);
306 else if (sflags < 0x10000000)
307 fprintf (fp, "[bad flag %0lx]", sflags);
308 else if (sflags == 0xffffffff)
309 fputs ("0", fp );
310 else
311 fputs ("a time"/*strtimestamp( sflags )*/, fp );
312 putc ('\n', fp );
315 fprintf (fp, "Ownertrust: %d\n", p[0] );
316 fprintf (fp, "All-Validity: %d\n", p[1] );
317 p += 4;
318 n = get32 (p); p += 4;
319 fprintf (fp, "Recheck-After: %lu\n", n );
320 n = get32 (p ); p += 4;
321 fprintf( fp, "Latest-Timestamp: %lu\n", n );
322 n = get32 (p ); p += 4;
323 fprintf (fp, "Created-At: %lu\n", n );
324 n = get32 (p ); p += 4;
325 fprintf (fp, "Reserved-Space: %lu\n", n );
327 /* check that the keyblock is at the correct offset and other bounds */
328 /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
329 return 0;
333 /* Compute the SHA_1 checksum of teh rawdata in BLOB and aput it into
334 DIGEST. */
335 static int
336 hash_blob_rawdata (KEYBOXBLOB blob, unsigned char *digest)
338 const unsigned char *buffer;
339 size_t n, length;
340 int type;
341 ulong rawdata_off, rawdata_len;
343 buffer = _keybox_get_blob_image (blob, &length);
345 if (length < 32)
346 return -1;
347 n = get32 (buffer);
348 if (n < length)
349 length = n; /* Blob larger than length in header - ignore the rest. */
351 type = buffer[4];
352 switch (type)
354 case BLOBTYPE_PGP:
355 case BLOBTYPE_X509:
356 break;
358 case BLOBTYPE_EMPTY:
359 case BLOBTYPE_HEADER:
360 default:
361 memset (digest, 0, 20);
362 return 0;
365 if (length < 40)
366 return -1;
368 rawdata_off = get32 (buffer + 8);
369 rawdata_len = get32 (buffer + 12);
371 if (rawdata_off > length || rawdata_len > length
372 || rawdata_off+rawdata_off > length)
373 return -1; /* Out of bounds. */
375 gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+rawdata_off, rawdata_len);
376 return 0;
380 struct file_stats_s
382 unsigned long too_short_blobs;
383 unsigned long too_large_blobs;
384 unsigned long total_blob_count;
385 unsigned long empty_blob_count;
386 unsigned long header_blob_count;
387 unsigned long pgp_blob_count;
388 unsigned long x509_blob_count;
389 unsigned long unknown_blob_count;
390 unsigned long non_flagged;
391 unsigned long secret_flagged;
392 unsigned long ephemeral_flagged;
395 static int
396 update_stats (KEYBOXBLOB blob, struct file_stats_s *s)
398 const unsigned char *buffer;
399 size_t length;
400 int type;
401 unsigned long n;
403 buffer = _keybox_get_blob_image (blob, &length);
404 if (length < 32)
406 s->too_short_blobs++;
407 return -1;
410 n = get32( buffer );
411 if (n > length)
412 s->too_large_blobs++;
413 else
414 length = n; /* ignore the rest */
416 s->total_blob_count++;
417 type = buffer[4];
418 switch (type)
420 case BLOBTYPE_EMPTY:
421 s->empty_blob_count++;
422 return 0;
423 case BLOBTYPE_HEADER:
424 s->header_blob_count++;
425 return 0;
426 case BLOBTYPE_PGP:
427 s->pgp_blob_count++;
428 break;
429 case BLOBTYPE_X509:
430 s->x509_blob_count++;
431 break;
432 default:
433 s->unknown_blob_count++;
434 return 0;
437 if (length < 40)
439 s->too_short_blobs++;
440 return -1;
443 n = get16 (buffer + 6);
444 if (n)
446 if ((n & 1))
447 s->secret_flagged++;
448 if ((n & 2))
449 s->ephemeral_flagged++;
451 else
452 s->non_flagged++;
454 return 0;
459 static FILE *
460 open_file (const char **filename, FILE *outfp)
462 FILE *fp;
464 if (!*filename)
466 *filename = "-";
467 fp = stdin;
469 else
470 fp = fopen (*filename, "rb");
471 if (!fp)
473 int save_errno = errno;
474 fprintf (outfp, "can't open `%s': %s\n", *filename, strerror(errno));
475 errno = save_errno;
477 return fp;
483 _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
485 FILE *fp;
486 KEYBOXBLOB blob;
487 int rc;
488 unsigned long count = 0;
489 struct file_stats_s stats;
491 memset (&stats, 0, sizeof stats);
493 if (!(fp = open_file (&filename, outfp)))
494 return gpg_error_from_syserror ();
496 while ( !(rc = _keybox_read_blob (&blob, fp)) )
498 if (stats_only)
500 update_stats (blob, &stats);
502 else
504 fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
505 _keybox_dump_blob (blob, outfp);
506 fprintf (outfp, "END-RECORD\n");
508 _keybox_release_blob (blob);
509 count++;
511 if (rc == -1)
512 rc = 0;
513 if (rc)
514 fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
516 if (fp != stdin)
517 fclose (fp);
519 if (stats_only)
521 fprintf (outfp,
522 "Total number of blobs: %8lu\n"
523 " header: %8lu\n"
524 " empty: %8lu\n"
525 " openpgp: %8lu\n"
526 " x509: %8lu\n"
527 " non flagged: %8lu\n"
528 " secret flagged: %8lu\n"
529 " ephemeral flagged: %8lu\n",
530 stats.total_blob_count,
531 stats.header_blob_count,
532 stats.empty_blob_count,
533 stats.pgp_blob_count,
534 stats.x509_blob_count,
535 stats.non_flagged,
536 stats.secret_flagged,
537 stats.ephemeral_flagged);
538 if (stats.unknown_blob_count)
539 fprintf (outfp, " unknown blob types: %8lu\n",
540 stats.unknown_blob_count);
541 if (stats.too_short_blobs)
542 fprintf (outfp, " too short blobs: %8lu\n",
543 stats.too_short_blobs);
544 if (stats.too_large_blobs)
545 fprintf (outfp, " too large blobs: %8lu\n",
546 stats.too_large_blobs);
549 return rc;
554 struct dupitem_s
556 unsigned long recno;
557 unsigned char digest[20];
561 static int
562 cmp_dupitems (const void *arg_a, const void *arg_b)
564 struct dupitem_s *a = (struct dupitem_s *)arg_a;
565 struct dupitem_s *b = (struct dupitem_s *)arg_b;
567 return memcmp (a->digest, b->digest, 20);
572 _keybox_dump_find_dups (const char *filename, int print_them, FILE *outfp)
574 FILE *fp;
575 KEYBOXBLOB blob;
576 int rc;
577 unsigned long recno = 0;
578 unsigned char zerodigest[20];
579 struct dupitem_s *dupitems;
580 size_t dupitems_size, dupitems_count, lastn, n;
581 char fprbuf[3*20+1];
583 (void)print_them;
585 memset (zerodigest, 0, sizeof zerodigest);
587 if (!(fp = open_file (&filename, outfp)))
588 return gpg_error_from_syserror ();
590 dupitems_size = 1000;
591 dupitems = malloc (dupitems_size * sizeof *dupitems);
592 if (!dupitems)
594 gpg_error_t tmperr = gpg_error_from_syserror ();
595 fprintf (outfp, "error allocating array for `%s': %s\n",
596 filename, strerror(errno));
597 return tmperr;
599 dupitems_count = 0;
601 while ( !(rc = _keybox_read_blob (&blob, fp)) )
603 unsigned char digest[20];
605 if (hash_blob_rawdata (blob, digest))
606 fprintf (outfp, "error in blob %ld of `%s'\n", recno, filename);
607 else if (memcmp (digest, zerodigest, 20))
609 if (dupitems_count >= dupitems_size)
611 struct dupitem_s *tmp;
613 dupitems_size += 1000;
614 tmp = realloc (dupitems, dupitems_size * sizeof *dupitems);
615 if (!tmp)
617 gpg_error_t tmperr = gpg_error_from_syserror ();
618 fprintf (outfp, "error reallocating array for `%s': %s\n",
619 filename, strerror(errno));
620 free (dupitems);
621 return tmperr;
623 dupitems = tmp;
625 dupitems[dupitems_count].recno = recno;
626 memcpy (dupitems[dupitems_count].digest, digest, 20);
627 dupitems_count++;
629 _keybox_release_blob (blob);
630 recno++;
632 if (rc == -1)
633 rc = 0;
634 if (rc)
635 fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
636 if (fp != stdin)
637 fclose (fp);
639 qsort (dupitems, dupitems_count, sizeof *dupitems, cmp_dupitems);
641 for (lastn=0, n=1; n < dupitems_count; lastn=n, n++)
643 if (!memcmp (dupitems[lastn].digest, dupitems[n].digest, 20))
645 bin2hexcolon (dupitems[lastn].digest, 20, fprbuf);
646 fprintf (outfp, "fpr=%s recno=%lu", fprbuf, dupitems[lastn].recno);
648 fprintf (outfp, " %lu", dupitems[n].recno);
649 while (++n < dupitems_count
650 && !memcmp (dupitems[lastn].digest, dupitems[n].digest, 20));
651 putc ('\n', outfp);
652 n--;
656 free (dupitems);
658 return rc;
662 /* Print records with record numbers FROM to TO to OUTFP. */
664 _keybox_dump_cut_records (const char *filename, unsigned long from,
665 unsigned long to, FILE *outfp)
667 FILE *fp;
668 KEYBOXBLOB blob;
669 int rc;
670 unsigned long recno = 0;
672 if (!(fp = open_file (&filename, stderr)))
673 return gpg_error_from_syserror ();
675 while ( !(rc = _keybox_read_blob (&blob, fp)) )
677 if (recno > to)
678 break; /* Ready. */
679 if (recno >= from)
681 if ((rc = _keybox_write_blob (blob, outfp)))
683 fprintf (stderr, "error writing output: %s\n",
684 gpg_strerror (rc));
685 goto leave;
688 _keybox_release_blob (blob);
689 recno++;
691 if (rc == -1)
692 rc = 0;
693 if (rc)
694 fprintf (stderr, "error reading `%s': %s\n", filename, gpg_strerror (rc));
695 leave:
696 if (fp != stdin)
697 fclose (fp);
698 return rc;