armor rewritten, but still buggy
[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 );
41 static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
42 static void skip_rest( IOBUF inp, unsigned long pktlen );
43 static int  parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen,
44                                                              PACKET *packet );
45 static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
46                                                          PKT_signature *sig );
47 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
48                                                         PKT_onepass_sig *ops );
49 static int  parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
50                                       byte *hdr, int hdrlen, PACKET *packet );
51 static int  parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
52                                                            PACKET *packet );
53 static void parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen );
54 static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen );
55 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen );
56 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
57                                                                 PACKET *pkt );
58 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
59                                                            PACKET *packet );
60 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
61                                                            PACKET *packet );
62 #if 0
63 static u16
64 checksum( byte *p )
65 {
66     u16 n, a;
67
68     n = *p++ << 8;
69     n |= *p++;
70     for(a=0; n; n-- )
71         a += *p++;
72     return a;
73 }
74 #endif
75
76 static unsigned short
77 read_16(IOBUF inp)
78 {
79     unsigned short a;
80     a = iobuf_get_noeof(inp) << 8;
81     a |= iobuf_get_noeof(inp);
82     return a;
83 }
84
85 static unsigned long
86 read_32(IOBUF inp)
87 {
88     unsigned long a;
89     a =  iobuf_get_noeof(inp) << 24;
90     a |= iobuf_get_noeof(inp) << 16;
91     a |= iobuf_get_noeof(inp) << 8;
92     a |= iobuf_get_noeof(inp);
93     return a;
94 }
95
96 int
97 set_packet_list_mode( int mode )
98 {
99     int old = list_mode;
100     list_mode = mode;
101     mpi_print_mode = DBG_MPI;
102     return old;
103 }
104
105 /****************
106  * Parse a Packet and return it in packet
107  * Returns: 0 := valid packet in pkt
108  *         -1 := no more packets
109  *         >0 := error
110  * Note: The function may return an error and a partly valid packet;
111  * caller must free this packet.
112  */
113 int
114 parse_packet( IOBUF inp, PACKET *pkt )
115 {
116     int skip, rc;
117
118     do {
119         rc = parse( inp, pkt, 0, NULL, &skip );
120     } while( skip );
121     return rc;
122 }
123
124 /****************
125  * Like parse packet, but do only return packet of the given type.
126  */
127 int
128 search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
129 {
130     int skip, rc;
131
132     do {
133         rc = parse( inp, pkt, pkttype, retpos, &skip );
134     } while( skip );
135     return rc;
136 }
137
138
139 /****************
140  * Parse packet. Set the variable skip points to to 1 if the packet
141  * should be skipped; this is the case if either there is a
142  * requested packet type and the parsed packet doesn't match or the
143  * packet-type is 0, indicating deleted stuff.
144  */
145 static int
146 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip )
147 {
148     int rc, c, ctb, pkttype, lenbytes;
149     unsigned long pktlen;
150     byte hdr[5];
151     int hdrlen;
152     int pgp3 = 0;
153
154     *skip = 0;
155     assert( !pkt->pkt.generic );
156     if( retpos )
157         *retpos = iobuf_tell(inp);
158     if( (ctb = iobuf_get(inp)) == -1 )
159         return -1;
160     hdrlen=0;
161     hdr[hdrlen++] = ctb;
162     if( !(ctb & 0x80) ) {
163         log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
164         return G10ERR_INVALID_PACKET;
165     }
166     pktlen = 0;
167     pgp3 = !!(ctb & 0x40);
168     if( pgp3 ) {
169         pkttype =  ctb & 0x3f;
170         if( (c = iobuf_get(inp)) == -1 ) {
171             log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
172             return G10ERR_INVALID_PACKET;
173         }
174         hdr[hdrlen++] = c;
175         if( c < 192 )
176             pktlen = c;
177         else if( c < 224 ) {
178             pktlen = (c - 192) * 256;
179             if( (c = iobuf_get(inp)) == -1 ) {
180                 log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
181                 return G10ERR_INVALID_PACKET;
182             }
183             hdr[hdrlen++] = c;
184             pktlen += c + 192;
185         }
186         else { /* partial body length */
187             pktlen = 1 << (c & 0x1f);
188             log_debug("partial body length of %lu bytes\n", pktlen );
189             iobuf_set_partial_block_mode(inp, pktlen);
190             pktlen = 0;/* to indicate partial length */
191         }
192     }
193     else {
194         pkttype = (ctb>>2)&0xf;
195         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
196         if( !lenbytes ) {
197             pktlen = 0; /* don't know the value */
198             if( pkttype != PKT_COMPRESSED )
199                 iobuf_set_block_mode(inp, 1);
200         }
201         else {
202             for( ; lenbytes; lenbytes-- ) {
203                 pktlen <<= 8;
204                 pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
205             }
206         }
207     }
208
209     if( !pkttype || (reqtype && pkttype != reqtype) ) {
210         skip_packet(inp, pkttype, pktlen);
211         *skip = 1;
212         return 0;
213     }
214
215     if( DBG_PACKET )
216         log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n",
217                    iobuf_id(inp), pkttype, pktlen, pgp3?" (pgp3)":"" );
218     pkt->pkttype = pkttype;
219     rc = G10ERR_UNKNOWN_PACKET; /* default error */
220     switch( pkttype ) {
221       case PKT_PUBLIC_CERT:
222         pkt->pkt.public_cert = m_alloc_clear(sizeof *pkt->pkt.public_cert );
223         rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
224         break;
225       case PKT_SECRET_CERT:
226       case PKT_SECKEY_SUBCERT:
227         pkt->pkt.secret_cert = m_alloc_clear(sizeof *pkt->pkt.secret_cert );
228         rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
229         break;
230       case PKT_PUBKEY_ENC:
231         rc = parse_publickey(inp, pkttype, pktlen, pkt );
232         break;
233       case PKT_SIGNATURE:
234         pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
235         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
236         break;
237       case PKT_ONEPASS_SIG:
238         pkt->pkt.onepass_sig = m_alloc_clear(sizeof *pkt->pkt.onepass_sig );
239         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
240         break;
241       case PKT_USER_ID:
242         rc = parse_user_id(inp, pkttype, pktlen, pkt );
243         break;
244       case PKT_PUBKEY_SUBCERT:
245         parse_subkey(inp, pkttype, pktlen);
246         break;
247       case PKT_COMMENT:
248         parse_comment(inp, pkttype, pktlen);
249         break;
250       case PKT_RING_TRUST:
251         parse_trust(inp, pkttype, pktlen);
252         break;
253       case PKT_PLAINTEXT:
254         rc = parse_plaintext(inp, pkttype, pktlen, pkt );
255         break;
256       case PKT_COMPRESSED:
257         rc = parse_compressed(inp, pkttype, pktlen, pkt );
258         break;
259       case PKT_ENCRYPTED:
260         rc = parse_encrypted(inp, pkttype, pktlen, pkt );
261         break;
262       default:
263         skip_packet(inp, pkttype, pktlen);
264         break;
265     }
266
267     return rc;
268 }
269
270 static void
271 dump_hex_line( int c, int *i )
272 {
273     if( *i && !(*i%8) ) {
274         if( *i && !(*i%24) )
275             printf("\n%4d:", *i );
276         else
277             putchar(' ');
278     }
279     if( c == -1 )
280         printf(" EOF" );
281     else
282         printf(" %02x", c );
283     ++*i;
284 }
285
286
287 static void
288 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
289 {
290     if( list_mode ) {
291         printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen );
292         if( pkttype ) {
293             int c, i=0 ;
294             printf("dump:");
295             if( iobuf_in_block_mode(inp) ) {
296                 while( (c=iobuf_get(inp)) != -1 )
297                     dump_hex_line(c, &i);
298             }
299             else {
300                 for( ; pktlen; pktlen-- )
301                     dump_hex_line(iobuf_get(inp), &i);
302             }
303             putchar('\n');
304             return;
305         }
306     }
307     skip_rest(inp,pktlen);
308 }
309
310 static void
311 skip_rest( IOBUF inp, unsigned long pktlen )
312 {
313     if( iobuf_in_block_mode(inp) ) {
314         while( iobuf_get(inp) != -1 )
315                 ;
316     }
317     else {
318         for( ; pktlen; pktlen-- )
319             iobuf_get(inp);
320     }
321 }
322
323
324 static int
325 parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
326 {
327     int version;
328     unsigned n;
329     PKT_pubkey_enc *k;
330
331     k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc );
332     if( pktlen < 12 ) {
333         log_error("packet(%d) too short\n", pkttype);
334         goto leave;
335     }
336     version = iobuf_get_noeof(inp); pktlen--;
337     if( version != 2 && version != 3 ) {
338         log_error("packet(%d) with unknown version %d\n", pkttype, version);
339         goto leave;
340     }
341     k->keyid[0] = read_32(inp); pktlen -= 4;
342     k->keyid[1] = read_32(inp); pktlen -= 4;
343     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
344     if( list_mode )
345         printf(":public key encoded packet: keyid %08lX%08lX\n",
346                                       (ulong)k->keyid[0], (ulong)k->keyid[1]);
347     if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
348         n = pktlen;
349         k->d.elg.a = mpi_read(inp, &n, 0); pktlen -=n;
350         k->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
351         if( list_mode ) {
352             printf("\telg a: ");
353             mpi_print(stdout, k->d.elg.a, mpi_print_mode );
354             printf("\n\telg b: ");
355             mpi_print(stdout, k->d.elg.b, mpi_print_mode );
356             putchar('\n');
357         }
358     }
359     else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) {
360         n = pktlen;
361         k->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
362         if( list_mode ) {
363             printf("\trsa integer: ");
364             mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode );
365             putchar('\n');
366         }
367     }
368     else if( list_mode )
369         printf("\tunknown algorithm %d\n", k->pubkey_algo );
370
371
372   leave:
373     skip_rest(inp, pktlen);
374     return 0;
375 }
376
377
378 static int
379 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
380                                           PKT_signature *sig )
381 {
382     int version, md5_len;
383     unsigned n;
384
385     if( pktlen < 16 ) {
386         log_error("packet(%d) too short\n", pkttype);
387         goto leave;
388     }
389     version = iobuf_get_noeof(inp); pktlen--;
390     if( version != 2 && version != 3 ) {
391         log_error("packet(%d) with unknown version %d\n", pkttype, version);
392         goto leave;
393     }
394     md5_len = iobuf_get_noeof(inp); pktlen--;
395     sig->sig_class = iobuf_get_noeof(inp); pktlen--;
396     sig->timestamp = read_32(inp); pktlen -= 4;
397     sig->keyid[0] = read_32(inp); pktlen -= 4;
398     sig->keyid[1] = read_32(inp); pktlen -= 4;
399     sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
400     if( list_mode )
401         printf(":signature packet: keyid %08lX%08lX\n"
402                "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
403                 (ulong)sig->keyid[0], (ulong)sig->keyid[1],
404                 version, (ulong)sig->timestamp, md5_len, sig->sig_class );
405     if( sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
406         if( pktlen < 5 ) {
407             log_error("packet(%d) too short\n", pkttype);
408             goto leave;
409         }
410         sig->d.elg.digest_algo = iobuf_get_noeof(inp); pktlen--;
411         sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
412         sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
413         n = pktlen;
414         sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n;
415         sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
416         if( list_mode ) {
417             printf("\tdigest algo %d, begin of digest %02x %02x\n",
418                     sig->d.elg.digest_algo,
419                     sig->d.elg.digest_start[0], sig->d.elg.digest_start[1] );
420             printf("\telg a: ");
421             mpi_print(stdout, sig->d.elg.a, mpi_print_mode );
422             printf("\n\telg b: ");
423             mpi_print(stdout, sig->d.elg.b, mpi_print_mode );
424             putchar('\n');
425         }
426     }
427     else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
428         if( pktlen < 5 ) {
429             log_error("packet(%d) too short\n", pkttype);
430             goto leave;
431         }
432         sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
433         sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
434         sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
435         n = pktlen;
436         sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n;
437         if( list_mode ) {
438             printf("\tdigest algo %d, begin of digest %02x %02x\n",
439                     sig->d.rsa.digest_algo,
440                     sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
441             printf("\trsa integer: ");
442             mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
443             putchar('\n');
444         }
445     }
446     else if( list_mode )
447         printf("\tunknown algorithm %d\n", sig->pubkey_algo );
448
449
450   leave:
451     skip_rest(inp, pktlen);
452     return 0;
453 }
454
455
456 static int
457 parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
458                                              PKT_onepass_sig *ops )
459 {
460     int version;
461
462     if( pktlen < 13 ) {
463         log_error("packet(%d) too short\n", pkttype);
464         goto leave;
465     }
466     version = iobuf_get_noeof(inp); pktlen--;
467     if( version != 3 ) {
468         log_error("onepass_sig with unknown version %d\n", version);
469         goto leave;
470     }
471     ops->sig_class = iobuf_get_noeof(inp); pktlen--;
472     ops->digest_algo = iobuf_get_noeof(inp); pktlen--;
473     ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
474     ops->keyid[0] = read_32(inp); pktlen -= 4;
475     ops->keyid[1] = read_32(inp); pktlen -= 4;
476     ops->last = iobuf_get_noeof(inp); pktlen--;
477     if( list_mode )
478         printf(":onepass_sig packet: keyid %08lX%08lX\n"
479                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
480                 (ulong)ops->keyid[0], (ulong)ops->keyid[1],
481                 version, ops->sig_class,
482                 ops->digest_algo, ops->pubkey_algo, ops->last );
483
484
485   leave:
486     skip_rest(inp, pktlen);
487     return 0;
488 }
489
490
491
492
493 static int
494 parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
495                               byte *hdr, int hdrlen, PACKET *pkt )
496 {
497     int i, version, algorithm;
498     unsigned n;
499     unsigned long timestamp;
500     unsigned short valid_period;
501     int is_v4=0;
502
503     if( pkttype == PKT_PUBLIC_CERT ) {
504         pkt->pkt.public_cert->mfx.md = md_open(DIGEST_ALGO_MD5, 0);
505         md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_RMD160);
506         md_enable(pkt->pkt.public_cert->mfx.md, DIGEST_ALGO_SHA1);
507         pkt->pkt.public_cert->mfx.maxbuf_size = 1;
508         md_write(pkt->pkt.public_cert->mfx.md, hdr, hdrlen);
509         iobuf_push_filter( inp, md_filter, &pkt->pkt.public_cert->mfx );
510     }
511
512     if( pktlen < 12 ) {
513         log_error("packet(%d) too short\n", pkttype);
514         goto leave;
515     }
516     version = iobuf_get_noeof(inp); pktlen--;
517     if( version == 4 )
518         is_v4=1;
519     else if( version != 2 && version != 3 ) {
520         log_error("packet(%d) with unknown version %d\n", pkttype, version);
521         goto leave;
522     }
523
524     timestamp = read_32(inp); pktlen -= 4;
525     if( is_v4 )
526         valid_period = 0;
527     else {
528         valid_period = read_16(inp); pktlen -= 2;
529     }
530     algorithm = iobuf_get_noeof(inp); pktlen--;
531     if( list_mode )
532         printf(":%s key packet:\n"
533                "\tversion %d, created %lu, valid for %hu days\n",
534                 pkttype == PKT_PUBLIC_CERT? "public": "secret",
535                 version, timestamp, valid_period );
536     if( pkttype == PKT_SECRET_CERT )  {
537         pkt->pkt.secret_cert->timestamp = timestamp;
538         pkt->pkt.secret_cert->valid_days = valid_period;
539         pkt->pkt.secret_cert->hdrbytes = hdrlen;
540         pkt->pkt.secret_cert->version = version;
541         pkt->pkt.secret_cert->pubkey_algo = algorithm;
542     }
543     else {
544         pkt->pkt.public_cert->timestamp = timestamp;
545         pkt->pkt.public_cert->valid_days = valid_period;
546         pkt->pkt.public_cert->hdrbytes    = hdrlen;
547         pkt->pkt.public_cert->version     = version;
548         pkt->pkt.public_cert->pubkey_algo = algorithm;
549     }
550
551     if( algorithm == PUBKEY_ALGO_ELGAMAL ) {
552         MPI elg_p, elg_g, elg_y;
553         n = pktlen; elg_p = mpi_read(inp, &n, 0 ); pktlen -=n;
554         n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n;
555         n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n;
556         if( list_mode ) {
557             printf(  "\telg p: ");
558             mpi_print(stdout, elg_p, mpi_print_mode  );
559             printf("\n\telg g: ");
560             mpi_print(stdout, elg_g, mpi_print_mode  );
561             printf("\n\telg y: ");
562             mpi_print(stdout, elg_y, mpi_print_mode  );
563             putchar('\n');
564         }
565         if( pkttype == PKT_PUBLIC_CERT ) {
566             pkt->pkt.public_cert->d.elg.p = elg_p;
567             pkt->pkt.public_cert->d.elg.g = elg_g;
568             pkt->pkt.public_cert->d.elg.y = elg_y;
569         }
570         else {
571             PKT_secret_cert *cert = pkt->pkt.secret_cert;
572             byte temp[8];
573
574             pkt->pkt.secret_cert->d.elg.p = elg_p;
575             pkt->pkt.secret_cert->d.elg.g = elg_g;
576             pkt->pkt.secret_cert->d.elg.y = elg_y;
577             cert->d.elg.protect_algo = iobuf_get_noeof(inp); pktlen--;
578             if( list_mode )
579                 printf(  "\tprotect algo: %d\n", cert->d.elg.protect_algo);
580             if( cert->d.elg.protect_algo ) {
581                 cert->d.elg.is_protected = 1;
582                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
583                     temp[i] = iobuf_get_noeof(inp);
584                 if( list_mode ) {
585                     printf(  "\tprotect IV: ");
586                     for(i=0; i < 8; i++ )
587                         printf(" %02x", temp[i] );
588                     putchar('\n');
589                 }
590                 if( cert->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH )
591                     memcpy(cert->d.elg.protect.blowfish.iv, temp, 8 );
592             }
593             else
594                 cert->d.elg.is_protected = 0;
595             /* It does not make sense to read it into secure memory.
596              * If the user is so careless, not to protect his secret key,
597              * we can assume, that he operates an open system :=(.
598              * So we put the key into secure memory when we unprotect him. */
599             n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 0 ); pktlen -=n;
600
601             cert->d.elg.csum = read_16(inp); pktlen -= 2;
602             if( list_mode ) {
603                 printf("\t[secret value x is not shown]\n"
604                        "\tchecksum: %04hx\n", cert->d.elg.csum);
605             }
606           /*log_mpidump("elg p=", cert->d.elg.p );
607             log_mpidump("elg g=", cert->d.elg.g );
608             log_mpidump("elg y=", cert->d.elg.y );
609             log_mpidump("elg x=", cert->d.elg.x ); */
610         }
611     }
612     else if( algorithm == PUBKEY_ALGO_RSA ) {
613         MPI rsa_pub_mod, rsa_pub_exp;
614
615         n = pktlen; rsa_pub_mod = mpi_read(inp, &n, 0); pktlen -=n;
616         n = pktlen; rsa_pub_exp = mpi_read(inp, &n, 0 ); pktlen -=n;
617         if( list_mode ) {
618             printf(  "\tpublic modulus  n:  ");
619             mpi_print(stdout, rsa_pub_mod, mpi_print_mode  );
620             printf("\n\tpublic exponent e: ");
621             mpi_print(stdout, rsa_pub_exp, mpi_print_mode  );
622             putchar('\n');
623         }
624         if( pkttype == PKT_PUBLIC_CERT ) {
625             pkt->pkt.public_cert->d.rsa.rsa_n = rsa_pub_mod;
626             pkt->pkt.public_cert->d.rsa.rsa_e = rsa_pub_exp;
627         }
628         else {
629             PKT_secret_cert *cert = pkt->pkt.secret_cert;
630             byte temp[8];
631
632             pkt->pkt.secret_cert->d.rsa.rsa_n = rsa_pub_mod;
633             pkt->pkt.secret_cert->d.rsa.rsa_e = rsa_pub_exp;
634             cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
635             if( list_mode )
636                 printf(  "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
637             if( cert->d.rsa.protect_algo ) {
638                 cert->d.rsa.is_protected = 1;
639                 for(i=0; i < 8 && pktlen; i++, pktlen-- )
640                     temp[i] = iobuf_get_noeof(inp);
641                 if( list_mode ) {
642                     printf(  "\tprotect IV: ");
643                     for(i=0; i < 8; i++ )
644                         printf(" %02x", temp[i] );
645                     putchar('\n');
646                 }
647                 if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
648                     memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
649             }
650             else
651                 cert->d.rsa.is_protected = 0;
652             /* (See comments at the code for elg keys) */
653             n = pktlen; cert->d.rsa.rsa_d = mpi_read(inp, &n, 0 ); pktlen -=n;
654             n = pktlen; cert->d.rsa.rsa_p = mpi_read(inp, &n, 0 ); pktlen -=n;
655             n = pktlen; cert->d.rsa.rsa_q = mpi_read(inp, &n, 0 ); pktlen -=n;
656             n = pktlen; cert->d.rsa.rsa_u = mpi_read(inp, &n, 0 ); pktlen -=n;
657
658             cert->d.rsa.csum = read_16(inp); pktlen -= 2;
659             if( list_mode ) {
660                 printf("\t[secret values d,p,q,u are not shown]\n"
661                        "\tchecksum: %04hx\n", cert->d.rsa.csum);
662             }
663          /* log_mpidump("rsa n=", cert->d.rsa.rsa_n );
664             log_mpidump("rsa e=", cert->d.rsa.rsa_e );
665             log_mpidump("rsa d=", cert->d.rsa.rsa_d );
666             log_mpidump("rsa p=", cert->d.rsa.rsa_p );
667             log_mpidump("rsa q=", cert->d.rsa.rsa_q );
668             log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */
669         }
670     }
671     else if( list_mode )
672         printf("\tunknown algorithm %d\n", algorithm );
673
674
675   leave:
676     if( pkttype == PKT_PUBLIC_CERT )
677         iobuf_pop_filter( inp, md_filter, &pkt->pkt.public_cert->mfx );
678     skip_rest(inp, pktlen);
679     return 0;
680 }
681
682
683 static int
684 parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
685 {
686     byte *p;
687
688     packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
689     packet->pkt.user_id->len = pktlen;
690     p = packet->pkt.user_id->name;
691     for( ; pktlen; pktlen--, p++ )
692         *p = iobuf_get_noeof(inp);
693
694     if( list_mode ) {
695         int n = packet->pkt.user_id->len;
696         printf(":user id packet: \"");
697         for(p=packet->pkt.user_id->name; n; p++, n-- ) {
698             if( *p >= ' ' && *p <= 'z' )
699                 putchar(*p);
700             else
701                 printf("\\x%02x", *p );
702         }
703         printf("\"\n");
704     }
705     return 0;
706 }
707
708
709 static void
710 parse_subkey( IOBUF inp, int pkttype, unsigned long pktlen )
711 {
712     int version;
713
714     version = iobuf_get_noeof(inp); pktlen--;
715     if( pkttype == PKT_PUBKEY_SUBCERT && version == '#' ) {
716         /* early versions of G10 use old comments packets; luckily all those
717          * comments are are started by a hash */
718         if( list_mode ) {
719             printf(":old comment packet: \"" );
720             for( ; pktlen; pktlen-- ) {
721                 int c;
722                 c = iobuf_get_noeof(inp);
723                 if( c >= ' ' && c <= 'z' )
724                     putchar(c);
725                 else
726                     printf("\\x%02x", c );
727             }
728             printf("\"\n");
729         }
730         skip_rest(inp, pktlen);
731         return;
732     }
733
734     if( list_mode )
735         printf(":public subkey packet: \"" );
736     skip_rest(inp, pktlen);
737 }
738
739
740
741 static void
742 parse_comment( IOBUF inp, int pkttype, unsigned long pktlen )
743 {
744     if( list_mode ) {
745         printf(":comment packet: \"" );
746         for( ; pktlen; pktlen-- ) {
747             int c;
748             c = iobuf_get_noeof(inp);
749             if( c >= ' ' && c <= 'z' )
750                 putchar(c);
751             else
752                 printf("\\x%02x", c );
753         }
754         printf("\"\n");
755     }
756     skip_rest(inp, pktlen);
757 }
758
759
760 static void
761 parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
762 {
763     int c;
764
765     c = iobuf_get_noeof(inp);
766     if( list_mode )
767         printf(":trust packet: flag=%02x\n", c );
768   #if 0 /* fixme: depending on the context we have different interpretations*/
769     if( prev_packet_is_a_key_packet ) {
770         int ot = c & 7;   /* ownertrust bits (for the key owner) */
771
772             !ot ? "undefined" :
773         ot == 1 ? "unknown"   : /* we don't know the owner of this key */
774         ot == 2 ? "no"        : /* usually we do not trust this key owner */
775                                 /* to sign other keys */
776         ot == 5 ? "usually"   : /* usually we trust this key owner to sign */
777         ot == 6 ? "always"    : /* always trust this key owner to sign */
778         ot == 7 ? "ultimate"  : /* also present in the secret keyring */
779               ""                /* reserved value */
780         if( c & (1<<5) )
781             "key is disabled"
782         if( c & (1<<7) )
783             "buckstop"
784     else if( prev_packet_is_user_is_packet ) {
785             int kl = c & 3; /* keylegit bits */
786         0 = "unknown, undefined, or uninitialized trust"
787         1 = "we do not trust this key's ownership"
788         2 = "we have marginal confidence of this key's ownership"
789         3 = "we completely trust this key's ownership."
790         if( c & 0x80 )
791             "warnonly"
792     else if( prev_packet_is_a_signature ) {
793     }
794   #endif
795 }
796
797
798 static int
799 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
800 {
801     int mode, namelen;
802     PKT_plaintext *pt;
803     byte *p;
804     int c, i;
805
806     if( pktlen && pktlen < 6 ) {
807         log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
808         goto leave;
809     }
810     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
811     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
812     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
813     pt->mode = mode;
814     pt->namelen = namelen;
815     if( pktlen ) {
816         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
817             pt->name[i] = iobuf_get_noeof(inp);
818     }
819     else {
820         for( i=0; i < namelen; i++ )
821             if( (c=iobuf_get(inp)) == -1 )
822                 break;
823             else
824                 pt->name[i] = c;
825     }
826     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
827     pt->len = pktlen;
828     pt->buf = inp;
829     pktlen = 0;
830
831     if( list_mode ) {
832         /* a value if 'c' is used by armor to indicate a faked packet
833          * it should be considered as 't' */
834         printf(":literal data packet:\n"
835                "\tmode %c, created %lu, name=\"",
836                     mode >= ' ' && mode <'z'? mode : '?',
837                     (ulong)pt->timestamp );
838         for(p=pt->name,i=0; i < namelen; p++, i++ ) {
839             if( *p >= ' ' && *p <= 'z' )
840                 putchar(*p);
841             else
842                 printf("\\x%02x", *p );
843         }
844         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
845     }
846
847   leave:
848     return 0;
849 }
850
851
852 static int
853 parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
854 {
855     PKT_compressed *zd;
856
857     /* pktlen is here 0, but data follows
858      * (this should be the last object in a file or
859      *  the compress algorithm should know the length)
860      */
861     zd = pkt->pkt.compressed =  m_alloc(sizeof *pkt->pkt.compressed );
862     zd->len = 0; /* not yet used */
863     zd->algorithm = iobuf_get_noeof(inp);
864     zd->buf = inp;
865     if( list_mode )
866         printf(":compressed packet: algo=%d\n", zd->algorithm);
867     return 0;
868 }
869
870
871 static int
872 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
873 {
874     PKT_encrypted *ed;
875
876     ed = pkt->pkt.encrypted =  m_alloc(sizeof *pkt->pkt.encrypted );
877     ed->len = pktlen;
878     ed->buf = NULL;
879     if( pktlen && pktlen < 10 ) {
880         log_error("packet(%d) too short\n", pkttype);
881         skip_rest(inp, pktlen);
882         goto leave;
883     }
884     if( list_mode )
885         if( pktlen )
886             printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
887         else
888             printf(":encrypted data packet:\n\tlength: unknown\n");
889
890     ed->buf = inp;
891     pktlen = 0;
892
893   leave:
894     return 0;
895 }
896
897