2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / kbx / keybox-dump.c
blobd286113774146161607a822358f957ab7e509115
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
28 #include "keybox-defs.h"
30 static ulong
31 get32 (const byte *buffer)
33 ulong a;
34 a = *buffer << 24;
35 a |= buffer[1] << 16;
36 a |= buffer[2] << 8;
37 a |= buffer[3];
38 return a;
41 static ulong
42 get16 (const byte *buffer)
44 ulong a;
45 a = *buffer << 8;
46 a |= buffer[1];
47 return a;
50 void
51 print_string (FILE *fp, const byte *p, size_t n, int delim)
53 for ( ; n; n--, p++ )
55 if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
57 putc('\\', fp);
58 if( *p == '\n' )
59 putc('n', fp);
60 else if( *p == '\r' )
61 putc('r', fp);
62 else if( *p == '\f' )
63 putc('f', fp);
64 else if( *p == '\v' )
65 putc('v', fp);
66 else if( *p == '\b' )
67 putc('b', fp);
68 else if( !*p )
69 putc('0', fp);
70 else
71 fprintf(fp, "x%02x", *p );
73 else
74 putc(*p, fp);
79 static int
80 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
82 unsigned long n;
84 if (length < 32)
86 fprintf (fp, "[blob too short]\n");
87 return -1;
89 fprintf (fp, "Version: %d\n", buffer[5]);
90 if ( memcmp (buffer+8, "KBXf", 4))
91 fprintf (fp, "[Error: invalid magic number]\n");
93 n = get32 (buffer+16);
94 fprintf( fp, "created-at: %lu\n", n );
95 n = get32 (buffer+20);
96 fprintf( fp, "last-maint: %lu\n", n );
98 return 0;
102 /* Dump one block to FP */
104 _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
106 const byte *buffer;
107 size_t length;
108 int type;
109 ulong n, nkeys, keyinfolen;
110 ulong nuids, uidinfolen;
111 ulong nsigs, siginfolen;
112 ulong rawdata_off, rawdata_len;
113 ulong nserial;
114 const byte *p;
116 buffer = _keybox_get_blob_image (blob, &length);
118 if (length < 32)
120 fprintf (fp, "[blob too short]\n");
121 return -1;
124 n = get32( buffer );
125 if (n > length)
126 fprintf (fp, "[blob larger than length - output truncated]\n");
127 else
128 length = n; /* ignore the rest */
130 fprintf (fp, "Length: %lu\n", n );
131 type = buffer[4];
132 switch (type)
134 case BLOBTYPE_EMPTY:
135 fprintf (fp, "Type: Empty\n");
136 return 0;
138 case BLOBTYPE_HEADER:
139 fprintf (fp, "Type: Header\n");
140 return dump_header_blob (buffer, length, fp);
141 case BLOBTYPE_PGP:
142 fprintf (fp, "Type: OpenPGP\n");
143 break;
144 case BLOBTYPE_X509:
145 fprintf (fp, "Type: X.509\n");
146 break;
147 default:
148 fprintf (fp, "Type: %d\n", type);
149 fprintf (fp, "[can't dump this blob type]\n");
150 return 0;
152 fprintf (fp, "Version: %d\n", buffer[5]);
154 if (length < 40)
156 fprintf (fp, "[blob too short]\n");
157 return -1;
160 n = get16 (buffer + 6);
161 fprintf( fp, "Blob-Flags: %04lX", n);
162 if (n)
164 int any = 0;
166 fputs (" (", fp);
167 if ((n & 1))
169 fputs ("secret", fp);
170 any++;
172 if ((n & 2))
174 if (any)
175 putc (',', fp);
176 fputs ("ephemeral", fp);
177 any++;
179 putc (')', fp);
181 putc ('\n', fp);
183 rawdata_off = get32 (buffer + 8);
184 rawdata_len = get32 (buffer + 12);
186 fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
187 fprintf( fp, "Data-Length: %lu\n", rawdata_len );
189 nkeys = get16 (buffer + 16);
190 fprintf (fp, "Key-Count: %lu\n", nkeys );
191 if (!nkeys)
192 fprintf (fp, "[Error: no keys]\n");
193 if (nkeys > 1 && type == BLOBTYPE_X509)
194 fprintf (fp, "[Error: only one key allowed for X509]\n");
196 keyinfolen = get16 (buffer + 18 );
197 fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
198 /* fixme: check bounds */
199 p = buffer + 20;
200 for (n=0; n < nkeys; n++, p += keyinfolen)
202 int i;
203 ulong kidoff, kflags;
205 fprintf (fp, "Key-Fpr[%lu]: ", n );
206 for (i=0; i < 20; i++ )
207 fprintf (fp, "%02X", p[i]);
208 kidoff = get32 (p + 20);
209 fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
210 fprintf (fp, "Key-Kid[%lu]: ", n );
211 /* fixme: check bounds */
212 for (i=0; i < 8; i++ )
213 fprintf (fp, "%02X", buffer[kidoff+i] );
214 kflags = get16 (p + 24 );
215 fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
218 /* serial number */
219 fputs ("Serial-No: ", fp);
220 nserial = get16 (p);
221 p += 2;
222 if (!nserial)
223 fputs ("none", fp);
224 else
226 for (; nserial; nserial--, p++)
227 fprintf (fp, "%02X", *p);
229 putc ('\n', fp);
231 /* user IDs */
232 nuids = get16 (p);
233 fprintf (fp, "Uid-Count: %lu\n", nuids );
234 uidinfolen = get16 (p + 2);
235 fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
236 /* fixme: check bounds */
237 p += 4;
238 for (n=0; n < nuids; n++, p += uidinfolen)
240 ulong uidoff, uidlen, uflags;
242 uidoff = get32( p );
243 uidlen = get32( p+4 );
244 if (type == BLOBTYPE_X509 && !n)
246 fprintf (fp, "Issuer-Off: %lu\n", uidoff );
247 fprintf (fp, "Issuer-Len: %lu\n", uidlen );
248 fprintf (fp, "Issuer: \"");
250 else if (type == BLOBTYPE_X509 && n == 1)
252 fprintf (fp, "Subject-Off: %lu\n", uidoff );
253 fprintf (fp, "Subject-Len: %lu\n", uidlen );
254 fprintf (fp, "Subject: \"");
256 else
258 fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
259 fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
260 fprintf (fp, "Uid[%lu]: \"", n );
262 print_string (fp, buffer+uidoff, uidlen, '\"');
263 fputs ("\"\n", fp);
264 uflags = get16 (p + 8);
265 if (type == BLOBTYPE_X509 && !n)
267 fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
268 fprintf (fp, "Issuer-Validity: %d\n", p[10] );
270 else if (type == BLOBTYPE_X509 && n == 1)
272 fprintf (fp, "Subject-Flags: %04lX\n", uflags );
273 fprintf (fp, "Subject-Validity: %d\n", p[10] );
275 else
277 fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
278 fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
282 nsigs = get16 (p);
283 fprintf (fp, "Sig-Count: %lu\n", nsigs );
284 siginfolen = get16 (p + 2);
285 fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
286 /* fixme: check bounds */
287 p += 4;
288 for (n=0; n < nsigs; n++, p += siginfolen)
290 ulong sflags;
292 sflags = get32 (p);
293 fprintf (fp, "Sig-Expire[%lu]: ", n );
294 if (!sflags)
295 fputs ("[not checked]", fp);
296 else if (sflags == 1 )
297 fputs ("[missing key]", fp);
298 else if (sflags == 2 )
299 fputs ("[bad signature]", fp);
300 else if (sflags < 0x10000000)
301 fprintf (fp, "[bad flag %0lx]", sflags);
302 else if (sflags == 0xffffffff)
303 fputs ("0", fp );
304 else
305 fputs ("a time"/*strtimestamp( sflags )*/, fp );
306 putc ('\n', fp );
309 fprintf (fp, "Ownertrust: %d\n", p[0] );
310 fprintf (fp, "All-Validity: %d\n", p[1] );
311 p += 4;
312 n = get32 (p); p += 4;
313 fprintf (fp, "Recheck-After: %lu\n", n );
314 n = get32 (p ); p += 4;
315 fprintf( fp, "Latest-Timestamp: %lu\n", n );
316 n = get32 (p ); p += 4;
317 fprintf (fp, "Created-At: %lu\n", n );
318 n = get32 (p ); p += 4;
319 fprintf (fp, "Reserved-Space: %lu\n", n );
321 /* check that the keyblock is at the correct offset and other bounds */
322 /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
323 return 0;
327 struct file_stats_s
329 unsigned long too_short_blobs;
330 unsigned long too_large_blobs;
331 unsigned long total_blob_count;
332 unsigned long empty_blob_count;
333 unsigned long header_blob_count;
334 unsigned long pgp_blob_count;
335 unsigned long x509_blob_count;
336 unsigned long unknown_blob_count;
337 unsigned long non_flagged;
338 unsigned long secret_flagged;
339 unsigned long ephemeral_flagged;
342 static int
343 update_stats (KEYBOXBLOB blob, struct file_stats_s *s)
345 const unsigned char *buffer;
346 size_t length;
347 int type;
348 unsigned long n;
350 buffer = _keybox_get_blob_image (blob, &length);
351 if (length < 32)
353 s->too_short_blobs++;
354 return -1;
357 n = get32( buffer );
358 if (n > length)
359 s->too_large_blobs++;
360 else
361 length = n; /* ignore the rest */
363 s->total_blob_count++;
364 type = buffer[4];
365 switch (type)
367 case BLOBTYPE_EMPTY:
368 s->empty_blob_count++;
369 return 0;
370 case BLOBTYPE_HEADER:
371 s->header_blob_count++;
372 return 0;
373 case BLOBTYPE_PGP:
374 s->pgp_blob_count++;
375 break;
376 case BLOBTYPE_X509:
377 s->x509_blob_count++;
378 break;
379 default:
380 s->unknown_blob_count++;
381 return 0;
384 if (length < 40)
386 s->too_short_blobs++;
387 return -1;
390 n = get16 (buffer + 6);
391 if (n)
393 if ((n & 1))
394 s->secret_flagged++;
395 if ((n & 2))
396 s->ephemeral_flagged++;
398 else
399 s->non_flagged++;
401 return 0;
407 _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
409 FILE *fp;
410 KEYBOXBLOB blob;
411 int rc;
412 unsigned long count = 0;
413 struct file_stats_s stats;
415 memset (&stats, 0, sizeof stats);
417 if (!filename)
419 filename = "-";
420 fp = stdin;
422 else
423 fp = fopen (filename, "rb");
424 if (!fp)
426 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
427 fprintf (outfp, "can't open `%s': %s\n", filename, strerror(errno));
428 return tmperr;
431 while ( !(rc = _keybox_read_blob (&blob, fp)) )
433 if (stats_only)
435 update_stats (blob, &stats);
437 else
439 fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
440 _keybox_dump_blob (blob, outfp);
441 fprintf (outfp, "END-RECORD\n");
443 _keybox_release_blob (blob);
444 count++;
446 if (rc == -1)
447 rc = 0;
448 if (rc)
449 fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
451 if (fp != stdin)
452 fclose (fp);
454 if (stats_only)
456 fprintf (outfp,
457 "Total number of blobs: %8lu\n"
458 " header: %8lu\n"
459 " empty: %8lu\n"
460 " openpgp: %8lu\n"
461 " x509: %8lu\n"
462 " non flagged: %8lu\n"
463 " secret flagged: %8lu\n"
464 " ephemeral flagged: %8lu\n",
465 stats.total_blob_count,
466 stats.header_blob_count,
467 stats.empty_blob_count,
468 stats.pgp_blob_count,
469 stats.x509_blob_count,
470 stats.non_flagged,
471 stats.secret_flagged,
472 stats.ephemeral_flagged);
473 if (stats.unknown_blob_count)
474 fprintf (outfp, " unknown blob types: %8lu\n",
475 stats.unknown_blob_count);
476 if (stats.too_short_blobs)
477 fprintf (outfp, " too short blobs: %8lu\n",
478 stats.too_short_blobs);
479 if (stats.too_large_blobs)
480 fprintf (outfp, " too large blobs: %8lu\n",
481 stats.too_large_blobs);
484 return rc;