added revcation stuff and fixed a couple of bugs
[gnupg.git] / g10 / parse-packet.c
1 /* parse-packet.c  - read packets
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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
595
596     if( pktlen < 12 ) {
597         log_error("packet(%d) too short\n", pkttype);
598         goto leave;
599     }
600     version = iobuf_get_noeof(inp); pktlen--;
601     if( version == 4 )
602         is_v4=1;
603     else if( version != 2 && version != 3 ) {
604         log_error("packet(%d) with unknown version %d\n", pkttype, version);
605         goto leave;
606     }
607
608     timestamp = read_32(inp); pktlen -= 4;
609     if( is_v4 )
610         valid_period = 0;
611     else {
612         valid_period = read_16(inp); pktlen -= 2;
613     }
614     algorithm = iobuf_get_noeof(inp); pktlen--;
615     if( list_mode )
616         printf(":%s key packet:\n"
617                "\tversion %d, created %lu, valid for %hu days\n",
618                 pkttype == PKT_PUBLIC_CERT? "public": "secret",
619                 version, timestamp, valid_period );
620     if( pkttype == PKT_SECRET_CERT )  {
621         pkt->pkt.secret_cert->timestamp = timestamp;
622         pkt->pkt.secret_cert->valid_days = valid_period;
623         pkt->pkt.secret_cert->hdrbytes = hdrlen;
624         pkt->pkt.secret_cert->version = version;
625         pkt->pkt.secret_cert->pubkey_algo = algorithm;
626     }
627     else {
628         pkt->pkt.public_cert->timestamp = timestamp;
629         pkt->pkt.public_cert->valid_days = valid_period;
630         pkt->pkt.public_cert->hdrbytes    = hdrlen;
631         pkt->pkt.public_cert->version     = version;
632         pkt->pkt.public_cert->pubkey_algo = algorithm;
633     }
634
635     if( algorithm == PUBKEY_ALGO_ELGAMAL ) {
636         MPI elg_p, elg_g, elg_y;
637         n = pktlen; elg_p = mpi_read(inp, &n, 0 ); pktlen -=n;
638         n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n;
639         n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n;
640         if( list_mode ) {
641             printf(  "\telg p: ");
642             mpi_print(stdout, elg_p, mpi_print_mode  );
643             printf("\n\telg g: ");
644             mpi_print(stdout, elg_g, mpi_print_mode  );
645             printf("\n\telg y: ");
646             mpi_print(stdout, elg_y, mpi_print_mode  );
647             putchar('\n');
648         }
649         if( pkttype == PKT_PUBLIC_CERT ) {
650             pkt->pkt.public_cert->d.elg.p = elg_p;
651             pkt->pkt.public_cert->d.elg.g = elg_g;
652             pkt->pkt.public_cert->d.elg.y = elg_y;
653         }
654         else {
655             PKT_secret_cert *cert = pkt->pkt.secret_cert;
656             byte temp[8];
657
658             pkt->pkt.secret_cert->d.elg.p = elg_p;
659             pkt->pkt.secret_cert->d.elg.g = elg_g;
660             pkt->pkt.secret_cert->d.elg.y = elg_y;
661             cert->d.elg.protect_algo = iobuf_get_noeof(inp); pktlen--;
662             if( list_mode )
663                 printf(  "\tprotect algo: %d\n", cert->d.elg.protect_algo);
664             if( cert->d.elg.protect_algo ) {
665                 cert->d.elg.is_protected = 1;
666                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
667                     temp[i] = iobuf_get_noeof(inp);
668                 if( list_mode ) {
669                     printf(  "\tprotect IV: ");
670                     for(i=0; i < 8; i++ )
671                         printf(" %02x", temp[i] );
672                     putchar('\n');
673                 }
674                 if( cert->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH )
675                     memcpy(cert->d.elg.protect.blowfish.iv, temp, 8 );
676             }
677             else
678                 cert->d.elg.is_protected = 0;
679             /* It does not make sense to read it into secure memory.
680              * If the user is so careless, not to protect his secret key,
681              * we can assume, that he operates an open system :=(.
682              * So we put the key into secure memory when we unprotect him. */
683             n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 0 ); pktlen -=n;
684
685             cert->d.elg.csum = read_16(inp); pktlen -= 2;
686             if( list_mode ) {
687                 printf("\t[secret value x is not shown]\n"
688                        "\tchecksum: %04hx\n", cert->d.elg.csum);
689             }
690           /*log_mpidump("elg p=", cert->d.elg.p );
691             log_mpidump("elg g=", cert->d.elg.g );
692             log_mpidump("elg y=", cert->d.elg.y );
693             log_mpidump("elg x=", cert->d.elg.x ); */
694         }
695     }
696     else if( algorithm == PUBKEY_ALGO_RSA ) {
697         MPI rsa_pub_mod, rsa_pub_exp;
698
699         n = pktlen; rsa_pub_mod = mpi_read(inp, &n, 0); pktlen -=n;
700         n = pktlen; rsa_pub_exp = mpi_read(inp, &n, 0 ); pktlen -=n;
701         if( list_mode ) {
702             printf(  "\tpublic modulus  n:  ");
703             mpi_print(stdout, rsa_pub_mod, mpi_print_mode  );
704             printf("\n\tpublic exponent e: ");
705             mpi_print(stdout, rsa_pub_exp, mpi_print_mode  );
706             putchar('\n');
707         }
708         if( pkttype == PKT_PUBLIC_CERT ) {
709             pkt->pkt.public_cert->d.rsa.rsa_n = rsa_pub_mod;
710             pkt->pkt.public_cert->d.rsa.rsa_e = rsa_pub_exp;
711         }
712         else {
713             PKT_secret_cert *cert = pkt->pkt.secret_cert;
714             byte temp[8];
715
716             pkt->pkt.secret_cert->d.rsa.rsa_n = rsa_pub_mod;
717             pkt->pkt.secret_cert->d.rsa.rsa_e = rsa_pub_exp;
718             cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
719             if( list_mode )
720                 printf(  "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
721             if( cert->d.rsa.protect_algo ) {
722                 cert->d.rsa.is_protected = 1;
723                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
724                     temp[i] = iobuf_get_noeof(inp);
725                 if( list_mode ) {
726                     printf(  "\tprotect IV: ");
727                     for(i=0; i < 8; i++ )
728                         printf(" %02x", temp[i] );
729                     putchar('\n');
730                 }
731                 if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
732                     memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
733             }
734             else
735                 cert->d.rsa.is_protected = 0;
736             /* (See comments at the code for elg keys) */
737             n = pktlen; cert->d.rsa.rsa_d = mpi_read(inp, &n, 0 ); pktlen -=n;
738             n = pktlen; cert->d.rsa.rsa_p = mpi_read(inp, &n, 0 ); pktlen -=n;
739             n = pktlen; cert->d.rsa.rsa_q = mpi_read(inp, &n, 0 ); pktlen -=n;
740             n = pktlen; cert->d.rsa.rsa_u = mpi_read(inp, &n, 0 ); pktlen -=n;
741
742             cert->d.rsa.csum = read_16(inp); pktlen -= 2;
743             if( list_mode ) {
744                 printf("\t[secret values d,p,q,u are not shown]\n"
745                        "\tchecksum: %04hx\n", cert->d.rsa.csum);
746             }
747          /* log_mpidump("rsa n=", cert->d.rsa.rsa_n );
748             log_mpidump("rsa e=", cert->d.rsa.rsa_e );
749             log_mpidump("rsa d=", cert->d.rsa.rsa_d );
750             log_mpidump("rsa p=", cert->d.rsa.rsa_p );
751             log_mpidump("rsa q=", cert->d.rsa.rsa_q );
752             log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */
753         }
754     }
755     else if( list_mode )
756         printf("\tunknown algorithm %d\n", algorithm );
757
758
759   leave:
760     skip_rest(inp, pktlen);
761     return 0;
762 }
763
764
765 static int
766 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
767 {
768     byte *p;
769
770     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
771     packet->pkt.user_id->len = pktlen;
772     p = packet->pkt.user_id->name;
773     for( ; pktlen; pktlen--, p++ )
774         *p = iobuf_get_noeof(inp);
775
776     if( list_mode ) {
777         int n = packet->pkt.user_id->len;
778         printf(":user id packet: \"");
779         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
780             if( *p >= ' ' && *p <= 'z' )
781                 putchar(*p);
782             else
783                 printf("\\x%02x", *p );
784         }
785         printf("\"\n");
786     }
787     return 0;
788 }
789
790
791 static void
792 parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen )
793 {
794     int version;
795
796     version = iobuf_get_noeof(inp); pktlen--;
797     if( pkttype == PKT_PUBKEY_SUBCERT && version == '#' ) {
798         /* early versions of G10 use old comments packets; luckily all those
799          * comments are started by a hash */
800         if( list_mode ) {
801             printf(":old comment packet: \"" );
802             for( ; pktlen; pktlen-- ) {
803                 int c;
804                 c = iobuf_get_noeof(inp);
805                 if( c >= ' ' && c <= 'z' )
806                     putchar(c);
807                 else
808                     printf("\\x%02x", c );
809             }
810             printf("\"\n");
811         }
812         skip_rest(inp, pktlen);
813         return;
814     }
815
816     if( list_mode )
817         printf(":public subkey packet: \"" );
818     skip_rest(inp, pktlen);
819 }
820
821
822
823 static int
824 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
825 {
826     byte *p;
827
828     packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
829     packet->pkt.comment->len = pktlen;
830     p = packet->pkt.comment->data;
831     for( ; pktlen; pktlen--, p++ )
832         *p = iobuf_get_noeof(inp);
833
834     if( list_mode ) {
835         int n = packet->pkt.comment->len;
836         printf(":comment packet: \"");
837         for(p=packet->pkt.comment->data; n; p++, n-- ) {
838             if( *p >= ' ' && *p <= 'z' )
839                 putchar(*p);
840             else
841                 printf("\\x%02x", *p );
842         }
843         printf("\"\n");
844     }
845     return 0;
846 }
847
848
849 static void
850 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
851 {
852     int c;
853
854     c = iobuf_get_noeof(inp);
855     if( list_mode )
856         printf(":trust packet: flag=%02x\n", c );
857 }
858
859
860 static int
861 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
862 {
863     int mode, namelen;
864     PKT_plaintext *pt;
865     byte *p;
866     int c, i;
867
868     if( pktlen && pktlen < 6 ) {
869         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
870         goto leave;
871     }
872     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
873     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
874     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
875     pt->mode = mode;
876     pt->namelen = namelen;
877     if( pktlen ) {
878         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
879             pt->name[i] = iobuf_get_noeof(inp);
880     }
881     else {
882         for( i=0; i < namelen; i++ )
883             if( (c=iobuf_get(inp)) == -1 )
884                 break;
885             else
886                 pt->name[i] = c;
887     }
888     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
889     pt->len = pktlen;
890     pt->buf = inp;
891     pktlen = 0;
892
893     if( list_mode ) {
894         printf(":literal data packet:\n"
895                "\tmode %c, created %lu, name=\"",
896                     mode >= ' ' && mode <'z'? mode : '?',
897                     (ulong)pt->timestamp );
898         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
899             if( *p >= ' ' && *p <= 'z' )
900                 putchar(*p);
901             else
902                 printf("\\x%02x", *p );
903         }
904         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
905     }
906
907   leave:
908     return 0;
909 }
910
911
912 static int
913 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
914 {
915     PKT_compressed *zd;
916
917     /* pktlen is here 0, but data follows
918      * (this should be the last object in a file or
919      *  the compress algorithm should know the length)
920      */
921     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
922     zd->len = 0; /* not yet used */
923     zd->algorithm = iobuf_get_noeof(inp);
924     zd->buf = inp;
925     if( list_mode )
926         printf(":compressed packet: algo=%d\n", zd->algorithm);
927     return 0;
928 }
929
930
931 static int
932 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
933 {
934     PKT_encrypted *ed;
935
936     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
937     ed->len = pktlen;
938     ed->buf = NULL;
939     if( pktlen && pktlen < 10 ) {
940         log_error("packet(%d) too short\n", pkttype);
941         skip_rest(inp, pktlen);
942         goto leave;
943     }
944     if( list_mode )
945         if( pktlen )
946             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
947         else
948             printf(":encrypted data packet:\n\tlength: unknown\n");
949
950     ed->buf = inp;
951     pktlen = 0;
952
953   leave:
954     return 0;
955 }
956
957