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