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