2fb0984c08d24655085684ae144db594a48b848f
[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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "keybox-defs.h"
28
29 static ulong
30 get32 (const byte *buffer)
31 {
32   ulong a;
33   a =  *buffer << 24;
34   a |= buffer[1] << 16;
35   a |= buffer[2] << 8;
36   a |= buffer[3];
37   return a;
38 }
39
40 static ulong
41 get16 (const byte *buffer)
42 {
43   ulong a;
44   a =  *buffer << 8;
45   a |= buffer[1];
46   return a;
47 }
48
49 void
50 print_string (FILE *fp, const byte *p, size_t n, int delim)
51 {
52   for ( ; n; n--, p++ )
53     {
54       if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
55         {
56           putc('\\', fp);
57           if( *p == '\n' )
58             putc('n', fp);
59           else if( *p == '\r' )
60             putc('r', fp);
61           else if( *p == '\f' )
62             putc('f', fp);
63           else if( *p == '\v' )
64             putc('v', fp);
65           else if( *p == '\b' )
66             putc('b', fp);
67           else if( !*p )
68             putc('0', fp);
69           else
70             fprintf(fp, "x%02x", *p );
71         }
72       else
73         putc(*p, fp);
74     }
75 }
76
77
78 static int
79 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
80 {
81   unsigned long n;
82
83   if (length < 32)
84     {
85       fprintf (fp, "[blob too short]\n");
86       return -1;
87     }
88   fprintf (fp, "Version: %d\n", buffer[5]);
89   if ( memcmp (buffer+8, "KBXf", 4))
90     fprintf (fp, "[Error: invalid magic number]\n");
91
92   n = get32 (buffer+16); 
93   fprintf( fp, "created-at: %lu\n", n );
94   n = get32 (buffer+20); 
95   fprintf( fp, "last-maint: %lu\n", n );
96
97   return 0;
98 }
99
100 \f
101 /* Dump one block to FP */
102 int
103 _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
104 {
105   const byte *buffer;
106   size_t length;
107   int type;
108   ulong n, nkeys, keyinfolen;
109   ulong nuids, uidinfolen;
110   ulong nsigs, siginfolen;
111   ulong rawdata_off, rawdata_len;
112   ulong nserial;
113   const byte *p;
114
115   buffer = _keybox_get_blob_image (blob, &length);
116   
117   if (length < 32)
118     {
119       fprintf (fp, "[blob too short]\n");
120       return -1;
121     }
122
123   n = get32( buffer );
124   if (n > length) 
125     fprintf (fp, "[blob larger than length - output truncated]\n");
126   else
127     length = n;  /* ignore the rest */
128
129   fprintf (fp, "Length: %lu\n", n );
130   type = buffer[4];
131   switch (type)
132     {
133     case BLOBTYPE_EMPTY:
134       fprintf (fp, "Type:   Empty\n");
135       return 0;
136
137     case BLOBTYPE_HEADER:
138       fprintf (fp, "Type:   Header\n");
139       return dump_header_blob (buffer, length, fp);
140     case BLOBTYPE_PGP:
141       fprintf (fp, "Type:   OpenPGP\n");
142       break;
143     case BLOBTYPE_X509:
144       fprintf (fp, "Type:   X.509\n");
145       break;
146     default:
147       fprintf (fp, "Type:   %d\n", type);
148       fprintf (fp, "[can't dump this blob type]\n");
149       return 0;
150     }
151   fprintf (fp, "Version: %d\n", buffer[5]);
152
153   if (length < 40)
154     {
155       fprintf (fp, "[blob too short]\n");
156       return -1;
157     }
158   
159   n = get16 (buffer + 6);
160   fprintf( fp, "Blob-Flags: %04lX", n);
161   if (n)
162     {
163       int any = 0;
164
165       fputs (" (", fp);
166       if ((n & 1))
167         {
168           fputs ("secret", fp);
169           any++;
170         }
171       if ((n & 2))
172         {
173           if (any)
174             putc (',', fp);
175           fputs ("ephemeral", fp);
176           any++;
177         }
178       putc (')', fp);
179     }
180   putc ('\n', fp);
181
182   rawdata_off = get32 (buffer + 8);
183   rawdata_len = get32 (buffer + 12);
184
185   fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
186   fprintf( fp, "Data-Length: %lu\n", rawdata_len );
187
188   nkeys = get16 (buffer + 16);
189   fprintf (fp, "Key-Count: %lu\n", nkeys );
190   if (!nkeys)
191     fprintf (fp, "[Error: no keys]\n");
192   if (nkeys > 1 && type == BLOBTYPE_X509)
193     fprintf (fp, "[Error: only one key allowed for X509]\n");
194
195   keyinfolen = get16 (buffer + 18 );
196   fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
197   /* fixme: check bounds */
198   p = buffer + 20;
199   for (n=0; n < nkeys; n++, p += keyinfolen)
200     {
201       int i;
202       ulong kidoff, kflags;
203     
204       fprintf (fp, "Key-Fpr[%lu]: ", n );
205       for (i=0; i < 20; i++ )
206         fprintf (fp, "%02X", p[i]);
207       kidoff = get32 (p + 20);
208       fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
209       fprintf (fp, "Key-Kid[%lu]: ", n );
210       /* fixme: check bounds */
211       for (i=0; i < 8; i++ )
212         fprintf (fp, "%02X", buffer[kidoff+i] );
213       kflags = get16 (p + 24 );
214       fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
215     }
216   
217   /* serial number */
218   fputs ("Serial-No: ", fp);
219   nserial = get16 (p);
220   p += 2;
221   if (!nserial)
222     fputs ("none", fp);
223   else
224     {
225       for (; nserial; nserial--, p++)
226         fprintf (fp, "%02X", *p);
227     }
228   putc ('\n', fp);
229
230   /* user IDs */
231   nuids = get16 (p);
232   fprintf (fp, "Uid-Count: %lu\n", nuids );
233   uidinfolen = get16  (p + 2);
234   fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
235   /* fixme: check bounds */
236   p += 4;
237   for (n=0; n < nuids; n++, p += uidinfolen)
238     {
239       ulong uidoff, uidlen, uflags;
240       
241       uidoff = get32( p );
242       uidlen = get32( p+4 );
243       if (type == BLOBTYPE_X509 && !n)
244         {
245           fprintf (fp, "Issuer-Off: %lu\n", uidoff );
246           fprintf (fp, "Issuer-Len: %lu\n", uidlen );
247           fprintf (fp, "Issuer: \"");
248         }
249       else if (type == BLOBTYPE_X509 && n == 1)
250         {
251           fprintf (fp, "Subject-Off: %lu\n", uidoff );
252           fprintf (fp, "Subject-Len: %lu\n", uidlen );
253           fprintf (fp, "Subject: \"");
254         }
255       else
256         {
257           fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
258           fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
259           fprintf (fp, "Uid[%lu]: \"", n );
260         }
261       print_string (fp, buffer+uidoff, uidlen, '\"');
262       fputs ("\"\n", fp);
263       uflags = get16 (p + 8);
264       if (type == BLOBTYPE_X509 && !n)
265         {
266           fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
267           fprintf (fp, "Issuer-Validity: %d\n", p[10] );
268         }
269       else if (type == BLOBTYPE_X509 && n == 1)
270         {
271           fprintf (fp, "Subject-Flags: %04lX\n", uflags );
272           fprintf (fp, "Subject-Validity: %d\n", p[10] );
273         }
274       else
275         {
276           fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
277           fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
278         }
279     }
280   
281   nsigs = get16 (p);
282   fprintf (fp, "Sig-Count: %lu\n", nsigs );
283   siginfolen = get16 (p + 2);
284   fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
285   /* fixme: check bounds  */
286   p += 4;
287   for (n=0; n < nsigs; n++, p += siginfolen)
288     {
289       ulong sflags;
290     
291       sflags = get32 (p);
292       fprintf (fp, "Sig-Expire[%lu]: ", n );
293       if (!sflags)
294         fputs ("[not checked]", fp);
295       else if (sflags == 1 )
296         fputs ("[missing key]", fp);
297       else if (sflags == 2 )
298         fputs ("[bad signature]", fp);
299       else if (sflags < 0x10000000)
300         fprintf (fp, "[bad flag %0lx]", sflags);
301       else if (sflags == 0xffffffff)
302         fputs ("0", fp );
303       else
304         fputs ("a time"/*strtimestamp( sflags )*/, fp );
305       putc ('\n', fp );
306     }
307
308   fprintf (fp, "Ownertrust: %d\n", p[0] );
309   fprintf (fp, "All-Validity: %d\n", p[1] );
310   p += 4;
311   n = get32 (p); p += 4;
312   fprintf (fp, "Recheck-After: %lu\n", n );
313   n = get32 (p ); p += 4;
314   fprintf( fp, "Latest-Timestamp: %lu\n", n );
315   n = get32 (p ); p += 4;
316   fprintf (fp, "Created-At: %lu\n", n );
317   n = get32 (p ); p += 4;
318   fprintf (fp, "Reserved-Space: %lu\n", n );
319
320   /* check that the keyblock is at the correct offset and other bounds */
321   /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
322   return 0;
323 }
324
325
326 \f
327 int
328 _keybox_dump_file (const char *filename, FILE *outfp)
329 {
330   FILE *fp;
331   KEYBOXBLOB blob;
332   int rc;
333   unsigned long count = 0;
334
335   if (!filename)
336     {
337       filename = "-";
338       fp = stdin;
339     }
340   else
341     fp = fopen (filename, "rb");
342   if (!fp)
343     {
344       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
345       fprintf (outfp, "can't open `%s': %s\n", filename, strerror(errno));
346       return tmperr;
347     }
348
349   while ( !(rc = _keybox_read_blob (&blob, fp)) )
350     {
351       fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
352       _keybox_dump_blob (blob, outfp);
353       _keybox_release_blob (blob);
354       fprintf (outfp, "END-RECORD\n");
355       count++;
356     }
357   if (rc == -1)
358     rc = 0;
359   if (rc)
360     fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
361   
362   if (fp != stdin)
363     fclose (fp);
364   return rc;
365 }