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