A couple of fixes. gpg2's key generation does now work.
[gnupg.git] / kbx / keybox-dump.c
1 /* keybox-dump.c - Debug helpers
2  *      Copyright (C) 2001, 2003 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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "keybox-defs.h"
29
30 static ulong
31 get32 (const byte *buffer)
32 {
33   ulong a;
34   a =  *buffer << 24;
35   a |= buffer[1] << 16;
36   a |= buffer[2] << 8;
37   a |= buffer[3];
38   return a;
39 }
40
41 static ulong
42 get16 (const byte *buffer)
43 {
44   ulong a;
45   a =  *buffer << 8;
46   a |= buffer[1];
47   return a;
48 }
49
50 void
51 print_string (FILE *fp, const byte *p, size_t n, int delim)
52 {
53   for ( ; n; n--, p++ )
54     {
55       if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
56         {
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 );
72         }
73       else
74         putc(*p, fp);
75     }
76 }
77
78
79 static int
80 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
81 {
82   unsigned long n;
83
84   if (length < 32)
85     {
86       fprintf (fp, "[blob too short]\n");
87       return -1;
88     }
89   fprintf (fp, "Version: %d\n", buffer[5]);
90   if ( memcmp (buffer+8, "KBXf", 4))
91     fprintf (fp, "[Error: invalid magic number]\n");
92
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 );
97
98   return 0;
99 }
100
101 \f
102 /* Dump one block to FP */
103 int
104 _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
105 {
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;
115
116   buffer = _keybox_get_blob_image (blob, &length);
117   
118   if (length < 32)
119     {
120       fprintf (fp, "[blob too short]\n");
121       return -1;
122     }
123
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 */
129
130   fprintf (fp, "Length: %lu\n", n );
131   type = buffer[4];
132   switch (type)
133     {
134     case BLOBTYPE_EMPTY:
135       fprintf (fp, "Type:   Empty\n");
136       return 0;
137
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;
151     }
152   fprintf (fp, "Version: %d\n", buffer[5]);
153
154   if (length < 40)
155     {
156       fprintf (fp, "[blob too short]\n");
157       return -1;
158     }
159   
160   n = get16 (buffer + 6);
161   fprintf( fp, "Blob-Flags: %04lX", n);
162   if (n)
163     {
164       int any = 0;
165
166       fputs (" (", fp);
167       if ((n & 1))
168         {
169           fputs ("secret", fp);
170           any++;
171         }
172       if ((n & 2))
173         {
174           if (any)
175             putc (',', fp);
176           fputs ("ephemeral", fp);
177           any++;
178         }
179       putc (')', fp);
180     }
181   putc ('\n', fp);
182
183   rawdata_off = get32 (buffer + 8);
184   rawdata_len = get32 (buffer + 12);
185
186   fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
187   fprintf( fp, "Data-Length: %lu\n", rawdata_len );
188
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");
195
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)
201     {
202       int i;
203       ulong kidoff, kflags;
204     
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);
216     }
217   
218   /* serial number */
219   fputs ("Serial-No: ", fp);
220   nserial = get16 (p);
221   p += 2;
222   if (!nserial)
223     fputs ("none", fp);
224   else
225     {
226       for (; nserial; nserial--, p++)
227         fprintf (fp, "%02X", *p);
228     }
229   putc ('\n', fp);
230
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)
239     {
240       ulong uidoff, uidlen, uflags;
241       
242       uidoff = get32( p );
243       uidlen = get32( p+4 );
244       if (type == BLOBTYPE_X509 && !n)
245         {
246           fprintf (fp, "Issuer-Off: %lu\n", uidoff );
247           fprintf (fp, "Issuer-Len: %lu\n", uidlen );
248           fprintf (fp, "Issuer: \"");
249         }
250       else if (type == BLOBTYPE_X509 && n == 1)
251         {
252           fprintf (fp, "Subject-Off: %lu\n", uidoff );
253           fprintf (fp, "Subject-Len: %lu\n", uidlen );
254           fprintf (fp, "Subject: \"");
255         }
256       else
257         {
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 );
261         }
262       print_string (fp, buffer+uidoff, uidlen, '\"');
263       fputs ("\"\n", fp);
264       uflags = get16 (p + 8);
265       if (type == BLOBTYPE_X509 && !n)
266         {
267           fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
268           fprintf (fp, "Issuer-Validity: %d\n", p[10] );
269         }
270       else if (type == BLOBTYPE_X509 && n == 1)
271         {
272           fprintf (fp, "Subject-Flags: %04lX\n", uflags );
273           fprintf (fp, "Subject-Validity: %d\n", p[10] );
274         }
275       else
276         {
277           fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
278           fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
279         }
280     }
281   
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)
289     {
290       ulong sflags;
291     
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 );
307     }
308
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 );
320
321   /* check that the keyblock is at the correct offset and other bounds */
322   /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
323   return 0;
324 }
325
326
327 struct file_stats_s
328 {
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;
340 };
341
342 static int
343 update_stats (KEYBOXBLOB blob, struct file_stats_s *s)
344 {
345   const unsigned char *buffer;
346   size_t length;
347   int type;
348   unsigned long n;
349
350   buffer = _keybox_get_blob_image (blob, &length);
351   if (length < 32)
352     {
353       s->too_short_blobs++;
354       return -1;
355     }
356
357   n = get32( buffer );
358   if (n > length) 
359     s->too_large_blobs++;
360   else
361     length = n;  /* ignore the rest */
362
363   s->total_blob_count++;
364   type = buffer[4];
365   switch (type)
366     {
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;
382     }
383
384   if (length < 40)
385     {
386       s->too_short_blobs++;
387       return -1;
388     }
389   
390   n = get16 (buffer + 6);
391   if (n)
392     {
393       if ((n & 1))
394         s->secret_flagged++;
395       if ((n & 2))
396         s->ephemeral_flagged++;
397     }
398   else
399     s->non_flagged++;
400
401   return 0;
402 }
403
404
405 \f
406 int
407 _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
408 {
409   FILE *fp;
410   KEYBOXBLOB blob;
411   int rc;
412   unsigned long count = 0;
413   struct file_stats_s stats;
414
415   memset (&stats, 0, sizeof stats);
416
417   if (!filename)
418     {
419       filename = "-";
420       fp = stdin;
421     }
422   else
423     fp = fopen (filename, "rb");
424   if (!fp)
425     {
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;
429     }
430
431   while ( !(rc = _keybox_read_blob (&blob, fp)) )
432     {
433       if (stats_only)
434         {
435           update_stats (blob, &stats);
436         }
437       else
438         {
439           fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
440           _keybox_dump_blob (blob, outfp);
441           fprintf (outfp, "END-RECORD\n");
442         }
443       _keybox_release_blob (blob);
444       count++;
445     }
446   if (rc == -1)
447     rc = 0;
448   if (rc)
449     fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
450   
451   if (fp != stdin)
452     fclose (fp);
453
454   if (stats_only)
455     {
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);
482     }
483
484   return rc;
485 }