Add features packet and fixes MIPS3.
[gnupg.git] / g10 / parse-packet.c
1 /* parse-packet.c  - read packets
2  *      Copyright (C) 1998, 1999, 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include <gcrypt.h>
28 #include "packet.h"
29 #include "iobuf.h"
30 #include "util.h"
31 #include "filter.h"
32 #include "options.h"
33 #include "main.h"
34 #include "i18n.h"
35
36 static int mpi_print_mode = 0;
37 static int list_mode = 0;
38
39 static int  parse( IOBUF inp, PACKET *pkt, int reqtype,
40                    ulong *retpos, int *skip, IOBUF out, int do_skip
41             #ifdef DEBUG_PARSE_PACKET
42                    ,const char *dbg_w, const char *dbg_f, int dbg_l
43             #endif
44                  );
45 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
46                                                unsigned long pktlen );
47 static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
48 static void skip_rest( IOBUF inp, unsigned long pktlen );
49 static void *read_rest( IOBUF inp, size_t pktlen );
50 static int  parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
51                                                              PACKET *packet );
52 static int  parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
53                                                              PACKET *packet );
54 static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
55                                                          PKT_signature *sig );
56 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
57                                                         PKT_onepass_sig *ops );
58 static int  parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
59                                       byte *hdr, int hdrlen, PACKET *packet );
60 static int  parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
61                                                            PACKET *packet );
62 static int  parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen,
63                                                            PACKET *packet );
64 static int  parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
65                                                            PACKET *packet );
66 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen,
67                                                            PACKET *packet );
68 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
69                                                PACKET *packet, int new_ctb);
70 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
71                                                PACKET *packet, int new_ctb );
72 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
73                                                PACKET *packet, int new_ctb);
74 static int  parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
75                                                PACKET *packet, int new_ctb);
76
77 static unsigned short
78 read_16(IOBUF inp)
79 {
80     unsigned short a;
81     a = iobuf_get_noeof(inp) << 8;
82     a |= iobuf_get_noeof(inp);
83     return a;
84 }
85
86 static unsigned long
87 read_32(IOBUF inp)
88 {
89     unsigned long a;
90     a =  iobuf_get_noeof(inp) << 24;
91     a |= iobuf_get_noeof(inp) << 16;
92     a |= iobuf_get_noeof(inp) << 8;
93     a |= iobuf_get_noeof(inp);
94     return a;
95 }
96
97
98 int
99 set_packet_list_mode( int mode )
100 {
101     int old = list_mode;
102     list_mode = mode;
103     mpi_print_mode = (opt.debug & DBG_MPI_VALUE);
104     return old;
105 }
106
107 static void
108 unknown_pubkey_warning( int algo )
109 {
110     static byte unknown_pubkey_algos[256];
111
112     algo &= 0xff;
113     if( !unknown_pubkey_algos[algo] ) {
114         if( opt.verbose )
115             log_info(_("can't handle public key algorithm %d\n"), algo );
116         unknown_pubkey_algos[algo] = 1;
117     }
118 }
119
120 /****************
121  * Parse a Packet and return it in packet
122  * Returns: 0 := valid packet in pkt
123  *         -1 := no more packets
124  *         >0 := error
125  * Note: The function may return an error and a partly valid packet;
126  * caller must free this packet.
127  */
128 #ifdef DEBUG_PARSE_PACKET
129 int
130 dbg_parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos,
131                   const char *dbg_f, int dbg_l )
132 {
133     int skip, rc;
134
135     do {
136         rc = parse( inp, pkt, 0, retpos,
137                     &skip, NULL, 0, "parse", dbg_f, dbg_l );
138     } while( skip );
139     return rc;
140 }
141 #else
142 int
143 parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos )
144 {
145     int skip, rc;
146
147     do {
148         rc = parse( inp, pkt, 0, retpos, &skip, NULL, 0 );
149     } while( skip );
150     return rc;
151 }
152 #endif
153
154 /****************
155  * Like parse packet, but only return packets of the given type.
156  */
157 #ifdef DEBUG_PARSE_PACKET
158 int
159 dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos,
160                    const char *dbg_f, int dbg_l )
161 {
162     int skip, rc;
163
164     do {
165         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
166     } while( skip );
167     return rc;
168 }
169 #else
170 int
171 search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
172 {
173     int skip, rc;
174
175     do {
176         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
177     } while( skip );
178     return rc;
179 }
180 #endif
181
182 /****************
183  * Copy all packets from INP to OUT, thereby removing unused spaces.
184  */
185 #ifdef DEBUG_PARSE_PACKET
186 int
187 dbg_copy_all_packets( IOBUF inp, IOBUF out,
188                    const char *dbg_f, int dbg_l )
189 {
190     PACKET pkt;
191     int skip, rc=0;
192     do {
193         init_packet(&pkt);
194     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l )));
195     return rc;
196 }
197 #else
198 int
199 copy_all_packets( IOBUF inp, IOBUF out )
200 {
201     PACKET pkt;
202     int skip, rc=0;
203     do {
204         init_packet(&pkt);
205     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));
206     return rc;
207 }
208 #endif
209
210 /****************
211  * Copy some packets from INP to OUT, thereby removing unused spaces.
212  * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets)
213  */
214 #ifdef DEBUG_PARSE_PACKET
215 int
216 dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff,
217                    const char *dbg_f, int dbg_l )
218 {
219     PACKET pkt;
220     int skip, rc=0;
221     do {
222         if( iobuf_tell(inp) >= stopoff )
223             return 0;
224         init_packet(&pkt);
225     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0,
226                                      "some", dbg_f, dbg_l )) );
227     return rc;
228 }
229 #else
230 int
231 copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff )
232 {
233     PACKET pkt;
234     int skip, rc=0;
235     do {
236         if( iobuf_tell(inp) >= stopoff )
237             return 0;
238         init_packet(&pkt);
239     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );
240     return rc;
241 }
242 #endif
243
244 /****************
245  * Skip over N packets
246  */
247 #ifdef DEBUG_PARSE_PACKET
248 int
249 dbg_skip_some_packets( IOBUF inp, unsigned n,
250                    const char *dbg_f, int dbg_l )
251 {
252     int skip, rc=0;
253     PACKET pkt;
254
255     for( ;n && !rc; n--) {
256         init_packet(&pkt);
257         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l );
258     }
259     return rc;
260 }
261 #else
262 int
263 skip_some_packets( IOBUF inp, unsigned n )
264 {
265     int skip, rc=0;
266     PACKET pkt;
267
268     for( ;n && !rc; n--) {
269         init_packet(&pkt);
270         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );
271     }
272     return rc;
273 }
274 #endif
275
276
277 /****************
278  * Parse packet. Set the variable skip points to to 1 if the packet
279  * should be skipped; this is the case if either there is a
280  * requested packet type and the parsed packet doesn't match or the
281  * packet-type is 0, indicating deleted stuff.
282  * if OUT is not NULL, a special copymode is used.
283  */
284 static int
285 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
286        int *skip, IOBUF out, int do_skip
287 #ifdef DEBUG_PARSE_PACKET
288        ,const char *dbg_w, const char *dbg_f, int dbg_l
289 #endif
290      )
291 {
292     int rc=0, c, ctb, pkttype, lenbytes;
293     unsigned long pktlen;
294     byte hdr[8];
295     int hdrlen;
296     int new_ctb = 0;
297
298     *skip = 0;
299     assert( !pkt->pkt.generic );
300     if( retpos )
301         *retpos = iobuf_tell(inp);
302
303     if( (ctb = iobuf_get(inp)) == -1 ) {
304         rc = -1;
305         goto leave;
306     }
307     hdrlen=0;
308     hdr[hdrlen++] = ctb;
309     if( !(ctb & 0x80) ) {
310         log_error("%s: invalid packet (ctb=%02x) near %lu\n",
311                             iobuf_where(inp), ctb, iobuf_tell(inp) );
312         rc = GPGERR_INVALID_PACKET;
313         goto leave;
314     }
315     pktlen = 0;
316     new_ctb = !!(ctb & 0x40);
317     if( new_ctb ) {
318         pkttype =  ctb & 0x3f;
319         if( (c = iobuf_get(inp)) == -1 ) {
320             log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
321             rc = GPGERR_INVALID_PACKET;
322             goto leave;
323         }
324         hdr[hdrlen++] = c;
325         if( c < 192 )
326             pktlen = c;
327         else if( c < 224 ) {
328             pktlen = (c - 192) * 256;
329             if( (c = iobuf_get(inp)) == -1 ) {
330                 log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
331                 rc = GPGERR_INVALID_PACKET;
332                 goto leave;
333             }
334             hdr[hdrlen++] = c;
335             pktlen += c + 192;
336         }
337         else if( c == 255 ) {
338             pktlen  = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24;
339             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16;
340             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
341             if( (c = iobuf_get(inp)) == -1 ) {
342                 log_error("%s: 4 byte length invalid\n", iobuf_where(inp) );
343                 rc = GPGERR_INVALID_PACKET;
344                 goto leave;
345             }
346             pktlen |= (hdr[hdrlen++] = c );
347         }
348         else { /* partial body length */
349             iobuf_set_partial_block_mode(inp, c & 0xff);
350             pktlen = 0;/* to indicate partial length */
351         }
352     }
353     else {
354         pkttype = (ctb>>2)&0xf;
355         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
356         if( !lenbytes ) {
357             pktlen = 0; /* don't know the value */
358             if( pkttype != PKT_COMPRESSED )
359                 iobuf_set_block_mode(inp, 1);
360         }
361         else {
362             for( ; lenbytes; lenbytes-- ) {
363                 pktlen <<= 8;
364                 pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
365             }
366         }
367     }
368
369     if( out && pkttype  ) {
370         if( iobuf_write( out, hdr, hdrlen ) == -1 )
371             rc = GPGERR_WRITE_FILE;
372         else
373             rc = copy_packet(inp, out, pkttype, pktlen );
374         goto leave;
375     }
376
377     if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
378         skip_rest(inp, pktlen);
379         *skip = 1;
380         rc = 0;
381         goto leave;
382     }
383
384     if( DBG_PACKET ) {
385       #ifdef DEBUG_PARSE_PACKET
386         log_debug("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n",
387                    iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"",
388                     dbg_w, dbg_f, dbg_l );
389       #else
390         log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n",
391                    iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"" );
392       #endif
393     }
394     pkt->pkttype = pkttype;
395     rc = GPGERR_UNKNOWN_PACKET; /* default error */
396     switch( pkttype ) {
397       case PKT_PUBLIC_KEY:
398       case PKT_PUBLIC_SUBKEY:
399         pkt->pkt.public_key = gcry_xcalloc( 1,sizeof *pkt->pkt.public_key );
400         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
401         break;
402       case PKT_SECRET_KEY:
403       case PKT_SECRET_SUBKEY:
404         pkt->pkt.secret_key = gcry_xcalloc( 1,sizeof *pkt->pkt.secret_key );
405         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
406         break;
407       case PKT_SYMKEY_ENC:
408         rc = parse_symkeyenc( inp, pkttype, pktlen, pkt );
409         break;
410       case PKT_PUBKEY_ENC:
411         rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );
412         break;
413       case PKT_SIGNATURE:
414         pkt->pkt.signature = gcry_xcalloc( 1,sizeof *pkt->pkt.signature );
415         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
416         break;
417       case PKT_ONEPASS_SIG:
418         pkt->pkt.onepass_sig = gcry_xcalloc( 1,sizeof *pkt->pkt.onepass_sig );
419         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
420         break;
421       case PKT_USER_ID:
422         rc = parse_user_id(inp, pkttype, pktlen, pkt );
423         break;
424       case PKT_PHOTO_ID:
425         pkt->pkttype = pkttype = PKT_USER_ID;  /* must fix it */
426         rc = parse_photo_id(inp, pkttype, pktlen, pkt);
427         break;
428       case PKT_OLD_COMMENT:
429       case PKT_COMMENT:
430         rc = parse_comment(inp, pkttype, pktlen, pkt);
431         break;
432       case PKT_RING_TRUST:
433         parse_trust(inp, pkttype, pktlen, pkt);
434         rc = 0;
435         break;
436       case PKT_PLAINTEXT:
437         rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );
438         break;
439       case PKT_COMPRESSED:
440         rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );
441         break;
442       case PKT_ENCRYPTED:
443       case PKT_ENCRYPTED_MDC:
444         rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );
445         break;
446       case PKT_MDC:
447         rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb );
448         break;
449       default:
450         skip_packet(inp, pkttype, pktlen);
451         break;
452     }
453
454   leave:
455     if( !rc && iobuf_error(inp) )
456         rc = GPGERR_INV_KEYRING;
457     return rc;
458 }
459
460 static void
461 dump_hex_line( int c, int *i )
462 {
463     if( *i && !(*i%8) ) {
464         if( *i && !(*i%24) )
465             printf("\n%4d:", *i );
466         else
467             putchar(' ');
468     }
469     if( c == -1 )
470         printf(" EOF" );
471     else
472         printf(" %02x", c );
473     ++*i;
474 }
475
476
477 static int
478 copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
479 {
480     int n;
481     char buf[100];
482
483     if( iobuf_in_block_mode(inp) ) {
484         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
485             if( iobuf_write(out, buf, n ) )
486                 return GPGERR_WRITE_FILE; /* write error */
487     }
488     else if( !pktlen && pkttype == PKT_COMPRESSED ) {
489         log_debug("copy_packet: compressed!\n");
490         /* compressed packet, copy till EOF */
491         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
492             if( iobuf_write(out, buf, n ) )
493                 return GPGERR_WRITE_FILE; /* write error */
494     }
495     else {
496         for( ; pktlen; pktlen -= n ) {
497             n = pktlen > 100 ? 100 : pktlen;
498             n = iobuf_read( inp, buf, n );
499             if( n == -1 )
500                 return GPGERR_READ_FILE;
501             if( iobuf_write(out, buf, n ) )
502                 return GPGERR_WRITE_FILE; /* write error */
503         }
504     }
505     return 0;
506 }
507
508
509 static void
510 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
511 {
512     if( list_mode ) {
513         if( pkttype == PKT_MARKER )
514             fputs(":marker packet:\n", stdout );
515         else
516             printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
517         if( pkttype ) {
518             int c, i=0 ;
519             if( pkttype != PKT_MARKER )
520                 fputs("dump:", stdout );
521             if( iobuf_in_block_mode(inp) ) {
522                 while( (c=iobuf_get(inp)) != -1 )
523                     dump_hex_line(c, &i);
524             }
525             else {
526                 for( ; pktlen; pktlen-- )
527                     dump_hex_line(iobuf_get(inp), &i);
528             }
529             putchar('\n');
530             return;
531         }
532     }
533     skip_rest(inp,pktlen);
534 }
535
536 static void
537 skip_rest( IOBUF inp, unsigned long pktlen )
538 {
539     if( iobuf_in_block_mode(inp) ) {
540         while( iobuf_get(inp) != -1 )
541                 ;
542     }
543     else {
544         for( ; pktlen; pktlen-- )
545             if( iobuf_get(inp) == -1 )
546                 break;
547     }
548 }
549
550
551 static void *
552 read_rest( IOBUF inp, size_t pktlen )
553 {
554     byte *p;
555     int i;
556
557     if( iobuf_in_block_mode(inp) ) {
558         log_error("read_rest: can't store stream data\n");
559         p = NULL;
560     }
561     else {
562         p = gcry_xmalloc( pktlen );
563         for(i=0; pktlen; pktlen--, i++ )
564             p[i] = iobuf_get(inp);
565     }
566     return p;
567 }
568
569
570
571 static int
572 parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
573 {
574     PKT_symkey_enc *k;
575     int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
576
577     if( pktlen < 4 ) {
578         log_error("packet(%d) too short\n", pkttype);
579         goto leave;
580     }
581     version = iobuf_get_noeof(inp); pktlen--;
582     if( version != 4 ) {
583         log_error("packet(%d) with unknown version %d\n", pkttype, version);
584         goto leave;
585     }
586     if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
587         log_error("packet(%d) too large\n", pkttype);
588         goto leave;
589     }
590     cipher_algo = iobuf_get_noeof(inp); pktlen--;
591     s2kmode = iobuf_get_noeof(inp); pktlen--;
592     hash_algo = iobuf_get_noeof(inp); pktlen--;
593     switch( s2kmode ) {
594       case 0:  /* simple s2k */
595         minlen = 0;
596         break;
597       case 1:  /* salted s2k */
598         minlen = 8;
599         break;
600       case 3:  /* iterated+salted s2k */
601         minlen = 9;
602         break;
603       default:
604         log_error("unknown S2K %d\n", s2kmode );
605         goto leave;
606     }
607     if( minlen > pktlen ) {
608         log_error("packet with S2K %d too short\n", s2kmode );
609         goto leave;
610     }
611     seskeylen = pktlen - minlen;
612     k = packet->pkt.symkey_enc = gcry_xcalloc( 1, sizeof *packet->pkt.symkey_enc
613                                                 + seskeylen - 1 );
614     k->version = version;
615     k->cipher_algo = cipher_algo;
616     k->s2k.mode = s2kmode;
617     k->s2k.hash_algo = hash_algo;
618     if( s2kmode == 1 || s2kmode == 3 ) {
619         for(i=0; i < 8 && pktlen; i++, pktlen-- )
620             k->s2k.salt[i] = iobuf_get_noeof(inp);
621     }
622     if( s2kmode == 3 ) {
623         k->s2k.count = iobuf_get(inp); pktlen--;
624     }
625     k->seskeylen = seskeylen;
626     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
627         k->seskey[i] = iobuf_get_noeof(inp);
628     assert( !pktlen );
629
630     if( list_mode ) {
631         printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
632                             version, cipher_algo, s2kmode, hash_algo);
633         if( s2kmode == 1 || s2kmode == 3 ) {
634             printf("\tsalt ");
635             for(i=0; i < 8; i++ )
636                 printf("%02x", k->s2k.salt[i]);
637             if( s2kmode == 3 )
638                 printf(", count %lu\n", (ulong)k->s2k.count );
639             printf("\n");
640         }
641     }
642
643   leave:
644     skip_rest(inp, pktlen);
645     return 0;
646 }
647
648 static int
649 parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
650 {
651     unsigned n;
652     int i, ndata;
653     PKT_pubkey_enc *k;
654
655     k = packet->pkt.pubkey_enc = gcry_xcalloc( 1,sizeof *packet->pkt.pubkey_enc);
656     if( pktlen < 12 ) {
657         log_error("packet(%d) too short\n", pkttype);
658         goto leave;
659     }
660     k->version = iobuf_get_noeof(inp); pktlen--;
661     if( k->version != 2 && k->version != 3 ) {
662         log_error("packet(%d) with unknown version %d\n", pkttype, k->version);
663         goto leave;
664     }
665     k->keyid[0] = read_32(inp); pktlen -= 4;
666     k->keyid[1] = read_32(inp); pktlen -= 4;
667     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
668     k->throw_keyid = 0; /* only used as flag for build_packet */
669     if( list_mode )
670         printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
671           k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
672
673     ndata = pubkey_get_nenc(k->pubkey_algo);
674     if( !ndata ) {
675         if( list_mode )
676             printf("\tunsupported algorithm %d\n", k->pubkey_algo );
677         unknown_pubkey_warning( k->pubkey_algo );
678         k->data[0] = NULL;  /* no need to store the encrypted data */
679     }
680     else {
681         for( i=0; i < ndata; i++ ) {
682             n = pktlen;
683             k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;
684             if( list_mode ) {
685                 printf("\tdata: ");
686                 mpi_print(stdout, k->data[i], mpi_print_mode );
687                 putchar('\n');
688             }
689         }
690     }
691
692   leave:
693     skip_rest(inp, pktlen);
694     return 0;
695 }
696
697
698 static void
699 dump_sig_subpkt( int hashed, int type, int critical,
700                  const byte *buffer, size_t buflen, size_t length )
701 {
702     const char *p=NULL;
703     int i;
704
705     /* The CERT has warning out with explains how to use GNUPG to
706      * detect the ARRs - we print our old message here when it is a faked
707      * ARR and add an additional notice */
708     if ( type == SIGSUBPKT_ARR && !hashed ) {
709         printf("\tsubpkt %d len %u (additional recipient request)\n"
710                "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
711                "encrypt to this key and thereby reveal the plaintext to "
712                "the owner of this ARR key. Detailed info follows:\n",
713                type, (unsigned)length );
714     }
715     
716     printf("\t%s%ssubpkt %d len %u (", /*)*/
717               critical ? "critical ":"",
718               hashed ? "hashed ":"", type, (unsigned)length );
719     buffer++;
720     length--;
721     if( length > buflen ) {
722         printf("too short: buffer is only %u)\n", (unsigned)buflen );
723         return;
724     }
725     switch( type ) {
726       case SIGSUBPKT_SIG_CREATED:
727         if( length >= 4 )
728             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
729         break;
730       case SIGSUBPKT_SIG_EXPIRE:
731         if( length >= 4 )
732             printf("sig expires after %s",
733                                      strtimevalue( buffer_to_u32(buffer) ) );
734         break;
735       case SIGSUBPKT_EXPORTABLE:
736         if( length )
737             printf("%sexportable", *buffer? "":"not ");
738         break;
739       case SIGSUBPKT_TRUST:
740         p = "trust signature";
741         break;
742       case SIGSUBPKT_REGEXP:
743         p = "regular expression";
744         break;
745       case SIGSUBPKT_REVOCABLE:
746         p = "revocable";
747         break;
748       case SIGSUBPKT_KEY_EXPIRE:
749         if( length >= 4 )
750             printf("key expires after %s",
751                                     strtimevalue( buffer_to_u32(buffer) ) );
752         break;
753       case SIGSUBPKT_PREF_SYM:
754         fputs("pref-sym-algos:", stdout );
755         for( i=0; i < length; i++ )
756             printf(" %d", buffer[i] );
757         break;
758       case SIGSUBPKT_REV_KEY:
759         fputs("revocation key: ", stdout );
760         if( length < 22 )
761             p = "[too short]";
762         else {
763             printf("c=%02x a=%d f=", buffer[0], buffer[1] );
764             for( i=2; i < length; i++ )
765                 printf("%02X", buffer[i] );
766         }
767         break;
768       case SIGSUBPKT_ISSUER:
769         if( length >= 8 )
770             printf("issuer key ID %08lX%08lX",
771                       (ulong)buffer_to_u32(buffer),
772                       (ulong)buffer_to_u32(buffer+4) );
773         break;
774       case SIGSUBPKT_NOTATION:
775         {
776             fputs("notation: ", stdout );
777             if( length < 8 )
778                 p = "[too short]";
779             else if( !(*buffer & 0x80) )
780                 p = "[not human readable]";
781             else {
782                 const byte *s = buffer;
783                 size_t n1, n2;
784
785                 n1 = (s[4] << 8) | s[5];
786                 n2 = (s[6] << 8) | s[7];
787                 s += 8;
788                 if( 8+n1+n2 != length )
789                     p = "[error]";
790                 else {
791                     print_string( stdout, s, n1, ')' );
792                     putc( '=', stdout );
793                     print_string( stdout, s+n1, n2, ')' );
794                 }
795             }
796         }
797         break;
798       case SIGSUBPKT_PREF_HASH:
799         fputs("pref-hash-algos:", stdout );
800         for( i=0; i < length; i++ )
801             printf(" %d", buffer[i] );
802         break;
803       case SIGSUBPKT_PREF_COMPR:
804         fputs("pref-zip-algos:", stdout );
805         for( i=0; i < length; i++ )
806             printf(" %d", buffer[i] );
807         break;
808       case SIGSUBPKT_KS_FLAGS:
809         p = "key server preferences";
810         break;
811       case SIGSUBPKT_PREF_KS:
812         p = "preferred key server";
813         break;
814       case SIGSUBPKT_PRIMARY_UID:
815         p = "primary user ID";
816         break;
817       case SIGSUBPKT_POLICY:
818         fputs("policy: ", stdout );
819         print_string( stdout, buffer, length, ')' );
820         break;
821       case SIGSUBPKT_KEY_FLAGS:
822         fputs ( "key flags:", stdout );
823         for( i=0; i < length; i++ )
824             printf(" %02X", buffer[i] );
825         break;
826       case SIGSUBPKT_SIGNERS_UID:
827         p = "signer's user ID";
828         break;
829       case SIGSUBPKT_REVOC_REASON:
830         if( length ) {
831             printf("revocation reason 0x%02x (", *buffer );
832             print_string( stdout, buffer+1, length-1, ')' );
833             p = ")";
834         }
835         break;
836       case SIGSUBPKT_ARR:
837         fputs("Big Brother's key (ignored): ", stdout );
838         if( length < 22 )
839             p = "[too short]";
840         else {
841             printf("c=%02x a=%d f=", buffer[0], buffer[1] );
842             for( i=2; i < length; i++ )
843                 printf("%02X", buffer[i] );
844         }
845         break;
846       case SIGSUBPKT_FEATURES:
847         fputs ( "features:", stdout );
848         for( i=0; i < length; i++ )
849             printf(" %02X", buffer[i] );
850         break;
851       case SIGSUBPKT_PRIV_ADD_SIG:  /* gnupg private - to be removed */
852         p = "signs additional user ID";
853         break;
854       default: p = "?"; break;
855     }
856
857     printf("%s)\n", p? p: "");
858 }
859
860 /****************
861  * Returns: >= 0 offset into buffer
862  *          -1 unknown type
863  *          -2 unsupported type
864  *          -3 subpacket too short
865  */
866 static int
867 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
868 {
869     switch( type ) {
870       case SIGSUBPKT_SIG_CREATED:
871       case SIGSUBPKT_SIG_EXPIRE:
872       case SIGSUBPKT_KEY_EXPIRE:
873         if( n < 4 )
874             break;
875         return 0;
876       case SIGSUBPKT_KEY_FLAGS:
877           return 0;  
878       case SIGSUBPKT_EXPORTABLE:
879         if( !n )
880             break;
881         return 0;
882       case SIGSUBPKT_ISSUER:/* issuer key ID */
883         if( n < 8 )
884             break;
885         return 0;
886       case SIGSUBPKT_NOTATION:
887         if( n < 8 ) /* minimum length needed */
888             break;
889         return 0;
890       case SIGSUBPKT_REVOC_REASON:
891         if( !n  )
892             break;
893         return 0;
894       case SIGSUBPKT_PREF_SYM:
895       case SIGSUBPKT_PREF_HASH:
896       case SIGSUBPKT_PREF_COMPR:
897       case SIGSUBPKT_FEATURES:
898       case SIGSUBPKT_POLICY:
899         return 0;
900       case SIGSUBPKT_PRIMARY_UID:
901           if ( n != 1 )
902               break;
903           return 0;   
904       case SIGSUBPKT_PRIV_ADD_SIG:
905         /* because we use private data, we check the GNUPG marker */
906         if( n < 24 )
907             break;
908         if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
909             return -2;
910         return 3;
911       default: return -1;
912     }
913     return -3;
914 }
915
916
917 static int
918 can_handle_critical( const byte *buffer, size_t n, int type )
919 {
920     switch( type ) {
921       case SIGSUBPKT_NOTATION:
922         if( n >= 8 && (*buffer & 0x80) )
923             return 1; /* human readable is handled */
924         return 0;
925
926       case SIGSUBPKT_SIG_CREATED:
927       case SIGSUBPKT_SIG_EXPIRE:
928       case SIGSUBPKT_KEY_EXPIRE:
929       case SIGSUBPKT_EXPORTABLE:
930       case SIGSUBPKT_ISSUER:/* issuer key ID */
931       case SIGSUBPKT_PREF_SYM:
932       case SIGSUBPKT_PREF_HASH:
933       case SIGSUBPKT_PREF_COMPR:
934       case SIGSUBPKT_FEATURES:
935       case SIGSUBPKT_KEY_FLAGS:
936         return 1;
937
938       case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
939       default:
940         return 0;
941     }
942 }
943
944
945 const byte *
946 enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
947                  size_t *ret_n, int *start )
948 {
949     int buflen;
950     int type;
951     int critical;
952     int offset;
953     size_t n;
954     int seq = 0;
955     int reqseq = start? *start: 0;
956
957     if( !buffer || reqseq == -1 ) {
958         /* return some value different from NULL to indicate that
959          * there is no crtitical bit we do not understand.  The caller
960          * will never use the value.  Yes I know, it is an ugly hack */
961         return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&buffer : NULL;
962     }
963     buflen = (*buffer << 8) | buffer[1];
964     buffer += 2;
965     while( buflen ) {
966         n = *buffer++; buflen--;
967         if( n == 255 ) {
968             if( buflen < 4 )
969                 goto too_short;
970             n = (buffer[0] << 24) | (buffer[1] << 16)
971                                   | (buffer[2] << 8) | buffer[3];
972             buffer += 4;
973             buflen -= 4;
974
975         }
976         else if( n >= 192 ) {
977             if( buflen < 2 )
978                 goto too_short;
979             n = (( n - 192 ) << 8) + *buffer + 192;
980             buffer++;
981             buflen--;
982         }
983         if( buflen < n )
984             goto too_short;
985         type = *buffer;
986         if( type & 0x80 ) {
987             type &= 0x7f;
988             critical = 1;
989         }
990         else
991             critical = 0;
992         if( !(++seq > reqseq) )
993             ;
994         else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
995             if( critical ) {
996                 if( n-1 > buflen+1 )
997                     goto too_short;
998                 if( !can_handle_critical(buffer+1, n-1, type ) ) {
999                     log_info(_("subpacket of type %d has critical bit set\n"),
1000                                                                         type);
1001                     if( start )
1002                         *start = seq;
1003                     return NULL; /* this is an error */
1004                 }
1005             }
1006         }
1007         else if( reqtype < 0 ) /* list packets */
1008             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
1009                                     type, critical, buffer, buflen, n );
1010         else if( type == reqtype ) { /* found */
1011             buffer++;
1012             n--;
1013             if( n > buflen )
1014                 goto too_short;
1015             if( ret_n )
1016                 *ret_n = n;
1017             offset = parse_one_sig_subpkt(buffer, n, type );
1018             switch( offset ) {
1019               case -3:
1020                 log_error("subpacket of type %d too short\n", type);
1021                 return NULL;
1022               case -2:
1023                 return NULL;
1024               case -1:
1025                 BUG(); /* not yet needed */
1026               default:
1027                 break;
1028             }
1029             if( start )
1030                 *start = seq;
1031             return buffer+offset;
1032         }
1033         buffer += n; buflen -=n;
1034     }
1035     if( reqtype == SIGSUBPKT_TEST_CRITICAL )
1036         return buffer; /* as value true to indicate that there is no */
1037                        /* critical bit we don't understand */
1038     if( start )
1039         *start = -1;
1040     return NULL; /* end of packets; not found */
1041
1042   too_short:
1043     log_error("buffer shorter than subpacket\n");
1044     if( start )
1045         *start = -1;
1046     return NULL;
1047 }
1048
1049
1050 const byte *
1051 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
1052 {
1053     return enum_sig_subpkt( buffer, reqtype, ret_n, NULL );
1054 }
1055
1056 const byte *
1057 parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
1058 {
1059     const byte *p;
1060
1061     p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
1062     if( !p )
1063         p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
1064     return p;
1065 }
1066
1067
1068
1069 static int
1070 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
1071                                           PKT_signature *sig )
1072 {
1073     int md5_len=0;
1074     unsigned n;
1075     int is_v4=0;
1076     int rc=0;
1077     int i, ndata;
1078
1079     if( pktlen < 16 ) {
1080         log_error("packet(%d) too short\n", pkttype);
1081         goto leave;
1082     }
1083     sig->version = iobuf_get_noeof(inp); pktlen--;
1084     if( sig->version == 4 )
1085         is_v4=1;
1086     else if( sig->version != 2 && sig->version != 3 ) {
1087         log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
1088         goto leave;
1089     }
1090
1091     if( !is_v4 ) {
1092         md5_len = iobuf_get_noeof(inp); pktlen--;
1093     }
1094     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
1095     if( !is_v4 ) {
1096         sig->timestamp = read_32(inp); pktlen -= 4;
1097         sig->keyid[0] = read_32(inp); pktlen -= 4;
1098         sig->keyid[1] = read_32(inp); pktlen -= 4;
1099     }
1100     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1101     sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
1102     if( is_v4 ) { /* read subpackets */
1103         n = read_16(inp); pktlen -= 2; /* length of hashed data */
1104         if( n > 10000 ) {
1105             log_error("signature packet: hashed data too long\n");
1106             rc = GPGERR_INVALID_PACKET;
1107             goto leave;
1108         }
1109         if( n ) {
1110             sig->hashed_data = gcry_xmalloc( n + 2 );
1111             sig->hashed_data[0] = n >> 8;
1112             sig->hashed_data[1] = n;
1113             if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
1114                 log_error("premature eof while reading hashed signature data\n");
1115                 rc = -1;
1116                 goto leave;
1117             }
1118             pktlen -= n;
1119         }
1120         n = read_16(inp); pktlen -= 2; /* length of unhashed data */
1121         if( n > 10000 ) {
1122             log_error("signature packet: unhashed data too long\n");
1123             rc = GPGERR_INVALID_PACKET;
1124             goto leave;
1125         }
1126         if( n ) {
1127             sig->unhashed_data = gcry_xmalloc( n + 2 );
1128             sig->unhashed_data[0] = n >> 8;
1129             sig->unhashed_data[1] = n;
1130             if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
1131                 log_error("premature eof while reading unhashed signature data\n");
1132                 rc = -1;
1133                 goto leave;
1134             }
1135             pktlen -= n;
1136         }
1137     }
1138
1139     if( pktlen < 5 ) { /* sanity check */
1140         log_error("packet(%d) too short\n", pkttype);
1141         rc = GPGERR_INVALID_PACKET;
1142         goto leave;
1143     }
1144
1145     sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
1146     sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
1147
1148     if( is_v4 && sig->pubkey_algo ) { /*extract required information */
1149         const byte *p;
1150
1151         /* set sig->flags.unknown_critical if there is a
1152          * critical bit set for packets which we do not understand */
1153         if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
1154            || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
1155                                                                         NULL) )
1156         {
1157             sig->flags.unknown_critical = 1;
1158         }
1159
1160         p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
1161         if( !p )
1162             log_error("signature packet without timestamp\n");
1163         else
1164             sig->timestamp = buffer_to_u32(p);
1165         p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
1166         if( !p )
1167             log_error("signature packet without keyid\n");
1168         else {
1169             sig->keyid[0] = buffer_to_u32(p);
1170             sig->keyid[1] = buffer_to_u32(p+4);
1171         }
1172     }
1173
1174     if( list_mode ) {
1175         printf(":signature packet: algo %d, keyid %08lX%08lX\n"
1176                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
1177                "\tdigest algo %d, begin of digest %02x %02x\n",
1178                 sig->pubkey_algo,
1179                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1180                 sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
1181                 sig->digest_algo,
1182                 sig->digest_start[0], sig->digest_start[1] );
1183         if( is_v4 ) {
1184             parse_sig_subpkt( sig->hashed_data,  SIGSUBPKT_LIST_HASHED, NULL );
1185             parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
1186         }
1187     }
1188
1189     ndata = pubkey_get_nsig(sig->pubkey_algo);
1190     if( !ndata ) {
1191         if( list_mode )
1192             printf("\tunknown algorithm %d\n", sig->pubkey_algo );
1193         unknown_pubkey_warning( sig->pubkey_algo );
1194         /* we store the plain material in data[0], so that we are able
1195          * to write it back with build_packet() */
1196         sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen );
1197         pktlen = 0;
1198     }
1199     else {
1200         for( i=0; i < ndata; i++ ) {
1201             n = pktlen;
1202             sig->data[i] = mpi_read(inp, &n, 0 );
1203             pktlen -=n;
1204             if( list_mode ) {
1205                 printf("\tdata: ");
1206                 mpi_print(stdout, sig->data[i], mpi_print_mode );
1207                 putchar('\n');
1208             }
1209         }
1210     }
1211
1212   leave:
1213     skip_rest(inp, pktlen);
1214     return rc;
1215 }
1216
1217
1218 static int
1219 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
1220                                              PKT_onepass_sig *ops )
1221 {
1222     int version;
1223
1224     if( pktlen < 13 ) {
1225         log_error("packet(%d) too short\n", pkttype);
1226         goto leave;
1227     }
1228     version = iobuf_get_noeof(inp); pktlen--;
1229     if( version != 3 ) {
1230         log_error("onepass_sig with unknown version %d\n", version);
1231         goto leave;
1232     }
1233     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
1234     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
1235     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1236     ops->keyid[0] = read_32(inp); pktlen -= 4;
1237     ops->keyid[1] = read_32(inp); pktlen -= 4;
1238     ops->last = iobuf_get_noeof(inp); pktlen--;
1239     if( list_mode )
1240         printf(":onepass_sig packet: keyid %08lX%08lX\n"
1241                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
1242                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
1243                 version, ops->sig_class,
1244                 ops->digest_algo, ops->pubkey_algo, ops->last );
1245
1246
1247   leave:
1248     skip_rest(inp, pktlen);
1249     return 0;
1250 }
1251
1252
1253
1254
1255 static int
1256 parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
1257                               byte *hdr, int hdrlen, PACKET *pkt )
1258 {
1259     int i, version, algorithm;
1260     unsigned n;
1261     unsigned long timestamp, expiredate;
1262     int npkey, nskey;
1263     int is_v4=0;
1264     int rc=0;
1265
1266     version = iobuf_get_noeof(inp); pktlen--;
1267     if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
1268         /* early versions of gpg use old PGP comments packets;
1269          * luckily all those comments are started by a hash */
1270         if( list_mode ) {
1271             printf(":rfc1991 comment packet: \"" );
1272             for( ; pktlen; pktlen-- ) {
1273                 int c;
1274                 c = iobuf_get_noeof(inp);
1275                 if( c >= ' ' && c <= 'z' )
1276                     putchar(c);
1277                 else
1278                     printf("\\x%02x", c );
1279             }
1280             printf("\"\n");
1281         }
1282         skip_rest(inp, pktlen);
1283         return 0;
1284     }
1285     else if( version == 4 )
1286         is_v4=1;
1287     else if( version != 2 && version != 3 ) {
1288         log_error("packet(%d) with unknown version %d\n", pkttype, version);
1289         goto leave;
1290     }
1291
1292     if( pktlen < 11 ) {
1293         log_error("packet(%d) too short\n", pkttype);
1294         goto leave;
1295     }
1296
1297     timestamp = read_32(inp); pktlen -= 4;
1298     if( is_v4 )
1299         expiredate = 0; /* have to get it from the selfsignature */
1300     else {
1301         unsigned short ndays;
1302         ndays = read_16(inp); pktlen -= 2;
1303         if( ndays )
1304             expiredate = timestamp + ndays * 86400L;
1305         else
1306             expiredate = 0;
1307     }
1308     algorithm = iobuf_get_noeof(inp); pktlen--;
1309     if( list_mode )
1310         printf(":%s key packet:\n"
1311                "\tversion %d, algo %d, created %lu, expires %lu\n",
1312                 pkttype == PKT_PUBLIC_KEY? "public" :
1313                 pkttype == PKT_SECRET_KEY? "secret" :
1314                 pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
1315                 pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
1316                 version, algorithm, timestamp, expiredate );
1317
1318     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
1319         PKT_secret_key *sk = pkt->pkt.secret_key;
1320
1321         sk->timestamp = timestamp;
1322         sk->expiredate = expiredate;
1323         sk->hdrbytes = hdrlen;
1324         sk->version = version;
1325         sk->is_primary = pkttype == PKT_SECRET_KEY;
1326         sk->pubkey_algo = algorithm;
1327         sk->req_usage = 0; 
1328         sk->pubkey_usage = 0; /* will be set by getkey functions */
1329     }
1330     else {
1331         PKT_public_key *pk = pkt->pkt.public_key;
1332
1333         pk->timestamp = timestamp;
1334         pk->expiredate = expiredate;
1335         pk->hdrbytes    = hdrlen;
1336         pk->version     = version;
1337         pk->pubkey_algo = algorithm;
1338         pk->req_usage = 0;
1339         pk->pubkey_usage = 0; /* will be set bey getkey functions */
1340         pk->is_revoked = 0;
1341         pk->keyid[0] = 0;
1342         pk->keyid[1] = 0;
1343     }
1344     nskey = pubkey_get_nskey( algorithm );
1345     npkey = pubkey_get_npkey( algorithm );
1346     if( !npkey ) {
1347         if( list_mode )
1348             printf("\tunknown algorithm %d\n", algorithm );
1349         unknown_pubkey_warning( algorithm );
1350     }
1351
1352
1353     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
1354         PKT_secret_key *sk = pkt->pkt.secret_key;
1355         byte temp[16];
1356
1357         if( !npkey ) {
1358             sk->skey[0] = gcry_mpi_set_opaque( NULL,
1359                                              read_rest(inp, pktlen), pktlen*8 );
1360             pktlen = 0;
1361             goto leave;
1362         }
1363
1364         for(i=0; i < npkey; i++ ) {
1365             n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1366             if( list_mode ) {
1367                 printf(  "\tskey[%d]: ", i);
1368                 mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1369                 putchar('\n');
1370             }
1371         }
1372         sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1373         if( sk->protect.algo ) {
1374             sk->is_protected = 1;
1375             sk->protect.s2k.count = 0;
1376             if( sk->protect.algo == 255 ) {
1377                 if( pktlen < 3 ) {
1378                     rc = GPGERR_INVALID_PACKET;
1379                     goto leave;
1380                 }
1381                 sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1382                 sk->protect.s2k.mode  = iobuf_get_noeof(inp); pktlen--;
1383                 sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
1384                 /* check for the special GNU extension */
1385                 if( is_v4 && sk->protect.s2k.mode == 101 ) {
1386                     for(i=0; i < 4 && pktlen; i++, pktlen-- )
1387                         temp[i] = iobuf_get_noeof(inp);
1388                     if( i < 4 || memcmp( temp, "GNU", 3 ) ) {
1389                         if( list_mode )
1390                             printf(  "\tunknown S2K %d\n",
1391                                                 sk->protect.s2k.mode );
1392                         rc = GPGERR_INVALID_PACKET;
1393                         goto leave;
1394                     }
1395                     /* here we know that it is a gnu extension
1396                      * What follows is the GNU protection mode:
1397                      * All values have special meanings
1398                      * and they are mapped in the mode with a base of 1000.
1399                      */
1400                     sk->protect.s2k.mode = 1000 + temp[3];
1401                 }
1402                 switch( sk->protect.s2k.mode ) {
1403                   case 1:
1404                   case 3:
1405                     for(i=0; i < 8 && pktlen; i++, pktlen-- )
1406                         temp[i] = iobuf_get_noeof(inp);
1407                     memcpy(sk->protect.s2k.salt, temp, 8 );
1408                     break;
1409                 }
1410                 switch( sk->protect.s2k.mode ) {
1411                   case 0: if( list_mode ) printf(  "\tsimple S2K" );
1412                     break;
1413                   case 1: if( list_mode ) printf(  "\tsalted S2K" );
1414                     break;
1415                   case 3: if( list_mode ) printf(  "\titer+salt S2K" );
1416                     break;
1417                   case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );
1418                     break;
1419                   default:
1420                     if( list_mode )
1421                         printf(  "\tunknown %sS2K %d\n",
1422                                  sk->protect.s2k.mode < 1000? "":"GNU ",
1423                                                    sk->protect.s2k.mode );
1424                     rc = GPGERR_INVALID_PACKET;
1425                     goto leave;
1426                 }
1427
1428                 if( list_mode ) {
1429                     printf(", algo: %d, hash: %d",
1430                                      sk->protect.algo,
1431                                      sk->protect.s2k.hash_algo );
1432                     if( sk->protect.s2k.mode == 1
1433                         || sk->protect.s2k.mode == 3 ) {
1434                         printf(", salt: ");
1435                         for(i=0; i < 8; i++ )
1436                             printf("%02x", sk->protect.s2k.salt[i]);
1437                     }
1438                     putchar('\n');
1439                 }
1440
1441                 if( sk->protect.s2k.mode == 3 ) {
1442                     if( pktlen < 1 ) {
1443                         rc = GPGERR_INVALID_PACKET;
1444                         goto leave;
1445                     }
1446                     sk->protect.s2k.count = iobuf_get(inp);
1447                     pktlen--;
1448                     if( list_mode )
1449                         printf("\tprotect count: %lu\n",
1450                                             (ulong)sk->protect.s2k.count);
1451                 }
1452             }
1453             else { /* old version; no S2K, so we set mode to 0, hash MD5 */
1454                 sk->protect.s2k.mode = 0;
1455                 sk->protect.s2k.hash_algo = GCRY_MD_MD5;
1456                 if( list_mode )
1457                     printf(  "\tprotect algo: %d  (hash algo: %d)\n",
1458                          sk->protect.algo, sk->protect.s2k.hash_algo );
1459             }
1460             /* It is really ugly that we don't know the size
1461              * of the IV here in cases we are not aware of the algorithm.
1462              * so a
1463              *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);
1464              * won't work.  The only solution I see is to hardwire it here.
1465              * NOTE: if you change the ivlen above 16, don't forget to
1466              * enlarge temp.
1467              */
1468             switch( sk->protect.algo ) {
1469               case 7: case 8: case 9: /* reserved for AES */
1470               case 10: /* Twofish */
1471                 sk->protect.ivlen = 16;
1472                 break;
1473               default:
1474                 sk->protect.ivlen = 8;
1475             }
1476             if( sk->protect.s2k.mode == 1001 )
1477                 sk->protect.ivlen = 0;
1478
1479             if( pktlen < sk->protect.ivlen ) {
1480                 rc = GPGERR_INVALID_PACKET;
1481                 goto leave;
1482             }
1483             for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
1484                 temp[i] = iobuf_get_noeof(inp);
1485             if( list_mode ) {
1486                 printf(  "\tprotect IV: ");
1487                 for(i=0; i < sk->protect.ivlen; i++ )
1488                     printf(" %02x", temp[i] );
1489                 putchar('\n');
1490             }
1491             memcpy(sk->protect.iv, temp, sk->protect.ivlen );
1492         }
1493         else
1494             sk->is_protected = 0;
1495         /* It does not make sense to read it into secure memory.
1496          * If the user is so careless, not to protect his secret key,
1497          * we can assume, that he operates an open system :=(.
1498          * So we put the key into secure memory when we unprotect it. */
1499         if( sk->protect.s2k.mode == 1001 ) {
1500             /* better set some dummy stuff here */
1501             sk->skey[npkey] = mpi_set_opaque(NULL, gcry_xstrdup("dummydata"), 10);
1502             pktlen = 0;
1503         }
1504         else if( is_v4 && sk->is_protected ) {
1505             /* ugly; the length is encrypted too, so we read all
1506              * stuff up to the end of the packet into the first
1507              * skey element */
1508             sk->skey[npkey] = gcry_mpi_set_opaque(NULL,
1509                                              read_rest(inp, pktlen), pktlen*8 );
1510             pktlen = 0;
1511             if( list_mode ) {
1512                 printf("\tencrypted stuff follows\n");
1513             }
1514         }
1515         else { /* unencrypted v4 or v3 method (where length is not encrypted) */
1516             for(i=npkey; i < nskey; i++ ) {
1517                 n = pktlen;
1518                 sk->skey[i] = sk->is_protected ? mpi_read_opaque(inp, &n )
1519                                                : mpi_read( inp, &n, 1 );
1520                 pktlen -=n;
1521                 if( list_mode ) {
1522                     printf(  "\tskey[%d]: ", i);
1523                     if( sk->is_protected )
1524                         printf(  "[encrypted]\n");
1525                     else {
1526                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1527                         putchar('\n');
1528                     }
1529                 }
1530             }
1531
1532             sk->csum = read_16(inp); pktlen -= 2;
1533             if( list_mode ) {
1534                 printf("\tchecksum: %04hx\n", sk->csum);
1535             }
1536         }
1537     }
1538     else {
1539         PKT_public_key *pk = pkt->pkt.public_key;
1540
1541         if( !npkey ) {
1542             pk->pkey[0] = gcry_mpi_set_opaque( NULL,
1543                                              read_rest(inp, pktlen), pktlen*8 );
1544             pktlen = 0;
1545             goto leave;
1546         }
1547
1548         for(i=0; i < npkey; i++ ) {
1549             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1550             if( list_mode ) {
1551                 printf(  "\tpkey[%d]: ", i);
1552                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
1553                 putchar('\n');
1554             }
1555         }
1556     }
1557
1558   leave:
1559     skip_rest(inp, pktlen);
1560     return rc;
1561 }
1562
1563
1564 static int
1565 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1566 {
1567     byte *p;
1568
1569     packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id  + pktlen);
1570     packet->pkt.user_id->len = pktlen;
1571     packet->pkt.user_id->photo = NULL;
1572     packet->pkt.user_id->photolen = 0;
1573     p = packet->pkt.user_id->name;
1574     for( ; pktlen; pktlen--, p++ )
1575         *p = iobuf_get_noeof(inp);
1576     *p = 0;
1577
1578     if( list_mode ) {
1579         int n = packet->pkt.user_id->len;
1580         printf(":user ID packet: \"");
1581         /* fixme: Hey why don't we replace this wioth print_string?? */
1582         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
1583             if( *p >= ' ' && *p <= 'z' )
1584                 putchar(*p);
1585             else
1586                 printf("\\x%02x", *p );
1587         }
1588         printf("\"\n");
1589     }
1590     return 0;
1591 }
1592
1593
1594 /****************
1595  * PGP generates a packet of type 17. We assume this is a photo ID and
1596  * simply store it here as a comment packet.
1597  */
1598 static int
1599 parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1600 {
1601     byte *p;
1602
1603     packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id  + 30);
1604     sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen );
1605     packet->pkt.user_id->len = strlen(packet->pkt.user_id->name);
1606
1607     packet->pkt.user_id->photo = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen);
1608     packet->pkt.user_id->photolen = pktlen;
1609     p = packet->pkt.user_id->photo;
1610     for( ; pktlen; pktlen--, p++ )
1611         *p = iobuf_get_noeof(inp);
1612
1613     if( list_mode ) {
1614         printf(":photo_id packet: %s\n", packet->pkt.user_id->name );
1615     }
1616     return 0;
1617 }
1618
1619
1620 static int
1621 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1622 {
1623     byte *p;
1624
1625     packet->pkt.comment = gcry_xmalloc(sizeof *packet->pkt.comment + pktlen - 1);
1626     packet->pkt.comment->len = pktlen;
1627     p = packet->pkt.comment->data;
1628     for( ; pktlen; pktlen--, p++ )
1629         *p = iobuf_get_noeof(inp);
1630
1631     if( list_mode ) {
1632         int n = packet->pkt.comment->len;
1633         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
1634                                          "OpenPGP draft " : "" );
1635         for(p=packet->pkt.comment->data; n; p++, n-- ) {
1636             if( *p >= ' ' && *p <= 'z' )
1637                 putchar(*p);
1638             else
1639                 printf("\\x%02x", *p );
1640         }
1641         printf("\"\n");
1642     }
1643     return 0;
1644 }
1645
1646
1647 static void
1648 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
1649 {
1650     int c;
1651
1652     c = iobuf_get_noeof(inp);
1653     pkt->pkt.ring_trust = gcry_xmalloc( sizeof *pkt->pkt.ring_trust );
1654     pkt->pkt.ring_trust->trustval = c;
1655     if( list_mode )
1656         printf(":trust packet: flag=%02x\n", c );
1657 }
1658
1659
1660 static int
1661 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
1662                                         PACKET *pkt, int new_ctb )
1663 {
1664     int mode, namelen;
1665     PKT_plaintext *pt;
1666     byte *p;
1667     int c, i;
1668
1669     if( pktlen && pktlen < 6 ) {
1670         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
1671         goto leave;
1672     }
1673     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1674     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1675     pt = pkt->pkt.plaintext = gcry_xmalloc(sizeof *pkt->pkt.plaintext + namelen -1);
1676     pt->new_ctb = new_ctb;
1677     pt->mode = mode;
1678     pt->namelen = namelen;
1679     if( pktlen ) {
1680         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
1681             pt->name[i] = iobuf_get_noeof(inp);
1682     }
1683     else {
1684         for( i=0; i < namelen; i++ )
1685             if( (c=iobuf_get(inp)) == -1 )
1686                 break;
1687             else
1688                 pt->name[i] = c;
1689     }
1690     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
1691     pt->len = pktlen;
1692     pt->buf = inp;
1693     pktlen = 0;
1694
1695     if( list_mode ) {
1696         printf(":literal data packet:\n"
1697                "\tmode %c, created %lu, name=\"",
1698                     mode >= ' ' && mode <'z'? mode : '?',
1699                     (ulong)pt->timestamp );
1700         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
1701             if( *p >= ' ' && *p <= 'z' )
1702                 putchar(*p);
1703             else
1704                 printf("\\x%02x", *p );
1705         }
1706         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
1707     }
1708
1709   leave:
1710     return 0;
1711 }
1712
1713
1714 static int
1715 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
1716                   PACKET *pkt, int new_ctb )
1717 {
1718     PKT_compressed *zd;
1719
1720     /* pktlen is here 0, but data follows
1721      * (this should be the last object in a file or
1722      *  the compress algorithm should know the length)
1723      */
1724     zd = pkt->pkt.compressed =  gcry_xmalloc(sizeof *pkt->pkt.compressed );
1725     zd->len = 0; /* not yet used */
1726     zd->algorithm = iobuf_get_noeof(inp);
1727     zd->new_ctb = new_ctb;
1728     zd->buf = inp;
1729     if( list_mode )
1730         printf(":compressed packet: algo=%d\n", zd->algorithm);
1731     return 0;
1732 }
1733
1734
1735 static int
1736 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
1737                                        PACKET *pkt, int new_ctb )
1738 {
1739     PKT_encrypted *ed;
1740
1741     ed = pkt->pkt.encrypted =  gcry_xmalloc(sizeof *pkt->pkt.encrypted );
1742     ed->len = pktlen;
1743     ed->buf = NULL;
1744     ed->new_ctb = new_ctb;
1745     ed->mdc_method = 0;
1746     if( pkttype == PKT_ENCRYPTED_MDC ) {
1747         /* fixme: add some pktlen sanity checks */
1748         int version;
1749
1750         version = iobuf_get_noeof(inp); pktlen--;
1751         if( version != 1 ) {
1752             log_error("encrypted_mdc packet with unknown version %d\n",
1753                                                                 version);
1754             goto leave;
1755         }
1756         ed->mdc_method = GCRY_MD_SHA1;
1757     }
1758     if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
1759         log_error("packet(%d) too short\n", pkttype);
1760         skip_rest(inp, pktlen);
1761         goto leave;
1762     }
1763     if( list_mode ) {
1764         if( pktlen )
1765             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen);
1766         else
1767             printf(":encrypted data packet:\n\tlength: unknown\n");
1768         if( ed->mdc_method )
1769             printf("\tmdc_method: %d\n", ed->mdc_method );
1770     }
1771
1772     ed->buf = inp;
1773     pktlen = 0;
1774
1775   leave:
1776     return 0;
1777 }
1778
1779
1780 static int
1781 parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
1782                                    PACKET *pkt, int new_ctb )
1783 {
1784     PKT_mdc *mdc;
1785     byte *p;
1786
1787     mdc = pkt->pkt.mdc=  gcry_xmalloc(sizeof *pkt->pkt.mdc );
1788     if( list_mode )
1789         printf(":mdc packet: length=%lu\n", pktlen);
1790     if( !new_ctb || pktlen != 20 ) {
1791         log_error("mdc_packet with invalid encoding\n");
1792         goto leave;
1793     }
1794     p = mdc->hash;
1795     for( ; pktlen; pktlen--, p++ )
1796         *p = iobuf_get_noeof(inp);
1797
1798   leave:
1799     return 0;
1800 }
1801