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/>.
26 #include "keybox-defs.h"
29 /* Argg, we can't include ../common/util.h */
30 char *bin2hexcolon (const void *buffer
, size_t length
, char *stringbuf
);
34 get32 (const byte
*buffer
)
45 get16 (const byte
*buffer
)
54 print_string (FILE *fp
, const byte
*p
, size_t n
, int delim
)
58 if (*p
< 0x20 || (*p
>= 0x7f && *p
< 0xa0) || *p
== delim
)
74 fprintf(fp
, "x%02x", *p
);
83 dump_header_blob (const byte
*buffer
, size_t length
, FILE *fp
)
89 fprintf (fp
, "[blob too short]\n");
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
);
105 /* Dump one block to FP */
107 _keybox_dump_blob (KEYBOXBLOB blob
, FILE *fp
)
112 ulong n
, nkeys
, keyinfolen
;
113 ulong nuids
, uidinfolen
;
114 ulong nsigs
, siginfolen
;
115 ulong rawdata_off
, rawdata_len
;
119 buffer
= _keybox_get_blob_image (blob
, &length
);
123 fprintf (fp
, "[blob too short]\n");
129 fprintf (fp
, "[blob larger than length - output truncated]\n");
131 length
= n
; /* ignore the rest */
133 fprintf (fp
, "Length: %lu\n", n
);
138 fprintf (fp
, "Type: Empty\n");
141 case BLOBTYPE_HEADER
:
142 fprintf (fp
, "Type: Header\n");
143 return dump_header_blob (buffer
, length
, fp
);
145 fprintf (fp
, "Type: OpenPGP\n");
148 fprintf (fp
, "Type: X.509\n");
151 fprintf (fp
, "Type: %d\n", type
);
152 fprintf (fp
, "[can't dump this blob type]\n");
155 fprintf (fp
, "Version: %d\n", buffer
[5]);
159 fprintf (fp
, "[blob too short]\n");
163 n
= get16 (buffer
+ 6);
164 fprintf( fp
, "Blob-Flags: %04lX", n
);
172 fputs ("secret", fp
);
179 fputs ("ephemeral", 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
);
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 */
206 for (n
=0; n
< nkeys
; n
++, p
+= keyinfolen
)
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
);
225 fputs ("Serial-No: ", fp
);
232 for (; nserial
; nserial
--, p
++)
233 fprintf (fp
, "%02X", *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 */
244 for (n
=0; n
< nuids
; n
++, p
+= uidinfolen
)
246 ulong uidoff
, uidlen
, uflags
;
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: \"");
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
, '\"');
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] );
283 fprintf (fp
, "Uid-Flags[%lu]: %04lX\n", n
, uflags
);
284 fprintf (fp
, "Uid-Validity[%lu]: %d\n", n
, p
[10] );
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 */
294 for (n
=0; n
< nsigs
; n
++, p
+= siginfolen
)
299 fprintf (fp
, "Sig-Expire[%lu]: ", n
);
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)
311 fputs ("a time"/*strtimestamp( sflags )*/, fp
);
315 fprintf (fp
, "Ownertrust: %d\n", p
[0] );
316 fprintf (fp
, "All-Validity: %d\n", p
[1] );
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");*/
333 /* Compute the SHA_1 checksum of teh rawdata in BLOB and aput it into
336 hash_blob_rawdata (KEYBOXBLOB blob
, unsigned char *digest
)
338 const unsigned char *buffer
;
341 ulong rawdata_off
, rawdata_len
;
343 buffer
= _keybox_get_blob_image (blob
, &length
);
349 length
= n
; /* Blob larger than length in header - ignore the rest. */
359 case BLOBTYPE_HEADER
:
361 memset (digest
, 0, 20);
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
);
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
;
396 update_stats (KEYBOXBLOB blob
, struct file_stats_s
*s
)
398 const unsigned char *buffer
;
403 buffer
= _keybox_get_blob_image (blob
, &length
);
406 s
->too_short_blobs
++;
412 s
->too_large_blobs
++;
414 length
= n
; /* ignore the rest */
416 s
->total_blob_count
++;
421 s
->empty_blob_count
++;
423 case BLOBTYPE_HEADER
:
424 s
->header_blob_count
++;
430 s
->x509_blob_count
++;
433 s
->unknown_blob_count
++;
439 s
->too_short_blobs
++;
443 n
= get16 (buffer
+ 6);
449 s
->ephemeral_flagged
++;
460 open_file (const char **filename
, FILE *outfp
)
470 fp
= fopen (*filename
, "rb");
473 int save_errno
= errno
;
474 fprintf (outfp
, "can't open `%s': %s\n", *filename
, strerror(errno
));
483 _keybox_dump_file (const char *filename
, int stats_only
, FILE *outfp
)
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
)) )
500 update_stats (blob
, &stats
);
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
);
514 fprintf (outfp
, "error reading `%s': %s\n", filename
, gpg_strerror (rc
));
522 "Total number of blobs: %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
,
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
);
557 unsigned char digest
[20];
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
)
577 unsigned long recno
= 0;
578 unsigned char zerodigest
[20];
579 struct dupitem_s
*dupitems
;
580 size_t dupitems_size
, dupitems_count
, lastn
, n
;
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
);
594 gpg_error_t tmperr
= gpg_error_from_syserror ();
595 fprintf (outfp
, "error allocating array for `%s': %s\n",
596 filename
, strerror(errno
));
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
);
617 gpg_error_t tmperr
= gpg_error_from_syserror ();
618 fprintf (outfp
, "error reallocating array for `%s': %s\n",
619 filename
, strerror(errno
));
625 dupitems
[dupitems_count
].recno
= recno
;
626 memcpy (dupitems
[dupitems_count
].digest
, digest
, 20);
629 _keybox_release_blob (blob
);
635 fprintf (outfp
, "error reading `%s': %s\n", filename
, gpg_strerror (rc
));
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));
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
)
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
)) )
681 if ((rc
= _keybox_write_blob (blob
, outfp
)))
683 fprintf (stderr
, "error writing output: %s\n",
688 _keybox_release_blob (blob
);
694 fprintf (stderr
, "error reading `%s': %s\n", filename
, gpg_strerror (rc
));