See ChangeLog: Tue Jul 25 17:44:15 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     printf("\t%s%ssubpkt %d len %u (", /*)*/
704               critical ? "critical ":"",
705               hashed ? "hashed ":"", type, (unsigned)length );
706     buffer++;
707     length--;
708     if( length > buflen ) {
709         printf("too short: buffer is only %u)\n", (unsigned)buflen );
710         return;
711     }
712     switch( type ) {
713       case SIGSUBPKT_SIG_CREATED:
714         if( length >= 4 )
715             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
716         break;
717       case SIGSUBPKT_SIG_EXPIRE:
718         if( length >= 4 )
719             printf("sig expires after %s",
720                                      strtimevalue( buffer_to_u32(buffer) ) );
721         break;
722       case SIGSUBPKT_EXPORTABLE:
723         if( length )
724             printf("%sexportable", *buffer? "":"not ");
725         break;
726       case SIGSUBPKT_TRUST:
727         p = "trust signature";
728         break;
729       case SIGSUBPKT_REGEXP:
730         p = "regular expression";
731         break;
732       case SIGSUBPKT_REVOCABLE:
733         p = "revocable";
734         break;
735       case SIGSUBPKT_KEY_EXPIRE:
736         if( length >= 4 )
737             printf("key expires after %s",
738                                     strtimevalue( buffer_to_u32(buffer) ) );
739         break;
740       case SIGSUBPKT_ARR:
741         p = "additional recipient request";
742         break;
743       case SIGSUBPKT_PREF_SYM:
744         fputs("pref-sym-algos:", stdout );
745         for( i=0; i < length; i++ )
746             printf(" %d", buffer[i] );
747         break;
748       case SIGSUBPKT_REV_KEY:
749         fputs("revocation key: ", stdout );
750         if( length < 22 )
751             p = "[too short]";
752         else {
753             printf("c=%02x a=%d f=", buffer[0], buffer[1] );
754             for( i=2; i < length; i++ )
755                 printf("%02X", buffer[i] );
756         }
757         break;
758       case SIGSUBPKT_ISSUER:
759         if( length >= 8 )
760             printf("issuer key ID %08lX%08lX",
761                       (ulong)buffer_to_u32(buffer),
762                       (ulong)buffer_to_u32(buffer+4) );
763         break;
764       case SIGSUBPKT_NOTATION:
765         {
766             fputs("notation: ", stdout );
767             if( length < 8 )
768                 p = "[too short]";
769             else if( !(*buffer & 0x80) )
770                 p = "[not human readable]";
771             else {
772                 const byte *s = buffer;
773                 size_t n1, n2;
774
775                 n1 = (s[4] << 8) | s[5];
776                 n2 = (s[6] << 8) | s[7];
777                 s += 8;
778                 if( 8+n1+n2 != length )
779                     p = "[error]";
780                 else {
781                     print_string( stdout, s, n1, ')' );
782                     putc( '=', stdout );
783                     print_string( stdout, s+n1, n2, ')' );
784                 }
785             }
786         }
787         break;
788       case SIGSUBPKT_PREF_HASH:
789         fputs("pref-hash-algos:", stdout );
790         for( i=0; i < length; i++ )
791             printf(" %d", buffer[i] );
792         break;
793       case SIGSUBPKT_PREF_COMPR:
794         fputs("pref-zip-algos:", stdout );
795         for( i=0; i < length; i++ )
796             printf(" %d", buffer[i] );
797         break;
798       case SIGSUBPKT_KS_FLAGS:
799         p = "key server preferences";
800         break;
801       case SIGSUBPKT_PREF_KS:
802         p = "preferred key server";
803         break;
804       case SIGSUBPKT_PRIMARY_UID:
805         p = "primary user ID";
806         break;
807       case SIGSUBPKT_POLICY:
808         fputs("policy: ", stdout );
809         print_string( stdout, buffer, length, ')' );
810         break;
811       case SIGSUBPKT_KEY_FLAGS:
812         p = "key flags";
813         break;
814       case SIGSUBPKT_SIGNERS_UID:
815         p = "signer's user ID";
816         break;
817       case SIGSUBPKT_REVOC_REASON:
818         if( length ) {
819             printf("revocation reason 0x%02x (", *buffer );
820             print_string( stdout, buffer+1, length-1, ')' );
821             p = ")";
822         }
823         break;
824       case SIGSUBPKT_PRIV_ADD_SIG:
825         p = "signs additional user ID";
826         break;
827       default: p = "?"; break;
828     }
829
830     printf("%s)\n", p? p: "");
831 }
832
833 /****************
834  * Returns: >= 0 offset into buffer
835  *          -1 unknown type
836  *          -2 unsupported type
837  *          -3 subpacket too short
838  */
839 static int
840 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
841 {
842     switch( type ) {
843       case SIGSUBPKT_SIG_CREATED:
844       case SIGSUBPKT_SIG_EXPIRE:
845       case SIGSUBPKT_KEY_EXPIRE:
846         if( n < 4 )
847             break;
848         return 0;
849       case SIGSUBPKT_EXPORTABLE:
850         if( !n )
851             break;
852         return 0;
853       case SIGSUBPKT_ISSUER:/* issuer key ID */
854         if( n < 8 )
855             break;
856         return 0;
857       case SIGSUBPKT_NOTATION:
858         if( n < 8 ) /* minimum length needed */
859             break;
860         return 0;
861       case SIGSUBPKT_REVOC_REASON:
862         if( !n  )
863             break;
864         return 0;
865       case SIGSUBPKT_PREF_SYM:
866       case SIGSUBPKT_PREF_HASH:
867       case SIGSUBPKT_PREF_COMPR:
868       case SIGSUBPKT_POLICY:
869         return 0;
870       case SIGSUBPKT_PRIV_ADD_SIG:
871         /* because we use private data, we check the GNUPG marker */
872         if( n < 24 )
873             break;
874         if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
875             return -2;
876         return 3;
877       default: return -1;
878     }
879     return -3;
880 }
881
882
883 static int
884 can_handle_critical( const byte *buffer, size_t n, int type )
885 {
886     switch( type ) {
887       case SIGSUBPKT_NOTATION:
888         if( n >= 8 && (*buffer & 0x80) )
889             return 1; /* human readable is handled */
890         return 0;
891
892       case SIGSUBPKT_SIG_CREATED:
893       case SIGSUBPKT_SIG_EXPIRE:
894       case SIGSUBPKT_KEY_EXPIRE:
895       case SIGSUBPKT_EXPORTABLE:
896       case SIGSUBPKT_ISSUER:/* issuer key ID */
897       case SIGSUBPKT_PREF_SYM:
898       case SIGSUBPKT_PREF_HASH:
899       case SIGSUBPKT_PREF_COMPR:
900         return 1;
901
902       case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
903       default:
904         return 0;
905     }
906 }
907
908
909 const byte *
910 enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
911                  size_t *ret_n, int *start )
912 {
913     int buflen;
914     int type;
915     int critical;
916     int offset;
917     size_t n;
918     int seq = 0;
919     int reqseq = start? *start: 0;
920
921     if( !buffer || reqseq == -1 ) {
922         /* return some value different from NULL to indicate that
923          * there is no crtitical bit we do not understand.  The caller
924          * will never use the value.  Yes I know, it is an ugly hack */
925         return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&buffer : NULL;
926     }
927     buflen = (*buffer << 8) | buffer[1];
928     buffer += 2;
929     while( buflen ) {
930         n = *buffer++; buflen--;
931         if( n == 255 ) {
932             if( buflen < 4 )
933                 goto too_short;
934             n = (buffer[0] << 24) | (buffer[1] << 16)
935                                   | (buffer[2] << 8) | buffer[3];
936             buffer += 4;
937             buflen -= 4;
938
939         }
940         else if( n >= 192 ) {
941             if( buflen < 2 )
942                 goto too_short;
943             n = (( n - 192 ) << 8) + *buffer + 192;
944             buffer++;
945             buflen--;
946         }
947         if( buflen < n )
948             goto too_short;
949         type = *buffer;
950         if( type & 0x80 ) {
951             type &= 0x7f;
952             critical = 1;
953         }
954         else
955             critical = 0;
956         if( !(++seq > reqseq) )
957             ;
958         else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
959             if( critical ) {
960                 if( n-1 > buflen+1 )
961                     goto too_short;
962                 if( !can_handle_critical(buffer+1, n-1, type ) ) {
963                     log_info(_("subpacket of type %d has critical bit set\n"),
964                                                                         type);
965                     if( start )
966                         *start = seq;
967                     return NULL; /* this is an error */
968                 }
969             }
970         }
971         else if( reqtype < 0 ) /* list packets */
972             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
973                                     type, critical, buffer, buflen, n );
974         else if( type == reqtype ) { /* found */
975             buffer++;
976             n--;
977             if( n > buflen )
978                 goto too_short;
979             if( ret_n )
980                 *ret_n = n;
981             offset = parse_one_sig_subpkt(buffer, n, type );
982             switch( offset ) {
983               case -3:
984                 log_error("subpacket of type %d too short\n", type);
985                 return NULL;
986               case -2:
987                 return NULL;
988               case -1:
989                 BUG(); /* not yet needed */
990               default:
991                 break;
992             }
993             if( start )
994                 *start = seq;
995             return buffer+offset;
996         }
997         buffer += n; buflen -=n;
998     }
999     if( reqtype == SIGSUBPKT_TEST_CRITICAL )
1000         return buffer; /* as value true to indicate that there is no */
1001                        /* critical bit we don't understand */
1002     if( start )
1003         *start = -1;
1004     return NULL; /* end of packets; not found */
1005
1006   too_short:
1007     log_error("buffer shorter than subpacket\n");
1008     if( start )
1009         *start = -1;
1010     return NULL;
1011 }
1012
1013
1014 const byte *
1015 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
1016 {
1017     return enum_sig_subpkt( buffer, reqtype, ret_n, NULL );
1018 }
1019
1020 const byte *
1021 parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
1022 {
1023     const byte *p;
1024
1025     p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
1026     if( !p )
1027         p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
1028     return p;
1029 }
1030
1031
1032
1033 static int
1034 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
1035                                           PKT_signature *sig )
1036 {
1037     int md5_len=0;
1038     unsigned n;
1039     int is_v4=0;
1040     int rc=0;
1041     int i, ndata;
1042
1043     if( pktlen < 16 ) {
1044         log_error("packet(%d) too short\n", pkttype);
1045         goto leave;
1046     }
1047     sig->version = iobuf_get_noeof(inp); pktlen--;
1048     if( sig->version == 4 )
1049         is_v4=1;
1050     else if( sig->version != 2 && sig->version != 3 ) {
1051         log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
1052         goto leave;
1053     }
1054
1055     if( !is_v4 ) {
1056         md5_len = iobuf_get_noeof(inp); pktlen--;
1057     }
1058     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
1059     if( !is_v4 ) {
1060         sig->timestamp = read_32(inp); pktlen -= 4;
1061         sig->keyid[0] = read_32(inp); pktlen -= 4;
1062         sig->keyid[1] = read_32(inp); pktlen -= 4;
1063     }
1064     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1065     sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
1066     if( is_v4 ) { /* read subpackets */
1067         n = read_16(inp); pktlen -= 2; /* length of hashed data */
1068         if( n > 10000 ) {
1069             log_error("signature packet: hashed data too long\n");
1070             rc = GPGERR_INVALID_PACKET;
1071             goto leave;
1072         }
1073         if( n ) {
1074             sig->hashed_data = gcry_xmalloc( n + 2 );
1075             sig->hashed_data[0] = n >> 8;
1076             sig->hashed_data[1] = n;
1077             if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
1078                 log_error("premature eof while reading hashed signature data\n");
1079                 rc = -1;
1080                 goto leave;
1081             }
1082             pktlen -= n;
1083         }
1084         n = read_16(inp); pktlen -= 2; /* length of unhashed data */
1085         if( n > 10000 ) {
1086             log_error("signature packet: unhashed data too long\n");
1087             rc = GPGERR_INVALID_PACKET;
1088             goto leave;
1089         }
1090         if( n ) {
1091             sig->unhashed_data = gcry_xmalloc( n + 2 );
1092             sig->unhashed_data[0] = n >> 8;
1093             sig->unhashed_data[1] = n;
1094             if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
1095                 log_error("premature eof while reading unhashed signature data\n");
1096                 rc = -1;
1097                 goto leave;
1098             }
1099             pktlen -= n;
1100         }
1101     }
1102
1103     if( pktlen < 5 ) { /* sanity check */
1104         log_error("packet(%d) too short\n", pkttype);
1105         rc = GPGERR_INVALID_PACKET;
1106         goto leave;
1107     }
1108
1109     sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--;
1110     sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--;
1111
1112     if( is_v4 && sig->pubkey_algo ) { /*extract required information */
1113         const byte *p;
1114
1115         /* set sig->flags.unknown_critical if there is a
1116          * critical bit set for packets which we do not understand */
1117         if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
1118            || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
1119                                                                         NULL) )
1120         {
1121             sig->flags.unknown_critical = 1;
1122         }
1123
1124         p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
1125         if( !p )
1126             log_error("signature packet without timestamp\n");
1127         else
1128             sig->timestamp = buffer_to_u32(p);
1129         p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
1130         if( !p )
1131             log_error("signature packet without keyid\n");
1132         else {
1133             sig->keyid[0] = buffer_to_u32(p);
1134             sig->keyid[1] = buffer_to_u32(p+4);
1135         }
1136     }
1137
1138     if( list_mode ) {
1139         printf(":signature packet: algo %d, keyid %08lX%08lX\n"
1140                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
1141                "\tdigest algo %d, begin of digest %02x %02x\n",
1142                 sig->pubkey_algo,
1143                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1144                 sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
1145                 sig->digest_algo,
1146                 sig->digest_start[0], sig->digest_start[1] );
1147         if( is_v4 ) {
1148             parse_sig_subpkt( sig->hashed_data,  SIGSUBPKT_LIST_HASHED, NULL );
1149             parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
1150         }
1151     }
1152
1153     ndata = pubkey_get_nsig(sig->pubkey_algo);
1154     if( !ndata ) {
1155         if( list_mode )
1156             printf("\tunknown algorithm %d\n", sig->pubkey_algo );
1157         unknown_pubkey_warning( sig->pubkey_algo );
1158         /* we store the plain material in data[0], so that we are able
1159          * to write it back with build_packet() */
1160         sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen );
1161         pktlen = 0;
1162     }
1163     else {
1164         for( i=0; i < ndata; i++ ) {
1165             n = pktlen;
1166             sig->data[i] = mpi_read(inp, &n, 0 );
1167             pktlen -=n;
1168             if( list_mode ) {
1169                 printf("\tdata: ");
1170                 mpi_print(stdout, sig->data[i], mpi_print_mode );
1171                 putchar('\n');
1172             }
1173         }
1174     }
1175
1176   leave:
1177     skip_rest(inp, pktlen);
1178     return rc;
1179 }
1180
1181
1182 static int
1183 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
1184                                              PKT_onepass_sig *ops )
1185 {
1186     int version;
1187
1188     if( pktlen < 13 ) {
1189         log_error("packet(%d) too short\n", pkttype);
1190         goto leave;
1191     }
1192     version = iobuf_get_noeof(inp); pktlen--;
1193     if( version != 3 ) {
1194         log_error("onepass_sig with unknown version %d\n", version);
1195         goto leave;
1196     }
1197     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
1198     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
1199     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
1200     ops->keyid[0] = read_32(inp); pktlen -= 4;
1201     ops->keyid[1] = read_32(inp); pktlen -= 4;
1202     ops->last = iobuf_get_noeof(inp); pktlen--;
1203     if( list_mode )
1204         printf(":onepass_sig packet: keyid %08lX%08lX\n"
1205                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
1206                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
1207                 version, ops->sig_class,
1208                 ops->digest_algo, ops->pubkey_algo, ops->last );
1209
1210
1211   leave:
1212     skip_rest(inp, pktlen);
1213     return 0;
1214 }
1215
1216
1217
1218
1219 static int
1220 parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
1221                               byte *hdr, int hdrlen, PACKET *pkt )
1222 {
1223     int i, version, algorithm;
1224     unsigned n;
1225     unsigned long timestamp, expiredate;
1226     int npkey, nskey;
1227     int is_v4=0;
1228     int rc=0;
1229
1230     version = iobuf_get_noeof(inp); pktlen--;
1231     if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
1232         /* early versions of gpg use old PGP comments packets;
1233          * luckily all those comments are started by a hash */
1234         if( list_mode ) {
1235             printf(":rfc1991 comment packet: \"" );
1236             for( ; pktlen; pktlen-- ) {
1237                 int c;
1238                 c = iobuf_get_noeof(inp);
1239                 if( c >= ' ' && c <= 'z' )
1240                     putchar(c);
1241                 else
1242                     printf("\\x%02x", c );
1243             }
1244             printf("\"\n");
1245         }
1246         skip_rest(inp, pktlen);
1247         return 0;
1248     }
1249     else if( version == 4 )
1250         is_v4=1;
1251     else if( version != 2 && version != 3 ) {
1252         log_error("packet(%d) with unknown version %d\n", pkttype, version);
1253         goto leave;
1254     }
1255
1256     if( pktlen < 11 ) {
1257         log_error("packet(%d) too short\n", pkttype);
1258         goto leave;
1259     }
1260
1261     timestamp = read_32(inp); pktlen -= 4;
1262     if( is_v4 )
1263         expiredate = 0; /* have to get it from the selfsignature */
1264     else {
1265         unsigned short ndays;
1266         ndays = read_16(inp); pktlen -= 2;
1267         if( ndays )
1268             expiredate = timestamp + ndays * 86400L;
1269         else
1270             expiredate = 0;
1271     }
1272     algorithm = iobuf_get_noeof(inp); pktlen--;
1273     if( list_mode )
1274         printf(":%s key packet:\n"
1275                "\tversion %d, algo %d, created %lu, expires %lu\n",
1276                 pkttype == PKT_PUBLIC_KEY? "public" :
1277                 pkttype == PKT_SECRET_KEY? "secret" :
1278                 pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
1279                 pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
1280                 version, algorithm, timestamp, expiredate );
1281
1282     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
1283         PKT_secret_key *sk = pkt->pkt.secret_key;
1284
1285         sk->timestamp = timestamp;
1286         sk->expiredate = expiredate;
1287         sk->hdrbytes = hdrlen;
1288         sk->version = version;
1289         sk->is_primary = pkttype == PKT_SECRET_KEY;
1290         sk->pubkey_algo = algorithm;
1291         sk->pubkey_usage = 0; /* not yet used */
1292     }
1293     else {
1294         PKT_public_key *pk = pkt->pkt.public_key;
1295
1296         pk->timestamp = timestamp;
1297         pk->expiredate = expiredate;
1298         pk->hdrbytes    = hdrlen;
1299         pk->version     = version;
1300         pk->pubkey_algo = algorithm;
1301         pk->pubkey_usage = 0; /* not yet used */
1302         pk->keyid[0] = 0;
1303         pk->keyid[1] = 0;
1304     }
1305     nskey = pubkey_get_nskey( algorithm );
1306     npkey = pubkey_get_npkey( algorithm );
1307     if( !npkey ) {
1308         if( list_mode )
1309             printf("\tunknown algorithm %d\n", algorithm );
1310         unknown_pubkey_warning( algorithm );
1311     }
1312
1313
1314     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
1315         PKT_secret_key *sk = pkt->pkt.secret_key;
1316         byte temp[16];
1317
1318         if( !npkey ) {
1319             sk->skey[0] = gcry_mpi_set_opaque( NULL,
1320                                              read_rest(inp, pktlen), pktlen*8 );
1321             pktlen = 0;
1322             goto leave;
1323         }
1324
1325         for(i=0; i < npkey; i++ ) {
1326             n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1327             if( list_mode ) {
1328                 printf(  "\tskey[%d]: ", i);
1329                 mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1330                 putchar('\n');
1331             }
1332         }
1333         sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1334         if( sk->protect.algo ) {
1335             sk->is_protected = 1;
1336             sk->protect.s2k.count = 0;
1337             if( sk->protect.algo == 255 ) {
1338                 if( pktlen < 3 ) {
1339                     rc = GPGERR_INVALID_PACKET;
1340                     goto leave;
1341                 }
1342                 sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
1343                 sk->protect.s2k.mode  = iobuf_get_noeof(inp); pktlen--;
1344                 sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
1345                 /* check for the special GNU extension */
1346                 if( is_v4 && sk->protect.s2k.mode == 101 ) {
1347                     for(i=0; i < 4 && pktlen; i++, pktlen-- )
1348                         temp[i] = iobuf_get_noeof(inp);
1349                     if( i < 4 || memcmp( temp, "GNU", 3 ) ) {
1350                         if( list_mode )
1351                             printf(  "\tunknown S2K %d\n",
1352                                                 sk->protect.s2k.mode );
1353                         rc = GPGERR_INVALID_PACKET;
1354                         goto leave;
1355                     }
1356                     /* here we know that it is a gnu extension
1357                      * What follows is the GNU protection mode:
1358                      * All values have special meanings
1359                      * and they are mapped in the mode with a base of 1000.
1360                      */
1361                     sk->protect.s2k.mode = 1000 + temp[3];
1362                 }
1363                 switch( sk->protect.s2k.mode ) {
1364                   case 1:
1365                   case 3:
1366                     for(i=0; i < 8 && pktlen; i++, pktlen-- )
1367                         temp[i] = iobuf_get_noeof(inp);
1368                     memcpy(sk->protect.s2k.salt, temp, 8 );
1369                     break;
1370                 }
1371                 switch( sk->protect.s2k.mode ) {
1372                   case 0: if( list_mode ) printf(  "\tsimple S2K" );
1373                     break;
1374                   case 1: if( list_mode ) printf(  "\tsalted S2K" );
1375                     break;
1376                   case 3: if( list_mode ) printf(  "\titer+salt S2K" );
1377                     break;
1378                   case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );
1379                     break;
1380                   default:
1381                     if( list_mode )
1382                         printf(  "\tunknown %sS2K %d\n",
1383                                  sk->protect.s2k.mode < 1000? "":"GNU ",
1384                                                    sk->protect.s2k.mode );
1385                     rc = GPGERR_INVALID_PACKET;
1386                     goto leave;
1387                 }
1388
1389                 if( list_mode ) {
1390                     printf(", algo: %d, hash: %d",
1391                                      sk->protect.algo,
1392                                      sk->protect.s2k.hash_algo );
1393                     if( sk->protect.s2k.mode == 1
1394                         || sk->protect.s2k.mode == 3 ) {
1395                         printf(", salt: ");
1396                         for(i=0; i < 8; i++ )
1397                             printf("%02x", sk->protect.s2k.salt[i]);
1398                     }
1399                     putchar('\n');
1400                 }
1401
1402                 if( sk->protect.s2k.mode == 3 ) {
1403                     if( pktlen < 1 ) {
1404                         rc = GPGERR_INVALID_PACKET;
1405                         goto leave;
1406                     }
1407                     sk->protect.s2k.count = iobuf_get(inp);
1408                     pktlen--;
1409                     if( list_mode )
1410                         printf("\tprotect count: %lu\n",
1411                                             (ulong)sk->protect.s2k.count);
1412                 }
1413             }
1414             else { /* old version; no S2K, so we set mode to 0, hash MD5 */
1415                 sk->protect.s2k.mode = 0;
1416                 sk->protect.s2k.hash_algo = GCRY_MD_MD5;
1417                 if( list_mode )
1418                     printf(  "\tprotect algo: %d  (hash algo: %d)\n",
1419                          sk->protect.algo, sk->protect.s2k.hash_algo );
1420             }
1421             /* It is really ugly that we don't know the size
1422              * of the IV here in cases we are not aware of the algorithm.
1423              * so a
1424              *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);
1425              * won't work.  The only solution I see is to hardwire it here.
1426              * NOTE: if you change the ivlen above 16, don't forget to
1427              * enlarge temp.
1428              */
1429             switch( sk->protect.algo ) {
1430               case 7: case 8: case 9: /* reserved for AES */
1431               case 10: /* Twofish */
1432                 sk->protect.ivlen = 16;
1433                 break;
1434               default:
1435                 sk->protect.ivlen = 8;
1436             }
1437             if( sk->protect.s2k.mode == 1001 )
1438                 sk->protect.ivlen = 0;
1439
1440             if( pktlen < sk->protect.ivlen ) {
1441                 rc = GPGERR_INVALID_PACKET;
1442                 goto leave;
1443             }
1444             for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
1445                 temp[i] = iobuf_get_noeof(inp);
1446             if( list_mode ) {
1447                 printf(  "\tprotect IV: ");
1448                 for(i=0; i < sk->protect.ivlen; i++ )
1449                     printf(" %02x", temp[i] );
1450                 putchar('\n');
1451             }
1452             memcpy(sk->protect.iv, temp, sk->protect.ivlen );
1453         }
1454         else
1455             sk->is_protected = 0;
1456         /* It does not make sense to read it into secure memory.
1457          * If the user is so careless, not to protect his secret key,
1458          * we can assume, that he operates an open system :=(.
1459          * So we put the key into secure memory when we unprotect it. */
1460         if( sk->protect.s2k.mode == 1001 ) {
1461             /* better set some dummy stuff here */
1462             sk->skey[npkey] = mpi_set_opaque(NULL, gcry_xstrdup("dummydata"), 10);
1463             pktlen = 0;
1464         }
1465         else if( is_v4 && sk->is_protected ) {
1466             /* ugly; the length is encrypted too, so we read all
1467              * stuff up to the end of the packet into the first
1468              * skey element */
1469             sk->skey[npkey] = gcry_mpi_set_opaque(NULL,
1470                                              read_rest(inp, pktlen), pktlen*8 );
1471             pktlen = 0;
1472             if( list_mode ) {
1473                 printf("\tencrypted stuff follows\n");
1474             }
1475         }
1476         else { /* unencrypted v4 or v3 method (where length is not encrypted) */
1477             for(i=npkey; i < nskey; i++ ) {
1478                 n = pktlen;
1479                 sk->skey[i] = sk->is_protected ? mpi_read_opaque(inp, &n )
1480                                                : mpi_read( inp, &n, 1 );
1481                 pktlen -=n;
1482                 if( list_mode ) {
1483                     printf(  "\tskey[%d]: ", i);
1484                     if( sk->is_protected )
1485                         printf(  "[encrypted]\n");
1486                     else {
1487                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1488                         putchar('\n');
1489                     }
1490                 }
1491             }
1492
1493             sk->csum = read_16(inp); pktlen -= 2;
1494             if( list_mode ) {
1495                 printf("\tchecksum: %04hx\n", sk->csum);
1496             }
1497         }
1498     }
1499     else {
1500         PKT_public_key *pk = pkt->pkt.public_key;
1501
1502         if( !npkey ) {
1503             pk->pkey[0] = gcry_mpi_set_opaque( NULL,
1504                                              read_rest(inp, pktlen), pktlen*8 );
1505             pktlen = 0;
1506             goto leave;
1507         }
1508
1509         for(i=0; i < npkey; i++ ) {
1510             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1511             if( list_mode ) {
1512                 printf(  "\tpkey[%d]: ", i);
1513                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
1514                 putchar('\n');
1515             }
1516         }
1517     }
1518
1519   leave:
1520     skip_rest(inp, pktlen);
1521     return rc;
1522 }
1523
1524
1525 static int
1526 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1527 {
1528     byte *p;
1529
1530     packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id  + pktlen);
1531     packet->pkt.user_id->len = pktlen;
1532     packet->pkt.user_id->photo = NULL;
1533     packet->pkt.user_id->photolen = 0;
1534     p = packet->pkt.user_id->name;
1535     for( ; pktlen; pktlen--, p++ )
1536         *p = iobuf_get_noeof(inp);
1537     *p = 0;
1538
1539     if( list_mode ) {
1540         int n = packet->pkt.user_id->len;
1541         printf(":user ID packet: \"");
1542         /* fixme: Hey why don't we replace this wioth print_string?? */
1543         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
1544             if( *p >= ' ' && *p <= 'z' )
1545                 putchar(*p);
1546             else
1547                 printf("\\x%02x", *p );
1548         }
1549         printf("\"\n");
1550     }
1551     return 0;
1552 }
1553
1554
1555 /****************
1556  * PGP generates a packet of type 17. We assume this is a photo ID and
1557  * simply store it here as a comment packet.
1558  */
1559 static int
1560 parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1561 {
1562     byte *p;
1563
1564     packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id  + 30);
1565     sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen );
1566     packet->pkt.user_id->len = strlen(packet->pkt.user_id->name);
1567
1568     packet->pkt.user_id->photo = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen);
1569     packet->pkt.user_id->photolen = pktlen;
1570     p = packet->pkt.user_id->photo;
1571     for( ; pktlen; pktlen--, p++ )
1572         *p = iobuf_get_noeof(inp);
1573
1574     if( list_mode ) {
1575         printf(":photo_id packet: %s\n", packet->pkt.user_id->name );
1576     }
1577     return 0;
1578 }
1579
1580
1581 static int
1582 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
1583 {
1584     byte *p;
1585
1586     packet->pkt.comment = gcry_xmalloc(sizeof *packet->pkt.comment + pktlen - 1);
1587     packet->pkt.comment->len = pktlen;
1588     p = packet->pkt.comment->data;
1589     for( ; pktlen; pktlen--, p++ )
1590         *p = iobuf_get_noeof(inp);
1591
1592     if( list_mode ) {
1593         int n = packet->pkt.comment->len;
1594         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
1595                                          "OpenPGP draft " : "" );
1596         for(p=packet->pkt.comment->data; n; p++, n-- ) {
1597             if( *p >= ' ' && *p <= 'z' )
1598                 putchar(*p);
1599             else
1600                 printf("\\x%02x", *p );
1601         }
1602         printf("\"\n");
1603     }
1604     return 0;
1605 }
1606
1607
1608 static void
1609 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
1610 {
1611     int c;
1612
1613     c = iobuf_get_noeof(inp);
1614     pkt->pkt.ring_trust = gcry_xmalloc( sizeof *pkt->pkt.ring_trust );
1615     pkt->pkt.ring_trust->trustval = c;
1616     if( list_mode )
1617         printf(":trust packet: flag=%02x\n", c );
1618 }
1619
1620
1621 static int
1622 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
1623                                         PACKET *pkt, int new_ctb )
1624 {
1625     int mode, namelen;
1626     PKT_plaintext *pt;
1627     byte *p;
1628     int c, i;
1629
1630     if( pktlen && pktlen < 6 ) {
1631         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
1632         goto leave;
1633     }
1634     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1635     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
1636     pt = pkt->pkt.plaintext = gcry_xmalloc(sizeof *pkt->pkt.plaintext + namelen -1);
1637     pt->new_ctb = new_ctb;
1638     pt->mode = mode;
1639     pt->namelen = namelen;
1640     if( pktlen ) {
1641         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
1642             pt->name[i] = iobuf_get_noeof(inp);
1643     }
1644     else {
1645         for( i=0; i < namelen; i++ )
1646             if( (c=iobuf_get(inp)) == -1 )
1647                 break;
1648             else
1649                 pt->name[i] = c;
1650     }
1651     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
1652     pt->len = pktlen;
1653     pt->buf = inp;
1654     pktlen = 0;
1655
1656     if( list_mode ) {
1657         printf(":literal data packet:\n"
1658                "\tmode %c, created %lu, name=\"",
1659                     mode >= ' ' && mode <'z'? mode : '?',
1660                     (ulong)pt->timestamp );
1661         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
1662             if( *p >= ' ' && *p <= 'z' )
1663                 putchar(*p);
1664             else
1665                 printf("\\x%02x", *p );
1666         }
1667         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
1668     }
1669
1670   leave:
1671     return 0;
1672 }
1673
1674
1675 static int
1676 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
1677                   PACKET *pkt, int new_ctb )
1678 {
1679     PKT_compressed *zd;
1680
1681     /* pktlen is here 0, but data follows
1682      * (this should be the last object in a file or
1683      *  the compress algorithm should know the length)
1684      */
1685     zd = pkt->pkt.compressed =  gcry_xmalloc(sizeof *pkt->pkt.compressed );
1686     zd->len = 0; /* not yet used */
1687     zd->algorithm = iobuf_get_noeof(inp);
1688     zd->new_ctb = new_ctb;
1689     zd->buf = inp;
1690     if( list_mode )
1691         printf(":compressed packet: algo=%d\n", zd->algorithm);
1692     return 0;
1693 }
1694
1695
1696 static int
1697 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
1698                                        PACKET *pkt, int new_ctb )
1699 {
1700     PKT_encrypted *ed;
1701
1702     ed = pkt->pkt.encrypted =  gcry_xmalloc(sizeof *pkt->pkt.encrypted );
1703     ed->len = pktlen;
1704     ed->buf = NULL;
1705     ed->new_ctb = new_ctb;
1706     ed->mdc_method = 0;
1707     if( pkttype == PKT_ENCRYPTED_MDC ) {
1708         /* fixme: add some pktlen sanity checks */
1709         int version;
1710
1711         version = iobuf_get_noeof(inp); pktlen--;
1712         if( version != 1 ) {
1713             log_error("encrypted_mdc packet with unknown version %d\n",
1714                                                                 version);
1715             goto leave;
1716         }
1717         ed->mdc_method = GCRY_MD_SHA1;
1718     }
1719     if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
1720         log_error("packet(%d) too short\n", pkttype);
1721         skip_rest(inp, pktlen);
1722         goto leave;
1723     }
1724     if( list_mode ) {
1725         if( pktlen )
1726             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen);
1727         else
1728             printf(":encrypted data packet:\n\tlength: unknown\n");
1729         if( ed->mdc_method )
1730             printf("\tmdc_method: %d\n", ed->mdc_method );
1731     }
1732
1733     ed->buf = inp;
1734     pktlen = 0;
1735
1736   leave:
1737     return 0;
1738 }
1739
1740
1741 static int
1742 parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
1743                                    PACKET *pkt, int new_ctb )
1744 {
1745     PKT_mdc *mdc;
1746     byte *p;
1747
1748     mdc = pkt->pkt.mdc=  gcry_xmalloc(sizeof *pkt->pkt.mdc );
1749     if( list_mode )
1750         printf(":mdc packet: length=%lu\n", pktlen);
1751     if( !new_ctb || pktlen != 20 ) {
1752         log_error("mdc_packet with invalid encoding\n");
1753         goto leave;
1754     }
1755     p = mdc->hash;
1756     for( ; pktlen; pktlen--, p++ )
1757         *p = iobuf_get_noeof(inp);
1758
1759   leave:
1760     return 0;
1761 }
1762