See ChangeLog: Mon Dec 14 21:18:49 CET 1998 Werner Koch
[gnupg.git] / g10 / parse-packet.c
1 /* parse-packet.c  - read packets
2  *      Copyright (C) 1998 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 "packet.h"
28 #include "iobuf.h"
29 #include "mpi.h"
30 #include "util.h"
31 #include "cipher.h"
32 #include "memory.h"
33 #include "filter.h"
34 #include "options.h"
35 #include "main.h"
36 #include "i18n.h"
37
38 static int mpi_print_mode = 0;
39 static int list_mode = 0;
40
41 static int  parse( IOBUF inp, PACKET *pkt, int reqtype,
42                    ulong *retpos, int *skip, IOBUF out, int do_skip );
43 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
44                                                unsigned long pktlen );
45 static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
46 static void skip_rest( IOBUF inp, unsigned long pktlen );
47 static void *read_rest( IOBUF inp, ulong *r_pktlen );
48 static int  parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
49                                                              PACKET *packet );
50 static int  parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
51                                                              PACKET *packet );
52 static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
53                                                          PKT_signature *sig );
54 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
55                                                         PKT_onepass_sig *ops );
56 static int  parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
57                                       byte *hdr, int hdrlen, PACKET *packet );
58 static int  parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
59                                                            PACKET *packet );
60 static int  parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
61                                                            PACKET *packet );
62 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen );
63 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
64                                                PACKET *packet, int new_ctb);
65 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
66                                                PACKET *packet, int new_ctb );
67 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
68                                                PACKET *packet, int new_ctb);
69
70
71 static unsigned short
72 read_16(IOBUF inp)
73 {
74     unsigned short a;
75     a = iobuf_get_noeof(inp) << 8;
76     a |= iobuf_get_noeof(inp);
77     return a;
78 }
79
80 static unsigned long
81 read_32(IOBUF inp)
82 {
83     unsigned long a;
84     a =  iobuf_get_noeof(inp) << 24;
85     a |= iobuf_get_noeof(inp) << 16;
86     a |= iobuf_get_noeof(inp) << 8;
87     a |= iobuf_get_noeof(inp);
88     return a;
89 }
90
91
92 int
93 set_packet_list_mode( int mode )
94 {
95     int old = list_mode;
96     list_mode = mode;
97     mpi_print_mode = DBG_MPI;
98     return old;
99 }
100
101 static void
102 unknown_pubkey_warning( int algo )
103 {
104     static byte unknown_pubkey_algos[256];
105
106     algo &= 0xff;
107     if( !unknown_pubkey_algos[algo] ) {
108         if( opt.verbose )
109             log_info(_("can't handle public key algorithm %d\n"), algo );
110         unknown_pubkey_algos[algo] = 1;
111     }
112 }
113
114 /****************
115  * Parse a Packet and return it in packet
116  * Returns: 0 := valid packet in pkt
117  *         -1 := no more packets
118  *         >0 := error
119  * Note: The function may return an error and a partly valid packet;
120  * caller must free this packet.
121  */
122 int
123 parse_packet( IOBUF inp, PACKET *pkt )
124 {
125     int skip, rc;
126
127     do {
128         rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );
129     } while( skip );
130     return rc;
131 }
132
133 /****************
134  * Like parse packet, but only return packets of the given type.
135  */
136 int
137 search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
138 {
139     int skip, rc;
140
141     do {
142         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
143     } while( skip );
144     return rc;
145 }
146
147 /****************
148  * Copy all packets from INP to OUT, thereby removing unused spaces.
149  */
150 int
151 copy_all_packets( IOBUF inp, IOBUF out )
152 {
153     PACKET pkt;
154     int skip, rc=0;
155     do {
156         init_packet(&pkt);
157     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));
158     return rc;
159 }
160
161 /****************
162  * Copy some packets from INP to OUT, thereby removing unused spaces.
163  * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets)
164  */
165 int
166 copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff )
167 {
168     PACKET pkt;
169     int skip, rc=0;
170     do {
171         if( iobuf_tell(inp) >= stopoff )
172             return 0;
173         init_packet(&pkt);
174     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );
175     return rc;
176 }
177
178 /****************
179  * Skip over N packets
180  */
181 int
182 skip_some_packets( IOBUF inp, unsigned n )
183 {
184     int skip, rc=0;
185     PACKET pkt;
186
187     for( ;n && !rc; n--) {
188         init_packet(&pkt);
189         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );
190     }
191     return rc;
192 }
193
194
195
196 /****************
197  * Parse packet. Set the variable skip points to to 1 if the packet
198  * should be skipped; this is the case if either there is a
199  * requested packet type and the parsed packet doesn't match or the
200  * packet-type is 0, indicating deleted stuff.
201  * if OUT is not NULL, a special copymode is used.
202  */
203 static int
204 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
205        int *skip, IOBUF out, int do_skip )
206 {
207     int rc=0, c, ctb, pkttype, lenbytes;
208     unsigned long pktlen;
209     byte hdr[8];
210     int hdrlen;
211     int new_ctb = 0;
212
213     *skip = 0;
214     assert( !pkt->pkt.generic );
215     if( retpos )
216         *retpos = iobuf_tell(inp);
217     if( (ctb = iobuf_get(inp)) == -1 ) {
218         rc = -1;
219         goto leave;
220     }
221     hdrlen=0;
222     hdr[hdrlen++] = ctb;
223     if( !(ctb & 0x80) ) {
224         log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
225         rc = G10ERR_INVALID_PACKET;
226         goto leave;
227     }
228     pktlen = 0;
229     new_ctb = !!(ctb & 0x40);
230     if( new_ctb ) {
231         pkttype =  ctb & 0x3f;
232         if( (c = iobuf_get(inp)) == -1 ) {
233             log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
234             rc = G10ERR_INVALID_PACKET;
235             goto leave;
236         }
237         hdr[hdrlen++] = c;
238         if( c < 192 )
239             pktlen = c;
240         else if( c < 224 ) {
241             pktlen = (c - 192) * 256;
242             if( (c = iobuf_get(inp)) == -1 ) {
243                 log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
244                 rc = G10ERR_INVALID_PACKET;
245                 goto leave;
246             }
247             hdr[hdrlen++] = c;
248             pktlen += c + 192;
249         }
250         else if( c == 255 ) {
251             pktlen  = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24;
252             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16;
253             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
254             if( (c = iobuf_get(inp)) == -1 ) {
255                 log_error("%s: 4 byte length invalid\n", iobuf_where(inp) );
256                 rc = G10ERR_INVALID_PACKET;
257                 goto leave;
258             }
259             pktlen |= (hdr[hdrlen++] = c );
260         }
261         else { /* partial body length */
262             iobuf_set_partial_block_mode(inp, c & 0xff);
263             pktlen = 0;/* to indicate partial length */
264         }
265     }
266     else {
267         pkttype = (ctb>>2)&0xf;
268         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
269         if( !lenbytes ) {
270             pktlen = 0; /* don't know the value */
271             if( pkttype != PKT_COMPRESSED )
272                 iobuf_set_block_mode(inp, 1);
273         }
274         else {
275             for( ; lenbytes; lenbytes-- ) {
276                 pktlen <<= 8;
277                 pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
278             }
279         }
280     }
281
282     if( out && pkttype  ) {
283         if( iobuf_write( out, hdr, hdrlen ) == -1 )
284             rc = G10ERR_WRITE_FILE;
285         else
286             rc = copy_packet(inp, out, pkttype, pktlen );
287         goto leave;
288     }
289
290     if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
291         skip_rest(inp, pktlen);
292         *skip = 1;
293         rc = 0;
294         goto leave;
295     }
296
297     if( DBG_PACKET )
298         log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n",
299                    iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"" );
300     pkt->pkttype = pkttype;
301     rc = G10ERR_UNKNOWN_PACKET; /* default error */
302     switch( pkttype ) {
303       case PKT_PUBLIC_KEY:
304       case PKT_PUBLIC_SUBKEY:
305         pkt->pkt.public_key = m_alloc_clear(sizeof *pkt->pkt.public_key );
306         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
307         break;
308       case PKT_SECRET_KEY:
309       case PKT_SECRET_SUBKEY:
310         pkt->pkt.secret_key = m_alloc_clear(sizeof *pkt->pkt.secret_key );
311         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
312         break;
313       case PKT_SYMKEY_ENC:
314         rc = parse_symkeyenc( inp, pkttype, pktlen, pkt );
315         break;
316       case PKT_PUBKEY_ENC:
317         rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );
318         break;
319       case PKT_SIGNATURE:
320         pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
321         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
322         break;
323       case PKT_ONEPASS_SIG:
324         pkt->pkt.onepass_sig = m_alloc_clear(sizeof *pkt->pkt.onepass_sig );
325         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
326         break;
327       case PKT_USER_ID:
328         rc = parse_user_id(inp, pkttype, pktlen, pkt );
329         break;
330       case PKT_OLD_COMMENT:
331       case PKT_COMMENT:
332         rc = parse_comment(inp, pkttype, pktlen, pkt);
333         break;
334       case PKT_RING_TRUST:
335         parse_trust(inp, pkttype, pktlen);
336         rc = G10ERR_UNKNOWN_PACKET;
337         break;
338       case PKT_PLAINTEXT:
339         rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );
340         break;
341       case PKT_COMPRESSED:
342         rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );
343         break;
344       case PKT_ENCRYPTED:
345         rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );
346         break;
347       default:
348         skip_packet(inp, pkttype, pktlen);
349         break;
350     }
351
352   leave:
353     if( !rc && iobuf_error(inp) )
354         rc = G10ERR_INV_KEYRING;
355     return rc;
356 }
357
358 static void
359 dump_hex_line( int c, int *i )
360 {
361     if( *i && !(*i%8) ) {
362         if( *i && !(*i%24) )
363             printf("\n%4d:", *i );
364         else
365             putchar(' ');
366     }
367     if( c == -1 )
368         printf(" EOF" );
369     else
370         printf(" %02x", c );
371     ++*i;
372 }
373
374
375 static int
376 copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
377 {
378     int n;
379     char buf[100];
380
381     if( iobuf_in_block_mode(inp) ) {
382         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
383             if( iobuf_write(out, buf, n ) )
384                 return G10ERR_WRITE_FILE; /* write error */
385     }
386     else if( !pktlen && pkttype == PKT_COMPRESSED ) {
387         /* compressed packet, copy till EOF */
388         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
389             if( iobuf_write(out, buf, n ) )
390                 return G10ERR_WRITE_FILE; /* write error */
391     }
392     else {
393         for( ; pktlen; pktlen -= n ) {
394             n = pktlen > 100 ? 100 : pktlen;
395             n = iobuf_read( inp, buf, n );
396             if( n == -1 )
397                 return G10ERR_READ_FILE;
398             if( iobuf_write(out, buf, n ) )
399                 return G10ERR_WRITE_FILE; /* write error */
400         }
401     }
402     return 0;
403 }
404
405
406 static void
407 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
408 {
409     if( list_mode ) {
410         if( pkttype == PKT_MARKER )
411             fputs(":marker packet:\n", stdout );
412         else
413             printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
414         if( pkttype ) {
415             int c, i=0 ;
416             if( pkttype != PKT_MARKER )
417                 fputs("dump:", stdout );
418             if( iobuf_in_block_mode(inp) ) {
419                 while( (c=iobuf_get(inp)) != -1 )
420                     dump_hex_line(c, &i);
421             }
422             else {
423                 for( ; pktlen; pktlen-- )
424                     dump_hex_line(iobuf_get(inp), &i);
425             }
426             putchar('\n');
427             return;
428         }
429     }
430     skip_rest(inp,pktlen);
431 }
432
433 static void
434 skip_rest( IOBUF inp, unsigned long pktlen )
435 {
436     if( iobuf_in_block_mode(inp) ) {
437         while( iobuf_get(inp) != -1 )
438                 ;
439     }
440     else {
441         for( ; pktlen; pktlen-- )
442             if( iobuf_get(inp) == -1 )
443                 break;
444     }
445 }
446
447 static void *
448 read_rest( IOBUF inp, ulong *r_pktlen )
449 {
450     byte *p;
451     int i;
452     size_t pktlen = *r_pktlen;
453
454     if( iobuf_in_block_mode(inp) ) {
455         log_error("read_rest: can't store stream data\n");
456         p = NULL;
457     }
458     else {
459         p = m_alloc( pktlen + 2 );
460         p[0] = pktlen >> 8;
461         p[1] = pktlen & 0xff;
462         for(i=2; pktlen; pktlen--, i++ )
463             p[i] = iobuf_get(inp);
464     }
465     *r_pktlen = 0;
466     return p;
467 }
468
469 static void *
470 read_rest2( IOBUF inp, size_t pktlen )
471 {
472     byte *p;
473     int i;
474
475     if( iobuf_in_block_mode(inp) ) {
476         log_error("read_rest: can't store stream data\n");
477         p = NULL;
478     }
479     else {
480         p = m_alloc( pktlen );
481         for(i=0; pktlen; pktlen--, i++ )
482             p[i] = iobuf_get(inp);
483     }
484     return p;
485 }
486
487
488
489 static int
490 parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
491 {
492     PKT_symkey_enc *k;
493     int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
494
495     if( pktlen < 4 ) {
496         log_error("packet(%d) too short\n", pkttype);
497         goto leave;
498     }
499     version = iobuf_get_noeof(inp); pktlen--;
500     if( version != 4 ) {
501         log_error("packet(%d) with unknown version %d\n", pkttype, version);
502         goto leave;
503     }
504     if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
505         log_error("packet(%d) too large\n", pkttype);
506         goto leave;
507     }
508     cipher_algo = iobuf_get_noeof(inp); pktlen--;
509     s2kmode = iobuf_get_noeof(inp); pktlen--;
510     hash_algo = iobuf_get_noeof(inp); pktlen--;
511     switch( s2kmode ) {
512       case 0:  /* simple s2k */
513         minlen = 0;
514         break;
515       case 1:  /* salted s2k */
516         minlen = 8;
517         break;
518       case 3:  /* iterated+salted s2k */
519         minlen = 9;
520         break;
521       default:
522         log_error("unknown S2K %d\n", s2kmode );
523         goto leave;
524     }
525     if( minlen > pktlen ) {
526         log_error("packet with S2K %d too short\n", s2kmode );
527         goto leave;
528     }
529     seskeylen = pktlen - minlen;
530     k = packet->pkt.symkey_enc = m_alloc_clear( sizeof *packet->pkt.symkey_enc
531                                                 + seskeylen - 1 );
532     k->version = version;
533     k->cipher_algo = cipher_algo;
534     k->s2k.mode = s2kmode;
535     k->s2k.hash_algo = hash_algo;
536     if( s2kmode == 1 || s2kmode == 3 ) {
537         for(i=0; i < 8 && pktlen; i++, pktlen-- )
538             k->s2k.salt[i] = iobuf_get_noeof(inp);
539     }
540     if( s2kmode == 3 ) {
541         k->s2k.count = iobuf_get(inp); pktlen--;
542     }
543     k->seskeylen = seskeylen;
544     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
545         k->seskey[i] = iobuf_get_noeof(inp);
546     assert( !pktlen );
547
548     if( list_mode ) {
549         printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
550                             version, cipher_algo, s2kmode, hash_algo);
551         if( s2kmode == 1 || s2kmode == 3 ) {
552             printf("\tsalt ");
553             for(i=0; i < 8; i++ )
554                 printf("%02x", k->s2k.salt[i]);
555             if( s2kmode == 3 )
556                 printf(", count %lu\n", (ulong)k->s2k.count );
557             printf("\n");
558         }
559     }
560
561   leave:
562     skip_rest(inp, pktlen);
563     return 0;
564 }
565
566 static int
567 parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
568 {
569     unsigned n;
570     int i, ndata;
571     PKT_pubkey_enc *k;
572
573     k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc );
574     if( pktlen < 12 ) {
575         log_error("packet(%d) too short\n", pkttype);
576         goto leave;
577     }
578     k->version = iobuf_get_noeof(inp); pktlen--;
579     if( k->version != 2 && k->version != 3 ) {
580         log_error("packet(%d) with unknown version %d\n", pkttype, k->version);
581         goto leave;
582     }
583     k->keyid[0] = read_32(inp); pktlen -= 4;
584     k->keyid[1] = read_32(inp); pktlen -= 4;
585     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
586     k->throw_keyid = 0; /* only used as flag for build_packet */
587     if( list_mode )
588         printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
589           k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
590
591     ndata = pubkey_get_nenc(k->pubkey_algo);
592     if( !ndata ) {
593         if( list_mode )
594             printf("\tunsupported algorithm %d\n", k->pubkey_algo );
595         unknown_pubkey_warning( k->pubkey_algo );
596         k->data[0] = NULL;  /* no need to store the encrypted data */
597     }
598     else {
599         for( i=0; i < ndata; i++ ) {
600             n = pktlen;
601             k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;
602             if( list_mode ) {
603                 printf("\tdata: ");
604                 mpi_print(stdout, k->data[i], mpi_print_mode );
605                 putchar('\n');
606             }
607         }
608     }
609
610   leave:
611     skip_rest(inp, pktlen);
612     return 0;
613 }
614
615
616 static void
617 dump_sig_subpkt( int hashed, int type, int critical,
618                  const byte *buffer, size_t buflen, size_t length )
619 {
620     const char *p=NULL;
621     int i;
622
623     printf("\t%s%ssubpkt %d len %u (", /*)*/
624               critical ? "critical ":"",
625               hashed ? "hashed ":"", type, (unsigned)length );
626     buffer++;
627     length--;
628     if( length > buflen ) {
629         printf("too short: buffer is only %u)\n", (unsigned)buflen );
630         return;
631     }
632     switch( type ) {
633       case SIGSUBPKT_SIG_CREATED:
634         if( length >= 4 )
635             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
636         break;
637       case SIGSUBPKT_SIG_EXPIRE:
638         if( length >= 4 )
639             printf("sig expires after %s",
640                                      strtimevalue( buffer_to_u32(buffer) ) );
641         break;
642       case SIGSUBPKT_EXPORTABLE:
643         if( length )
644             printf("%sexportable", *buffer? "":"not ");
645         break;
646       case SIGSUBPKT_TRUST:
647         p = "trust signature";
648         break;
649       case SIGSUBPKT_REGEXP:
650         p = "regular expression";
651         break;
652       case SIGSUBPKT_REVOCABLE:
653         p = "revocable";
654         break;
655       case SIGSUBPKT_KEY_EXPIRE:
656         if( length >= 4 )
657             printf("key expires after %s",
658                                     strtimevalue( buffer_to_u32(buffer) ) );
659         break;
660       case SIGSUBPKT_ARR:
661         p = "additional recipient request";
662         break;
663       case SIGSUBPKT_PREF_SYM:
664         fputs("pref-sym-algos:", stdout );
665         for( i=0; i < length; i++ )
666             printf(" %d", buffer[i] );
667         break;
668       case SIGSUBPKT_REV_KEY:
669         p = "revocation key";
670         break;
671       case SIGSUBPKT_ISSUER:
672         if( length >= 8 )
673             printf("issuer key ID %08lX%08lX",
674                       (ulong)buffer_to_u32(buffer),
675                       (ulong)buffer_to_u32(buffer+4) );
676         break;
677       case SIGSUBPKT_NOTATION:
678         p = "notation data";
679         break;
680       case SIGSUBPKT_PREF_HASH:
681         fputs("pref-hash-algos:", stdout );
682         for( i=0; i < length; i++ )
683             printf(" %d", buffer[i] );
684         break;
685       case SIGSUBPKT_PREF_COMPR:
686         fputs("pref-zip-algos:", stdout );
687         for( i=0; i < length; i++ )
688             printf(" %d", buffer[i] );
689         break;
690       case SIGSUBPKT_KS_FLAGS:
691         p = "key server preferences";
692         break;
693       case SIGSUBPKT_PREF_KS:
694         p = "preferred key server";
695         break;
696       case SIGSUBPKT_PRIMARY_UID:
697         p = "primary user id";
698         break;
699       case SIGSUBPKT_POLICY:
700         p = "policy URL";
701         break;
702       case SIGSUBPKT_KEY_FLAGS:
703         p = "key flags";
704         break;
705       case SIGSUBPKT_SIGNERS_UID:
706         p = "signer's user id";
707         break;
708       case SIGSUBPKT_PRIV_ADD_SIG:
709         p = "signs additional user id";
710         break;
711       default: p = "?"; break;
712     }
713
714     printf("%s)\n", p? p: "");
715 }
716
717 /****************
718  * Returns: >= 0 offset into buffer
719  *          -1 unknown type
720  *          -2 unsupported type
721  *          -3 subpacket too short
722  */
723 static int
724 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
725 {
726     switch( type ) {
727       case SIGSUBPKT_SIG_CREATED:
728       case SIGSUBPKT_SIG_EXPIRE:
729       case SIGSUBPKT_KEY_EXPIRE:
730         if( n < 4 )
731             break;
732         return 0;
733       case SIGSUBPKT_EXPORTABLE:
734         if( !n )
735             break;
736         return 0;
737       case SIGSUBPKT_ISSUER:/* issuer key ID */
738         if( n < 8 )
739             break;
740         return 0;
741       case SIGSUBPKT_PREF_SYM:
742       case SIGSUBPKT_PREF_HASH:
743       case SIGSUBPKT_PREF_COMPR:
744         return 0;
745       case SIGSUBPKT_PRIV_ADD_SIG:
746         /* because we use private data, we check the GNUPG marker */
747         if( n < 24 )
748             break;
749         if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
750             return -2;
751         return 3;
752       default: return -1;
753     }
754     return -3;
755 }
756
757 const byte *
758 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
759 {
760     int buflen;
761     int type;
762     int critical;
763     int offset;
764     size_t n;
765
766     if( !buffer )
767         return NULL;
768     buflen = (*buffer << 8) | buffer[1];
769     buffer += 2;
770     while( buflen ) {
771         n = *buffer++; buflen--;
772         if( n == 255 ) {
773             if( buflen < 4 )
774                 goto too_short;
775             n = (buffer[0] << 24) | (buffer[1] << 16)
776                                   | (buffer[2] << 8) | buffer[3];
777             buffer += 4;
778             buflen -= 4;
779
780         }
781         else if( n >= 192 ) {
782             if( buflen < 2 )
783                 goto too_short;
784             n = (( n - 192 ) << 8) + *buffer + 192;
785             buflen--;
786         }
787         if( buflen < n )
788             goto too_short;
789         type = *buffer;
790         if( type & 0x80 ) {
791             type &= 0x7f;
792             critical = 1;
793         }
794         else
795             critical = 0;
796         if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
797             if( critical ) {
798                 if( n-1 > buflen+1 )
799                     goto too_short;
800                 if( parse_one_sig_subpkt(buffer+1, n-1, type ) < 0 ) {
801                     log_info(_("subpacket of type %d has critical bit set\n"),
802                                                                         type);
803                     return NULL; /* this is an error */
804                 }
805             }
806         }
807         else if( reqtype < 0 ) /* list packets */
808             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
809                                     type, critical, buffer, buflen, n );
810         else if( type == reqtype ) { /* found */
811             buffer++;
812             n--;
813             if( n > buflen )
814                 goto too_short;
815             if( ret_n )
816                 *ret_n = n;
817             offset = parse_one_sig_subpkt(buffer, n, type );
818             switch( offset ) {
819               case -3:
820                 log_error("subpacket of type %d too short\n", type);
821                 return NULL;
822               case -2:
823                 return NULL;
824               case -1:
825                 BUG(); /* not yet needed */
826               default:
827                 break;
828             }
829             return buffer+offset;
830         }
831         buffer += n; buflen -=n;
832     }
833     if( reqtype == SIGSUBPKT_TEST_CRITICAL )
834         return buffer; /* as value true to indicate that there is no
835                        /* critical bit we don't understand */
836     return NULL; /* end of packets; not found */
837
838   too_short:
839     log_error("buffer shorter than subpacket\n");
840     return NULL;
841 }
842
843
844 const byte *
845 parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
846 {
847     const byte *p;
848
849     p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
850     if( !p )
851         p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
852     return p;
853 }
854
855
856
857 static int
858 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
859                                           PKT_signature *sig )
860 {
861     int md5_len=0;
862     unsigned n;
863     int is_v4=0;
864     int rc=0;
865     int i, ndata;
866
867     if( pktlen < 16 ) {
868         log_error("packet(%d) too short\n", pkttype);
869         goto leave;
870     }
871     sig->version = iobuf_get_noeof(inp); pktlen--;
872     if( sig->version == 4 )
873         is_v4=1;
874     else if( sig->version != 2 && sig->version != 3 ) {
875         log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
876         goto leave;
877     }
878
879     if( !is_v4 ) {
880         md5_len = iobuf_get_noeof(inp); pktlen--;
881     }
882     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
883     if( !is_v4 ) {
884         sig->timestamp = read_32(inp); pktlen -= 4;
885         sig->keyid[0] = read_32(inp); pktlen -= 4;
886         sig->keyid[1] = read_32(inp); pktlen -= 4;
887     }
888     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
889     sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
890     if( is_v4 ) { /* read subpackets */
891         n = read_16(inp); pktlen -= 2; /* length of hashed data */
892         if( n > 10000 ) {
893             log_error("signature packet: hashed data too long\n");
894             rc = G10ERR_INVALID_PACKET;
895             goto leave;
896         }
897         if( n ) {
898             sig->hashed_data = m_alloc( n + 2 );
899             sig->hashed_data[0] = n << 8;
900             sig->hashed_data[1] = n;
901             if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
902                 log_error("premature eof while reading hashed signature data\n");
903                 rc = -1;
904                 goto leave;
905             }
906             pktlen -= n;
907         }
908         n = read_16(inp); pktlen -= 2; /* length of unhashed data */
909         if( n > 10000 ) {
910             log_error("signature packet: unhashed data too long\n");
911             rc = G10ERR_INVALID_PACKET;
912             goto leave;
913         }
914         if( n ) {
915             sig->unhashed_data = m_alloc( n + 2 );
916             sig->unhashed_data[0] = n << 8;
917             sig->unhashed_data[1] = n;
918             if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
919                 log_error("premature eof while reading unhashed signature data\n");
920                 rc = -1;
921                 goto leave;
922             }
923             pktlen -= n;
924         }
925     }
926
927     if( pktlen < 5 ) { /* sanity check */
928         log_error("packet(%d) too short\n", pkttype);
929         rc = G10ERR_INVALID_PACKET;
930         goto leave;
931     }
932
933     sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
934     sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
935
936     if( is_v4 ) { /*extract required information */
937         const byte *p;
938
939         /* set sig->flags.unknown_critical if there is a
940          * critical bit set for packets which we do not understand */
941         if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
942            || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
943                                                                         NULL) )
944         {
945             sig->flags.unknown_critical = 1;
946         }
947
948         p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
949         if( !p )
950             log_error("signature packet without timestamp\n");
951         else
952             sig->timestamp = buffer_to_u32(p);
953         p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
954         if( !p )
955             log_error("signature packet without keyid\n");
956         else {
957             sig->keyid[0] = buffer_to_u32(p);
958             sig->keyid[1] = buffer_to_u32(p+4);
959         }
960     }
961
962     if( list_mode ) {
963         printf(":signature packet: algo %d, keyid %08lX%08lX\n"
964                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
965                "\tdigest algo %d, begin of digest %02x %02x\n",
966                 sig->pubkey_algo,
967                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
968                 sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
969                 sig->digest_algo,
970                 sig->digest_start[0], sig->digest_start[1] );
971         if( is_v4 ) {
972             parse_sig_subpkt( sig->hashed_data,  SIGSUBPKT_LIST_HASHED, NULL );
973             parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
974         }
975     }
976
977     ndata = pubkey_get_nsig(sig->pubkey_algo);
978     if( !ndata ) {
979         if( list_mode )
980             printf("\tunknown algorithm %d\n", sig->pubkey_algo );
981         unknown_pubkey_warning( sig->pubkey_algo );
982         /* we store the plain material in data[0], so that we are able
983          * to write it back with build_packet() */
984         sig->data[0] = read_rest(inp, &pktlen );
985     }
986     else {
987         for( i=0; i < ndata; i++ ) {
988             n = pktlen;
989             sig->data[i] = mpi_read(inp, &n, 0 );
990             pktlen -=n;
991             if( list_mode ) {
992                 printf("\tdata: ");
993                 mpi_print(stdout, sig->data[i], mpi_print_mode );
994                 putchar('\n');
995             }
996         }
997     }
998
999
1000   leave:
1001     skip_rest(inp, pktlen);
1002     return rc;
1003 }
1004
1005
1006 static int
1007 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
1008                                              PKT_onepass_sig *ops )
1009 {
1010     int version;
1011
1012     if( pktlen < 13 ) {
1013         log_error("packet(%d) too short\n", pkttype);
1014         goto leave;
1015     }
1016     version = iobuf_get_noeof(inp); pktlen--;
1017     if( version != 3 ) {
1018         log_error("onepass_sig with unknown version %d\n", version);
1019         goto leave;
1020     }
1021     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
1022     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
1023     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1024     ops->keyid[0] = read_32(inp); pktlen -= 4;
1025     ops->keyid[1] = read_32(inp); pktlen -= 4;
1026     ops->last = iobuf_get_noeof(inp); pktlen--;
1027     if( list_mode )
1028         printf(":onepass_sig packet: keyid %08lX%08lX\n"
1029                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
1030                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
1031                 version, ops->sig_class,
1032                 ops->digest_algo, ops->pubkey_algo, ops->last );
1033
1034
1035   leave:
1036     skip_rest(inp, pktlen);
1037     return 0;
1038 }
1039
1040
1041
1042
1043 static int
1044 parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
1045                               byte *hdr, int hdrlen, PACKET *pkt )
1046 {
1047     int i, version, algorithm;
1048     unsigned n;
1049     unsigned long timestamp, expiredate;
1050     int npkey, nskey;
1051     int is_v4=0;
1052     int rc=0;
1053
1054     version = iobuf_get_noeof(inp); pktlen--;
1055     if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
1056         /* early versions of G10 use old PGP comments packets;
1057          * luckily all those comments are started by a hash */
1058         if( list_mode ) {
1059             printf(":rfc1991 comment packet: \"" );
1060             for( ; pktlen; pktlen-- ) {
1061                 int c;
1062                 c = iobuf_get_noeof(inp);
1063                 if( c >= ' ' && c <= 'z' )
1064                     putchar(c);
1065                 else
1066                     printf("\\x%02x", c );
1067             }
1068             printf("\"\n");
1069         }
1070         skip_rest(inp, pktlen);
1071         return 0;
1072     }
1073     else if( version == 4 )
1074         is_v4=1;
1075     else if( version != 2 && version != 3 ) {
1076         log_error("packet(%d) with unknown version %d\n", pkttype, version);
1077         goto leave;
1078     }
1079
1080     if( pktlen < 11 ) {
1081         log_error("packet(%d) too short\n", pkttype);
1082         goto leave;
1083     }
1084
1085     timestamp = read_32(inp); pktlen -= 4;
1086     if( is_v4 )
1087         expiredate = 0; /* have to get it from the selfsignature */
1088     else {
1089         unsigned short ndays;
1090         ndays = read_16(inp); pktlen -= 2;
1091         if( ndays )
1092             expiredate = timestamp + ndays * 86400L;
1093         else
1094             expiredate = 0;
1095     }
1096     algorithm = iobuf_get_noeof(inp); pktlen--;
1097     if( list_mode )
1098         printf(":%s key packet:\n"
1099                "\tversion %d, algo %d, created %lu, expires %lu\n",
1100                 pkttype == PKT_PUBLIC_KEY? "public" :
1101                 pkttype == PKT_SECRET_KEY? "secret" :
1102                 pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
1103                 pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
1104                 version, algorithm, timestamp, expiredate );
1105
1106     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
1107         PKT_secret_key *sk = pkt->pkt.secret_key;
1108
1109         sk->timestamp = timestamp;
1110         sk->expiredate = expiredate;
1111         sk->hdrbytes = hdrlen;
1112         sk->version = version;
1113         sk->pubkey_algo = algorithm;
1114         sk->pubkey_usage = 0; /* not yet used */
1115     }
1116     else {
1117         PKT_public_key *pk = pkt->pkt.public_key;
1118
1119         pk->timestamp = timestamp;
1120         pk->expiredate = expiredate;
1121         pk->hdrbytes    = hdrlen;
1122         pk->version     = version;
1123         pk->pubkey_algo = algorithm;
1124         pk->pubkey_usage = 0; /* not yet used */
1125         pk->keyid[0] = 0;
1126         pk->keyid[1] = 0;
1127     }
1128     nskey = pubkey_get_nskey( algorithm );
1129     npkey = pubkey_get_npkey( algorithm );
1130     if( !npkey ) {
1131         if( list_mode )
1132             printf("\tunknown algorithm %d\n", algorithm );
1133         unknown_pubkey_warning( algorithm );
1134     }
1135
1136
1137     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
1138         PKT_secret_key *sk = pkt->pkt.secret_key;
1139         byte temp[8];
1140
1141         if( !npkey ) {
1142             sk->skey[0] = read_rest( inp, &pktlen );
1143             goto leave;
1144         }
1145
1146         for(i=0; i < npkey; i++ ) {
1147             n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1148             if( list_mode ) {
1149                 printf(  "\tskey[%d]: ", i);
1150                 mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1151                 putchar('\n');
1152             }
1153         }
1154         sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1155         if( sk->protect.algo ) {
1156             sk->is_protected = 1;
1157             sk->protect.s2k.count = 0;
1158             if( sk->protect.algo == 255 ) {
1159                 if( pktlen < 3 ) {
1160                     rc = G10ERR_INVALID_PACKET;
1161                     goto leave;
1162                 }
1163                 sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1164                 sk->protect.s2k.mode  = iobuf_get_noeof(inp); pktlen--;
1165                 sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
1166                 switch( sk->protect.s2k.mode ) {
1167                   case 1:
1168                   case 3:
1169                     for(i=0; i < 8 && pktlen; i++, pktlen-- )
1170                         temp[i] = iobuf_get_noeof(inp);
1171                     memcpy(sk->protect.s2k.salt, temp, 8 );
1172                     break;
1173                 }
1174                 switch( sk->protect.s2k.mode ) {
1175                   case 0: if( list_mode ) printf(  "\tsimple S2K" );
1176                     break;
1177                   case 1: if( list_mode ) printf(  "\tsalted S2K" );
1178                     break;
1179                   case 3: if( list_mode ) printf(  "\titer+salt S2K" );
1180                     break;
1181                   default:
1182                     if( list_mode )
1183                         printf(  "\tunknown S2K %d\n",
1184                                             sk->protect.s2k.mode );
1185                     rc = G10ERR_INVALID_PACKET;
1186                     goto leave;
1187                 }
1188
1189                 if( list_mode ) {
1190                     printf(", algo: %d, hash: %d",
1191                                      sk->protect.algo,
1192                                      sk->protect.s2k.hash_algo );
1193                     if( sk->protect.s2k.mode == 1
1194                         || sk->protect.s2k.mode == 3 ) {
1195                         printf(", salt: ");
1196                         for(i=0; i < 8; i++ )
1197                             printf("%02x", sk->protect.s2k.salt[i]);
1198                     }
1199                     putchar('\n');
1200                 }
1201
1202                 if( sk->protect.s2k.mode == 3 ) {
1203                     if( pktlen < 1 ) {
1204                         rc = G10ERR_INVALID_PACKET;
1205                         goto leave;
1206                     }
1207                     sk->protect.s2k.count = iobuf_get(inp);
1208                     pktlen--;
1209                     if( list_mode )
1210                         printf("\tprotect count: %lu\n",
1211                                             (ulong)sk->protect.s2k.count);
1212                 }
1213             }
1214             else { /* old version; no S2K, so we set mode to 0, hash MD5 */
1215                 sk->protect.s2k.mode = 0;
1216                 /* We need a kludge to cope with old GNUPG versions */
1217                 sk->protect.s2k.hash_algo =
1218                              ( sk->protect.algo == CIPHER_ALGO_BLOWFISH160
1219                                && algorithm == PUBKEY_ALGO_ELGAMAL_E ) ?
1220                                       DIGEST_ALGO_RMD160 : DIGEST_ALGO_MD5;
1221                 if( list_mode )
1222                     printf(  "\tprotect algo: %d  (hash algo: %d)\n",
1223                          sk->protect.algo, sk->protect.s2k.hash_algo );
1224             }
1225             if( pktlen < 8 ) {
1226                 rc = G10ERR_INVALID_PACKET;
1227                 goto leave;
1228             }
1229             /* fixme: Add support for other blocksizes */
1230             for(i=0; i < 8 && pktlen; i++, pktlen-- )
1231                 temp[i] = iobuf_get_noeof(inp);
1232             if( list_mode ) {
1233                 printf(  "\tprotect IV: ");
1234                 for(i=0; i < 8; i++ )
1235                     printf(" %02x", temp[i] );
1236                 putchar('\n');
1237             }
1238             memcpy(sk->protect.iv, temp, 8 );
1239         }
1240         else
1241             sk->is_protected = 0;
1242         /* It does not make sense to read it into secure memory.
1243          * If the user is so careless, not to protect his secret key,
1244          * we can assume, that he operates an open system :=(.
1245          * So we put the key into secure memory when we unprotect it. */
1246         if( is_v4 && sk->is_protected ){
1247             /* ugly; the length is encrypted too, so we read all
1248              * stuff up to the end of the packet into the first
1249              * skey element */
1250             sk->skey[npkey] = mpi_set_opaque(NULL,
1251                                              read_rest2(inp, pktlen), pktlen );
1252             pktlen = 0;
1253             if( list_mode ) {
1254                 printf("\tencrypted stuff follows\n");
1255             }
1256         }
1257         else { /* v3 method: the mpi length is not encrypted */
1258             for(i=npkey; i < nskey; i++ ) {
1259                 n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1260                 if( sk->is_protected )
1261                     mpi_set_protect_flag(sk->skey[i]);
1262                 if( list_mode ) {
1263                     printf(  "\tskey[%d]: ", i);
1264                     if( sk->is_protected )
1265                         printf(  "[encrypted]\n");
1266                     else {
1267                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1268                         putchar('\n');
1269                     }
1270                 }
1271             }
1272
1273             sk->csum = read_16(inp); pktlen -= 2;
1274             if( list_mode ) {
1275                 printf("\tchecksum: %04hx\n", sk->csum);
1276             }
1277         }
1278     }
1279     else {
1280         PKT_public_key *pk = pkt->pkt.public_key;
1281
1282         if( !npkey ) {
1283             pk->pkey[0] = read_rest( inp, &pktlen );
1284             goto leave;
1285         }
1286
1287         for(i=0; i < npkey; i++ ) {
1288             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1289             if( list_mode ) {
1290                 printf(  "\tpkey[%d]: ", i);
1291                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
1292                 putchar('\n');
1293             }
1294         }
1295     }
1296
1297   leave:
1298     skip_rest(inp, pktlen);
1299     return rc;
1300 }
1301
1302
1303 static int
1304 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1305 {
1306     byte *p;
1307
1308     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
1309     packet->pkt.user_id->len = pktlen;
1310     p = packet->pkt.user_id->name;
1311     for( ; pktlen; pktlen--, p++ )
1312         *p = iobuf_get_noeof(inp);
1313
1314     if( list_mode ) {
1315         int n = packet->pkt.user_id->len;
1316         printf(":user id packet: \"");
1317         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
1318             if( *p >= ' ' && *p <= 'z' )
1319                 putchar(*p);
1320             else
1321                 printf("\\x%02x", *p );
1322         }
1323         printf("\"\n");
1324     }
1325     return 0;
1326 }
1327
1328
1329
1330 static int
1331 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1332 {
1333     byte *p;
1334
1335     packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
1336     packet->pkt.comment->len = pktlen;
1337     p = packet->pkt.comment->data;
1338     for( ; pktlen; pktlen--, p++ )
1339         *p = iobuf_get_noeof(inp);
1340
1341     if( list_mode ) {
1342         int n = packet->pkt.comment->len;
1343         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
1344                                          "OpenPGP draft " : "" );
1345         for(p=packet->pkt.comment->data; n; p++, n-- ) {
1346             if( *p >= ' ' && *p <= 'z' )
1347                 putchar(*p);
1348             else
1349                 printf("\\x%02x", *p );
1350         }
1351         printf("\"\n");
1352     }
1353     return 0;
1354 }
1355
1356
1357 static void
1358 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
1359 {
1360     int c;
1361
1362     c = iobuf_get_noeof(inp);
1363     if( list_mode )
1364         printf(":trust packet: flag=%02x\n", c );
1365 }
1366
1367
1368 static int
1369 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
1370                                         PACKET *pkt, int new_ctb )
1371 {
1372     int mode, namelen;
1373     PKT_plaintext *pt;
1374     byte *p;
1375     int c, i;
1376
1377     if( pktlen && pktlen < 6 ) {
1378         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
1379         goto leave;
1380     }
1381     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1382     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1383     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
1384     pt->new_ctb = new_ctb;
1385     pt->mode = mode;
1386     pt->namelen = namelen;
1387     if( pktlen ) {
1388         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
1389             pt->name[i] = iobuf_get_noeof(inp);
1390     }
1391     else {
1392         for( i=0; i < namelen; i++ )
1393             if( (c=iobuf_get(inp)) == -1 )
1394                 break;
1395             else
1396                 pt->name[i] = c;
1397     }
1398     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
1399     pt->len = pktlen;
1400     pt->buf = inp;
1401     pktlen = 0;
1402
1403     if( list_mode ) {
1404         printf(":literal data packet:\n"
1405                "\tmode %c, created %lu, name=\"",
1406                     mode >= ' ' && mode <'z'? mode : '?',
1407                     (ulong)pt->timestamp );
1408         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
1409             if( *p >= ' ' && *p <= 'z' )
1410                 putchar(*p);
1411             else
1412                 printf("\\x%02x", *p );
1413         }
1414         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
1415     }
1416
1417   leave:
1418     return 0;
1419 }
1420
1421
1422 static int
1423 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
1424                   PACKET *pkt, int new_ctb )
1425 {
1426     PKT_compressed *zd;
1427
1428     /* pktlen is here 0, but data follows
1429      * (this should be the last object in a file or
1430      *  the compress algorithm should know the length)
1431      */
1432     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
1433     zd->len = 0; /* not yet used */
1434     zd->algorithm = iobuf_get_noeof(inp);
1435     zd->new_ctb = new_ctb;
1436     zd->buf = inp;
1437     if( list_mode )
1438         printf(":compressed packet: algo=%d\n", zd->algorithm);
1439     return 0;
1440 }
1441
1442
1443 static int
1444 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
1445                                        PACKET *pkt, int new_ctb )
1446 {
1447     PKT_encrypted *ed;
1448
1449     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
1450     ed->len = pktlen;
1451     ed->buf = NULL;
1452     ed->new_ctb = new_ctb;
1453     if( pktlen && pktlen < 10 ) {
1454         log_error("packet(%d) too short\n", pkttype);
1455         skip_rest(inp, pktlen);
1456         goto leave;
1457     }
1458     if( list_mode ) {
1459         if( pktlen )
1460             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
1461         else
1462             printf(":encrypted data packet:\n\tlength: unknown\n");
1463     }
1464
1465     ed->buf = inp;
1466     pktlen = 0;
1467
1468   leave:
1469     return 0;
1470 }
1471
1472
1473