~ubuntu-branches/ubuntu/karmic/gnupg2/karmic-updates

« back to all changes in this revision

Viewing changes to g10/kbxblob.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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