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