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