Renamed to GNUPG
[gnupg.git] / g10 / parse-packet.c
1 /* parse-packet.c  - read packets
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "packet.h"
28 #include "iobuf.h"
29 #include "mpi.h"
30 #include "util.h"
31 #include "cipher.h"
32 #include "memory.h"
33 #include "filter.h"
34 #include "options.h"
35
36 static mpi_print_mode = 0;
37 static 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 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
42                                                unsigned long pktlen );
43 static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
44 static void skip_rest( IOBUF inp, unsigned long pktlen );
45 static int  parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen,
46                                                              PACKET *packet );
47 static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
48                                                          PKT_signature *sig );
49 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
50                                                         PKT_onepass_sig *ops );
51 static int  parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
52                                       byte *hdr, int hdrlen, PACKET *packet );
53 static int  parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
54                                                            PACKET *packet );
55 static void parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen );
56 static int  parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
57                                                            PACKET *packet );
58 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen );
59 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
60                                                                 PACKET *pkt );
61 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
62                                                            PACKET *packet );
63 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
64                                                            PACKET *packet );
65 #if 0
66 static u16
67 checksum( byte *p )
68 {
69     u16 n, a;
70
71     n = *p++ << 8;
72     n |= *p++;
73     for(a=0; n; n-- )
74         a += *p++;
75     return a;
76 }
77 #endif
78
79 static unsigned short
80 read_16(IOBUF inp)
81 {
82     unsigned short a;
83     a = iobuf_get_noeof(inp) << 8;
84     a |= iobuf_get_noeof(inp);
85     return a;
86 }
87
88 static unsigned long
89 read_32(IOBUF inp)
90 {
91     unsigned long a;
92     a =  iobuf_get_noeof(inp) << 24;
93     a |= iobuf_get_noeof(inp) << 16;
94     a |= iobuf_get_noeof(inp) << 8;
95     a |= iobuf_get_noeof(inp);
96     return a;
97 }
98
99 int
100 set_packet_list_mode( int mode )
101 {
102     int old = list_mode;
103     list_mode = mode;
104     mpi_print_mode = DBG_MPI;
105     return old;
106 }
107
108 /****************
109  * Parse a Packet and return it in packet
110  * Returns: 0 := valid packet in pkt
111  *         -1 := no more packets
112  *         >0 := error
113  * Note: The function may return an error and a partly valid packet;
114  * caller must free this packet.
115  */
116 int
117 parse_packet( IOBUF inp, PACKET *pkt )
118 {
119     int skip, rc;
120
121     do {
122         rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );
123     } while( skip );
124     return rc;
125 }
126
127 /****************
128  * Like parse packet, but do only return packets of the given type.
129  */
130 int
131 search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
132 {
133     int skip, rc;
134
135     do {
136         rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
137     } while( skip );
138     return rc;
139 }
140
141 /****************
142  * Copy all packets from INP to OUT, thereby removing unused spaces.
143  */
144 int
145 copy_all_packets( IOBUF inp, IOBUF out )
146 {
147     PACKET pkt;
148     int skip, rc=0;
149     do {
150         init_packet(&pkt);
151     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));
152     return rc;
153 }
154
155 /****************
156  * Copy some packets from INP to OUT, thereby removing unused spaces.
157  * Stop after at offset STOPoff (i.e. don't copy the packet at this offset)
158  */
159 int
160 copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff )
161 {
162     PACKET pkt;
163     int skip, rc=0;
164     do {
165         if( iobuf_tell(inp) >= stopoff )
166             return 0;
167         init_packet(&pkt);
168     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );
169     return rc;
170 }
171
172 /****************
173  * Skip over N packets
174  */
175 int
176 skip_some_packets( IOBUF inp, unsigned n )
177 {
178     int skip, rc=0;
179     PACKET pkt;
180
181     for( ;n && !rc; n--) {
182         init_packet(&pkt);
183         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );
184     }
185     return rc;
186 }
187
188 /****************
189  * Parse packet. Set the variable skip points to to 1 if the packet
190  * should be skipped; this is the case if either there is a
191  * requested packet type and the parsed packet doesn't match or the
192  * packet-type is 0, indicating deleted stuff.
193  * if OUT is not NULL, a special copymode is used.
194  */
195 static int
196 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
197        int *skip, IOBUF out, int do_skip )
198 {
199     int rc, c, ctb, pkttype, lenbytes;
200     unsigned long pktlen;
201     byte hdr[5];
202     int hdrlen;
203     int pgp3 = 0;
204
205     *skip = 0;
206     assert( !pkt->pkt.generic );
207     if( retpos )
208         *retpos = iobuf_tell(inp);
209     if( (ctb = iobuf_get(inp)) == -1 )
210         return -1;
211     hdrlen=0;
212     hdr[hdrlen++] = ctb;
213     if( !(ctb & 0x80) ) {
214         log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
215         return G10ERR_INVALID_PACKET;
216     }
217     pktlen = 0;
218     pgp3 = !!(ctb & 0x40);
219     if( pgp3 ) {
220         pkttype =  ctb & 0x3f;
221         if( (c = iobuf_get(inp)) == -1 ) {
222             log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
223             return G10ERR_INVALID_PACKET;
224         }
225         hdr[hdrlen++] = c;
226         if( c < 192 )
227             pktlen = c;
228         else if( c < 224 ) {
229             pktlen = (c - 192) * 256;
230             if( (c = iobuf_get(inp)) == -1 ) {
231                 log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
232                 return G10ERR_INVALID_PACKET;
233             }
234             hdr[hdrlen++] = c;
235             pktlen += c + 192;
236         }
237         else { /* partial body length */
238             pktlen = 1 << (c & 0x1f);
239             log_debug("partial body length of %lu bytes\n", pktlen );
240             iobuf_set_partial_block_mode(inp, pktlen);
241             pktlen = 0;/* to indicate partial length */
242         }
243     }
244     else {
245         pkttype = (ctb>>2)&0xf;
246         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
247         if( !lenbytes ) {
248             pktlen = 0; /* don't know the value */
249             if( pkttype != PKT_COMPRESSED )
250                 iobuf_set_block_mode(inp, 1);
251         }
252         else {
253             for( ; lenbytes; lenbytes-- ) {
254                 pktlen <<= 8;
255                 pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
256             }
257         }
258     }
259
260     if( out && pkttype  ) {
261         if( iobuf_write( out, hdr, hdrlen ) == -1 )
262             rc = G10ERR_WRITE_FILE;
263         else
264             rc = copy_packet(inp, out, pkttype, pktlen );
265         return rc;
266     }
267
268     if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
269         skip_packet(inp, pkttype, pktlen);
270         *skip = 1;
271         return 0;
272     }
273
274     if( DBG_PACKET )
275         log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n",
276                    iobuf_id(inp), pkttype, pktlen, pgp3?" (pgp3)":"" );
277     pkt->pkttype = pkttype;
278     rc = G10ERR_UNKNOWN_PACKET; /* default error */
279     switch( pkttype ) {
280       case PKT_PUBLIC_CERT:
281         pkt->pkt.public_cert = m_alloc_clear(sizeof *pkt->pkt.public_cert );
282         rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
283         break;
284       case PKT_SECRET_CERT:
285       case PKT_SECKEY_SUBCERT:
286         pkt->pkt.secret_cert = m_alloc_clear(sizeof *pkt->pkt.secret_cert );
287         rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
288         break;
289       case PKT_PUBKEY_ENC:
290         rc = parse_publickey(inp, pkttype, pktlen, pkt );
291         break;
292       case PKT_SIGNATURE:
293         pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
294         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
295         break;
296       case PKT_ONEPASS_SIG:
297         pkt->pkt.onepass_sig = m_alloc_clear(sizeof *pkt->pkt.onepass_sig );
298         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
299         break;
300       case PKT_USER_ID:
301         rc = parse_user_id(inp, pkttype, pktlen, pkt );
302         break;
303       case PKT_PUBKEY_SUBCERT:
304         parse_subkey(inp, pkttype, pktlen);
305         break;
306       case PKT_COMMENT:
307         rc = parse_comment(inp, pkttype, pktlen, pkt);
308         break;
309       case PKT_RING_TRUST:
310         parse_trust(inp, pkttype, pktlen);
311         break;
312       case PKT_PLAINTEXT:
313         rc = parse_plaintext(inp, pkttype, pktlen, pkt );
314         break;
315       case PKT_COMPRESSED:
316         rc = parse_compressed(inp, pkttype, pktlen, pkt );
317         break;
318       case PKT_ENCRYPTED:
319         rc = parse_encrypted(inp, pkttype, pktlen, pkt );
320         break;
321       default:
322         skip_packet(inp, pkttype, pktlen);
323         break;
324     }
325
326     return rc;
327 }
328
329 static void
330 dump_hex_line( int c, int *i )
331 {
332     if( *i && !(*i%8) ) {
333         if( *i && !(*i%24) )
334             printf("\n%4d:", *i );
335         else
336             putchar(' ');
337     }
338     if( c == -1 )
339         printf(" EOF" );
340     else
341         printf(" %02x", c );
342     ++*i;
343 }
344
345
346 static int
347 copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
348 {
349     int n;
350     char buf[100];
351
352     if( iobuf_in_block_mode(inp) ) {
353         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
354             if( iobuf_write(out, buf, n ) )
355                 return G10ERR_WRITE_FILE; /* write error */
356     }
357     else if( !pktlen && pkttype == PKT_COMPRESSED ) {
358         /* compressed packet, copy till EOF */
359         while( (n = iobuf_read( inp, buf, 100 )) != -1 )
360             if( iobuf_write(out, buf, n ) )
361                 return G10ERR_WRITE_FILE; /* write error */
362     }
363     else {
364         for( ; pktlen; pktlen -= n ) {
365             n = pktlen > 100 ? 100 : pktlen;
366             n = iobuf_read( inp, buf, n );
367             if( n == -1 )
368                 return G10ERR_READ_FILE;
369             if( iobuf_write(out, buf, n ) )
370                 return G10ERR_WRITE_FILE; /* write error */
371         }
372     }
373     return 0;
374 }
375
376
377 static void
378 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
379 {
380     if( list_mode ) {
381         printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen );
382         if( pkttype ) {
383             int c, i=0 ;
384             printf("dump:");
385             if( iobuf_in_block_mode(inp) ) {
386                 while( (c=iobuf_get(inp)) != -1 )
387                     dump_hex_line(c, &i);
388             }
389             else {
390                 for( ; pktlen; pktlen-- )
391                     dump_hex_line(iobuf_get(inp), &i);
392             }
393             putchar('\n');
394             return;
395         }
396     }
397     skip_rest(inp,pktlen);
398 }
399
400 static void
401 skip_rest( IOBUF inp, unsigned long pktlen )
402 {
403     if( iobuf_in_block_mode(inp) ) {
404         while( iobuf_get(inp) != -1 )
405                 ;
406     }
407     else {
408         for( ; pktlen; pktlen-- )
409             iobuf_get(inp);
410     }
411 }
412
413
414 static int
415 parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
416 {
417     int version;
418     unsigned n;
419     PKT_pubkey_enc *k;
420
421     k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc );
422     if( pktlen < 12 ) {
423         log_error("packet(%d) too short\n", pkttype);
424         goto leave;
425     }
426     version = iobuf_get_noeof(inp); pktlen--;
427     if( version != 2 && version != 3 ) {
428         log_error("packet(%d) with unknown version %d\n", pkttype, version);
429         goto leave;
430     }
431     k->keyid[0] = read_32(inp); pktlen -= 4;
432     k->keyid[1] = read_32(inp); pktlen -= 4;
433     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
434     if( list_mode )
435         printf(":public key encoded packet: keyid %08lX%08lX\n",
436                                       (ulong)k->keyid[0], (ulong)k->keyid[1]);
437     if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
438         n = pktlen;
439         k->d.elg.a = mpi_read(inp, &n, 0); pktlen -=n;
440         n = pktlen;
441         k->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
442         if( list_mode ) {
443             printf("\telg a: ");
444             mpi_print(stdout, k->d.elg.a, mpi_print_mode );
445             printf("\n\telg b: ");
446             mpi_print(stdout, k->d.elg.b, mpi_print_mode );
447             putchar('\n');
448         }
449     }
450     else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) {
451         n = pktlen;
452         k->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
453         if( list_mode ) {
454             printf("\trsa integer: ");
455             mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode );
456             putchar('\n');
457         }
458     }
459     else if( list_mode )
460         printf("\tunknown algorithm %d\n", k->pubkey_algo );
461
462
463   leave:
464     skip_rest(inp, pktlen);
465     return 0;
466 }
467
468
469 static int
470 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
471                                           PKT_signature *sig )
472 {
473     int version, md5_len;
474     unsigned n;
475
476     if( pktlen < 16 ) {
477         log_error("packet(%d) too short\n", pkttype);
478         goto leave;
479     }
480     version = iobuf_get_noeof(inp); pktlen--;
481     if( version != 2 && version != 3 ) {
482         log_error("packet(%d) with unknown version %d\n", pkttype, version);
483         goto leave;
484     }
485     md5_len = iobuf_get_noeof(inp); pktlen--;
486     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
487     sig->timestamp = read_32(inp); pktlen -= 4;
488     sig->keyid[0] = read_32(inp); pktlen -= 4;
489     sig->keyid[1] = read_32(inp); pktlen -= 4;
490     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
491     if( list_mode )
492         printf(":signature packet: keyid %08lX%08lX\n"
493                "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
494                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
495                 version, (ulong)sig->timestamp, md5_len, sig->sig_class );
496     if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
497         if( pktlen < 5 ) {
498             log_error("packet(%d) too short\n", pkttype);
499             goto leave;
500         }
501         sig->d.elg.digest_algo = iobuf_get_noeof(inp); pktlen--;
502         sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
503         sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
504         n = pktlen;
505         sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n;
506         n = pktlen;
507         sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
508         if( list_mode ) {
509             printf("\tdigest algo %d, begin of digest %02x %02x\n",
510                     sig->d.elg.digest_algo,
511                     sig->d.elg.digest_start[0], sig->d.elg.digest_start[1] );
512             printf("\telg a: ");
513             mpi_print(stdout, sig->d.elg.a, mpi_print_mode );
514             printf("\n\telg b: ");
515             mpi_print(stdout, sig->d.elg.b, mpi_print_mode );
516             putchar('\n');
517         }
518     }
519     else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
520         if( pktlen < 5 ) {
521             log_error("packet(%d) too short\n", pkttype);
522             goto leave;
523         }
524         sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
525         sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
526         sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
527         n = pktlen;
528         sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
529         if( list_mode ) {
530             printf("\tdigest algo %d, begin of digest %02x %02x\n",
531                     sig->d.rsa.digest_algo,
532                     sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
533             printf("\trsa integer: ");
534             mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
535             putchar('\n');
536         }
537     }
538     else if( list_mode )
539         printf("\tunknown algorithm %d\n", sig->pubkey_algo );
540
541
542   leave:
543     skip_rest(inp, pktlen);
544     return 0;
545 }
546
547
548 static int
549 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
550                                              PKT_onepass_sig *ops )
551 {
552     int version;
553
554     if( pktlen < 13 ) {
555         log_error("packet(%d) too short\n", pkttype);
556         goto leave;
557     }
558     version = iobuf_get_noeof(inp); pktlen--;
559     if( version != 3 ) {
560         log_error("onepass_sig with unknown version %d\n", version);
561         goto leave;
562     }
563     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
564     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
565     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
566     ops->keyid[0] = read_32(inp); pktlen -= 4;
567     ops->keyid[1] = read_32(inp); pktlen -= 4;
568     ops->last = iobuf_get_noeof(inp); pktlen--;
569     if( list_mode )
570         printf(":onepass_sig packet: keyid %08lX%08lX\n"
571                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
572                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
573                 version, ops->sig_class,
574                 ops->digest_algo, ops->pubkey_algo, ops->last );
575
576
577   leave:
578     skip_rest(inp, pktlen);
579     return 0;
580 }
581
582
583
584
585 static int
586 parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
587                               byte *hdr, int hdrlen, PACKET *pkt )
588 {
589     int i, version, algorithm;
590     unsigned n;
591     unsigned long timestamp;
592     unsigned short valid_period;
593     int is_v4=0;
594     int rc=0;
595
596
597     if( pktlen < 12 ) {
598         log_error("packet(%d) too short\n", pkttype);
599         goto leave;
600     }
601     version = iobuf_get_noeof(inp); pktlen--;
602     if( version == 4 )
603         is_v4=1;
604     else if( version != 2 && version != 3 ) {
605         log_error("packet(%d) with unknown version %d\n", pkttype, version);
606         goto leave;
607     }
608
609     timestamp = read_32(inp); pktlen -= 4;
610     if( is_v4 )
611         valid_period = 0;
612     else {
613         valid_period = read_16(inp); pktlen -= 2;
614     }
615     algorithm = iobuf_get_noeof(inp); pktlen--;
616     if( list_mode )
617         printf(":%s key packet:\n"
618                "\tversion %d, created %lu, valid for %hu days\n",
619                 pkttype == PKT_PUBLIC_CERT? "public": "secret",
620                 version, timestamp, valid_period );
621     if( pkttype == PKT_SECRET_CERT )  {
622         pkt->pkt.secret_cert->timestamp = timestamp;
623         pkt->pkt.secret_cert->valid_days = valid_period;
624         pkt->pkt.secret_cert->hdrbytes = hdrlen;
625         pkt->pkt.secret_cert->version = version;
626         pkt->pkt.secret_cert->pubkey_algo = algorithm;
627     }
628     else {
629         pkt->pkt.public_cert->timestamp = timestamp;
630         pkt->pkt.public_cert->valid_days = valid_period;
631         pkt->pkt.public_cert->hdrbytes    = hdrlen;
632         pkt->pkt.public_cert->version     = version;
633         pkt->pkt.public_cert->pubkey_algo = algorithm;
634     }
635
636     if( algorithm == PUBKEY_ALGO_ELGAMAL ) {
637         MPI elg_p, elg_g, elg_y;
638         n = pktlen; elg_p = mpi_read(inp, &n, 0 ); pktlen -=n;
639         n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n;
640         n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n;
641         if( list_mode ) {
642             printf(  "\telg p: ");
643             mpi_print(stdout, elg_p, mpi_print_mode  );
644             printf("\n\telg g: ");
645             mpi_print(stdout, elg_g, mpi_print_mode  );
646             printf("\n\telg y: ");
647             mpi_print(stdout, elg_y, mpi_print_mode  );
648             putchar('\n');
649         }
650         if( pkttype == PKT_PUBLIC_CERT ) {
651             pkt->pkt.public_cert->d.elg.p = elg_p;
652             pkt->pkt.public_cert->d.elg.g = elg_g;
653             pkt->pkt.public_cert->d.elg.y = elg_y;
654         }
655         else {
656             PKT_secret_cert *cert = pkt->pkt.secret_cert;
657             byte temp[8];
658
659             pkt->pkt.secret_cert->d.elg.p = elg_p;
660             pkt->pkt.secret_cert->d.elg.g = elg_g;
661             pkt->pkt.secret_cert->d.elg.y = elg_y;
662             cert->d.elg.protect.algo = iobuf_get_noeof(inp); pktlen--;
663             if( cert->d.elg.protect.algo ) {
664                 cert->d.elg.is_protected = 1;
665                 cert->d.elg.protect.count = 0;
666                 if( cert->d.elg.protect.algo == 255 ) {
667                     if( pktlen < 3 ) {
668                         rc = G10ERR_INVALID_PACKET;
669                         goto leave;
670                     }
671                     cert->d.elg.protect.algo = iobuf_get_noeof(inp); pktlen--;
672                     cert->d.elg.protect.s2k  = iobuf_get_noeof(inp); pktlen--;
673                     cert->d.elg.protect.hash = iobuf_get_noeof(inp); pktlen--;
674                     switch( cert->d.elg.protect.s2k ) {
675                       case 1:
676                       case 3:
677                         for(i=0; i < 8 && pktlen; i++, pktlen-- )
678                             temp[i] = iobuf_get_noeof(inp);
679                         memcpy(cert->d.elg.protect.salt, temp, 8 );
680                         break;
681                     }
682                     switch( cert->d.elg.protect.s2k ) {
683                       case 0: if( list_mode ) printf(  "\tsimple S2K" );
684                         break;
685                       case 1: if( list_mode ) printf(  "\tsalted S2K" );
686                         break;
687                       case 3: if( list_mode ) printf(  "\titer+salt S2K" );
688                         break;
689                       default:
690                         if( list_mode )
691                             printf(  "\tunknown S2K %d\n",
692                                                 cert->d.elg.protect.s2k );
693                         rc = G10ERR_INVALID_PACKET;
694                         goto leave;
695                     }
696
697                     if( list_mode ) {
698                         printf(", algo: %d, hash: %d",
699                                          cert->d.elg.protect.algo,
700                                          cert->d.elg.protect.hash );
701                         if( cert->d.elg.protect.s2k == 1
702                             || cert->d.elg.protect.s2k == 3 ) {
703                             printf(", salt: ");
704                             for(i=0; i < 8; i++ )
705                                 printf("%02x", cert->d.elg.protect.salt[i]);
706                         }
707                         putchar('\n');
708                     }
709
710                     if( cert->d.elg.protect.s2k == 3 ) {
711                         if( !pktlen ) {
712                             rc = G10ERR_INVALID_PACKET;
713                             goto leave;
714                         }
715                         cert->d.elg.protect.count = iobuf_get_noeof(inp);
716                         pktlen--;
717                     }
718
719                 }
720                 else {
721                     if( list_mode )
722                         printf(  "\tprotect algo: %d\n",
723                                                 cert->d.elg.protect.algo);
724                     /* old version, we don't have a S2K, so we fake one */
725                     cert->d.elg.protect.s2k = 0;
726                     /* We need this kludge to cope with old GNUPG versions */
727                     cert->d.elg.protect.hash =
728                          cert->d.elg.protect.algo == CIPHER_ALGO_BLOWFISH?
729                                       DIGEST_ALGO_RMD160 : DIGEST_ALGO_MD5;
730                 }
731                 if( pktlen < 8 ) {
732                     rc = G10ERR_INVALID_PACKET;
733                     goto leave;
734                 }
735                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
736                     temp[i] = iobuf_get_noeof(inp);
737                 if( list_mode ) {
738                     printf(  "\tprotect IV: ");
739                     for(i=0; i < 8; i++ )
740                         printf(" %02x", temp[i] );
741                     putchar('\n');
742                 }
743                 memcpy(cert->d.elg.protect.iv, temp, 8 );
744             }
745             else
746                 cert->d.elg.is_protected = 0;
747             /* It does not make sense to read it into secure memory.
748              * If the user is so careless, not to protect his secret key,
749              * we can assume, that he operates an open system :=(.
750              * So we put the key into secure memory when we unprotect him. */
751             n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 0 ); pktlen -=n;
752
753             cert->d.elg.csum = read_16(inp); pktlen -= 2;
754             if( list_mode ) {
755                 printf("\t[secret value x is not shown]\n"
756                        "\tchecksum: %04hx\n", cert->d.elg.csum);
757             }
758           /*log_mpidump("elg p=", cert->d.elg.p );
759             log_mpidump("elg g=", cert->d.elg.g );
760             log_mpidump("elg y=", cert->d.elg.y );
761             log_mpidump("elg x=", cert->d.elg.x ); */
762         }
763     }
764     else if( algorithm == PUBKEY_ALGO_RSA ) {
765         MPI rsa_pub_mod, rsa_pub_exp;
766
767         n = pktlen; rsa_pub_mod = mpi_read(inp, &n, 0); pktlen -=n;
768         n = pktlen; rsa_pub_exp = mpi_read(inp, &n, 0 ); pktlen -=n;
769         if( list_mode ) {
770             printf(  "\tpublic modulus  n:  ");
771             mpi_print(stdout, rsa_pub_mod, mpi_print_mode  );
772             printf("\n\tpublic exponent e: ");
773             mpi_print(stdout, rsa_pub_exp, mpi_print_mode  );
774             putchar('\n');
775         }
776         if( pkttype == PKT_PUBLIC_CERT ) {
777             pkt->pkt.public_cert->d.rsa.rsa_n = rsa_pub_mod;
778             pkt->pkt.public_cert->d.rsa.rsa_e = rsa_pub_exp;
779         }
780         else {
781             PKT_secret_cert *cert = pkt->pkt.secret_cert;
782             byte temp[8];
783
784             pkt->pkt.secret_cert->d.rsa.rsa_n = rsa_pub_mod;
785             pkt->pkt.secret_cert->d.rsa.rsa_e = rsa_pub_exp;
786             cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
787             if( list_mode )
788                 printf(  "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
789             if( cert->d.rsa.protect_algo ) {
790                 cert->d.rsa.is_protected = 1;
791                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
792                     temp[i] = iobuf_get_noeof(inp);
793                 if( list_mode ) {
794                     printf(  "\tprotect IV: ");
795                     for(i=0; i < 8; i++ )
796                         printf(" %02x", temp[i] );
797                     putchar('\n');
798                 }
799                 if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
800                     memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
801             }
802             else
803                 cert->d.rsa.is_protected = 0;
804             /* (See comments at the code for elg keys) */
805             n = pktlen; cert->d.rsa.rsa_d = mpi_read(inp, &n, 0 ); pktlen -=n;
806             n = pktlen; cert->d.rsa.rsa_p = mpi_read(inp, &n, 0 ); pktlen -=n;
807             n = pktlen; cert->d.rsa.rsa_q = mpi_read(inp, &n, 0 ); pktlen -=n;
808             n = pktlen; cert->d.rsa.rsa_u = mpi_read(inp, &n, 0 ); pktlen -=n;
809
810             cert->d.rsa.csum = read_16(inp); pktlen -= 2;
811             if( list_mode ) {
812                 printf("\t[secret values d,p,q,u are not shown]\n"
813                        "\tchecksum: %04hx\n", cert->d.rsa.csum);
814             }
815          /* log_mpidump("rsa n=", cert->d.rsa.rsa_n );
816             log_mpidump("rsa e=", cert->d.rsa.rsa_e );
817             log_mpidump("rsa d=", cert->d.rsa.rsa_d );
818             log_mpidump("rsa p=", cert->d.rsa.rsa_p );
819             log_mpidump("rsa q=", cert->d.rsa.rsa_q );
820             log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */
821         }
822     }
823     else if( list_mode )
824         printf("\tunknown algorithm %d\n", algorithm );
825
826
827   leave:
828     skip_rest(inp, pktlen);
829     return rc;
830 }
831
832
833 static int
834 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
835 {
836     byte *p;
837
838     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
839     packet->pkt.user_id->len = pktlen;
840     p = packet->pkt.user_id->name;
841     for( ; pktlen; pktlen--, p++ )
842         *p = iobuf_get_noeof(inp);
843
844     if( list_mode ) {
845         int n = packet->pkt.user_id->len;
846         printf(":user id packet: \"");
847         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
848             if( *p >= ' ' && *p <= 'z' )
849                 putchar(*p);
850             else
851                 printf("\\x%02x", *p );
852         }
853         printf("\"\n");
854     }
855     return 0;
856 }
857
858
859 static void
860 parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen )
861 {
862     int version;
863
864     version = iobuf_get_noeof(inp); pktlen--;
865     if( pkttype == PKT_PUBKEY_SUBCERT && version == '#' ) {
866         /* early versions of G10 use old comments packets; luckily all those
867          * comments are started by a hash */
868         if( list_mode ) {
869             printf(":old comment packet: \"" );
870             for( ; pktlen; pktlen-- ) {
871                 int c;
872                 c = iobuf_get_noeof(inp);
873                 if( c >= ' ' && c <= 'z' )
874                     putchar(c);
875                 else
876                     printf("\\x%02x", c );
877             }
878             printf("\"\n");
879         }
880         skip_rest(inp, pktlen);
881         return;
882     }
883
884     if( list_mode )
885         printf(":public subkey packet: \"" );
886     skip_rest(inp, pktlen);
887 }
888
889
890
891 static int
892 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
893 {
894     byte *p;
895
896     packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
897     packet->pkt.comment->len = pktlen;
898     p = packet->pkt.comment->data;
899     for( ; pktlen; pktlen--, p++ )
900         *p = iobuf_get_noeof(inp);
901
902     if( list_mode ) {
903         int n = packet->pkt.comment->len;
904         printf(":comment packet: \"");
905         for(p=packet->pkt.comment->data; n; p++, n-- ) {
906             if( *p >= ' ' && *p <= 'z' )
907                 putchar(*p);
908             else
909                 printf("\\x%02x", *p );
910         }
911         printf("\"\n");
912     }
913     return 0;
914 }
915
916
917 static void
918 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
919 {
920     int c;
921
922     c = iobuf_get_noeof(inp);
923     if( list_mode )
924         printf(":trust packet: flag=%02x\n", c );
925 }
926
927
928 static int
929 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
930 {
931     int mode, namelen;
932     PKT_plaintext *pt;
933     byte *p;
934     int c, i;
935
936     if( pktlen && pktlen < 6 ) {
937         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
938         goto leave;
939     }
940     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
941     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
942     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
943     pt->mode = mode;
944     pt->namelen = namelen;
945     if( pktlen ) {
946         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
947             pt->name[i] = iobuf_get_noeof(inp);
948     }
949     else {
950         for( i=0; i < namelen; i++ )
951             if( (c=iobuf_get(inp)) == -1 )
952                 break;
953             else
954                 pt->name[i] = c;
955     }
956     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
957     pt->len = pktlen;
958     pt->buf = inp;
959     pktlen = 0;
960
961     if( list_mode ) {
962         printf(":literal data packet:\n"
963                "\tmode %c, created %lu, name=\"",
964                     mode >= ' ' && mode <'z'? mode : '?',
965                     (ulong)pt->timestamp );
966         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
967             if( *p >= ' ' && *p <= 'z' )
968                 putchar(*p);
969             else
970                 printf("\\x%02x", *p );
971         }
972         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
973     }
974
975   leave:
976     return 0;
977 }
978
979
980 static int
981 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
982 {
983     PKT_compressed *zd;
984
985     /* pktlen is here 0, but data follows
986      * (this should be the last object in a file or
987      *  the compress algorithm should know the length)
988      */
989     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
990     zd->len = 0; /* not yet used */
991     zd->algorithm = iobuf_get_noeof(inp);
992     zd->buf = inp;
993     if( list_mode )
994         printf(":compressed packet: algo=%d\n", zd->algorithm);
995     return 0;
996 }
997
998
999 static int
1000 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
1001 {
1002     PKT_encrypted *ed;
1003
1004     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
1005     ed->len = pktlen;
1006     ed->buf = NULL;
1007     if( pktlen && pktlen < 10 ) {
1008         log_error("packet(%d) too short\n", pkttype);
1009         skip_rest(inp, pktlen);
1010         goto leave;
1011     }
1012     if( list_mode )
1013         if( pktlen )
1014             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
1015         else
1016             printf(":encrypted data packet:\n\tlength: unknown\n");
1017
1018     ed->buf = inp;
1019     pktlen = 0;
1020
1021   leave:
1022     return 0;
1023 }
1024
1025