2e3cf21be5ca2d9f76311facf497054923a1d1d8
[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         k->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
441         if( list_mode ) {
442             printf("\telg a: ");
443             mpi_print(stdout, k->d.elg.a, mpi_print_mode );
444             printf("\n\telg b: ");
445             mpi_print(stdout, k->d.elg.b, mpi_print_mode );
446             putchar('\n');
447         }
448     }
449     else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) {
450         n = pktlen;
451         k->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
452         if( list_mode ) {
453             printf("\trsa integer: ");
454             mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode );
455             putchar('\n');
456         }
457     }
458     else if( list_mode )
459         printf("\tunknown algorithm %d\n", k->pubkey_algo );
460
461
462   leave:
463     skip_rest(inp, pktlen);
464     return 0;
465 }
466
467
468 static int
469 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
470                                           PKT_signature *sig )
471 {
472     int version, md5_len;
473     unsigned n;
474
475     if( pktlen < 16 ) {
476         log_error("packet(%d) too short\n", pkttype);
477         goto leave;
478     }
479     version = iobuf_get_noeof(inp); pktlen--;
480     if( version != 2 && version != 3 ) {
481         log_error("packet(%d) with unknown version %d\n", pkttype, version);
482         goto leave;
483     }
484     md5_len = iobuf_get_noeof(inp); pktlen--;
485     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
486     sig->timestamp = read_32(inp); pktlen -= 4;
487     sig->keyid[0] = read_32(inp); pktlen -= 4;
488     sig->keyid[1] = read_32(inp); pktlen -= 4;
489     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
490     if( list_mode )
491         printf(":signature packet: keyid %08lX%08lX\n"
492                "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
493                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
494                 version, (ulong)sig->timestamp, md5_len, sig->sig_class );
495     if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
496         if( pktlen < 5 ) {
497             log_error("packet(%d) too short\n", pkttype);
498             goto leave;
499         }
500         sig->d.elg.digest_algo = iobuf_get_noeof(inp); pktlen--;
501         sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
502         sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
503         n = pktlen;
504         sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n;
505         sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
506         if( list_mode ) {
507             printf("\tdigest algo %d, begin of digest %02x %02x\n",
508                     sig->d.elg.digest_algo,
509                     sig->d.elg.digest_start[0], sig->d.elg.digest_start[1] );
510             printf("\telg a: ");
511             mpi_print(stdout, sig->d.elg.a, mpi_print_mode );
512             printf("\n\telg b: ");
513             mpi_print(stdout, sig->d.elg.b, mpi_print_mode );
514             putchar('\n');
515         }
516     }
517     else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
518         if( pktlen < 5 ) {
519             log_error("packet(%d) too short\n", pkttype);
520             goto leave;
521         }
522         sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
523         sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
524         sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
525         n = pktlen;
526         sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
527         if( list_mode ) {
528             printf("\tdigest algo %d, begin of digest %02x %02x\n",
529                     sig->d.rsa.digest_algo,
530                     sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
531             printf("\trsa integer: ");
532             mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
533             putchar('\n');
534         }
535     }
536     else if( list_mode )
537         printf("\tunknown algorithm %d\n", sig->pubkey_algo );
538
539
540   leave:
541     skip_rest(inp, pktlen);
542     return 0;
543 }
544
545
546 static int
547 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
548                                              PKT_onepass_sig *ops )
549 {
550     int version;
551
552     if( pktlen < 13 ) {
553         log_error("packet(%d) too short\n", pkttype);
554         goto leave;
555     }
556     version = iobuf_get_noeof(inp); pktlen--;
557     if( version != 3 ) {
558         log_error("onepass_sig with unknown version %d\n", version);
559         goto leave;
560     }
561     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
562     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
563     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
564     ops->keyid[0] = read_32(inp); pktlen -= 4;
565     ops->keyid[1] = read_32(inp); pktlen -= 4;
566     ops->last = iobuf_get_noeof(inp); pktlen--;
567     if( list_mode )
568         printf(":onepass_sig packet: keyid %08lX%08lX\n"
569                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
570                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
571                 version, ops->sig_class,
572                 ops->digest_algo, ops->pubkey_algo, ops->last );
573
574
575   leave:
576     skip_rest(inp, pktlen);
577     return 0;
578 }
579
580
581
582
583 static int
584 parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
585                               byte *hdr, int hdrlen, PACKET *pkt )
586 {
587     int i, version, algorithm;
588     unsigned n;
589     unsigned long timestamp;
590     unsigned short valid_period;
591     int is_v4=0;
592
593     if( pkttype == PKT_PUBLIC_CERT ) {
594         pkt->pkt.public_cert->mfx.md = md_open(DIGEST_ALGO_MD5, 0);
595         md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_RMD160);
596         md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_SHA1);
597         pkt->pkt.public_cert->mfx.maxbuf_size = 1;
598         md_write(pkt->pkt.public_cert->mfx.md, hdr, hdrlen);
599         iobuf_push_filter( inp, md_filter, &pkt->pkt.public_cert->mfx );
600     }
601
602     if( pktlen < 12 ) {
603         log_error("packet(%d) too short\n", pkttype);
604         goto leave;
605     }
606     version = iobuf_get_noeof(inp); pktlen--;
607     if( version == 4 )
608         is_v4=1;
609     else if( version != 2 && version != 3 ) {
610         log_error("packet(%d) with unknown version %d\n", pkttype, version);
611         goto leave;
612     }
613
614     timestamp = read_32(inp); pktlen -= 4;
615     if( is_v4 )
616         valid_period = 0;
617     else {
618         valid_period = read_16(inp); pktlen -= 2;
619     }
620     algorithm = iobuf_get_noeof(inp); pktlen--;
621     if( list_mode )
622         printf(":%s key packet:\n"
623                "\tversion %d, created %lu, valid for %hu days\n",
624                 pkttype == PKT_PUBLIC_CERT? "public": "secret",
625                 version, timestamp, valid_period );
626     if( pkttype == PKT_SECRET_CERT )  {
627         pkt->pkt.secret_cert->timestamp = timestamp;
628         pkt->pkt.secret_cert->valid_days = valid_period;
629         pkt->pkt.secret_cert->hdrbytes = hdrlen;
630         pkt->pkt.secret_cert->version = version;
631         pkt->pkt.secret_cert->pubkey_algo = algorithm;
632     }
633     else {
634         pkt->pkt.public_cert->timestamp = timestamp;
635         pkt->pkt.public_cert->valid_days = valid_period;
636         pkt->pkt.public_cert->hdrbytes    = hdrlen;
637         pkt->pkt.public_cert->version     = version;
638         pkt->pkt.public_cert->pubkey_algo = algorithm;
639     }
640
641     if( algorithm == PUBKEY_ALGO_ELGAMAL ) {
642         MPI elg_p, elg_g, elg_y;
643         n = pktlen; elg_p = mpi_read(inp, &n, 0 ); pktlen -=n;
644         n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n;
645         n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n;
646         if( list_mode ) {
647             printf(  "\telg p: ");
648             mpi_print(stdout, elg_p, mpi_print_mode  );
649             printf("\n\telg g: ");
650             mpi_print(stdout, elg_g, mpi_print_mode  );
651             printf("\n\telg y: ");
652             mpi_print(stdout, elg_y, mpi_print_mode  );
653             putchar('\n');
654         }
655         if( pkttype == PKT_PUBLIC_CERT ) {
656             pkt->pkt.public_cert->d.elg.p = elg_p;
657             pkt->pkt.public_cert->d.elg.g = elg_g;
658             pkt->pkt.public_cert->d.elg.y = elg_y;
659         }
660         else {
661             PKT_secret_cert *cert = pkt->pkt.secret_cert;
662             byte temp[8];
663
664             pkt->pkt.secret_cert->d.elg.p = elg_p;
665             pkt->pkt.secret_cert->d.elg.g = elg_g;
666             pkt->pkt.secret_cert->d.elg.y = elg_y;
667             cert->d.elg.protect_algo = iobuf_get_noeof(inp); pktlen--;
668             if( list_mode )
669                 printf(  "\tprotect algo: %d\n", cert->d.elg.protect_algo);
670             if( cert->d.elg.protect_algo ) {
671                 cert->d.elg.is_protected = 1;
672                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
673                     temp[i] = iobuf_get_noeof(inp);
674                 if( list_mode ) {
675                     printf(  "\tprotect IV: ");
676                     for(i=0; i < 8; i++ )
677                         printf(" %02x", temp[i] );
678                     putchar('\n');
679                 }
680                 if( cert->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH )
681                     memcpy(cert->d.elg.protect.blowfish.iv, temp, 8 );
682             }
683             else
684                 cert->d.elg.is_protected = 0;
685             /* It does not make sense to read it into secure memory.
686              * If the user is so careless, not to protect his secret key,
687              * we can assume, that he operates an open system :=(.
688              * So we put the key into secure memory when we unprotect him. */
689             n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 0 ); pktlen -=n;
690
691             cert->d.elg.csum = read_16(inp); pktlen -= 2;
692             if( list_mode ) {
693                 printf("\t[secret value x is not shown]\n"
694                        "\tchecksum: %04hx\n", cert->d.elg.csum);
695             }
696           /*log_mpidump("elg p=", cert->d.elg.p );
697             log_mpidump("elg g=", cert->d.elg.g );
698             log_mpidump("elg y=", cert->d.elg.y );
699             log_mpidump("elg x=", cert->d.elg.x ); */
700         }
701     }
702     else if( algorithm == PUBKEY_ALGO_RSA ) {
703         MPI rsa_pub_mod, rsa_pub_exp;
704
705         n = pktlen; rsa_pub_mod = mpi_read(inp, &n, 0); pktlen -=n;
706         n = pktlen; rsa_pub_exp = mpi_read(inp, &n, 0 ); pktlen -=n;
707         if( list_mode ) {
708             printf(  "\tpublic modulus  n:  ");
709             mpi_print(stdout, rsa_pub_mod, mpi_print_mode  );
710             printf("\n\tpublic exponent e: ");
711             mpi_print(stdout, rsa_pub_exp, mpi_print_mode  );
712             putchar('\n');
713         }
714         if( pkttype == PKT_PUBLIC_CERT ) {
715             pkt->pkt.public_cert->d.rsa.rsa_n = rsa_pub_mod;
716             pkt->pkt.public_cert->d.rsa.rsa_e = rsa_pub_exp;
717         }
718         else {
719             PKT_secret_cert *cert = pkt->pkt.secret_cert;
720             byte temp[8];
721
722             pkt->pkt.secret_cert->d.rsa.rsa_n = rsa_pub_mod;
723             pkt->pkt.secret_cert->d.rsa.rsa_e = rsa_pub_exp;
724             cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
725             if( list_mode )
726                 printf(  "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
727             if( cert->d.rsa.protect_algo ) {
728                 cert->d.rsa.is_protected = 1;
729                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
730                     temp[i] = iobuf_get_noeof(inp);
731                 if( list_mode ) {
732                     printf(  "\tprotect IV: ");
733                     for(i=0; i < 8; i++ )
734                         printf(" %02x", temp[i] );
735                     putchar('\n');
736                 }
737                 if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
738                     memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
739             }
740             else
741                 cert->d.rsa.is_protected = 0;
742             /* (See comments at the code for elg keys) */
743             n = pktlen; cert->d.rsa.rsa_d = mpi_read(inp, &n, 0 ); pktlen -=n;
744             n = pktlen; cert->d.rsa.rsa_p = mpi_read(inp, &n, 0 ); pktlen -=n;
745             n = pktlen; cert->d.rsa.rsa_q = mpi_read(inp, &n, 0 ); pktlen -=n;
746             n = pktlen; cert->d.rsa.rsa_u = mpi_read(inp, &n, 0 ); pktlen -=n;
747
748             cert->d.rsa.csum = read_16(inp); pktlen -= 2;
749             if( list_mode ) {
750                 printf("\t[secret values d,p,q,u are not shown]\n"
751                        "\tchecksum: %04hx\n", cert->d.rsa.csum);
752             }
753          /* log_mpidump("rsa n=", cert->d.rsa.rsa_n );
754             log_mpidump("rsa e=", cert->d.rsa.rsa_e );
755             log_mpidump("rsa d=", cert->d.rsa.rsa_d );
756             log_mpidump("rsa p=", cert->d.rsa.rsa_p );
757             log_mpidump("rsa q=", cert->d.rsa.rsa_q );
758             log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */
759         }
760     }
761     else if( list_mode )
762         printf("\tunknown algorithm %d\n", algorithm );
763
764
765   leave:
766     if( pkttype == PKT_PUBLIC_CERT )
767         iobuf_pop_filter( inp, md_filter, &pkt->pkt.public_cert->mfx );
768     skip_rest(inp, pktlen);
769     return 0;
770 }
771
772
773 static int
774 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
775 {
776     byte *p;
777
778     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
779     packet->pkt.user_id->len = pktlen;
780     p = packet->pkt.user_id->name;
781     for( ; pktlen; pktlen--, p++ )
782         *p = iobuf_get_noeof(inp);
783
784     if( list_mode ) {
785         int n = packet->pkt.user_id->len;
786         printf(":user id packet: \"");
787         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
788             if( *p >= ' ' && *p <= 'z' )
789                 putchar(*p);
790             else
791                 printf("\\x%02x", *p );
792         }
793         printf("\"\n");
794     }
795     return 0;
796 }
797
798
799 static void
800 parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen )
801 {
802     int version;
803
804     version = iobuf_get_noeof(inp); pktlen--;
805     if( pkttype == PKT_PUBKEY_SUBCERT && version == '#' ) {
806         /* early versions of G10 use old comments packets; luckily all those
807          * comments are started by a hash */
808         if( list_mode ) {
809             printf(":old comment packet: \"" );
810             for( ; pktlen; pktlen-- ) {
811                 int c;
812                 c = iobuf_get_noeof(inp);
813                 if( c >= ' ' && c <= 'z' )
814                     putchar(c);
815                 else
816                     printf("\\x%02x", c );
817             }
818             printf("\"\n");
819         }
820         skip_rest(inp, pktlen);
821         return;
822     }
823
824     if( list_mode )
825         printf(":public subkey packet: \"" );
826     skip_rest(inp, pktlen);
827 }
828
829
830
831 static int
832 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
833 {
834     byte *p;
835
836     packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
837     packet->pkt.comment->len = pktlen;
838     p = packet->pkt.comment->data;
839     for( ; pktlen; pktlen--, p++ )
840         *p = iobuf_get_noeof(inp);
841
842     if( list_mode ) {
843         int n = packet->pkt.comment->len;
844         printf(":comment packet: \"");
845         for(p=packet->pkt.comment->data; n; p++, n-- ) {
846             if( *p >= ' ' && *p <= 'z' )
847                 putchar(*p);
848             else
849                 printf("\\x%02x", *p );
850         }
851         printf("\"\n");
852     }
853     return 0;
854 }
855
856
857 static void
858 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
859 {
860     int c;
861
862     c = iobuf_get_noeof(inp);
863     if( list_mode )
864         printf(":trust packet: flag=%02x\n", c );
865 }
866
867
868 static int
869 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
870 {
871     int mode, namelen;
872     PKT_plaintext *pt;
873     byte *p;
874     int c, i;
875
876     if( pktlen && pktlen < 6 ) {
877         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
878         goto leave;
879     }
880     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
881     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
882     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
883     pt->mode = mode;
884     pt->namelen = namelen;
885     if( pktlen ) {
886         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
887             pt->name[i] = iobuf_get_noeof(inp);
888     }
889     else {
890         for( i=0; i < namelen; i++ )
891             if( (c=iobuf_get(inp)) == -1 )
892                 break;
893             else
894                 pt->name[i] = c;
895     }
896     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
897     pt->len = pktlen;
898     pt->buf = inp;
899     pktlen = 0;
900
901     if( list_mode ) {
902         printf(":literal data packet:\n"
903                "\tmode %c, created %lu, name=\"",
904                     mode >= ' ' && mode <'z'? mode : '?',
905                     (ulong)pt->timestamp );
906         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
907             if( *p >= ' ' && *p <= 'z' )
908                 putchar(*p);
909             else
910                 printf("\\x%02x", *p );
911         }
912         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
913     }
914
915   leave:
916     return 0;
917 }
918
919
920 static int
921 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
922 {
923     PKT_compressed *zd;
924
925     /* pktlen is here 0, but data follows
926      * (this should be the last object in a file or
927      *  the compress algorithm should know the length)
928      */
929     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
930     zd->len = 0; /* not yet used */
931     zd->algorithm = iobuf_get_noeof(inp);
932     zd->buf = inp;
933     if( list_mode )
934         printf(":compressed packet: algo=%d\n", zd->algorithm);
935     return 0;
936 }
937
938
939 static int
940 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
941 {
942     PKT_encrypted *ed;
943
944     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
945     ed->len = pktlen;
946     ed->buf = NULL;
947     if( pktlen && pktlen < 10 ) {
948         log_error("packet(%d) too short\n", pkttype);
949         skip_rest(inp, pktlen);
950         goto leave;
951     }
952     if( list_mode )
953         if( pktlen )
954             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
955         else
956             printf(":encrypted data packet:\n\tlength: unknown\n");
957
958     ed->buf = inp;
959     pktlen = 0;
960
961   leave:
962     return 0;
963 }
964
965