See ChangeLog: Mon Jan 24 22:24:38 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 "dummy-cipher.h"
31 #include <gcrypt.h>
32 #include "filter.h"
33 #include "options.h"
34 #include "main.h"
35 #include "i18n.h"
36
37 static int mpi_print_mode = 0;
38 static int list_mode = 0;
39
40 static int  parse( IOBUF inp, PACKET *pkt, int reqtype,
41                    ulong *retpos, int *skip, IOBUF out, int do_skip
42             #ifdef DEBUG_PARSE_PACKET
43                    ,const char *dbg_w, const char *dbg_f, int dbg_l
44             #endif
45                  );
46 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
47                                                unsigned long pktlen );
48 static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
49 static void skip_rest( IOBUF inp, unsigned long pktlen );
50 static void *read_rest( IOBUF inp, size_t pktlen );
51 static int  parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
52                                                              PACKET *packet );
53 static int  parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
54                                                              PACKET *packet );
55 static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
56                                                          PKT_signature *sig );
57 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
58                                                         PKT_onepass_sig *ops );
59 static int  parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
60                                       byte *hdr, int hdrlen, PACKET *packet );
61 static int  parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
62                                                            PACKET *packet );
63 static int  parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
64                                                            PACKET *packet );
65 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen,
66                                                            PACKET *packet );
67 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
68                                                PACKET *packet, int new_ctb);
69 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
70                                                PACKET *packet, int new_ctb );
71 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
72                                                PACKET *packet, int new_ctb);
73
74 static unsigned short
75 read_16(IOBUF inp)
76 {
77     unsigned short a;
78     a = iobuf_get_noeof(inp) << 8;
79     a |= iobuf_get_noeof(inp);
80     return a;
81 }
82
83 static unsigned long
84 read_32(IOBUF inp)
85 {
86     unsigned long a;
87     a =  iobuf_get_noeof(inp) << 24;
88     a |= iobuf_get_noeof(inp) << 16;
89     a |= iobuf_get_noeof(inp) << 8;
90     a |= iobuf_get_noeof(inp);
91     return a;
92 }
93
94
95 int
96 set_packet_list_mode( int mode )
97 {
98     int old = list_mode;
99     list_mode = mode;
100     mpi_print_mode = (opt.debug & DBG_MPI_VALUE);
101     return old;
102 }
103
104 static void
105 unknown_pubkey_warning( int algo )
106 {
107     static byte unknown_pubkey_algos[256];
108
109     algo &= 0xff;
110     if( !unknown_pubkey_algos[algo] ) {
111         if( opt.verbose )
112             log_info(_("can't handle public key algorithm %d\n"), algo );
113         unknown_pubkey_algos[algo] = 1;
114     }
115 }
116
117 /****************
118  * Parse a Packet and return it in packet
119  * Returns: 0 := valid packet in pkt
120  *         -1 := no more packets
121  *         >0 := error
122  * Note: The function may return an error and a partly valid packet;
123  * caller must free this packet.
124  */
125 #ifdef DEBUG_PARSE_PACKET
126 int
127 dbg_parse_packet( IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l )
128 {
129     int skip, rc;
130
131     do {
132         rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l );
133     } while( skip );
134     return rc;
135 }
136 #else
137 int
138 parse_packet( IOBUF inp, PACKET *pkt )
139 {
140     int skip, rc;
141
142     do {
143         rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );
144     } while( skip );
145     return rc;
146 }
147 #endif
148
149 /****************
150  * Like parse packet, but only return packets of the given type.
151  */
152 #ifdef DEBUG_PARSE_PACKET
153 int
154 dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos,
155                    const char *dbg_f, int dbg_l )
156 {
157     int skip, rc;
158
159     do {
160         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
161     } while( skip );
162     return rc;
163 }
164 #else
165 int
166 search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
167 {
168     int skip, rc;
169
170     do {
171         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
172     } while( skip );
173     return rc;
174 }
175 #endif
176
177 /****************
178  * Copy all packets from INP to OUT, thereby removing unused spaces.
179  */
180 #ifdef DEBUG_PARSE_PACKET
181 int
182 dbg_copy_all_packets( IOBUF inp, IOBUF out,
183                    const char *dbg_f, int dbg_l )
184 {
185     PACKET pkt;
186     int skip, rc=0;
187     do {
188         init_packet(&pkt);
189     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l )));
190     return rc;
191 }
192 #else
193 int
194 copy_all_packets( IOBUF inp, IOBUF out )
195 {
196     PACKET pkt;
197     int skip, rc=0;
198     do {
199         init_packet(&pkt);
200     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));
201     return rc;
202 }
203 #endif
204
205 /****************
206  * Copy some packets from INP to OUT, thereby removing unused spaces.
207  * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets)
208  */
209 #ifdef DEBUG_PARSE_PACKET
210 int
211 dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff,
212                    const char *dbg_f, int dbg_l )
213 {
214     PACKET pkt;
215     int skip, rc=0;
216     do {
217         if( iobuf_tell(inp) >= stopoff )
218             return 0;
219         init_packet(&pkt);
220     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0,
221                                      "some", dbg_f, dbg_l )) );
222     return rc;
223 }
224 #else
225 int
226 copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff )
227 {
228     PACKET pkt;
229     int skip, rc=0;
230     do {
231         if( iobuf_tell(inp) >= stopoff )
232             return 0;
233         init_packet(&pkt);
234     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );
235     return rc;
236 }
237 #endif
238
239 /****************
240  * Skip over N packets
241  */
242 #ifdef DEBUG_PARSE_PACKET
243 int
244 dbg_skip_some_packets( IOBUF inp, unsigned n,
245                    const char *dbg_f, int dbg_l )
246 {
247     int skip, rc=0;
248     PACKET pkt;
249
250     for( ;n && !rc; n--) {
251         init_packet(&pkt);
252         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l );
253     }
254     return rc;
255 }
256 #else
257 int
258 skip_some_packets( IOBUF inp, unsigned n )
259 {
260     int skip, rc=0;
261     PACKET pkt;
262
263     for( ;n && !rc; n--) {
264         init_packet(&pkt);
265         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );
266     }
267     return rc;
268 }
269 #endif
270
271
272 /****************
273  * Parse packet. Set the variable skip points to to 1 if the packet
274  * should be skipped; this is the case if either there is a
275  * requested packet type and the parsed packet doesn't match or the
276  * packet-type is 0, indicating deleted stuff.
277  * if OUT is not NULL, a special copymode is used.
278  */
279 static int
280 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
281        int *skip, IOBUF out, int do_skip
282 #ifdef DEBUG_PARSE_PACKET
283        ,const char *dbg_w, const char *dbg_f, int dbg_l
284 #endif
285      )
286 {
287     int rc=0, c, ctb, pkttype, lenbytes;
288     unsigned long pktlen;
289     byte hdr[8];
290     int hdrlen;
291     int new_ctb = 0;
292
293     *skip = 0;
294     assert( !pkt->pkt.generic );
295     if( retpos )
296         *retpos = iobuf_tell(inp);
297
298     if( (ctb = iobuf_get(inp)) == -1 ) {
299         rc = -1;
300         goto leave;
301     }
302     hdrlen=0;
303     hdr[hdrlen++] = ctb;
304     if( !(ctb & 0x80) ) {
305         log_error("%s: invalid packet (ctb=%02x) near %lu\n",
306                             iobuf_where(inp), ctb, iobuf_tell(inp) );
307         rc = G10ERR_INVALID_PACKET;
308         goto leave;
309     }
310     pktlen = 0;
311     new_ctb = !!(ctb & 0x40);
312     if( new_ctb ) {
313         pkttype =  ctb & 0x3f;
314         if( (c = iobuf_get(inp)) == -1 ) {
315             log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
316             rc = G10ERR_INVALID_PACKET;
317             goto leave;
318         }
319         hdr[hdrlen++] = c;
320         if( c < 192 )
321             pktlen = c;
322         else if( c < 224 ) {
323             pktlen = (c - 192) * 256;
324             if( (c = iobuf_get(inp)) == -1 ) {
325                 log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
326                 rc = G10ERR_INVALID_PACKET;
327                 goto leave;
328             }
329             hdr[hdrlen++] = c;
330             pktlen += c + 192;
331         }
332         else if( c == 255 ) {
333             pktlen  = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24;
334             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16;
335             pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
336             if( (c = iobuf_get(inp)) == -1 ) {
337                 log_error("%s: 4 byte length invalid\n", iobuf_where(inp) );
338                 rc = G10ERR_INVALID_PACKET;
339                 goto leave;
340             }
341             pktlen |= (hdr[hdrlen++] = c );
342         }
343         else { /* partial body length */
344             iobuf_set_partial_block_mode(inp, c & 0xff);
345             pktlen = 0;/* to indicate partial length */
346         }
347     }
348     else {
349         pkttype = (ctb>>2)&0xf;
350         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
351         if( !lenbytes ) {
352             pktlen = 0; /* don't know the value */
353             if( pkttype != PKT_COMPRESSED )
354                 iobuf_set_block_mode(inp, 1);
355         }
356         else {
357             for( ; lenbytes; lenbytes-- ) {
358                 pktlen <<= 8;
359                 pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
360             }
361         }
362     }
363
364     if( out && pkttype  ) {
365         if( iobuf_write( out, hdr, hdrlen ) == -1 )
366             rc = G10ERR_WRITE_FILE;
367         else
368             rc = copy_packet(inp, out, pkttype, pktlen );
369         goto leave;
370     }
371
372     if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
373         skip_rest(inp, pktlen);
374         *skip = 1;
375         rc = 0;
376         goto leave;
377     }
378
379     if( DBG_PACKET ) {
380       #ifdef DEBUG_PARSE_PACKET
381         log_debug("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n",
382                    iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"",
383                     dbg_w, dbg_f, dbg_l );
384       #else
385         log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n",
386                    iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"" );
387       #endif
388     }
389     pkt->pkttype = pkttype;
390     rc = G10ERR_UNKNOWN_PACKET; /* default error */
391     switch( pkttype ) {
392       case PKT_PUBLIC_KEY:
393       case PKT_PUBLIC_SUBKEY:
394         pkt->pkt.public_key = gcry_xcalloc( 1,sizeof *pkt->pkt.public_key );
395         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
396         break;
397       case PKT_SECRET_KEY:
398       case PKT_SECRET_SUBKEY:
399         pkt->pkt.secret_key = gcry_xcalloc( 1,sizeof *pkt->pkt.secret_key );
400         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
401         break;
402       case PKT_SYMKEY_ENC:
403         rc = parse_symkeyenc( inp, pkttype, pktlen, pkt );
404         break;
405       case PKT_PUBKEY_ENC:
406         rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );
407         break;
408       case PKT_SIGNATURE:
409         pkt->pkt.signature = gcry_xcalloc( 1,sizeof *pkt->pkt.signature );
410         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
411         break;
412       case PKT_ONEPASS_SIG:
413         pkt->pkt.onepass_sig = gcry_xcalloc( 1,sizeof *pkt->pkt.onepass_sig );
414         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
415         break;
416       case PKT_USER_ID:
417         rc = parse_user_id(inp, pkttype, pktlen, pkt );
418         break;
419       case PKT_OLD_COMMENT:
420       case PKT_COMMENT:
421         rc = parse_comment(inp, pkttype, pktlen, pkt);
422         break;
423       case PKT_RING_TRUST:
424         parse_trust(inp, pkttype, pktlen, pkt);
425         rc = 0;
426         break;
427       case PKT_PLAINTEXT:
428         rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );
429         break;
430       case PKT_COMPRESSED:
431         rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );
432         break;
433       case PKT_ENCRYPTED:
434       case PKT_ENCRYPTED_MDC:
435         rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );
436         break;
437       default:
438         skip_packet(inp, pkttype, pktlen);
439         break;
440     }
441
442   leave:
443     if( !rc && iobuf_error(inp) )
444         rc = G10ERR_INV_KEYRING;
445     return rc;
446 }
447
448 static void
449 dump_hex_line( int c, int *i )
450 {
451     if( *i && !(*i%8) ) {
452         if( *i && !(*i%24) )
453             printf("\n%4d:", *i );
454         else
455             putchar(' ');
456     }
457     if( c == -1 )
458         printf(" EOF" );
459     else
460         printf(" %02x", c );
461     ++*i;
462 }
463
464
465 static int
466 copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
467 {
468     int n;
469     char buf[100];
470
471     if( iobuf_in_block_mode(inp) ) {
472         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
473             if( iobuf_write(out, buf, n ) )
474                 return G10ERR_WRITE_FILE; /* write error */
475     }
476     else if( !pktlen && pkttype == PKT_COMPRESSED ) {
477         log_debug("copy_packet: compressed!\n");
478         /* compressed packet, copy till EOF */
479         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
480             if( iobuf_write(out, buf, n ) )
481                 return G10ERR_WRITE_FILE; /* write error */
482     }
483     else {
484         for( ; pktlen; pktlen -= n ) {
485             n = pktlen > 100 ? 100 : pktlen;
486             n = iobuf_read( inp, buf, n );
487             if( n == -1 )
488                 return G10ERR_READ_FILE;
489             if( iobuf_write(out, buf, n ) )
490                 return G10ERR_WRITE_FILE; /* write error */
491         }
492     }
493     return 0;
494 }
495
496
497 static void
498 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
499 {
500     if( list_mode ) {
501         if( pkttype == PKT_MARKER )
502             fputs(":marker packet:\n", stdout );
503         else
504             printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
505         if( pkttype ) {
506             int c, i=0 ;
507             if( pkttype != PKT_MARKER )
508                 fputs("dump:", stdout );
509             if( iobuf_in_block_mode(inp) ) {
510                 while( (c=iobuf_get(inp)) != -1 )
511                     dump_hex_line(c, &i);
512             }
513             else {
514                 for( ; pktlen; pktlen-- )
515                     dump_hex_line(iobuf_get(inp), &i);
516             }
517             putchar('\n');
518             return;
519         }
520     }
521     skip_rest(inp,pktlen);
522 }
523
524 static void
525 skip_rest( IOBUF inp, unsigned long pktlen )
526 {
527     if( iobuf_in_block_mode(inp) ) {
528         while( iobuf_get(inp) != -1 )
529                 ;
530     }
531     else {
532         for( ; pktlen; pktlen-- )
533             if( iobuf_get(inp) == -1 )
534                 break;
535     }
536 }
537
538
539 static void *
540 read_rest( IOBUF inp, size_t pktlen )
541 {
542     byte *p;
543     int i;
544
545     if( iobuf_in_block_mode(inp) ) {
546         log_error("read_rest: can't store stream data\n");
547         p = NULL;
548     }
549     else {
550         p = gcry_xmalloc( pktlen );
551         for(i=0; pktlen; pktlen--, i++ )
552             p[i] = iobuf_get(inp);
553     }
554     return p;
555 }
556
557
558
559 static int
560 parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
561 {
562     PKT_symkey_enc *k;
563     int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
564
565     if( pktlen < 4 ) {
566         log_error("packet(%d) too short\n", pkttype);
567         goto leave;
568     }
569     version = iobuf_get_noeof(inp); pktlen--;
570     if( version != 4 ) {
571         log_error("packet(%d) with unknown version %d\n", pkttype, version);
572         goto leave;
573     }
574     if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
575         log_error("packet(%d) too large\n", pkttype);
576         goto leave;
577     }
578     cipher_algo = iobuf_get_noeof(inp); pktlen--;
579     s2kmode = iobuf_get_noeof(inp); pktlen--;
580     hash_algo = iobuf_get_noeof(inp); pktlen--;
581     switch( s2kmode ) {
582       case 0:  /* simple s2k */
583         minlen = 0;
584         break;
585       case 1:  /* salted s2k */
586         minlen = 8;
587         break;
588       case 3:  /* iterated+salted s2k */
589         minlen = 9;
590         break;
591       default:
592         log_error("unknown S2K %d\n", s2kmode );
593         goto leave;
594     }
595     if( minlen > pktlen ) {
596         log_error("packet with S2K %d too short\n", s2kmode );
597         goto leave;
598     }
599     seskeylen = pktlen - minlen;
600     k = packet->pkt.symkey_enc = gcry_xcalloc( 1, sizeof *packet->pkt.symkey_enc
601                                                 + seskeylen - 1 );
602     k->version = version;
603     k->cipher_algo = cipher_algo;
604     k->s2k.mode = s2kmode;
605     k->s2k.hash_algo = hash_algo;
606     if( s2kmode == 1 || s2kmode == 3 ) {
607         for(i=0; i < 8 && pktlen; i++, pktlen-- )
608             k->s2k.salt[i] = iobuf_get_noeof(inp);
609     }
610     if( s2kmode == 3 ) {
611         k->s2k.count = iobuf_get(inp); pktlen--;
612     }
613     k->seskeylen = seskeylen;
614     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
615         k->seskey[i] = iobuf_get_noeof(inp);
616     assert( !pktlen );
617
618     if( list_mode ) {
619         printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
620                             version, cipher_algo, s2kmode, hash_algo);
621         if( s2kmode == 1 || s2kmode == 3 ) {
622             printf("\tsalt ");
623             for(i=0; i < 8; i++ )
624                 printf("%02x", k->s2k.salt[i]);
625             if( s2kmode == 3 )
626                 printf(", count %lu\n", (ulong)k->s2k.count );
627             printf("\n");
628         }
629     }
630
631   leave:
632     skip_rest(inp, pktlen);
633     return 0;
634 }
635
636 static int
637 parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
638 {
639     unsigned n;
640     int i, ndata;
641     PKT_pubkey_enc *k;
642
643     k = packet->pkt.pubkey_enc = gcry_xcalloc( 1,sizeof *packet->pkt.pubkey_enc);
644     if( pktlen < 12 ) {
645         log_error("packet(%d) too short\n", pkttype);
646         goto leave;
647     }
648     k->version = iobuf_get_noeof(inp); pktlen--;
649     if( k->version != 2 && k->version != 3 ) {
650         log_error("packet(%d) with unknown version %d\n", pkttype, k->version);
651         goto leave;
652     }
653     k->keyid[0] = read_32(inp); pktlen -= 4;
654     k->keyid[1] = read_32(inp); pktlen -= 4;
655     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
656     k->throw_keyid = 0; /* only used as flag for build_packet */
657     if( list_mode )
658         printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
659           k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
660
661     ndata = pubkey_get_nenc(k->pubkey_algo);
662     if( !ndata ) {
663         if( list_mode )
664             printf("\tunsupported algorithm %d\n", k->pubkey_algo );
665         unknown_pubkey_warning( k->pubkey_algo );
666         k->data[0] = NULL;  /* no need to store the encrypted data */
667     }
668     else {
669         for( i=0; i < ndata; i++ ) {
670             n = pktlen;
671             k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;
672             if( list_mode ) {
673                 printf("\tdata: ");
674                 mpi_print(stdout, k->data[i], mpi_print_mode );
675                 putchar('\n');
676             }
677         }
678     }
679
680   leave:
681     skip_rest(inp, pktlen);
682     return 0;
683 }
684
685
686 static void
687 dump_sig_subpkt( int hashed, int type, int critical,
688                  const byte *buffer, size_t buflen, size_t length )
689 {
690     const char *p=NULL;
691     int i;
692
693     printf("\t%s%ssubpkt %d len %u (", /*)*/
694               critical ? "critical ":"",
695               hashed ? "hashed ":"", type, (unsigned)length );
696     buffer++;
697     length--;
698     if( length > buflen ) {
699         printf("too short: buffer is only %u)\n", (unsigned)buflen );
700         return;
701     }
702     switch( type ) {
703       case SIGSUBPKT_SIG_CREATED:
704         if( length >= 4 )
705             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
706         break;
707       case SIGSUBPKT_SIG_EXPIRE:
708         if( length >= 4 )
709             printf("sig expires after %s",
710                                      strtimevalue( buffer_to_u32(buffer) ) );
711         break;
712       case SIGSUBPKT_EXPORTABLE:
713         if( length )
714             printf("%sexportable", *buffer? "":"not ");
715         break;
716       case SIGSUBPKT_TRUST:
717         p = "trust signature";
718         break;
719       case SIGSUBPKT_REGEXP:
720         p = "regular expression";
721         break;
722       case SIGSUBPKT_REVOCABLE:
723         p = "revocable";
724         break;
725       case SIGSUBPKT_KEY_EXPIRE:
726         if( length >= 4 )
727             printf("key expires after %s",
728                                     strtimevalue( buffer_to_u32(buffer) ) );
729         break;
730       case SIGSUBPKT_ARR:
731         p = "additional recipient request";
732         break;
733       case SIGSUBPKT_PREF_SYM:
734         fputs("pref-sym-algos:", stdout );
735         for( i=0; i < length; i++ )
736             printf(" %d", buffer[i] );
737         break;
738       case SIGSUBPKT_REV_KEY:
739         fputs("revocation key: ", stdout );
740         if( length < 22 )
741             p = "[too short]";
742         else {
743             printf("c=%02x a=%d f=", buffer[0], buffer[1] );
744             for( i=2; i < length; i++ )
745                 printf("%02X", buffer[i] );
746         }
747         break;
748       case SIGSUBPKT_ISSUER:
749         if( length >= 8 )
750             printf("issuer key ID %08lX%08lX",
751                       (ulong)buffer_to_u32(buffer),
752                       (ulong)buffer_to_u32(buffer+4) );
753         break;
754       case SIGSUBPKT_NOTATION:
755         {
756             fputs("notation: ", stdout );
757             if( length < 8 )
758                 p = "[too short]";
759             else if( !(*buffer & 0x80) )
760                 p = "[not human readable]";
761             else {
762                 const byte *s = buffer;
763                 size_t n1, n2;
764
765                 n1 = (s[4] << 8) | s[5];
766                 n2 = (s[6] << 8) | s[7];
767                 s += 8;
768                 if( 8+n1+n2 != length )
769                     p = "[error]";
770                 else {
771                     print_string( stdout, s, n1, ')' );
772                     putc( '=', stdout );
773                     print_string( stdout, s+n1, n2, ')' );
774                 }
775             }
776         }
777         break;
778       case SIGSUBPKT_PREF_HASH:
779         fputs("pref-hash-algos:", stdout );
780         for( i=0; i < length; i++ )
781             printf(" %d", buffer[i] );
782         break;
783       case SIGSUBPKT_PREF_COMPR:
784         fputs("pref-zip-algos:", stdout );
785         for( i=0; i < length; i++ )
786             printf(" %d", buffer[i] );
787         break;
788       case SIGSUBPKT_KS_FLAGS:
789         p = "key server preferences";
790         break;
791       case SIGSUBPKT_PREF_KS:
792         p = "preferred key server";
793         break;
794       case SIGSUBPKT_PRIMARY_UID:
795         p = "primary user ID";
796         break;
797       case SIGSUBPKT_POLICY:
798         fputs("policy: ", stdout );
799         print_string( stdout, buffer, length, ')' );
800         break;
801       case SIGSUBPKT_KEY_FLAGS:
802         p = "key flags";
803         break;
804       case SIGSUBPKT_SIGNERS_UID:
805         p = "signer's user ID";
806         break;
807       case SIGSUBPKT_PRIV_ADD_SIG:
808         p = "signs additional user ID";
809         break;
810       default: p = "?"; break;
811     }
812
813     printf("%s)\n", p? p: "");
814 }
815
816 /****************
817  * Returns: >= 0 offset into buffer
818  *          -1 unknown type
819  *          -2 unsupported type
820  *          -3 subpacket too short
821  */
822 static int
823 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
824 {
825     switch( type ) {
826       case SIGSUBPKT_SIG_CREATED:
827       case SIGSUBPKT_SIG_EXPIRE:
828       case SIGSUBPKT_KEY_EXPIRE:
829         if( n < 4 )
830             break;
831         return 0;
832       case SIGSUBPKT_EXPORTABLE:
833         if( !n )
834             break;
835         return 0;
836       case SIGSUBPKT_ISSUER:/* issuer key ID */
837         if( n < 8 )
838             break;
839         return 0;
840       case SIGSUBPKT_NOTATION:
841         if( n < 8 ) /* minimum length needed */
842             break;
843         return 0;
844       case SIGSUBPKT_PREF_SYM:
845       case SIGSUBPKT_PREF_HASH:
846       case SIGSUBPKT_PREF_COMPR:
847       case SIGSUBPKT_POLICY:
848         return 0;
849       case SIGSUBPKT_PRIV_ADD_SIG:
850         /* because we use private data, we check the GNUPG marker */
851         if( n < 24 )
852             break;
853         if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
854             return -2;
855         return 3;
856       default: return -1;
857     }
858     return -3;
859 }
860
861
862 static int
863 can_handle_critical( const byte *buffer, size_t n, int type )
864 {
865     switch( type ) {
866       case SIGSUBPKT_NOTATION:
867         if( n >= 8 && (*buffer & 0x80) )
868             return 1; /* human readable is handled */
869         return 0;
870
871       case SIGSUBPKT_SIG_CREATED:
872       case SIGSUBPKT_SIG_EXPIRE:
873       case SIGSUBPKT_KEY_EXPIRE:
874       case SIGSUBPKT_EXPORTABLE:
875       case SIGSUBPKT_ISSUER:/* issuer key ID */
876       case SIGSUBPKT_PREF_SYM:
877       case SIGSUBPKT_PREF_HASH:
878       case SIGSUBPKT_PREF_COMPR:
879         return 1;
880
881       case SIGSUBPKT_POLICY: /* Is enough to show the policy? */
882       default:
883         return 0;
884     }
885 }
886
887
888 const byte *
889 enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
890                  size_t *ret_n, int *start )
891 {
892     int buflen;
893     int type;
894     int critical;
895     int offset;
896     size_t n;
897     int seq = 0;
898     int reqseq = start? *start: 0;
899
900     if( !buffer || reqseq == -1 )
901         return NULL;
902     buflen = (*buffer << 8) | buffer[1];
903     buffer += 2;
904     while( buflen ) {
905         n = *buffer++; buflen--;
906         if( n == 255 ) {
907             if( buflen < 4 )
908                 goto too_short;
909             n = (buffer[0] << 24) | (buffer[1] << 16)
910                                   | (buffer[2] << 8) | buffer[3];
911             buffer += 4;
912             buflen -= 4;
913
914         }
915         else if( n >= 192 ) {
916             if( buflen < 2 )
917                 goto too_short;
918             n = (( n - 192 ) << 8) + *buffer + 192;
919             buffer++;
920             buflen--;
921         }
922         if( buflen < n )
923             goto too_short;
924         type = *buffer;
925         if( type & 0x80 ) {
926             type &= 0x7f;
927             critical = 1;
928         }
929         else
930             critical = 0;
931         if( !(++seq > reqseq) )
932             ;
933         else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
934             if( critical ) {
935                 if( n-1 > buflen+1 )
936                     goto too_short;
937                 if( !can_handle_critical(buffer+1, n-1, type ) ) {
938                     log_info(_("subpacket of type %d has critical bit set\n"),
939                                                                         type);
940                     if( start )
941                         *start = seq;
942                     return NULL; /* this is an error */
943                 }
944             }
945         }
946         else if( reqtype < 0 ) /* list packets */
947             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
948                                     type, critical, buffer, buflen, n );
949         else if( type == reqtype ) { /* found */
950             buffer++;
951             n--;
952             if( n > buflen )
953                 goto too_short;
954             if( ret_n )
955                 *ret_n = n;
956             offset = parse_one_sig_subpkt(buffer, n, type );
957             switch( offset ) {
958               case -3:
959                 log_error("subpacket of type %d too short\n", type);
960                 return NULL;
961               case -2:
962                 return NULL;
963               case -1:
964                 BUG(); /* not yet needed */
965               default:
966                 break;
967             }
968             if( start )
969                 *start = seq;
970             return buffer+offset;
971         }
972         buffer += n; buflen -=n;
973     }
974     if( reqtype == SIGSUBPKT_TEST_CRITICAL )
975         return buffer; /* as value true to indicate that there is no */
976                        /* critical bit we don't understand */
977     if( start )
978         *start = -1;
979     return NULL; /* end of packets; not found */
980
981   too_short:
982     log_error("buffer shorter than subpacket\n");
983     if( start )
984         *start = -1;
985     return NULL;
986 }
987
988
989 const byte *
990 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
991 {
992     return enum_sig_subpkt( buffer, reqtype, ret_n, NULL );
993 }
994
995 const byte *
996 parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
997 {
998     const byte *p;
999
1000     p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
1001     if( !p )
1002         p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
1003     return p;
1004 }
1005
1006
1007
1008 static int
1009 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
1010                                           PKT_signature *sig )
1011 {
1012     int md5_len=0;
1013     unsigned n;
1014     int is_v4=0;
1015     int rc=0;
1016     int i, ndata;
1017
1018     if( pktlen < 16 ) {
1019         log_error("packet(%d) too short\n", pkttype);
1020         goto leave;
1021     }
1022     sig->version = iobuf_get_noeof(inp); pktlen--;
1023     if( sig->version == 4 )
1024         is_v4=1;
1025     else if( sig->version != 2 && sig->version != 3 ) {
1026         log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
1027         goto leave;
1028     }
1029
1030     if( !is_v4 ) {
1031         md5_len = iobuf_get_noeof(inp); pktlen--;
1032     }
1033     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
1034     if( !is_v4 ) {
1035         sig->timestamp = read_32(inp); pktlen -= 4;
1036         sig->keyid[0] = read_32(inp); pktlen -= 4;
1037         sig->keyid[1] = read_32(inp); pktlen -= 4;
1038     }
1039     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1040     sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
1041     if( is_v4 ) { /* read subpackets */
1042         n = read_16(inp); pktlen -= 2; /* length of hashed data */
1043         if( n > 10000 ) {
1044             log_error("signature packet: hashed data too long\n");
1045             rc = G10ERR_INVALID_PACKET;
1046             goto leave;
1047         }
1048         if( n ) {
1049             sig->hashed_data = gcry_xmalloc( n + 2 );
1050             sig->hashed_data[0] = n >> 8;
1051             sig->hashed_data[1] = n;
1052             if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
1053                 log_error("premature eof while reading hashed signature data\n");
1054                 rc = -1;
1055                 goto leave;
1056             }
1057             pktlen -= n;
1058         }
1059         n = read_16(inp); pktlen -= 2; /* length of unhashed data */
1060         if( n > 10000 ) {
1061             log_error("signature packet: unhashed data too long\n");
1062             rc = G10ERR_INVALID_PACKET;
1063             goto leave;
1064         }
1065         if( n ) {
1066             sig->unhashed_data = gcry_xmalloc( n + 2 );
1067             sig->unhashed_data[0] = n >> 8;
1068             sig->unhashed_data[1] = n;
1069             if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
1070                 log_error("premature eof while reading unhashed signature data\n");
1071                 rc = -1;
1072                 goto leave;
1073             }
1074             pktlen -= n;
1075         }
1076     }
1077
1078     if( pktlen < 5 ) { /* sanity check */
1079         log_error("packet(%d) too short\n", pkttype);
1080         rc = G10ERR_INVALID_PACKET;
1081         goto leave;
1082     }
1083
1084     sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
1085     sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
1086
1087     if( is_v4 && sig->pubkey_algo ) { /*extract required information */
1088         const byte *p;
1089
1090         /* set sig->flags.unknown_critical if there is a
1091          * critical bit set for packets which we do not understand */
1092         if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
1093            || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
1094                                                                         NULL) )
1095         {
1096             sig->flags.unknown_critical = 1;
1097         }
1098
1099         p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
1100         if( !p )
1101             log_error("signature packet without timestamp\n");
1102         else
1103             sig->timestamp = buffer_to_u32(p);
1104         p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
1105         if( !p )
1106             log_error("signature packet without keyid\n");
1107         else {
1108             sig->keyid[0] = buffer_to_u32(p);
1109             sig->keyid[1] = buffer_to_u32(p+4);
1110         }
1111     }
1112
1113     if( list_mode ) {
1114         printf(":signature packet: algo %d, keyid %08lX%08lX\n"
1115                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
1116                "\tdigest algo %d, begin of digest %02x %02x\n",
1117                 sig->pubkey_algo,
1118                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1119                 sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
1120                 sig->digest_algo,
1121                 sig->digest_start[0], sig->digest_start[1] );
1122         if( is_v4 ) {
1123             parse_sig_subpkt( sig->hashed_data,  SIGSUBPKT_LIST_HASHED, NULL );
1124             parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
1125         }
1126     }
1127
1128     ndata = pubkey_get_nsig(sig->pubkey_algo);
1129     if( !ndata ) {
1130         if( list_mode )
1131             printf("\tunknown algorithm %d\n", sig->pubkey_algo );
1132         unknown_pubkey_warning( sig->pubkey_algo );
1133         /* we store the plain material in data[0], so that we are able
1134          * to write it back with build_packet() */
1135         sig->data[0] = gcry_mpi_set_opaque(NULL,
1136                                            read_rest(inp, pktlen), pktlen*8 );
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] = gcry_mpi_set_opaque( NULL,
1296                                              read_rest(inp, pktlen), pktlen*8 );
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 = GCRY_MD_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 (which is the one indexed by npkey) */
1416             sk->skey[npkey] = gcry_mpi_set_opaque(NULL,
1417                                              read_rest(inp, pktlen), pktlen*8 );
1418             pktlen = 0;
1419             if( list_mode ) {
1420                 printf("\tencrypted stuff follows\n");
1421             }
1422         }
1423         else { /* unencrypted v4 or v3 method (where length is not encrypted) */
1424             for(i=npkey; i < nskey; i++ ) {
1425                 n = pktlen;
1426                 sk->skey[i] = sk->is_protected ? mpi_read_opaque(inp, &n )
1427                                                : mpi_read( inp, &n, 1 );
1428                 pktlen -=n;
1429                 if( list_mode ) {
1430                     printf(  "\tskey[%d]: ", i);
1431                     if( sk->is_protected )
1432                         printf(  "[encrypted]\n");
1433                     else {
1434                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1435                         putchar('\n');
1436                     }
1437                 }
1438             }
1439
1440             sk->csum = read_16(inp); pktlen -= 2;
1441             if( list_mode ) {
1442                 printf("\tchecksum: %04hx\n", sk->csum);
1443             }
1444         }
1445     }
1446     else {
1447         PKT_public_key *pk = pkt->pkt.public_key;
1448
1449         if( !npkey ) {
1450             pk->pkey[0] = gcry_mpi_set_opaque( NULL,
1451                                              read_rest(inp, pktlen), pktlen*8 );
1452             pktlen = 0;
1453             goto leave;
1454         }
1455
1456         for(i=0; i < npkey; i++ ) {
1457             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1458             if( list_mode ) {
1459                 printf(  "\tpkey[%d]: ", i);
1460                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
1461                 putchar('\n');
1462             }
1463         }
1464     }
1465
1466   leave:
1467     skip_rest(inp, pktlen);
1468     return rc;
1469 }
1470
1471
1472 static int
1473 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1474 {
1475     byte *p;
1476
1477     packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id  + pktlen);
1478     packet->pkt.user_id->len = pktlen;
1479     p = packet->pkt.user_id->name;
1480     for( ; pktlen; pktlen--, p++ )
1481         *p = iobuf_get_noeof(inp);
1482     *p = 0;
1483
1484     if( list_mode ) {
1485         int n = packet->pkt.user_id->len;
1486         printf(":user ID packet: \"");
1487         /* fixme: Hey why don't we replace this wioth print_string?? */
1488         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
1489             if( *p >= ' ' && *p <= 'z' )
1490                 putchar(*p);
1491             else
1492                 printf("\\x%02x", *p );
1493         }
1494         printf("\"\n");
1495     }
1496     return 0;
1497 }
1498
1499
1500
1501 static int
1502 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1503 {
1504     byte *p;
1505
1506     packet->pkt.comment = gcry_xmalloc(sizeof *packet->pkt.comment + pktlen - 1);
1507     packet->pkt.comment->len = pktlen;
1508     p = packet->pkt.comment->data;
1509     for( ; pktlen; pktlen--, p++ )
1510         *p = iobuf_get_noeof(inp);
1511
1512     if( list_mode ) {
1513         int n = packet->pkt.comment->len;
1514         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
1515                                          "OpenPGP draft " : "" );
1516         for(p=packet->pkt.comment->data; n; p++, n-- ) {
1517             if( *p >= ' ' && *p <= 'z' )
1518                 putchar(*p);
1519             else
1520                 printf("\\x%02x", *p );
1521         }
1522         printf("\"\n");
1523     }
1524     return 0;
1525 }
1526
1527
1528 static void
1529 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
1530 {
1531     int c;
1532
1533     c = iobuf_get_noeof(inp);
1534     pkt->pkt.ring_trust = gcry_xmalloc( sizeof *pkt->pkt.ring_trust );
1535     pkt->pkt.ring_trust->trustval = c;
1536     if( list_mode )
1537         printf(":trust packet: flag=%02x\n", c );
1538 }
1539
1540
1541 static int
1542 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
1543                                         PACKET *pkt, int new_ctb )
1544 {
1545     int mode, namelen;
1546     PKT_plaintext *pt;
1547     byte *p;
1548     int c, i;
1549
1550     if( pktlen && pktlen < 6 ) {
1551         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
1552         goto leave;
1553     }
1554     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1555     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1556     pt = pkt->pkt.plaintext = gcry_xmalloc(sizeof *pkt->pkt.plaintext + namelen -1);
1557     pt->new_ctb = new_ctb;
1558     pt->mode = mode;
1559     pt->namelen = namelen;
1560     if( pktlen ) {
1561         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
1562             pt->name[i] = iobuf_get_noeof(inp);
1563     }
1564     else {
1565         for( i=0; i < namelen; i++ )
1566             if( (c=iobuf_get(inp)) == -1 )
1567                 break;
1568             else
1569                 pt->name[i] = c;
1570     }
1571     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
1572     pt->len = pktlen;
1573     pt->buf = inp;
1574     pktlen = 0;
1575
1576     if( list_mode ) {
1577         printf(":literal data packet:\n"
1578                "\tmode %c, created %lu, name=\"",
1579                     mode >= ' ' && mode <'z'? mode : '?',
1580                     (ulong)pt->timestamp );
1581         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
1582             if( *p >= ' ' && *p <= 'z' )
1583                 putchar(*p);
1584             else
1585                 printf("\\x%02x", *p );
1586         }
1587         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
1588     }
1589
1590   leave:
1591     return 0;
1592 }
1593
1594
1595 static int
1596 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
1597                   PACKET *pkt, int new_ctb )
1598 {
1599     PKT_compressed *zd;
1600
1601     /* pktlen is here 0, but data follows
1602      * (this should be the last object in a file or
1603      *  the compress algorithm should know the length)
1604      */
1605     zd = pkt->pkt.compressed =  gcry_xmalloc(sizeof *pkt->pkt.compressed );
1606     zd->len = 0; /* not yet used */
1607     zd->algorithm = iobuf_get_noeof(inp);
1608     zd->new_ctb = new_ctb;
1609     zd->buf = inp;
1610     if( list_mode )
1611         printf(":compressed packet: algo=%d\n", zd->algorithm);
1612     return 0;
1613 }
1614
1615
1616 static int
1617 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
1618                                        PACKET *pkt, int new_ctb )
1619 {
1620     PKT_encrypted *ed;
1621
1622     ed = pkt->pkt.encrypted =  gcry_xmalloc(sizeof *pkt->pkt.encrypted );
1623     ed->len = pktlen;
1624     ed->buf = NULL;
1625     ed->new_ctb = new_ctb;
1626     ed->mdc_method = 0;
1627     if( pkttype == PKT_ENCRYPTED_MDC ) {
1628         /* test: this is the new encrypted_mdc packet */
1629         /* fixme: add some pktlen sanity checks */
1630         int version, method;
1631
1632         version = iobuf_get_noeof(inp); pktlen--;
1633         if( version != 1 ) {
1634             log_error("encrypted_mdc packet with unknown version %d\n",
1635                                                                 version);
1636             goto leave;
1637         }
1638         method = iobuf_get_noeof(inp); pktlen--;
1639         if( method != GCRY_MD_SHA1 ) {
1640             log_error("encrypted_mdc does not use SHA1 method\n" );
1641             goto leave;
1642         }
1643         ed->mdc_method = method;
1644     }
1645     if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
1646         log_error("packet(%d) too short\n", pkttype);
1647         skip_rest(inp, pktlen);
1648         goto leave;
1649     }
1650     if( list_mode ) {
1651         if( pktlen )
1652             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen);
1653         else
1654             printf(":encrypted data packet:\n\tlength: unknown\n");
1655         if( ed->mdc_method )
1656             printf("\tmdc_method: %d\n", ed->mdc_method );
1657     }
1658
1659     ed->buf = inp;
1660     pktlen = 0;
1661
1662   leave:
1663     return 0;
1664 }
1665