* call-agent.c (start_agent): Make copies of old locales and check
[gnupg.git] / g10 / kbxblob.c
1 /* kbxblob.c - KBX Blob handling
2  *      Copyright (C) 2000 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
22 /* The keybox data formats
23
24 The KeyBox uses an augmented OpenPGP key format.  This makes random
25 access to a keyblock easier and also gives the opportunity to store
26 additional information (e.g. the fingerprint) along with the key.
27 All integers are stored in network byte order, offsets are counted from
28 the beginning of the Blob.
29
30 The first record of a plain KBX file has a special format:
31
32  u32  length of the first record
33  byte Blob type (1)
34  byte version number (1)
35  byte reserved
36  byte reserved
37  u32  magic 'KBXf'
38  byte marginals  used for validity calculation of this file
39  byte completes  ditto.
40  byte cert_depth ditto.
41
42 The standard KBX Blob looks like this:
43
44  u32  length of this blob (including these 4 bytes)
45  byte Blob type (2)
46  byte version number of this blob type (1)
47  u16  Blob flags
48         bit 0 = contains secret key material
49
50  u32  offset to the OpenPGP keyblock
51  u32  length of the keyblock
52  u16  number of keys (at least 1!)
53  u16  size of additional key information
54  n times:
55    b20  The keys fingerprint
56         (fingerprints are always 20 bytes, MD5 left padded with zeroes)
57    u32  offset to the n-th key's keyID (a keyID is always 8 byte)
58    u16  special key flags
59          bit 0 =
60    u16  reserved
61  u16  number of user IDs
62  u16  size of additional user ID information
63  n times:
64    u32  offset to the n-th user ID
65    u32  length of this user ID.
66    u16  special user ID flags.
67          bit 0 =
68    byte validity
69    byte reserved
70  u16  number of signatures
71  u16  size of signature information (4)
72    u32  expiration time of signature with some special values:
73         0x00000000 = not checked
74         0x00000001 = missing key
75         0x00000002 = bad signature
76         0x10000000 = valid and expires at some date in 1978.
77         0xffffffff = valid and does not expire
78  u8     assigned ownertrust
79  u8     all_validity
80  u16    reserved
81  u32    recheck_after
82  u32    Newest timestamp in the keyblock (useful for KS syncronsiation?)
83  u32    Blob created at
84  u32    size of reserved space (not including this field)
85       reserved space
86
87     Here we might want to put other data
88
89     Here comes the keyblock
90
91     maybe we put a signature here later.
92
93  b16    MD5 checksum  (useful for KS syncronisation)
94  *
95  */
96
97
98 #include <config.h>
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <string.h>
102 #include <errno.h>
103 #include <assert.h>
104 #include <gcrypt.h>
105
106 #include "iobuf.h"
107 #include "util.h"
108 #include "kbx.h"
109
110 /* special values of the signature status */
111 #define SF_NONE(a)  ( !(a) )
112 #define SF_NOKEY(a) ((a) & (1<<0))
113 #define SF_BAD(a)   ((a) & (1<<1))
114 #define SF_VALID(a) ((a) & (1<<29))
115
116 #if MAX_FINGERPRINT_LEN < 20
117   #error fingerprints are 20 bytes
118 #endif
119
120 struct kbxblob_key {
121     char   fpr[20];
122     u32    off_kid;
123     ulong  off_kid_addr;
124     u16    flags;
125 };
126 struct kbxblob_uid {
127     ulong  off_addr;
128     u32    len;
129     u16    flags;
130     byte   validity;
131 };
132
133 struct keyid_list {
134     struct keyid_list *next;
135     int seqno;
136     byte kid[8];
137 };
138
139 struct fixup_list {
140     struct fixup_list *next;
141     u32 off;
142     u32 val;
143 };
144
145
146 struct kbxblob {
147     byte *blob;
148     size_t bloblen;
149
150     /* stuff used only by kbx_create_blob */
151     int nkeys;
152     struct kbxblob_key *keys;
153     int nuids;
154     struct kbxblob_uid *uids;
155     int nsigs;
156     u32  *sigs;
157     struct fixup_list *fixups;
158
159     struct keyid_list *temp_kids;
160     IOBUF buf;  /* the KBX is temporarly stored here */
161 };
162
163 void kbx_release_blob ( KBXBLOB blob );
164
165 /* Note: this functions are only used for temportay iobufs and therefore
166  * they can't fail */
167 static void
168 put8 ( IOBUF out, byte a )
169 {
170     iobuf_put ( out, a );
171 }
172
173 static void
174 put16 ( IOBUF out, u16 a )
175 {
176     iobuf_put ( out, a>>8 );
177     iobuf_put ( out, a );
178 }
179
180 static void
181 put32 ( IOBUF out, u32 a )
182 {
183     iobuf_put (out, a>> 24);
184     iobuf_put (out, a>> 16);
185     iobuf_put (out, a>> 8);
186     iobuf_put (out, a );
187 }
188
189 static void
190 putn ( IOBUF out, const byte *p, size_t n )
191 {
192     for ( ; n; p++, n-- ) {
193         iobuf_put ( out, *p );
194     }
195 }
196
197
198 /****************
199  * We must store the keyid at some place because we can't calculate the
200  * offset yet.  This is only used for v3 keyIDs.  Function returns an index
201  * value for later fixupd; this must be a non-zero value
202  */
203 static int
204 temp_store_kid ( KBXBLOB blob, PKT_public_key *pk )
205 {
206     struct keyid_list *k, *r;
207
208     k = gcry_xmalloc ( sizeof *k );
209     k->kid[0] = pk->keyid[0] >> 24 ;
210     k->kid[1] = pk->keyid[0] >> 16 ;
211     k->kid[2] = pk->keyid[0] >>  8 ;
212     k->kid[3] = pk->keyid[0]       ;
213     k->kid[4] = pk->keyid[0] >> 24 ;
214     k->kid[5] = pk->keyid[0] >> 16 ;
215     k->kid[6] = pk->keyid[0] >>  8 ;
216     k->kid[7] = pk->keyid[0]       ;
217     k->seqno = 0;
218     k->next = blob->temp_kids;
219     blob->temp_kids = k;
220     for ( r=k; r; r = r->next ) {
221         k->seqno++;
222     }
223
224     return k->seqno;
225 }
226
227 static void
228 put_stored_kid( KBXBLOB blob, int seqno )
229 {
230     struct keyid_list *r;
231
232     for ( r = blob->temp_kids; r; r = r->next ) {
233         if( r->seqno == seqno ) {
234             putn ( blob->buf, r->kid, 8 );
235             return;
236         }
237     }
238     BUG();
239 }
240
241 static void
242 release_kid_list ( struct keyid_list *kl )
243 {
244     struct keyid_list *r, *r2;
245
246     for ( r = kl; r; r = r2 ) {
247         r2 = r->next;
248         gcry_free( r );
249     }
250 }
251
252
253 static int
254 create_key_part( KBXBLOB blob, KBNODE keyblock )
255 {
256     KBNODE node;
257     size_t fprlen;
258     int n;
259
260     for ( n=0, node = keyblock; node; node = node->next ) {
261         if ( node->pkt->pkttype == PKT_PUBLIC_KEY
262              || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
263             PKT_public_key *pk = node->pkt->pkt.public_key;
264             char tmp[20];
265
266             fingerprint_from_pk( pk, tmp , &fprlen );
267             memcpy(blob->keys[n].fpr,tmp,20);
268             if ( fprlen != 20 ) { /*v3 fpr - shift right and fill with zeroes*/
269                 assert( fprlen == 16 );
270                 memmove( blob->keys[n].fpr+4, blob->keys[n].fpr, 16);
271                 memset( blob->keys[n].fpr, 0, 4 );
272                 blob->keys[n].off_kid = temp_store_kid( blob, pk );
273             }
274             else {
275                 blob->keys[n].off_kid = 0; /* will be fixed up later */
276             }
277             blob->keys[n].flags = 0;
278             n++;
279         }
280         else if ( node->pkt->pkttype == PKT_SECRET_KEY
281                   || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
282             BUG(); /* not yet implemented */
283         }
284     }
285     assert( n == blob->nkeys );
286     return 0;
287 }
288
289 static int
290 create_uid_part( KBXBLOB blob, KBNODE keyblock )
291 {
292     KBNODE node;
293     int n;
294
295     for ( n=0, node = keyblock; node; node = node->next ) {
296         if ( node->pkt->pkttype == PKT_USER_ID ) {
297             PKT_user_id *u = node->pkt->pkt.user_id;
298
299             blob->uids[n].len   = u->len;
300             blob->uids[n].flags = 0;
301             blob->uids[n].validity = 0;
302             n++;
303         }
304     }
305     assert( n == blob->nuids );
306     return 0;
307 }
308
309 static int
310 create_sig_part( KBXBLOB blob, KBNODE keyblock )
311 {
312     KBNODE node;
313     int n;
314
315     for ( n=0, node = keyblock; node; node = node->next ) {
316         if ( node->pkt->pkttype == PKT_SIGNATURE ) {
317             PKT_signature *sig = node->pkt->pkt.signature;
318
319             blob->sigs[n] = 0;  /* FIXME: check the signature here */
320             n++;
321         }
322     }
323     assert( n == blob->nsigs );
324     return 0;
325 }
326
327
328 static int
329 create_blob_header( KBXBLOB blob )
330 {
331     IOBUF a = blob->buf;
332     int i;
333
334     put32 ( a, 0 ); /* blob length, needs fixup */
335     put8 ( a, 2 );  /* blob type */
336     put8 ( a, 1 );  /* blob type version */
337     put16 ( a, 0 ); /* blob flags */
338
339     put32 ( a, 0 ); /* offset to the keyblock, needs fixup */
340     put32 ( a, 0 ); /* length of the keyblock, needs fixup */
341
342     put16 ( a, blob->nkeys );
343     put16 ( a, 20 + 4 + 2 + 2 );  /* size of key info */
344     for ( i=0; i < blob->nkeys; i++ ) {
345         putn ( a, blob->keys[i].fpr, 20 );
346         blob->keys[i].off_kid_addr = iobuf_get_temp_length (a);
347         put32 ( a, 0 ); /* offset to keyid, fixed up later */
348         put16 ( a, blob->keys[i].flags );
349         put16 ( a, 0 ); /* reserved */
350     }
351
352     put16 ( a, blob->nuids );
353     put16 ( a, 4 + 4 + 2 + 1 + 1 );  /* size of uid info */
354     for ( i=0; i < blob->nuids; i++ ) {
355         blob->uids[i].off_addr = iobuf_get_temp_length ( a );
356         put32 ( a, 0 ); /* offset to userid, fixed up later */
357         put32 ( a, blob->uids[i].len );
358         put16 ( a, blob->uids[i].flags );
359         put8  ( a, 0 ); /* validity */
360         put8  ( a, 0 ); /* reserved */
361     }
362
363     put16 ( a, blob->nsigs );
364     put16 ( a, 4 );  /* size of sig info */
365     for ( i=0; i < blob->nsigs; i++ ) {
366         put32 ( a, blob->sigs[i] );
367     }
368
369     put8 ( a, 0 );  /* assigned ownertrust */
370     put8 ( a, 0 );  /* validity of all user IDs */
371     put16 ( a, 0 );  /* reserved */
372     put32 ( a, 0 );  /* time of next recheck */
373     put32 ( a, 0 );  /* newest timestamp (none) */
374     put32 ( a, make_timestamp() );  /* creation time */
375     put32 ( a, 0 );  /* size of reserved space */
376         /* reserved space (which is currently of size 0) */
377
378     /* We need to store the keyids for all v3 keys because those key IDs are
379      * not part of the fingerprint.  While we are doing that, we fixup all
380      * the keyID offsets */
381     for ( i=0; i < blob->nkeys; i++ ) {
382         struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
383         fl->off = blob->keys[i].off_kid_addr;
384         fl->next = blob->fixups;
385         blob->fixups = fl;
386
387         if ( blob->keys[i].off_kid ) { /* this is a v3 one */
388             fl->val = iobuf_get_temp_length (a);
389             put_stored_kid ( blob, blob->keys[i].off_kid );
390         }
391         else { /* the better v4 key IDs - just store an offset 8 bytes back */
392             fl->val = blob->keys[i].off_kid_addr-8;
393         }
394     }
395
396
397     return 0;
398 }
399
400 static int
401 create_blob_keyblock( KBXBLOB blob, KBNODE keyblock )
402 {
403     IOBUF a = blob->buf;
404     KBNODE node;
405     int rc;
406     int n;
407     u32 kbstart = iobuf_get_temp_length ( a );
408
409     {
410             struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
411             fl->off = 8;
412             fl->val = kbstart;
413             fl->next = blob->fixups;
414             blob->fixups = fl;
415     }
416     for ( n = 0, node = keyblock; node; node = node->next ) {
417         rc = build_packet ( a, node->pkt );
418         if ( rc ) {
419             gpg_log_error("build_packet(%d) for kbxblob failed: %s\n",
420                         node->pkt->pkttype, gpg_errstr(rc) );
421             return GPGERR_WRITE_FILE;
422         }
423         if ( node->pkt->pkttype == PKT_USER_ID ) {
424             PKT_user_id *u = node->pkt->pkt.user_id;
425             /* build_packet has set the offset of the name into u ;
426              * now we can do the fixup */
427             struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
428             fl->off = blob->uids[n].off_addr;
429             fl->val = u->stored_at;
430             fl->next = blob->fixups;
431             blob->fixups = fl;
432             n++;
433         }
434     }
435     assert( n == blob->nuids );
436     {
437             struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
438             fl->off = 12;
439             fl->val = iobuf_get_temp_length (a) - kbstart;
440             fl->next = blob->fixups;
441             blob->fixups = fl;
442     }
443     return 0;
444 }
445
446 static int
447 create_blob_trailer( KBXBLOB blob )
448 {
449     IOBUF a = blob->buf;
450     return 0;
451 }
452
453 static int
454 create_blob_finish( KBXBLOB blob )
455 {
456     IOBUF a = blob->buf;
457     byte *p;
458     char *pp;
459     int i;
460     size_t n;
461
462     /* write a placeholder for the checksum */
463     for ( i = 0; i < 16; i++ )
464         put32( a, 0 );
465     /* get the memory area */
466     iobuf_flush_temp ( a );
467     p = iobuf_get_temp_buffer ( a );
468     n = iobuf_get_temp_length ( a );
469     assert( n >= 20 );
470
471     /* fixup the length */
472     {
473         struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
474         fl->off = 0;
475         fl->val = n;
476         fl->next = blob->fixups;
477         blob->fixups = fl;
478     }
479     /* do the fixups */
480     {
481         struct fixup_list *fl;
482         for ( fl = blob->fixups; fl; fl = fl->next ) {
483             assert( fl->off+4 <= n );
484             p[fl->off+0] = fl->val >> 24 ;
485             p[fl->off+1] = fl->val >> 16 ;
486             p[fl->off+2] = fl->val >>  8 ;
487             p[fl->off+3] = fl->val       ;
488         }
489
490     }
491
492     /* calculate and store the MD5 checksum */
493     gcry_md_hash_buffer( GCRY_MD_MD5, p + n - 16, p, n - 16 );
494
495     pp = gcry_malloc ( n );
496     if ( !pp )
497         return GCRYERR_NO_MEM;
498     memcpy ( pp , p, n );
499     blob->blob = pp;
500     blob->bloblen = n;
501
502     return 0;
503 }
504
505
506 int
507 kbx_create_blob ( KBXBLOB *r_blob,  KBNODE keyblock )
508 {
509     int rc = 0;
510     KBNODE node;
511     KBXBLOB blob;
512
513     *r_blob = NULL;
514     blob = gcry_xcalloc (1, sizeof *blob );
515     if( !blob )
516         return GCRYERR_NO_MEM;
517
518     /* fixme: Do some sanity checks on the keyblock */
519
520     /* count userids and keys so that we can allocate the arrays */
521     for ( node = keyblock; node; node = node->next ) {
522         switch ( node->pkt->pkttype ) {
523           case PKT_PUBLIC_KEY:
524           case PKT_SECRET_KEY:
525           case PKT_PUBLIC_SUBKEY:
526           case PKT_SECRET_SUBKEY: blob->nkeys++; break;
527           case PKT_USER_ID:  blob->nuids++; break;
528           case PKT_SIGNATURE: blob->nsigs++; break;
529           default: break;
530         }
531     }
532     blob->keys = gcry_xcalloc ( blob->nkeys, sizeof ( *blob->keys ) );
533     blob->uids = gcry_xcalloc ( blob->nuids, sizeof ( *blob->uids ) );
534     blob->sigs = gcry_xcalloc ( blob->nsigs, sizeof ( *blob->sigs ) );
535     if ( !blob->keys || !blob->uids || !blob->sigs ) {
536         rc = GCRYERR_NO_MEM;
537         goto leave;
538     }
539
540     rc = create_key_part ( blob, keyblock );
541     if( rc )
542         goto leave;
543     rc = create_uid_part ( blob, keyblock );
544     if( rc )
545         goto leave;
546     rc = create_sig_part ( blob, keyblock );
547     if( rc )
548         goto leave;
549
550     blob->buf = iobuf_temp();
551     rc = create_blob_header ( blob );
552     if( rc )
553         goto leave;
554     rc = create_blob_keyblock ( blob, keyblock );
555     if( rc )
556         goto leave;
557     rc = create_blob_trailer ( blob );
558     if( rc )
559         goto leave;
560     rc = create_blob_finish ( blob );
561     if( rc )
562         goto leave;
563
564
565   leave:
566     release_kid_list( blob->temp_kids );
567     blob->temp_kids = NULL;
568     if ( rc ) {
569         kbx_release_blob ( blob );
570         *r_blob = NULL;
571     }
572     else  {
573         *r_blob = blob;
574     }
575     return rc;
576 }
577
578 int
579 kbx_new_blob ( KBXBLOB *r_blob,  char *image, size_t imagelen )
580 {
581     KBXBLOB blob;
582
583     *r_blob = NULL;
584     blob = gcry_xcalloc (1, sizeof *blob );
585     if( !blob )
586         return GCRYERR_NO_MEM;
587     blob->blob = image;
588     blob->bloblen = imagelen;
589     *r_blob = blob;
590     return 0;
591 }
592
593
594
595 const char *
596 kbx_get_blob_image ( KBXBLOB blob, size_t *n )
597 {
598     *n = blob->bloblen;
599     return blob->blob;
600 }
601
602 void
603 kbx_release_blob ( KBXBLOB blob )
604 {
605     if( !blob )
606         return;
607     if( blob->buf )
608         iobuf_cancel( blob->buf );
609     gcry_free( blob->keys );
610     gcry_free( blob->uids );
611     gcry_free( blob->sigs );
612
613     gcry_free ( blob->blob );
614
615     gcry_free( blob );
616 }
617
618 static ulong
619 get32( const byte *buffer )
620 {
621     ulong a;
622     a =  *buffer << 24;
623     a |= buffer[1] << 16;
624     a |= buffer[2] << 8;
625     a |= buffer[3];
626     return a;
627 }
628
629 static ulong
630 get16( const byte *buffer )
631 {
632     ulong a;
633     a =  *buffer << 8;
634     a |= buffer[1];
635     return a;
636 }
637
638
639 int
640 kbx_dump_blob ( FILE *fp, KBXBLOB blob  )
641 {
642     const byte *buffer = blob->blob;
643     size_t length = blob->bloblen;
644     ulong n, nkeys, keyinfolen;
645     ulong nuids, uidinfolen;
646     ulong nsigs, siginfolen;
647     ulong keyblock_off, keyblock_len;
648     const byte *p;
649
650     if( length < 40 )  {
651         fprintf( fp, "blob too short\n");
652         return -1;
653     }
654     n = get32( buffer );
655     if( n > length ) {
656         fprintf( fp, "blob larger than length - output truncated\n");
657     }
658     else
659         length = n;  /* ignore the rest */
660     fprintf( fp, "Length: %lu\n", n );
661     fprintf( fp, "Type:   %d\n", buffer[4] );
662     fprintf( fp, "Version: %d\n", buffer[5] );
663     if( buffer[4] != 2 ) {
664         fprintf( fp, "can't dump this blob type\n" );
665         return 0;
666     }
667
668     n = get16( buffer + 6 );
669     fprintf( fp, "Blob-Flags: %04lX\n", n );
670     keyblock_off = get32( buffer + 8 );
671     keyblock_len = get32( buffer + 12 );
672     fprintf( fp, "Keyblock-Offset: %lu\n", keyblock_off );
673     fprintf( fp, "Keyblock-Length: %lu\n", keyblock_len );
674
675     nkeys = get16( buffer + 16 );
676     fprintf( fp, "Key-Count: %lu\n", nkeys );
677     keyinfolen = get16( buffer + 18 );
678     fprintf( fp, "Key-Info-Length: %lu\n", keyinfolen );
679     /* fixme: check bounds */
680     p = buffer + 20;
681     for(n=0; n < nkeys; n++, p += keyinfolen ) {
682         int i;
683         ulong kidoff, kflags;
684
685         fprintf( fp, "Key-%lu-Fpr: ", n );
686         for(i=0; i < 20; i++ )
687             fprintf( fp, "%02X", p[i] );
688         kidoff = get32( p + 20 );
689         fprintf( fp, "\nKey-%lu-Kid-Off: %lu\n", n, kidoff );
690         fprintf( fp, "Key-%lu-Kid: ", n );
691         /* fixme: check bounds */
692         for(i=0; i < 8; i++ )
693             fprintf( fp, "%02X", buffer[kidoff+i] );
694         kflags = get16( p + 24 );
695         fprintf( fp, "\nKey-%lu-Flags: %04lX\n", n, kflags );
696     }
697
698
699     nuids = get16( p );
700     fprintf( fp, "Uid-Count: %lu\n", nuids );
701     uidinfolen = get16( p + 2 );
702     fprintf( fp, "Uid-Info-Length: %lu\n", uidinfolen );
703     /* fixme: check bounds */
704     p += 4;
705     for(n=0; n < nuids; n++, p += uidinfolen ) {
706         ulong uidoff, uidlen, uflags;
707
708         uidoff = get32( p );
709         uidlen = get32( p+4 );
710         fprintf( fp, "Uid-%lu-Off: %lu\n", n, uidoff );
711         fprintf( fp, "Uid-%lu-Len: %lu\n", n, uidlen );
712         fprintf( fp, "Uid-%lu: \"", n );
713         print_string( fp, buffer+uidoff, uidlen, '\"' );
714         fputs("\"\n", fp );
715         uflags = get16( p + 8 );
716         fprintf( fp, "Uid-%lu-Flags: %04lX\n", n, uflags );
717         fprintf( fp, "Uid-%lu-Validity: %d\n", n, p[10] );
718     }
719
720     nsigs = get16( p );
721     fprintf( fp, "Sig-Count: %lu\n", nsigs );
722     siginfolen = get16( p + 2 );
723     fprintf( fp, "Sig-Info-Length: %lu\n", siginfolen );
724     /* fixme: check bounds  */
725     p += 4;
726     for(n=0; n < nsigs; n++, p += siginfolen ) {
727         ulong sflags;
728
729         sflags = get32( p );
730         fprintf( fp, "Sig-%lu-Expire: ", n );
731         if( !sflags )
732             fputs( "[not checked]", fp );
733         else if( sflags == 1 )
734             fputs( "[missing key]", fp );
735         else if( sflags == 2 )
736             fputs( "[bad signature]", fp );
737         else if( sflags < 0x10000000 )
738             fprintf( fp, "[bad flag %0lx]", sflags );
739         else if( sflags == 0xffffffff )
740             fputs( "0", fp );
741         else
742             fputs( strtimestamp( sflags ), fp );
743         putc('\n', fp );
744     }
745
746     fprintf( fp, "Ownertrust: %d\n", p[0] );
747     fprintf( fp, "All-Validity: %d\n", p[1] );
748     p += 4;
749     n = get32( p ); p += 4;
750     fprintf( fp, "Recheck-After: %s\n", n? strtimestamp(n) : "0" );
751     n = get32( p ); p += 4;
752     fprintf( fp, "Latest-Timestamp: %s\n", strtimestamp(n) );
753     n = get32( p ); p += 4;
754     fprintf( fp, "Created-At: %s\n", strtimestamp(n) );
755     n = get32( p ); p += 4;
756     fprintf( fp, "Reserved-Space: %lu\n", n );
757
758
759     /* check that the keyblock is at the correct offset and other bounds */
760
761
762     fprintf( fp, "Blob-Checksum: [MD5-hash]\n" );
763     return 0;
764 }
765
766 /****************
767  * Check whether the given fingerprint (20 bytes) is in the
768  * given keyblob.  fpr is always 20 bytes.
769  * Return: 0 = found
770  *         -1 = not found
771           other = error  (fixme: do not always reurn gpgerr_general)
772  */
773 int
774 kbx_blob_has_fpr ( KBXBLOB blob, const byte *fpr )
775 {
776     ulong n, nkeys, keyinfolen;
777     const byte *p, *pend;
778     byte *buffer = blob->blob;
779     size_t buflen = blob->bloblen;
780
781     if ( buflen < 40 )
782         return GPGERR_GENERAL; /* blob too short */
783     n = get32( buffer );
784     if ( n > buflen )
785         return GPGERR_GENERAL; /* blob larger than announced length */
786     buflen = n;  /* ignore trailing stuff */
787     pend = buffer + n - 1;
788
789     if ( buffer[4] != 2 )
790         return GPGERR_GENERAL; /* invalid blob type */
791     if ( buffer[5] != 1 )
792         return GPGERR_GENERAL; /* invalid blob format version */
793
794     nkeys = get16( buffer + 16 );
795     keyinfolen = get16( buffer + 18 );
796     p = buffer + 20;
797     for(n=0; n < nkeys; n++, p += keyinfolen ) {
798         if ( p+20 > pend )
799             return GPGERR_GENERAL; /* blob shorter than required */
800         if (!memcmp ( p, fpr, 20 ) )
801             return 0; /* found */
802     }
803     return -1;
804 }
805
806 /****************
807  * Check whether the given keyID (20 bytes) is in the
808  * given keyblob.
809  * Return: 0 = found
810  *         -1 = not found
811           other = error  (fixme: do not always return gpgerr_general)
812  */
813 int
814 kbx_blob_has_kid ( KBXBLOB blob, const byte *keyidbuf, size_t keyidlen )
815 {
816     ulong n, nkeys, keyinfolen, off;
817     const byte *p, *pend;
818     byte *buffer = blob->blob;
819     size_t buflen = blob->bloblen;
820
821     if ( buflen < 40 )
822         return GPGERR_GENERAL; /* blob too short */
823     n = get32( buffer );
824     if ( n > buflen )
825         return GPGERR_GENERAL; /* blob larger than announced length */
826     buflen = n;  /* ignore trailing stuff */
827     pend = buffer + n - 1;
828
829     if ( buffer[4] != 2 )
830         return GPGERR_GENERAL; /* invalid blob type */
831     if ( buffer[5] != 1 )
832         return GPGERR_GENERAL; /* invalid blob format version */
833
834     nkeys = get16( buffer + 16 );
835     keyinfolen = get16( buffer + 18 );
836     p = buffer + 20;
837     for(n=0; n < nkeys; n++, p += keyinfolen ) {
838         if ( p+24 > pend )
839             return GPGERR_GENERAL; /* blob shorter than required */
840         off = get32 ( p + 20 );
841         if (keyidlen < 8 ) /* actually keyidlen may either be 4 or 8 */
842             off +=4;
843         if ( off+keyidlen > buflen )
844             return GPGERR_GENERAL; /* offset out of bounds */
845         if ( !memcmp ( buffer+off, keyidbuf, keyidlen ) )
846             return 0; /* found */
847     }
848     return -1;
849 }
850
851
852
853 int
854 kbx_blob_has_uid ( KBXBLOB blob,
855                    int (*cmp)(const byte *, size_t, void *), void *opaque )
856 {
857     ulong n, nuids, uidinfolen, off, len;
858     const byte *p, *pend;
859     byte *buffer = blob->blob;
860     size_t buflen = blob->bloblen;
861
862     if ( buflen < 40 )
863         return GPGERR_GENERAL; /* blob too short */
864     n = get32( buffer );
865     if ( n > buflen )
866         return GPGERR_GENERAL; /* blob larger than announced length */
867     buflen = n;  /* ignore trailing stuff */
868     pend = buffer + n - 1;
869
870     if ( buffer[4] != 2 )
871         return GPGERR_GENERAL; /* invalid blob type */
872     if ( buffer[5] != 1 )
873         return GPGERR_GENERAL; /* invalid blob format version */
874
875     p = buffer + 20 + get16( buffer + 16 ) * get16( buffer + 18 );
876     if ( p+4 > pend )
877         return GPGERR_GENERAL; /* blob shorter than required */
878
879     nuids = get16( p ); p+= 2;
880     uidinfolen = get16( p ); p+=2;
881     for(n=0; n < nuids; n++, p += uidinfolen ) {
882         if ( p+8 > pend )
883             return GPGERR_GENERAL; /* blob shorter than required */
884         off = get32 ( p );
885         len = get32 ( p + 4 );
886         if ( off+len > buflen )
887             return GPGERR_GENERAL; /* offset out of bounds */
888         if ( (*cmp) ( buffer+off, len, opaque ) )
889             return 0; /* found */
890     }
891
892     return -1;
893 }
894
895