See ChangeLog: Wed Sep 1 15:30:44 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, size_t 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                                                            PACKET *packet );
68 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
69                                                PACKET *packet, int new_ctb);
70 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
71                                                PACKET *packet, int new_ctb );
72 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
73                                                PACKET *packet, int new_ctb);
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, pkt);
426         rc = 0;
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       case PKT_ENCRYPTED_MDC:
436         rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );
437         break;
438       default:
439         skip_packet(inp, pkttype, pktlen);
440         break;
441     }
442
443   leave:
444     if( !rc && iobuf_error(inp) )
445         rc = G10ERR_INV_KEYRING;
446     return rc;
447 }
448
449 static void
450 dump_hex_line( int c, int *i )
451 {
452     if( *i && !(*i%8) ) {
453         if( *i && !(*i%24) )
454             printf("\n%4d:", *i );
455         else
456             putchar(' ');
457     }
458     if( c == -1 )
459         printf(" EOF" );
460     else
461         printf(" %02x", c );
462     ++*i;
463 }
464
465
466 static int
467 copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
468 {
469     int n;
470     char buf[100];
471
472     if( iobuf_in_block_mode(inp) ) {
473         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
474             if( iobuf_write(out, buf, n ) )
475                 return G10ERR_WRITE_FILE; /* write error */
476     }
477     else if( !pktlen && pkttype == PKT_COMPRESSED ) {
478         log_debug("copy_packet: compressed!\n");
479         /* compressed packet, copy till EOF */
480         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
481             if( iobuf_write(out, buf, n ) )
482                 return G10ERR_WRITE_FILE; /* write error */
483     }
484     else {
485         for( ; pktlen; pktlen -= n ) {
486             n = pktlen > 100 ? 100 : pktlen;
487             n = iobuf_read( inp, buf, n );
488             if( n == -1 )
489                 return G10ERR_READ_FILE;
490             if( iobuf_write(out, buf, n ) )
491                 return G10ERR_WRITE_FILE; /* write error */
492         }
493     }
494     return 0;
495 }
496
497
498 static void
499 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
500 {
501     if( list_mode ) {
502         if( pkttype == PKT_MARKER )
503             fputs(":marker packet:\n", stdout );
504         else
505             printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
506         if( pkttype ) {
507             int c, i=0 ;
508             if( pkttype != PKT_MARKER )
509                 fputs("dump:", stdout );
510             if( iobuf_in_block_mode(inp) ) {
511                 while( (c=iobuf_get(inp)) != -1 )
512                     dump_hex_line(c, &i);
513             }
514             else {
515                 for( ; pktlen; pktlen-- )
516                     dump_hex_line(iobuf_get(inp), &i);
517             }
518             putchar('\n');
519             return;
520         }
521     }
522     skip_rest(inp,pktlen);
523 }
524
525 static void
526 skip_rest( IOBUF inp, unsigned long pktlen )
527 {
528     if( iobuf_in_block_mode(inp) ) {
529         while( iobuf_get(inp) != -1 )
530                 ;
531     }
532     else {
533         for( ; pktlen; pktlen-- )
534             if( iobuf_get(inp) == -1 )
535                 break;
536     }
537 }
538
539
540 static void *
541 read_rest( IOBUF inp, size_t pktlen )
542 {
543     byte *p;
544     int i;
545
546     if( iobuf_in_block_mode(inp) ) {
547         log_error("read_rest: can't store stream data\n");
548         p = NULL;
549     }
550     else {
551         p = m_alloc( pktlen );
552         for(i=0; pktlen; pktlen--, i++ )
553             p[i] = iobuf_get(inp);
554     }
555     return p;
556 }
557
558
559
560 static int
561 parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
562 {
563     PKT_symkey_enc *k;
564     int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
565
566     if( pktlen < 4 ) {
567         log_error("packet(%d) too short\n", pkttype);
568         goto leave;
569     }
570     version = iobuf_get_noeof(inp); pktlen--;
571     if( version != 4 ) {
572         log_error("packet(%d) with unknown version %d\n", pkttype, version);
573         goto leave;
574     }
575     if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
576         log_error("packet(%d) too large\n", pkttype);
577         goto leave;
578     }
579     cipher_algo = iobuf_get_noeof(inp); pktlen--;
580     s2kmode = iobuf_get_noeof(inp); pktlen--;
581     hash_algo = iobuf_get_noeof(inp); pktlen--;
582     switch( s2kmode ) {
583       case 0:  /* simple s2k */
584         minlen = 0;
585         break;
586       case 1:  /* salted s2k */
587         minlen = 8;
588         break;
589       case 3:  /* iterated+salted s2k */
590         minlen = 9;
591         break;
592       default:
593         log_error("unknown S2K %d\n", s2kmode );
594         goto leave;
595     }
596     if( minlen > pktlen ) {
597         log_error("packet with S2K %d too short\n", s2kmode );
598         goto leave;
599     }
600     seskeylen = pktlen - minlen;
601     k = packet->pkt.symkey_enc = m_alloc_clear( sizeof *packet->pkt.symkey_enc
602                                                 + seskeylen - 1 );
603     k->version = version;
604     k->cipher_algo = cipher_algo;
605     k->s2k.mode = s2kmode;
606     k->s2k.hash_algo = hash_algo;
607     if( s2kmode == 1 || s2kmode == 3 ) {
608         for(i=0; i < 8 && pktlen; i++, pktlen-- )
609             k->s2k.salt[i] = iobuf_get_noeof(inp);
610     }
611     if( s2kmode == 3 ) {
612         k->s2k.count = iobuf_get(inp); pktlen--;
613     }
614     k->seskeylen = seskeylen;
615     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
616         k->seskey[i] = iobuf_get_noeof(inp);
617     assert( !pktlen );
618
619     if( list_mode ) {
620         printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
621                             version, cipher_algo, s2kmode, hash_algo);
622         if( s2kmode == 1 || s2kmode == 3 ) {
623             printf("\tsalt ");
624             for(i=0; i < 8; i++ )
625                 printf("%02x", k->s2k.salt[i]);
626             if( s2kmode == 3 )
627                 printf(", count %lu\n", (ulong)k->s2k.count );
628             printf("\n");
629         }
630     }
631
632   leave:
633     skip_rest(inp, pktlen);
634     return 0;
635 }
636
637 static int
638 parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
639 {
640     unsigned n;
641     int i, ndata;
642     PKT_pubkey_enc *k;
643
644     k = packet->pkt.pubkey_enc = m_alloc_clear(sizeof *packet->pkt.pubkey_enc);
645     if( pktlen < 12 ) {
646         log_error("packet(%d) too short\n", pkttype);
647         goto leave;
648     }
649     k->version = iobuf_get_noeof(inp); pktlen--;
650     if( k->version != 2 && k->version != 3 ) {
651         log_error("packet(%d) with unknown version %d\n", pkttype, k->version);
652         goto leave;
653     }
654     k->keyid[0] = read_32(inp); pktlen -= 4;
655     k->keyid[1] = read_32(inp); pktlen -= 4;
656     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
657     k->throw_keyid = 0; /* only used as flag for build_packet */
658     if( list_mode )
659         printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
660           k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
661
662     ndata = pubkey_get_nenc(k->pubkey_algo);
663     if( !ndata ) {
664         if( list_mode )
665             printf("\tunsupported algorithm %d\n", k->pubkey_algo );
666         unknown_pubkey_warning( k->pubkey_algo );
667         k->data[0] = NULL;  /* no need to store the encrypted data */
668     }
669     else {
670         for( i=0; i < ndata; i++ ) {
671             n = pktlen;
672             k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;
673             if( list_mode ) {
674                 printf("\tdata: ");
675                 mpi_print(stdout, k->data[i], mpi_print_mode );
676                 putchar('\n');
677             }
678         }
679     }
680
681   leave:
682     skip_rest(inp, pktlen);
683     return 0;
684 }
685
686
687 static void
688 dump_sig_subpkt( int hashed, int type, int critical,
689                  const byte *buffer, size_t buflen, size_t length )
690 {
691     const char *p=NULL;
692     int i;
693
694     printf("\t%s%ssubpkt %d len %u (", /*)*/
695               critical ? "critical ":"",
696               hashed ? "hashed ":"", type, (unsigned)length );
697     buffer++;
698     length--;
699     if( length > buflen ) {
700         printf("too short: buffer is only %u)\n", (unsigned)buflen );
701         return;
702     }
703     switch( type ) {
704       case SIGSUBPKT_SIG_CREATED:
705         if( length >= 4 )
706             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
707         break;
708       case SIGSUBPKT_SIG_EXPIRE:
709         if( length >= 4 )
710             printf("sig expires after %s",
711                                      strtimevalue( buffer_to_u32(buffer) ) );
712         break;
713       case SIGSUBPKT_EXPORTABLE:
714         if( length )
715             printf("%sexportable", *buffer? "":"not ");
716         break;
717       case SIGSUBPKT_TRUST:
718         p = "trust signature";
719         break;
720       case SIGSUBPKT_REGEXP:
721         p = "regular expression";
722         break;
723       case SIGSUBPKT_REVOCABLE:
724         p = "revocable";
725         break;
726       case SIGSUBPKT_KEY_EXPIRE:
727         if( length >= 4 )
728             printf("key expires after %s",
729                                     strtimevalue( buffer_to_u32(buffer) ) );
730         break;
731       case SIGSUBPKT_ARR:
732         p = "additional recipient request";
733         break;
734       case SIGSUBPKT_PREF_SYM:
735         fputs("pref-sym-algos:", stdout );
736         for( i=0; i < length; i++ )
737             printf(" %d", buffer[i] );
738         break;
739       case SIGSUBPKT_REV_KEY:
740         fputs("revocation key: ", stdout );
741         if( length < 22 )
742             p = "[too short]";
743         else {
744             printf("c=%02x a=%d f=", buffer[0], buffer[1] );
745             for( i=2; i < length; i++ )
746                 printf("%02X", buffer[i] );
747         }
748         break;
749       case SIGSUBPKT_ISSUER:
750         if( length >= 8 )
751             printf("issuer key ID %08lX%08lX",
752                       (ulong)buffer_to_u32(buffer),
753                       (ulong)buffer_to_u32(buffer+4) );
754         break;
755       case SIGSUBPKT_NOTATION:
756         {
757             fputs("notation: ", stdout );
758             if( length < 8 )
759                 p = "[too short]";
760             else if( !(*buffer & 0x80) )
761                 p = "[not human readable]";
762             else {
763                 const byte *s = buffer;
764                 size_t n1, n2;
765
766                 n1 = (s[4] << 8) | s[5];
767                 n2 = (s[6] << 8) | s[7];
768                 s += 8;
769                 if( 8+n1+n2 != length )
770                     p = "[error]";
771                 else {
772                     print_string( stdout, s, n1, ')' );
773                     putc( '=', stdout );
774                     print_string( stdout, s+n1, n2, ')' );
775                 }
776             }
777         }
778         break;
779       case SIGSUBPKT_PREF_HASH:
780         fputs("pref-hash-algos:", stdout );
781         for( i=0; i < length; i++ )
782             printf(" %d", buffer[i] );
783         break;
784       case SIGSUBPKT_PREF_COMPR:
785         fputs("pref-zip-algos:", stdout );
786         for( i=0; i < length; i++ )
787             printf(" %d", buffer[i] );
788         break;
789       case SIGSUBPKT_KS_FLAGS:
790         p = "key server preferences";
791         break;
792       case SIGSUBPKT_PREF_KS:
793         p = "preferred key server";
794         break;
795       case SIGSUBPKT_PRIMARY_UID:
796         p = "primary user ID";
797         break;
798       case SIGSUBPKT_POLICY:
799         fputs("policy: ", stdout );
800         print_string( stdout, buffer, length, ')' );
801         break;
802       case SIGSUBPKT_KEY_FLAGS:
803         p = "key flags";
804         break;
805       case SIGSUBPKT_SIGNERS_UID:
806         p = "signer's user ID";
807         break;
808       case SIGSUBPKT_PRIV_ADD_SIG:
809         p = "signs additional user ID";
810         break;
811       default: p = "?"; break;
812     }
813
814     printf("%s)\n", p? p: "");
815 }
816
817 /****************
818  * Returns: >= 0 offset into buffer
819  *          -1 unknown type
820  *          -2 unsupported type
821  *          -3 subpacket too short
822  */
823 static int
824 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
825 {
826     switch( type ) {
827       case SIGSUBPKT_SIG_CREATED:
828       case SIGSUBPKT_SIG_EXPIRE:
829       case SIGSUBPKT_KEY_EXPIRE:
830         if( n < 4 )
831             break;
832         return 0;
833       case SIGSUBPKT_EXPORTABLE:
834         if( !n )
835             break;
836         return 0;
837       case SIGSUBPKT_ISSUER:/* issuer key ID */
838         if( n < 8 )
839             break;
840         return 0;
841       case SIGSUBPKT_NOTATION:
842         if( n < 8 ) /* minimum length needed */
843             break;
844         return 0;
845       case SIGSUBPKT_PREF_SYM:
846       case SIGSUBPKT_PREF_HASH:
847       case SIGSUBPKT_PREF_COMPR:
848       case SIGSUBPKT_POLICY:
849         return 0;
850       case SIGSUBPKT_PRIV_ADD_SIG:
851         /* because we use private data, we check the GNUPG marker */
852         if( n < 24 )
853             break;
854         if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
855             return -2;
856         return 3;
857       default: return -1;
858     }
859     return -3;
860 }
861
862
863 static int
864 can_handle_critical( const byte *buffer, size_t n, int type )
865 {
866     switch( type ) {
867       case SIGSUBPKT_NOTATION:
868         if( n >= 8 && (*buffer & 0x80) )
869             return 1; /* human readable is handled */
870         return 0;
871
872       case SIGSUBPKT_SIG_CREATED:
873       case SIGSUBPKT_SIG_EXPIRE:
874       case SIGSUBPKT_KEY_EXPIRE:
875       case SIGSUBPKT_EXPORTABLE:
876       case SIGSUBPKT_ISSUER:/* issuer key ID */
877       case SIGSUBPKT_PREF_SYM:
878       case SIGSUBPKT_PREF_HASH:
879       case SIGSUBPKT_PREF_COMPR:
880         return 1;
881
882       case SIGSUBPKT_POLICY: /* Is enough to show the policy? */
883       default:
884         return 0;
885     }
886 }
887
888
889 const byte *
890 enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
891                  size_t *ret_n, int *start )
892 {
893     int buflen;
894     int type;
895     int critical;
896     int offset;
897     size_t n;
898     int seq = 0;
899     int reqseq = start? *start: 0;
900
901     if( !buffer || reqseq == -1 )
902         return NULL;
903     buflen = (*buffer << 8) | buffer[1];
904     buffer += 2;
905     while( buflen ) {
906         n = *buffer++; buflen--;
907         if( n == 255 ) {
908             if( buflen < 4 )
909                 goto too_short;
910             n = (buffer[0] << 24) | (buffer[1] << 16)
911                                   | (buffer[2] << 8) | buffer[3];
912             buffer += 4;
913             buflen -= 4;
914
915         }
916         else if( n >= 192 ) {
917             if( buflen < 2 )
918                 goto too_short;
919             n = (( n - 192 ) << 8) + *buffer + 192;
920             buffer++;
921             buflen--;
922         }
923         if( buflen < n )
924             goto too_short;
925         type = *buffer;
926         if( type & 0x80 ) {
927             type &= 0x7f;
928             critical = 1;
929         }
930         else
931             critical = 0;
932         if( !(++seq > reqseq) )
933             ;
934         else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
935             if( critical ) {
936                 if( n-1 > buflen+1 )
937                     goto too_short;
938                 if( !can_handle_critical(buffer+1, n-1, type ) ) {
939                     log_info(_("subpacket of type %d has critical bit set\n"),
940                                                                         type);
941                     if( start )
942                         *start = seq;
943                     return NULL; /* this is an error */
944                 }
945             }
946         }
947         else if( reqtype < 0 ) /* list packets */
948             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
949                                     type, critical, buffer, buflen, n );
950         else if( type == reqtype ) { /* found */
951             buffer++;
952             n--;
953             if( n > buflen )
954                 goto too_short;
955             if( ret_n )
956                 *ret_n = n;
957             offset = parse_one_sig_subpkt(buffer, n, type );
958             switch( offset ) {
959               case -3:
960                 log_error("subpacket of type %d too short\n", type);
961                 return NULL;
962               case -2:
963                 return NULL;
964               case -1:
965                 BUG(); /* not yet needed */
966               default:
967                 break;
968             }
969             if( start )
970                 *start = seq;
971             return buffer+offset;
972         }
973         buffer += n; buflen -=n;
974     }
975     if( reqtype == SIGSUBPKT_TEST_CRITICAL )
976         return buffer; /* as value true to indicate that there is no */
977                        /* critical bit we don't understand */
978     if( start )
979         *start = -1;
980     return NULL; /* end of packets; not found */
981
982   too_short:
983     log_error("buffer shorter than subpacket\n");
984     if( start )
985         *start = -1;
986     return NULL;
987 }
988
989
990 const byte *
991 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
992 {
993     return enum_sig_subpkt( buffer, reqtype, ret_n, NULL );
994 }
995
996 const byte *
997 parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
998 {
999     const byte *p;
1000
1001     p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
1002     if( !p )
1003         p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
1004     return p;
1005 }
1006
1007
1008
1009 static int
1010 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
1011                                           PKT_signature *sig )
1012 {
1013     int md5_len=0;
1014     unsigned n;
1015     int is_v4=0;
1016     int rc=0;
1017     int i, ndata;
1018
1019     if( pktlen < 16 ) {
1020         log_error("packet(%d) too short\n", pkttype);
1021         goto leave;
1022     }
1023     sig->version = iobuf_get_noeof(inp); pktlen--;
1024     if( sig->version == 4 )
1025         is_v4=1;
1026     else if( sig->version != 2 && sig->version != 3 ) {
1027         log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
1028         goto leave;
1029     }
1030
1031     if( !is_v4 ) {
1032         md5_len = iobuf_get_noeof(inp); pktlen--;
1033     }
1034     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
1035     if( !is_v4 ) {
1036         sig->timestamp = read_32(inp); pktlen -= 4;
1037         sig->keyid[0] = read_32(inp); pktlen -= 4;
1038         sig->keyid[1] = read_32(inp); pktlen -= 4;
1039     }
1040     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1041     sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
1042     if( is_v4 ) { /* read subpackets */
1043         n = read_16(inp); pktlen -= 2; /* length of hashed data */
1044         if( n > 10000 ) {
1045             log_error("signature packet: hashed data too long\n");
1046             rc = G10ERR_INVALID_PACKET;
1047             goto leave;
1048         }
1049         if( n ) {
1050             sig->hashed_data = m_alloc( n + 2 );
1051             sig->hashed_data[0] = n >> 8;
1052             sig->hashed_data[1] = n;
1053             if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
1054                 log_error("premature eof while reading hashed signature data\n");
1055                 rc = -1;
1056                 goto leave;
1057             }
1058             pktlen -= n;
1059         }
1060         n = read_16(inp); pktlen -= 2; /* length of unhashed data */
1061         if( n > 10000 ) {
1062             log_error("signature packet: unhashed data too long\n");
1063             rc = G10ERR_INVALID_PACKET;
1064             goto leave;
1065         }
1066         if( n ) {
1067             sig->unhashed_data = m_alloc( n + 2 );
1068             sig->unhashed_data[0] = n >> 8;
1069             sig->unhashed_data[1] = n;
1070             if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
1071                 log_error("premature eof while reading unhashed signature data\n");
1072                 rc = -1;
1073                 goto leave;
1074             }
1075             pktlen -= n;
1076         }
1077     }
1078
1079     if( pktlen < 5 ) { /* sanity check */
1080         log_error("packet(%d) too short\n", pkttype);
1081         rc = G10ERR_INVALID_PACKET;
1082         goto leave;
1083     }
1084
1085     sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
1086     sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
1087
1088     if( is_v4 && sig->pubkey_algo ) { /*extract required information */
1089         const byte *p;
1090
1091         /* set sig->flags.unknown_critical if there is a
1092          * critical bit set for packets which we do not understand */
1093         if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
1094            || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
1095                                                                         NULL) )
1096         {
1097             sig->flags.unknown_critical = 1;
1098         }
1099
1100         p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
1101         if( !p )
1102             log_error("signature packet without timestamp\n");
1103         else
1104             sig->timestamp = buffer_to_u32(p);
1105         p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
1106         if( !p )
1107             log_error("signature packet without keyid\n");
1108         else {
1109             sig->keyid[0] = buffer_to_u32(p);
1110             sig->keyid[1] = buffer_to_u32(p+4);
1111         }
1112     }
1113
1114     if( list_mode ) {
1115         printf(":signature packet: algo %d, keyid %08lX%08lX\n"
1116                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
1117                "\tdigest algo %d, begin of digest %02x %02x\n",
1118                 sig->pubkey_algo,
1119                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1120                 sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
1121                 sig->digest_algo,
1122                 sig->digest_start[0], sig->digest_start[1] );
1123         if( is_v4 ) {
1124             parse_sig_subpkt( sig->hashed_data,  SIGSUBPKT_LIST_HASHED, NULL );
1125             parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
1126         }
1127     }
1128
1129     ndata = pubkey_get_nsig(sig->pubkey_algo);
1130     if( !ndata ) {
1131         if( list_mode )
1132             printf("\tunknown algorithm %d\n", sig->pubkey_algo );
1133         unknown_pubkey_warning( sig->pubkey_algo );
1134         /* we store the plain material in data[0], so that we are able
1135          * to write it back with build_packet() */
1136         sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen );
1137         pktlen = 0;
1138     }
1139     else {
1140         for( i=0; i < ndata; i++ ) {
1141             n = pktlen;
1142             sig->data[i] = mpi_read(inp, &n, 0 );
1143             pktlen -=n;
1144             if( list_mode ) {
1145                 printf("\tdata: ");
1146                 mpi_print(stdout, sig->data[i], mpi_print_mode );
1147                 putchar('\n');
1148             }
1149         }
1150     }
1151
1152   leave:
1153     skip_rest(inp, pktlen);
1154     return rc;
1155 }
1156
1157
1158 static int
1159 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
1160                                              PKT_onepass_sig *ops )
1161 {
1162     int version;
1163
1164     if( pktlen < 13 ) {
1165         log_error("packet(%d) too short\n", pkttype);
1166         goto leave;
1167     }
1168     version = iobuf_get_noeof(inp); pktlen--;
1169     if( version != 3 ) {
1170         log_error("onepass_sig with unknown version %d\n", version);
1171         goto leave;
1172     }
1173     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
1174     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
1175     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1176     ops->keyid[0] = read_32(inp); pktlen -= 4;
1177     ops->keyid[1] = read_32(inp); pktlen -= 4;
1178     ops->last = iobuf_get_noeof(inp); pktlen--;
1179     if( list_mode )
1180         printf(":onepass_sig packet: keyid %08lX%08lX\n"
1181                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
1182                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
1183                 version, ops->sig_class,
1184                 ops->digest_algo, ops->pubkey_algo, ops->last );
1185
1186
1187   leave:
1188     skip_rest(inp, pktlen);
1189     return 0;
1190 }
1191
1192
1193
1194
1195 static int
1196 parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
1197                               byte *hdr, int hdrlen, PACKET *pkt )
1198 {
1199     int i, version, algorithm;
1200     unsigned n;
1201     unsigned long timestamp, expiredate;
1202     int npkey, nskey;
1203     int is_v4=0;
1204     int rc=0;
1205
1206     version = iobuf_get_noeof(inp); pktlen--;
1207     if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
1208         /* early versions of G10 use old PGP comments packets;
1209          * luckily all those comments are started by a hash */
1210         if( list_mode ) {
1211             printf(":rfc1991 comment packet: \"" );
1212             for( ; pktlen; pktlen-- ) {
1213                 int c;
1214                 c = iobuf_get_noeof(inp);
1215                 if( c >= ' ' && c <= 'z' )
1216                     putchar(c);
1217                 else
1218                     printf("\\x%02x", c );
1219             }
1220             printf("\"\n");
1221         }
1222         skip_rest(inp, pktlen);
1223         return 0;
1224     }
1225     else if( version == 4 )
1226         is_v4=1;
1227     else if( version != 2 && version != 3 ) {
1228         log_error("packet(%d) with unknown version %d\n", pkttype, version);
1229         goto leave;
1230     }
1231
1232     if( pktlen < 11 ) {
1233         log_error("packet(%d) too short\n", pkttype);
1234         goto leave;
1235     }
1236
1237     timestamp = read_32(inp); pktlen -= 4;
1238     if( is_v4 )
1239         expiredate = 0; /* have to get it from the selfsignature */
1240     else {
1241         unsigned short ndays;
1242         ndays = read_16(inp); pktlen -= 2;
1243         if( ndays )
1244             expiredate = timestamp + ndays * 86400L;
1245         else
1246             expiredate = 0;
1247     }
1248     algorithm = iobuf_get_noeof(inp); pktlen--;
1249     if( list_mode )
1250         printf(":%s key packet:\n"
1251                "\tversion %d, algo %d, created %lu, expires %lu\n",
1252                 pkttype == PKT_PUBLIC_KEY? "public" :
1253                 pkttype == PKT_SECRET_KEY? "secret" :
1254                 pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
1255                 pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
1256                 version, algorithm, timestamp, expiredate );
1257
1258     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
1259         PKT_secret_key *sk = pkt->pkt.secret_key;
1260
1261         sk->timestamp = timestamp;
1262         sk->expiredate = expiredate;
1263         sk->hdrbytes = hdrlen;
1264         sk->version = version;
1265         sk->is_primary = pkttype == PKT_SECRET_KEY;
1266         sk->pubkey_algo = algorithm;
1267         sk->pubkey_usage = 0; /* not yet used */
1268     }
1269     else {
1270         PKT_public_key *pk = pkt->pkt.public_key;
1271
1272         pk->timestamp = timestamp;
1273         pk->expiredate = expiredate;
1274         pk->hdrbytes    = hdrlen;
1275         pk->version     = version;
1276         pk->pubkey_algo = algorithm;
1277         pk->pubkey_usage = 0; /* not yet used */
1278         pk->keyid[0] = 0;
1279         pk->keyid[1] = 0;
1280     }
1281     nskey = pubkey_get_nskey( algorithm );
1282     npkey = pubkey_get_npkey( algorithm );
1283     if( !npkey ) {
1284         if( list_mode )
1285             printf("\tunknown algorithm %d\n", algorithm );
1286         unknown_pubkey_warning( algorithm );
1287     }
1288
1289
1290     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
1291         PKT_secret_key *sk = pkt->pkt.secret_key;
1292         byte temp[16];
1293
1294         if( !npkey ) {
1295             sk->skey[0] = mpi_set_opaque( NULL,
1296                                           read_rest(inp, pktlen), pktlen );
1297             pktlen = 0;
1298             goto leave;
1299         }
1300
1301         for(i=0; i < npkey; i++ ) {
1302             n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1303             if( list_mode ) {
1304                 printf(  "\tskey[%d]: ", i);
1305                 mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1306                 putchar('\n');
1307             }
1308         }
1309         sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1310         if( sk->protect.algo ) {
1311             sk->is_protected = 1;
1312             sk->protect.s2k.count = 0;
1313             if( sk->protect.algo == 255 ) {
1314                 if( pktlen < 3 ) {
1315                     rc = G10ERR_INVALID_PACKET;
1316                     goto leave;
1317                 }
1318                 sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1319                 sk->protect.s2k.mode  = iobuf_get_noeof(inp); pktlen--;
1320                 sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
1321                 switch( sk->protect.s2k.mode ) {
1322                   case 1:
1323                   case 3:
1324                     for(i=0; i < 8 && pktlen; i++, pktlen-- )
1325                         temp[i] = iobuf_get_noeof(inp);
1326                     memcpy(sk->protect.s2k.salt, temp, 8 );
1327                     break;
1328                 }
1329                 switch( sk->protect.s2k.mode ) {
1330                   case 0: if( list_mode ) printf(  "\tsimple S2K" );
1331                     break;
1332                   case 1: if( list_mode ) printf(  "\tsalted S2K" );
1333                     break;
1334                   case 3: if( list_mode ) printf(  "\titer+salt S2K" );
1335                     break;
1336                   default:
1337                     if( list_mode )
1338                         printf(  "\tunknown S2K %d\n",
1339                                             sk->protect.s2k.mode );
1340                     rc = G10ERR_INVALID_PACKET;
1341                     goto leave;
1342                 }
1343
1344                 if( list_mode ) {
1345                     printf(", algo: %d, hash: %d",
1346                                      sk->protect.algo,
1347                                      sk->protect.s2k.hash_algo );
1348                     if( sk->protect.s2k.mode == 1
1349                         || sk->protect.s2k.mode == 3 ) {
1350                         printf(", salt: ");
1351                         for(i=0; i < 8; i++ )
1352                             printf("%02x", sk->protect.s2k.salt[i]);
1353                     }
1354                     putchar('\n');
1355                 }
1356
1357                 if( sk->protect.s2k.mode == 3 ) {
1358                     if( pktlen < 1 ) {
1359                         rc = G10ERR_INVALID_PACKET;
1360                         goto leave;
1361                     }
1362                     sk->protect.s2k.count = iobuf_get(inp);
1363                     pktlen--;
1364                     if( list_mode )
1365                         printf("\tprotect count: %lu\n",
1366                                             (ulong)sk->protect.s2k.count);
1367                 }
1368             }
1369             else { /* old version; no S2K, so we set mode to 0, hash MD5 */
1370                 sk->protect.s2k.mode = 0;
1371                 sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5;
1372                 if( list_mode )
1373                     printf(  "\tprotect algo: %d  (hash algo: %d)\n",
1374                          sk->protect.algo, sk->protect.s2k.hash_algo );
1375             }
1376             /* It is really ugly that we don't know the size
1377              * of the IV here in cases we are not aware of the algorithm.
1378              * so a
1379              *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);
1380              * won't work.  The only solution I see is to hardwire it here.
1381              * NOTE: if you change the ivlen above 16, don't forget to
1382              * enlarge temp.
1383              */
1384             switch( sk->protect.algo ) {
1385               case 7: case 8: case 9: /* reserved for AES */
1386               case 10: /* Twofish */
1387                 sk->protect.ivlen = 16;
1388                 break;
1389               default:
1390                 sk->protect.ivlen = 8;
1391             }
1392             if( pktlen < sk->protect.ivlen ) {
1393                 rc = G10ERR_INVALID_PACKET;
1394                 goto leave;
1395             }
1396             for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
1397                 temp[i] = iobuf_get_noeof(inp);
1398             if( list_mode ) {
1399                 printf(  "\tprotect IV: ");
1400                 for(i=0; i < sk->protect.ivlen; i++ )
1401                     printf(" %02x", temp[i] );
1402                 putchar('\n');
1403             }
1404             memcpy(sk->protect.iv, temp, sk->protect.ivlen );
1405         }
1406         else
1407             sk->is_protected = 0;
1408         /* It does not make sense to read it into secure memory.
1409          * If the user is so careless, not to protect his secret key,
1410          * we can assume, that he operates an open system :=(.
1411          * So we put the key into secure memory when we unprotect it. */
1412         if( is_v4 && sk->is_protected ) {
1413             /* ugly; the length is encrypted too, so we read all
1414              * stuff up to the end of the packet into the first
1415              * skey element */
1416             sk->skey[npkey] = mpi_set_opaque(NULL,
1417                                              read_rest(inp, pktlen), pktlen );
1418             pktlen = 0;
1419             if( list_mode ) {
1420                 printf("\tencrypted stuff follows\n");
1421             }
1422         }
1423         else { /* v3 method: the mpi length is not encrypted */
1424             for(i=npkey; i < nskey; i++ ) {
1425                 n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1426                 if( sk->is_protected )
1427                     mpi_set_protect_flag(sk->skey[i]);
1428                 if( list_mode ) {
1429                     printf(  "\tskey[%d]: ", i);
1430                     if( sk->is_protected )
1431                         printf(  "[encrypted]\n");
1432                     else {
1433                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1434                         putchar('\n');
1435                     }
1436                 }
1437             }
1438
1439             sk->csum = read_16(inp); pktlen -= 2;
1440             if( list_mode ) {
1441                 printf("\tchecksum: %04hx\n", sk->csum);
1442             }
1443         }
1444     }
1445     else {
1446         PKT_public_key *pk = pkt->pkt.public_key;
1447
1448         if( !npkey ) {
1449             pk->pkey[0] = mpi_set_opaque( NULL,
1450                                           read_rest(inp, pktlen), pktlen );
1451             pktlen = 0;
1452             goto leave;
1453         }
1454
1455         for(i=0; i < npkey; i++ ) {
1456             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1457             if( list_mode ) {
1458                 printf(  "\tpkey[%d]: ", i);
1459                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
1460                 putchar('\n');
1461             }
1462         }
1463     }
1464
1465   leave:
1466     skip_rest(inp, pktlen);
1467     return rc;
1468 }
1469
1470
1471 static int
1472 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1473 {
1474     byte *p;
1475
1476     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen);
1477     packet->pkt.user_id->len = pktlen;
1478     p = packet->pkt.user_id->name;
1479     for( ; pktlen; pktlen--, p++ )
1480         *p = iobuf_get_noeof(inp);
1481     *p = 0;
1482
1483     if( list_mode ) {
1484         int n = packet->pkt.user_id->len;
1485         printf(":user ID packet: \"");
1486         /* fixme: Hey why don't we replace this wioth print_string?? */
1487         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
1488             if( *p >= ' ' && *p <= 'z' )
1489                 putchar(*p);
1490             else
1491                 printf("\\x%02x", *p );
1492         }
1493         printf("\"\n");
1494     }
1495     return 0;
1496 }
1497
1498
1499
1500 static int
1501 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1502 {
1503     byte *p;
1504
1505     packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
1506     packet->pkt.comment->len = pktlen;
1507     p = packet->pkt.comment->data;
1508     for( ; pktlen; pktlen--, p++ )
1509         *p = iobuf_get_noeof(inp);
1510
1511     if( list_mode ) {
1512         int n = packet->pkt.comment->len;
1513         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
1514                                          "OpenPGP draft " : "" );
1515         for(p=packet->pkt.comment->data; n; p++, n-- ) {
1516             if( *p >= ' ' && *p <= 'z' )
1517                 putchar(*p);
1518             else
1519                 printf("\\x%02x", *p );
1520         }
1521         printf("\"\n");
1522     }
1523     return 0;
1524 }
1525
1526
1527 static void
1528 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
1529 {
1530     int c;
1531
1532     c = iobuf_get_noeof(inp);
1533     pkt->pkt.ring_trust = m_alloc( sizeof *pkt->pkt.ring_trust );
1534     pkt->pkt.ring_trust->trustval = c;
1535     if( list_mode )
1536         printf(":trust packet: flag=%02x\n", c );
1537 }
1538
1539
1540 static int
1541 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
1542                                         PACKET *pkt, int new_ctb )
1543 {
1544     int mode, namelen;
1545     PKT_plaintext *pt;
1546     byte *p;
1547     int c, i;
1548
1549     if( pktlen && pktlen < 6 ) {
1550         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
1551         goto leave;
1552     }
1553     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1554     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1555     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
1556     pt->new_ctb = new_ctb;
1557     pt->mode = mode;
1558     pt->namelen = namelen;
1559     if( pktlen ) {
1560         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
1561             pt->name[i] = iobuf_get_noeof(inp);
1562     }
1563     else {
1564         for( i=0; i < namelen; i++ )
1565             if( (c=iobuf_get(inp)) == -1 )
1566                 break;
1567             else
1568                 pt->name[i] = c;
1569     }
1570     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
1571     pt->len = pktlen;
1572     pt->buf = inp;
1573     pktlen = 0;
1574
1575     if( list_mode ) {
1576         printf(":literal data packet:\n"
1577                "\tmode %c, created %lu, name=\"",
1578                     mode >= ' ' && mode <'z'? mode : '?',
1579                     (ulong)pt->timestamp );
1580         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
1581             if( *p >= ' ' && *p <= 'z' )
1582                 putchar(*p);
1583             else
1584                 printf("\\x%02x", *p );
1585         }
1586         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
1587     }
1588
1589   leave:
1590     return 0;
1591 }
1592
1593
1594 static int
1595 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
1596                   PACKET *pkt, int new_ctb )
1597 {
1598     PKT_compressed *zd;
1599
1600     /* pktlen is here 0, but data follows
1601      * (this should be the last object in a file or
1602      *  the compress algorithm should know the length)
1603      */
1604     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
1605     zd->len = 0; /* not yet used */
1606     zd->algorithm = iobuf_get_noeof(inp);
1607     zd->new_ctb = new_ctb;
1608     zd->buf = inp;
1609     if( list_mode )
1610         printf(":compressed packet: algo=%d\n", zd->algorithm);
1611     return 0;
1612 }
1613
1614
1615 static int
1616 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
1617                                        PACKET *pkt, int new_ctb )
1618 {
1619     PKT_encrypted *ed;
1620
1621     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
1622     ed->len = pktlen;
1623     ed->buf = NULL;
1624     ed->new_ctb = new_ctb;
1625     ed->mdc_method = 0;
1626     if( pkttype == PKT_ENCRYPTED_MDC ) {
1627         /* test: this is the new encrypted_mdc packet */
1628         /* fixme: add some pktlen sanity checks */
1629         int version, method;
1630
1631         version = iobuf_get_noeof(inp); pktlen--;
1632         if( version != 1 ) {
1633             log_error("encrypted_mdc packet with unknown version %d\n",
1634                                                                 version);
1635             goto leave;
1636         }
1637         method = iobuf_get_noeof(inp); pktlen--;
1638         if( method != DIGEST_ALGO_SHA1 ) {
1639             log_error("encrypted_mdc does not use SHA1 method\n" );
1640             goto leave;
1641         }
1642         ed->mdc_method = method;
1643     }
1644     if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
1645         log_error("packet(%d) too short\n", pkttype);
1646         skip_rest(inp, pktlen);
1647         goto leave;
1648     }
1649     if( list_mode ) {
1650         if( pktlen )
1651             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen);
1652         else
1653             printf(":encrypted data packet:\n\tlength: unknown\n");
1654         if( ed->mdc_method )
1655             printf("\tmdc_method: %d\n", ed->mdc_method );
1656     }
1657
1658     ed->buf = inp;
1659     pktlen = 0;
1660
1661   leave:
1662     return 0;
1663 }
1664