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