/[winpt]/trunk/Gnupg/parse-packet.c
ViewVC logotype

Diff of /trunk/Gnupg/parse-packet.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 309 by twoaday, Sat Apr 7 11:07:07 2007 UTC
# Line 1  Line 1 
1  /* parse-packet.c  - read packets  /* parse-packet.c  - read packets
2   * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.   * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3   *   *
4   * This file is part of GnuPG.   * This file is part of GnuPG.
5   *   *
6   * GnuPG is free software; you can redistribute it and/or modify   * GnuPG is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * 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   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * GnuPG is distributed in the hope that it will be useful,   * GnuPG is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20    
21  #include <stdio.h>  #ifdef HAVE_CONFIG_H
22  #include <stdlib.h>  #include <config.h>
23  #include <string.h>  #endif
24  #include <time.h>  
25  #include <assert.h>  #include <stdio.h>
26  #include <process.h>  #include <stdio.h>
27  #include <sys/types.h>  #include <stdlib.h>
28    #include <string.h>
29  #include "openpgp.h"  #include <time.h>
30  #include "packet.h"  #include <assert.h>
31  #include "md.h"  #include <process.h>
32    #include <sys/types.h>
33  static int mpi_print_mode = 0;  
34  static int list_mode = 0;  #include "openpgp.h"
35    #include "packet.h"
36  static int  parse( gpg_iobuf_t inp, PACKET *pkt, int onlykeypkts,  #include "md.h"
37                    _off_t *retpos, int *skip, gpg_iobuf_t out, int do_skip );  
38  static int  copy_packet( gpg_iobuf_t inp, gpg_iobuf_t out, int pkttype,  static int mpi_print_mode = 0;
39                                                 unsigned long pktlen );  static int list_mode = 0;
40  static void skip_packet( gpg_iobuf_t inp, int pkttype, unsigned long pktlen );  
41  static void skip_rest( gpg_iobuf_t inp, unsigned long pktlen );  static int  parse( gpg_iobuf_t inp, PACKET *pkt, int onlykeypkts,
42  static void *read_rest( gpg_iobuf_t inp, size_t pktlen );                    _off_t *retpos, int *skip, gpg_iobuf_t out, int do_skip );
43  static int  parse_symkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  static int  copy_packet( gpg_iobuf_t inp, gpg_iobuf_t out, int pkttype,
44                                                               PACKET *packet );                                                 unsigned long pktlen );
45  static int  parse_pubkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  static void skip_packet( gpg_iobuf_t inp, int pkttype, unsigned long pktlen );
46                                                               PACKET *packet );  static void skip_rest( gpg_iobuf_t inp, unsigned long pktlen );
47  static int  parse_signature( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  static void *read_rest( gpg_iobuf_t inp, size_t pktlen );
48                                                           PKT_signature *sig );  static int  parse_symkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
49  static int  parse_onepass_sig( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                               PACKET *packet );
50                                                          PKT_onepass_sig *ops );  static int  parse_pubkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
51  static int  parse_key( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                               PACKET *packet );
52                                        byte *hdr, int hdrlen, PACKET *packet );  static int  parse_signature( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
53  static int  parse_user_id( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                           PKT_signature *sig );
54                                                             PACKET *packet );  static int  parse_onepass_sig( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
55  static int  parse_attribute( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                          PKT_onepass_sig *ops );
56                                                             PACKET *packet );  static int  parse_key( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
57  static int  parse_comment( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                        byte *hdr, int hdrlen, PACKET *packet );
58                                                             PACKET *packet );  static int  parse_user_id( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
59  static void parse_trust( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                             PACKET *packet );
60                                                             PACKET *packet );  static int  parse_attribute( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
61  static int  parse_plaintext( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                             PACKET *packet );
62                                                 PACKET *packet, int new_ctb);  static int  parse_comment( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
63  static int  parse_compressed( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                             PACKET *packet );
64                                                 PACKET *packet, int new_ctb );  static void parse_trust( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
65  static int  parse_encrypted( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                             PACKET *packet );
66                                                 PACKET *packet, int new_ctb);  static int  parse_plaintext( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
67  static int  parse_mdc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                 PACKET *packet, int new_ctb);
68                                                 PACKET *packet, int new_ctb);  static int  parse_compressed( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
69  static int  parse_gpg_control( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,                                                 PACKET *packet, int new_ctb );
70                                 PACKET *packet );  static int  parse_encrypted( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
71                                                   PACKET *packet, int new_ctb);
72  static unsigned short  static int  parse_mdc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
73  read_16(gpg_iobuf_t inp)                                                 PACKET *packet, int new_ctb);
74  {  static int  parse_gpg_control( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
75      unsigned short a;                                 PACKET *packet );
76      a = gpg_iobuf_get_noeof(inp) << 8;  
77      a |= gpg_iobuf_get_noeof(inp);  static unsigned short
78      return a;  read_16(gpg_iobuf_t inp)
79  }  {
80        unsigned short a;
81  static unsigned long      a = gpg_iobuf_get_noeof(inp) << 8;
82  read_32(gpg_iobuf_t inp)      a |= gpg_iobuf_get_noeof(inp);
83  {      return a;
84      unsigned long a;  }
85      a =  gpg_iobuf_get_noeof(inp) << 24;  
86      a |= gpg_iobuf_get_noeof(inp) << 16;  static unsigned long
87      a |= gpg_iobuf_get_noeof(inp) << 8;  read_32(gpg_iobuf_t inp)
88      a |= gpg_iobuf_get_noeof(inp);  {
89      return a;      unsigned long a;
90  }      a =  gpg_iobuf_get_noeof(inp) << 24;
91        a |= gpg_iobuf_get_noeof(inp) << 16;
92  static unsigned long      a |= gpg_iobuf_get_noeof(inp) << 8;
93  buffer_to_u32( const unsigned char *buffer )      a |= gpg_iobuf_get_noeof(inp);
94  {      return a;
95      unsigned long a;  }
96      a =  *buffer << 24;  
97      a |= buffer[1] << 16;  static unsigned long
98      a |= buffer[2] << 8;  buffer_to_u32( const unsigned char *buffer )
99      a |= buffer[3];  {
100      return a;      unsigned long a;
101  }      a =  *buffer << 24;
102        a |= buffer[1] << 16;
103  int      a |= buffer[2] << 8;
104  set_packet_list_mode( int mode )      a |= buffer[3];
105  {      return a;
106      int old = list_mode;  }
107      list_mode = mode;  
108      mpi_print_mode = 0;  
     return old;  
 }  
   
 static void  
 unknown_pubkey_warning( int algo )  
 {  
     static byte unknown_pubkey_algos[256];  
       
     algo &= 0xff;  
     if( !unknown_pubkey_algos[algo] ) {  
         unknown_pubkey_algos[algo] = 1;  
     }  
 }  
   
 static const char *  
 strtimestamp( unsigned long stamp )  
 {  
     static char buffer[11+5];  
     struct tm *tp;  
     time_t atime = stamp;  
       
     if (atime < 0) {  
         strcpy (buffer, "????" "-??" "-??");  
     }  
     else {  
         tp = gmtime( &atime );  
         sprintf(buffer,"%04d-%02d-%02d",  
                 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );  
     }  
     return buffer;  
 }  
   
 static const char *  
 strtimevalue( unsigned long value )  
 {  
     static char buffer[30];  
     unsigned int years, days, hours, minutes;  
       
     value /= 60;  
     minutes = value % 60;  
     value /= 60;  
     hours = value % 24;  
     value /= 24;  
     days = value % 365;  
     value /= 365;  
     years = value;  
       
     sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );  
     if( years )  
         return buffer;  
     if( days )  
         return strchr( buffer, 'y' ) + 1;  
     return strchr( buffer, 'd' ) + 1;  
 }  
   
   
 static gpg_mpi_t  
 mpi_read( gpg_iobuf_t inp, size_t *ret_n, int flags )  
 {  
     gpg_mpi_t a;  
     int i = 0, j = 0;  
     u32 t;  
     size_t n;  
       
     a = calloc( 1, sizeof *a );  
     a->nbits = read_16( inp );  
     n = (a->nbits + 7) / 8;          
     a->alloced = n;  
     a->d = calloc( n, 4 );  
     i = 4 - n % 4;  
     i %= 4;  
     j = (n+4-1) / 4;      
     for( ; j > 0; j-- ) {  
         t = 0;  
         for( ; i < 4; i++ ) {  
             t <<= 8;  
             t |= gpg_iobuf_get( inp ) & 0xff;  
         }  
         i = 0;  
         a->d[j-1] = t;  
     }  
     if( *ret_n )  
         *ret_n = n + 2;  
       
     return a;  
 }  
   
 void  
 mpi_print( FILE *fp, gpg_mpi_t a, int mode )  
 {  
     int i;  
     for( i = 0; i < a->alloced / 4; i++ )  
         printf( "%08x", a->d[i] );  
 }  
   
 static void  
 mpi_set_protect_flag( gpg_mpi_t a )  
 {  
     a->flags = 1;  
 }  
   
 static gpg_mpi_t  
 mpi_set_opaque( gpg_mpi_t a, void *p, int len )  
 {  
     if( !a ) {  
         a = calloc( 1, sizeof *a );  
     }  
       
     if( a->flags & 4 )  
         safe_free( a->d );  
     else {  
         safe_free( a->d );  
     }  
       
     a->d = p;  
     a->alloced = 0;  
     a->nlimbs = 0;  
     a->nbits = len;  
     a->flags = 4;  
     return a;  
 }  
   
 void  
 free_symkey_enc( PKT_symkey_enc *enc )  
 {  
     safe_free(enc);  
 }  
   
 void  
 free_pubkey_enc( PKT_pubkey_enc *enc )  
 {  
     int n, i;  
     n = pubkey_get_nenc( enc->pubkey_algo );  
     if( !n )  
         safe_free(enc->data[0]);  
     for(i=0; i < n; i++ )  
         safe_free( enc->data[i] );  
     safe_free(enc);  
 }  
   
 void  
 free_seckey_enc( PKT_signature *sig )  
 {  
     int n, i;  
       
     n = pubkey_get_nsig( sig->pubkey_algo );  
     if( !n )  
         safe_free(sig->data[0]);  
     for(i=0; i < n; i++ )  
         safe_free( sig->data[i] );  
       
     safe_free(sig->revkey);  
     safe_free(sig->hashed);  
     safe_free(sig->unhashed);  
     safe_free(sig);  
 }  
   
   
   
 void  
 release_public_key_parts( PKT_public_key *pk )  
 {  
     int n, i;  
     n = pubkey_get_npkey( pk->pubkey_algo );  
     if( !n )  
         safe_free(pk->pkey[0]);  
     for(i=0; i < n; i++ ) {  
         safe_free( pk->pkey[i] );  
         pk->pkey[i] = NULL;  
     }  
     if (pk->prefs) {  
         safe_free (pk->prefs);  
         pk->prefs = NULL;  
     }  
     if( pk->namehash ) {  
         safe_free(pk->namehash);  
         pk->namehash = NULL;  
     }  
     if (pk->user_id) {  
         free_user_id (pk->user_id);  
         pk->user_id = NULL;  
     }  
     if (pk->revkey) {  
         safe_free(pk->revkey);  
         pk->revkey=NULL;  
         pk->numrevkeys=0;  
     }  
 }  
   
   
 void  
 free_public_key( PKT_public_key *pk )  
 {  
     release_public_key_parts( pk );  
     safe_free(pk);  
 }  
   
   
 int  
 pubkey_get_nenc( int algo )  
 {  
     switch( algo ) {  
     case 1:  
     case 2:  
     case 3:  return 1;            
     case 16:  
     case 20: return 2;  
     }  
     return 0;  
 }  
   
 int  
 pubkey_get_nsig( algo )  
 {  
     switch( algo ) {  
     case  1:  
     case  2:  
     case  3: return 1;  
     case 17:  
     case 16:  
     case 20: return 2;  
     }  
     return 0;  
 }  
   
 int  
 pubkey_get_npkey( int algo )  
 {        
     if( is_ELGAMAL( algo ) )   return 3;          
     else if ( algo == 17 )     return 4;  
     else if ( is_RSA( algo ) ) return 2;  
     return 0;  
 } /* cdk_pk_get_npkey */  
   
 int  
 pubkey_get_nskey( int algo )  
 {  
     if ( is_ELGAMAL( algo ) ) return 4;  
     else if ( algo == 17 )    return 5;  
     else if ( is_RSA( algo ) )return 6;  
     return 0;  
 } /* cdk_pk_get_nskey */  
   
   
 static subpktarea_t *  
 cp_subpktarea (subpktarea_t *s )  
 {  
     subpktarea_t *d;  
       
     if( !s )  
         return NULL;  
     d = malloc (sizeof (*d) + s->size - 1 );  
     d->size = s->size;  
     d->len = s->len;  
     memcpy (d->data, s->data, s->len);  
     return d;  
 }  
   
 /*  
  * Return a copy of the preferences  
  */  
 prefitem_t *  
 copy_prefs (const prefitem_t *prefs)  
 {  
     size_t n;  
     prefitem_t *new;  
       
     if (!prefs)  
         return NULL;  
       
     for (n=0; prefs[n].type; n++)  
         ;  
     new = malloc ( sizeof (*new) * (n+1));  
     for (n=0; prefs[n].type; n++) {  
         new[n].type = prefs[n].type;  
         new[n].value = prefs[n].value;  
     }  
     new[n].type = PREFTYPE_NONE;  
     new[n].value = 0;  
       
     return new;  
 }  
   
 /****************  
  * Replace all common parts of a sk by the one from the public key.  
  * This is a hack and a better solution will be to just store the real secret  
  * parts somewhere and don't duplicate all the other stuff.  
  */  
 void  
 copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )  
 {  
     sk->expiredate  = pk->expiredate;      
     sk->pubkey_algo = pk->pubkey_algo;      
     sk->pubkey_usage= pk->pubkey_usage;  
     sk->req_usage   = pk->req_usage;  
     sk->req_algo    = pk->req_algo;  
     sk->has_expired = pk->has_expired;      
     sk->is_revoked  = pk->is_revoked;      
     sk->is_valid    = pk->is_valid;      
     sk->main_keyid[0]= pk->main_keyid[0];  
     sk->main_keyid[1]= pk->main_keyid[1];  
     sk->keyid[0]    = pk->keyid[0];  
     sk->keyid[1]    = pk->keyid[1];  
 }  
   
 void  
 release_secret_key_parts( PKT_secret_key *sk )  
 {  
     int n, i;  
       
     n = pubkey_get_nskey( sk->pubkey_algo );  
     if( !n )  
         safe_free(sk->skey[0]);  
     for(i=0; i < n; i++ ) {  
         safe_free( sk->skey[i] );  
         sk->skey[i] = NULL;  
     }  
 }  
   
 void  
 free_secret_key( PKT_secret_key *sk )  
 {  
     release_secret_key_parts( sk );  
     safe_free(sk);  
 }  
   
 void  
 free_comment( PKT_comment *rem )  
 {  
     safe_free(rem);  
 }  
   
 void  
 free_attributes(PKT_user_id *uid)  
 {  
     safe_free(uid->attribs);  
     safe_free(uid->attrib_data);  
       
     uid->attribs=NULL;  
     uid->attrib_data=NULL;  
     uid->attrib_len=0;  
 }  
   
 void  
 free_user_id (PKT_user_id *uid)  
 {  
     assert (uid->ref > 0);  
     if (--uid->ref)  
         return;  
       
     free_attributes(uid);  
       
     if (uid->prefs)  
         safe_free (uid->prefs);  
     safe_free (uid);  
 }  
   
 void  
 free_compressed( PKT_compressed *zd )  
 {  
     if( zd->buf ) { /* have to skip some bytes */  
         /* don't have any information about the length, so  
          * we assume this is the last packet */  
         while( gpg_iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )  
             ;  
     }  
     safe_free(zd);  
 }  
   
 void  
 free_encrypted( PKT_encrypted *ed )  
 {  
     if( ed->buf ) { /* have to skip some bytes */  
         if( gpg_iobuf_in_block_mode(ed->buf) ) {  
             while( gpg_iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )  
                 ;  
         }  
         else {  
             while( ed->len ) { /* skip the packet */  
                 int n = gpg_iobuf_read( ed->buf, NULL, ed->len );  
                 if( n == -1 )  
                     ed->len = 0;  
                 else  
                     ed->len -= n;  
             }  
         }  
     }  
     safe_free(ed);  
 }  
   
   
 void  
 free_plaintext( PKT_plaintext *pt )  
 {  
     if( pt->buf ) { /* have to skip some bytes */  
         if( gpg_iobuf_in_block_mode(pt->buf) ) {  
             while( gpg_iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )  
                 ;  
         }  
         else {  
             while( pt->len ) { /* skip the packet */  
                 int n = gpg_iobuf_read( pt->buf, NULL, pt->len );  
                 if( n == -1 )  
                     pt->len = 0;  
                 else  
                     pt->len -= n;  
             }  
         }  
     }  
     safe_free(pt);  
 }  
   
 /****************  
  * Free the packet in pkt.  
  */  
 void  
 gpg_free_packet( PACKET *pkt )  
 {  
     if( !pkt || !pkt->pkt.generic )  
         return;  
       
     switch( pkt->pkttype ) {  
     case PKT_SIGNATURE:  
         free_seckey_enc( pkt->pkt.signature );  
         break;  
     case PKT_PUBKEY_ENC:  
         free_pubkey_enc( pkt->pkt.pubkey_enc );  
         break;  
     case PKT_SYMKEY_ENC:  
         free_symkey_enc( pkt->pkt.symkey_enc );  
         break;  
     case PKT_PUBLIC_KEY:  
     case PKT_PUBLIC_SUBKEY:  
         free_public_key( pkt->pkt.public_key );  
         break;  
     case PKT_SECRET_KEY:  
     case PKT_SECRET_SUBKEY:  
         free_secret_key( pkt->pkt.secret_key );  
         break;  
     case PKT_COMMENT:  
         free_comment( pkt->pkt.comment );  
         break;  
     case PKT_USER_ID:  
         free_user_id( pkt->pkt.user_id );  
         break;  
     case PKT_COMPRESSED:  
         free_compressed( pkt->pkt.compressed);  
         break;  
     case PKT_ENCRYPTED:  
     case PKT_ENCRYPTED_MDC:  
         free_encrypted( pkt->pkt.encrypted );  
         break;  
     case PKT_PLAINTEXT:  
         free_plaintext( pkt->pkt.plaintext );  
         break;  
     default:  
         safe_free( pkt->pkt.generic );  
         break;  
     }  
     pkt->pkt.generic = NULL;  
 }  
   
   
   
 /****************  
  * Parse a Packet and return it in packet  
  * Returns: 0 := valid packet in pkt  
  *         -1 := no more packets  
  *         >0 := error  
  * Note: The function may return an error and a partly valid packet;  
  * caller must free this packet.  
  */  
 int  
 gpg_parse_packet( gpg_iobuf_t inp, PACKET *pkt )  
 {  
     int skip, rc;  
       
     do {  
         rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );  
     } while( skip );  
     return rc;  
 }  
   
 /****************  
  * Like parse packet, but only return secret or public (sub)key packets.  
  */  
 int  
 search_packet( gpg_iobuf_t inp, PACKET *pkt, _off_t *retpos, int with_uid )  
 {  
     int skip, rc;  
       
     do {  
         rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 );  
     } while( skip );  
     return rc;  
 }  
   
 /****************  
  * Copy all packets from INP to OUT, thereby removing unused spaces.  
  */  
 int  
 copy_all_packets( gpg_iobuf_t inp, gpg_iobuf_t out )  
 {  
     PACKET pkt;  
     int skip, rc=0;  
     do {  
         gpg_init_packet(&pkt);  
     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));  
     return rc;  
 }  
   
 /****************  
  * Copy some packets from INP to OUT, thereby removing unused spaces.  
  * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets)  
  */  
 int  
 copy_some_packets( gpg_iobuf_t inp, gpg_iobuf_t out, _off_t stopoff )  
 {  
     PACKET pkt;  
     int skip, rc=0;  
     do {  
         if( gpg_iobuf_tell(inp) >= stopoff )  
             return 0;  
         gpg_init_packet(&pkt);  
     } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );  
     return rc;  
 }  
   
 /****************  
  * Skip over N packets  
  */  
 int  
 skip_some_packets( gpg_iobuf_t inp, unsigned n )  
 {  
     int skip, rc=0;  
     PACKET pkt;  
       
     for( ;n && !rc; n--) {  
         gpg_init_packet(&pkt);  
         rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );  
     }  
     return rc;  
 }  
   
 /****************  
  * Parse packet. Set the variable skip points to 1 if the packet  
  * should be skipped; this is the case if either ONLYKEYPKTS is set  
  * and the parsed packet isn't one or the  
  * packet-type is 0, indicating deleted stuff.  
  * if OUT is not NULL, a special copymode is used.  
  */  
 static int  
 parse( gpg_iobuf_t inp, PACKET *pkt, int onlykeypkts, _off_t *retpos,  
        int *skip, gpg_iobuf_t out, int do_skip  
      )  
 {  
     int rc=0, c, ctb, pkttype, lenbytes;  
     unsigned long pktlen;  
     byte hdr[8];  
     int hdrlen;  
     int new_ctb = 0;  
     int with_uid = (onlykeypkts == 2);  
       
     *skip = 0;  
     /*assert( !pkt->pkt.generic );*/  
     if( retpos )  
         *retpos = gpg_iobuf_tell(inp);  
       
     if( (ctb = gpg_iobuf_get(inp)) == -1 ) {  
         rc = -1;  
         goto leave;  
     }  
     hdrlen=0;  
     hdr[hdrlen++] = ctb;  
     if( !(ctb & 0x80) ) {  
         printf("%s: invalid packet (ctb=%02x)\n", gpg_iobuf_where(inp), ctb );  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     pktlen = 0;  
     new_ctb = !!(ctb & 0x40);  
     if( new_ctb ) {  
         pkttype = ctb & 0x3f;  
         if( (c = gpg_iobuf_get(inp)) == -1 ) {  
             printf("%s: 1st length byte missing\n", gpg_iobuf_where(inp) );  
             rc = G10ERR_INVALID_PACKET;  
             goto leave;  
         }  
         if (pkttype == PKT_COMPRESSED) {  
             gpg_iobuf_set_partial_block_mode(inp, c & 0xff);  
             pktlen = 0;/* to indicate partial length */  
         }  
         else {  
             hdr[hdrlen++] = c;  
             if( c < 192 )  
                 pktlen = c;  
             else if( c < 224 ) {  
                 pktlen = (c - 192) * 256;  
                 if( (c = gpg_iobuf_get(inp)) == -1 ) {  
                     printf("%s: 2nd length byte missing\n",  
                            gpg_iobuf_where(inp) );  
                     rc = G10ERR_INVALID_PACKET;  
                     goto leave;  
                 }  
                 hdr[hdrlen++] = c;  
                 pktlen += c + 192;  
             }  
             else if( c == 255 ) {  
                 pktlen  = (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 24;  
                 pktlen |= (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 16;  
                 pktlen |= (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 8;  
                 if( (c = gpg_iobuf_get(inp)) == -1 ) {  
                     printf("%s: 4 byte length invalid\n",  
                            gpg_iobuf_where(inp) );  
                     rc = G10ERR_INVALID_PACKET;  
                     goto leave;  
                 }  
                 pktlen |= (hdr[hdrlen++] = c );  
             }  
             else { /* partial body length */  
                 gpg_iobuf_set_partial_block_mode(inp, c & 0xff);  
                 pktlen = 0;/* to indicate partial length */  
             }  
         }  
     }  
     else {  
         pkttype = (ctb>>2)&0xf;  
         lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));  
         if( !lenbytes ) {  
             pktlen = 0; /* don't know the value */  
             if( pkttype != PKT_COMPRESSED )  
                 gpg_iobuf_set_block_mode(inp, 1);  
         }  
         else {  
             for( ; lenbytes; lenbytes-- ) {  
                 pktlen <<= 8;  
                 pktlen |= hdr[hdrlen++] = gpg_iobuf_get_noeof(inp);  
             }  
         }  
     }  
       
     if (pktlen == 0xffffffff) {  
         /* with a some probability this is caused by a problem in the  
          * the uncompressing layer - in some error cases it just loops  
          * and spits out 0xff bytes. */  
         printf ("%s: garbled packet detected\n", gpg_iobuf_where(inp) );  
         exit (2);  
     }  
       
     if( out && pkttype  ) {  
         if( gpg_iobuf_write( out, hdr, hdrlen ) == -1 )  
             rc = G10ERR_WRITE_FILE;  
         else  
             rc = copy_packet(inp, out, pkttype, pktlen );  
         goto leave;  
     }  
       
     if (with_uid && pkttype == PKT_USER_ID)  
         ;  
     else if( do_skip  
              || !pkttype  
              || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY  
                  && pkttype != PKT_PUBLIC_KEY  
                  && pkttype != PKT_SECRET_SUBKEY  
                  && pkttype != PKT_SECRET_KEY  ) ) {  
         skip_rest(inp, pktlen);  
         *skip = 1;  
         rc = 0;  
         goto leave;  
     }  
       
     pkt->pkttype = pkttype;  
     rc = G10ERR_UNKNOWN_PACKET; /* default error */  
     switch( pkttype ) {  
     case PKT_PUBLIC_KEY:  
     case PKT_PUBLIC_SUBKEY:  
         pkt->pkt.public_key = calloc(1, sizeof *pkt->pkt.public_key );  
         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );  
         break;  
     case PKT_SECRET_KEY:  
     case PKT_SECRET_SUBKEY:  
         pkt->pkt.secret_key = calloc(1,sizeof *pkt->pkt.secret_key );  
         rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );  
         break;  
     case PKT_SYMKEY_ENC:  
         rc = parse_symkeyenc( inp, pkttype, pktlen, pkt );  
         break;  
     case PKT_PUBKEY_ENC:  
         rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );  
         break;  
     case PKT_SIGNATURE:  
         pkt->pkt.signature = calloc(1,sizeof *pkt->pkt.signature );  
         rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );  
         break;  
     case PKT_ONEPASS_SIG:  
         pkt->pkt.onepass_sig = calloc(1,sizeof *pkt->pkt.onepass_sig );  
         rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );  
         break;  
     case PKT_USER_ID:  
         rc = parse_user_id(inp, pkttype, pktlen, pkt );  
         break;  
     case PKT_ATTRIBUTE:  
         pkt->pkttype = pkttype = PKT_USER_ID;  /* we store it in the userID */  
         rc = parse_attribute(inp, pkttype, pktlen, pkt);  
         break;  
     case PKT_OLD_COMMENT:  
     case PKT_COMMENT:  
         rc = parse_comment(inp, pkttype, pktlen, pkt);  
         break;  
     case PKT_RING_TRUST:  
         parse_trust(inp, pkttype, pktlen, pkt);  
         rc = 0;  
         break;  
     case PKT_PLAINTEXT:  
         rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );  
         break;  
     case PKT_COMPRESSED:  
         rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );  
         break;  
     case PKT_ENCRYPTED:  
     case PKT_ENCRYPTED_MDC:  
         rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );  
         break;  
     case PKT_MDC:  
         rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb );  
         break;  
     case PKT_GPG_CONTROL:  
         rc = parse_gpg_control(inp, pkttype, pktlen, pkt );  
         break;  
     default:  
         skip_packet(inp, pkttype, pktlen);  
         break;  
     }  
       
 leave:  
     if( !rc && gpg_iobuf_error(inp) )  
         rc = G10ERR_INV_KEYRING;  
     return rc;  
 }  
   
 static void  
 dump_hex_line( int c, int *i )  
 {  
     if( *i && !(*i%8) ) {  
         if( *i && !(*i%24) )  
             printf("\n%4d:", *i );  
         else  
             putchar(' ');  
     }  
     if( c == -1 )  
         printf(" EOF" );  
     else  
         printf(" %02x", c );  
     ++*i;  
 }  
   
   
 static int  
 copy_packet( gpg_iobuf_t inp, gpg_iobuf_t out, int pkttype, unsigned long pktlen )  
 {  
     int n;  
     char buf[100];  
       
     if( gpg_iobuf_in_block_mode(inp) ) {  
         while( (n = gpg_iobuf_read( inp, buf, 100 )) != -1 )  
             if( gpg_iobuf_write(out, buf, n ) )  
                 return G10ERR_WRITE_FILE; /* write error */  
     }  
     else if( !pktlen && pkttype == PKT_COMPRESSED ) {  
         printf("copy_packet: compressed!\n");  
         /* compressed packet, copy till EOF */  
         while( (n = gpg_iobuf_read( inp, buf, 100 )) != -1 )  
             if( gpg_iobuf_write(out, buf, n ) )  
                 return G10ERR_WRITE_FILE; /* write error */  
     }  
     else {  
         for( ; pktlen; pktlen -= n ) {  
             n = pktlen > 100 ? 100 : pktlen;  
             n = gpg_iobuf_read( inp, buf, n );  
             if( n == -1 )  
                 return G10ERR_READ_FILE;  
             if( gpg_iobuf_write(out, buf, n ) )  
                 return G10ERR_WRITE_FILE; /* write error */  
         }  
     }  
     return 0;  
 }  
   
   
 static void  
 skip_packet( gpg_iobuf_t inp, int pkttype, unsigned long pktlen )  
 {  
     if( list_mode ) {  
         if( pkttype == PKT_MARKER )  
             fputs(":marker packet:\n", stdout );  
         else  
             printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);  
         if( pkttype ) {  
             int c, i=0 ;  
             if( pkttype != PKT_MARKER )  
                 fputs("dump:", stdout );  
             if( gpg_iobuf_in_block_mode(inp) ) {  
                 while( (c=gpg_iobuf_get(inp)) != -1 )  
                     dump_hex_line(c, &i);  
             }  
             else {  
                 for( ; pktlen; pktlen-- )  
                     dump_hex_line(gpg_iobuf_get(inp), &i);  
             }  
             putchar('\n');  
             return;  
         }  
     }  
     skip_rest(inp,pktlen);  
 }  
   
 static void  
 skip_rest( gpg_iobuf_t inp, unsigned long pktlen )  
 {  
     if( gpg_iobuf_in_block_mode(inp) ) {  
         while( gpg_iobuf_get(inp) != -1 )  
             ;  
     }  
     else {  
         for( ; pktlen; pktlen-- )  
             if( gpg_iobuf_get(inp) == -1 )  
                 break;  
     }  
 }  
   
   
 static void *  
 read_rest( gpg_iobuf_t inp, size_t pktlen )  
 {  
     byte *p;  
     int i;  
       
     if( gpg_iobuf_in_block_mode(inp) ) {  
         printf("read_rest: can't store stream data\n");  
         p = NULL;  
     }  
     else {  
         p = malloc( pktlen );  
         for(i=0; pktlen; pktlen--, i++ )  
             p[i] = gpg_iobuf_get(inp);  
     }  
     return p;  
 }  
   
   
   
 static int  
 parse_symkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     PKT_symkey_enc *k;  
     int rc = 0;  
     int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;  
       
     if( pktlen < 4 ) {  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     version = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( version != 4 ) {  
         printf("packet(%d) with unknown version %d\n", pkttype, version);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */  
         printf("packet(%d) too large\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     cipher_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     s2kmode = gpg_iobuf_get_noeof(inp); pktlen--;  
     hash_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     switch( s2kmode ) {  
     case 0:  /* simple s2k */  
         minlen = 0;  
         break;  
     case 1:  /* salted s2k */  
         minlen = 8;  
         break;  
     case 3:  /* iterated+salted s2k */  
         minlen = 9;  
         break;  
     default:  
         printf("unknown S2K %d\n", s2kmode );  
         goto leave;  
     }  
     if( minlen > pktlen ) {  
         printf("packet with S2K %d too short\n", s2kmode );  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     seskeylen = pktlen - minlen;  
     k = packet->pkt.symkey_enc = calloc(1, sizeof *packet->pkt.symkey_enc  
                                                 + seskeylen - 1 );  
     k->version = version;  
     k->cipher_algo = cipher_algo;  
     k->s2k.mode = s2kmode;  
     k->s2k.hash_algo = hash_algo;  
     if( s2kmode == 1 || s2kmode == 3 ) {  
         for(i=0; i < 8 && pktlen; i++, pktlen-- )  
             k->s2k.salt[i] = gpg_iobuf_get_noeof(inp);  
     }  
     if( s2kmode == 3 ) {  
         k->s2k.count = gpg_iobuf_get(inp); pktlen--;  
     }  
     k->seskeylen = seskeylen;  
     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )  
         k->seskey[i] = gpg_iobuf_get_noeof(inp);  
     assert( !pktlen );  
       
     if( list_mode ) {  
         printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",  
                version, cipher_algo, s2kmode, hash_algo);  
         if( s2kmode == 1 || s2kmode == 3 ) {  
             printf("\tsalt ");  
             for(i=0; i < 8; i++ )  
                 printf("%02x", k->s2k.salt[i]);  
             if( s2kmode == 3 )  
                 printf(", count %lu\n", (ulong)k->s2k.count );  
             printf("\n");  
         }  
     }  
       
 leave:  
     skip_rest(inp, pktlen);  
     return rc;  
 }  
   
 static int  
 parse_pubkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     unsigned int n;  
     int rc = 0;  
     int i, ndata;  
     PKT_pubkey_enc *k;  
       
     k = packet->pkt.pubkey_enc = calloc(1, sizeof *packet->pkt.pubkey_enc);  
     if( pktlen < 12 ) {  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     k->version = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( k->version != 2 && k->version != 3 ) {  
         printf("packet(%d) with unknown version %d\n", pkttype, k->version);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     k->keyid[0] = read_32(inp); pktlen -= 4;  
     k->keyid[1] = read_32(inp); pktlen -= 4;  
     k->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     k->throw_keyid = 0; /* only used as flag for build_packet */  
     if( list_mode )  
         printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",  
                k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);  
       
     ndata = pubkey_get_nenc(k->pubkey_algo);  
     if( !ndata ) {  
         if( list_mode )  
             printf("\tunsupported algorithm %d\n", k->pubkey_algo );  
         unknown_pubkey_warning( k->pubkey_algo );  
         k->data[0] = NULL;  /* no need to store the encrypted data */  
     }  
     else {  
         for( i=0; i < ndata; i++ ) {  
             n = pktlen;  
             k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;  
             if( list_mode ) {  
                 printf("\tdata: ");  
                 mpi_print(stdout, k->data[i], mpi_print_mode );  
                 putchar('\n');  
             }  
             if (!k->data[i])  
                 rc = G10ERR_INVALID_PACKET;  
         }  
     }  
       
 leave:  
     skip_rest(inp, pktlen);  
     return rc;  
 }  
   
 static void  
 dump_sig_subpkt( int hashed, int type, int critical,  
                  const byte *buffer, size_t buflen, size_t length )  
 {  
     const char *p=NULL;  
     int i;  
       
     /* The CERT has warning out with explains how to use GNUPG to  
      * detect the ARRs - we print our old message here when it is a faked  
      * ARR and add an additional notice */  
     if ( type == SIGSUBPKT_ARR && !hashed ) {  
         printf("\tsubpkt %d len %u (additional recipient request)\n"  
                "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "  
                "encrypt to this key and thereby reveal the plaintext to "  
                "the owner of this ARR key. Detailed info follows:\n",  
                type, (unsigned)length );  
     }  
       
       
     printf("\t%s%ssubpkt %d len %u (", /*)*/  
            critical ? "critical ":"",  
            hashed ? "hashed ":"", type, (unsigned)length );  
     buffer++;  
     length--;  
     if( length > buflen ) {  
         printf("too short: buffer is only %u)\n", (unsigned)buflen );  
         return;  
     }  
     switch( type ) {  
     case SIGSUBPKT_SIG_CREATED:  
         if( length >= 4 )  
             printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );  
         break;  
     case SIGSUBPKT_SIG_EXPIRE:  
         if( length >= 4 )  
             printf("sig expires after %s",  
                    strtimevalue( buffer_to_u32(buffer) ) );  
         break;  
     case SIGSUBPKT_EXPORTABLE:  
         if( length )  
             printf("%sexportable", *buffer? "":"not ");  
         break;  
     case SIGSUBPKT_TRUST:  
         if(length!=2)  
             p="[invalid trust signature]";  
         else  
             printf("trust signature of level %d, amount %d",buffer[0],buffer[1]);  
         break;  
     case SIGSUBPKT_REGEXP:  
         if(!length)  
             p="[invalid regexp]";  
         else  
             printf("regular expression: \"%s\"",buffer);  
         break;  
     case SIGSUBPKT_REVOCABLE:  
         if( length )  
             printf("%srevocable", *buffer? "":"not ");  
         break;  
     case SIGSUBPKT_KEY_EXPIRE:  
         if( length >= 4 )  
             printf("key expires after %s",  
                    strtimevalue( buffer_to_u32(buffer) ) );  
         break;  
     case SIGSUBPKT_PREF_SYM:  
         fputs("pref-sym-algos:", stdout );  
         for( i=0; i < length; i++ )  
             printf(" %d", buffer[i] );  
         break;  
     case SIGSUBPKT_REV_KEY:  
         fputs("revocation key: ", stdout );  
         if( length < 22 )  
             p = "[too short]";  
         else {  
             printf("c=%02x a=%d f=", buffer[0], buffer[1] );  
             for( i=2; i < length; i++ )  
                 printf("%02X", buffer[i] );  
         }  
         break;  
     case SIGSUBPKT_ISSUER:  
         if( length >= 8 )  
             printf("issuer key ID %08lX%08lX",  
                    (ulong)buffer_to_u32(buffer),  
                    (ulong)buffer_to_u32(buffer+4) );  
         break;  
     case SIGSUBPKT_NOTATION:  
     {  
         fputs("notation: ", stdout );  
         if( length < 8 )  
             p = "[too short]";  
         else if( !(*buffer & 0x80) )  
             p = "[not human readable]";  
         else {  
             const byte *s = buffer;  
             size_t n1, n2;  
               
             n1 = (s[4] << 8) | s[5];  
             n2 = (s[6] << 8) | s[7];  
             s += 8;  
             if( 8+n1+n2 != length )  
                 p = "[error]";  
             else {  
                 print_string( stdout, s, n1, ')' );  
                 putc( '=', stdout );  
                 print_string( stdout, s+n1, n2, ')' );  
             }  
         }  
     }  
     break;  
     case SIGSUBPKT_PREF_HASH:  
         fputs("pref-hash-algos:", stdout );  
         for( i=0; i < length; i++ )  
             printf(" %d", buffer[i] );  
         break;  
     case SIGSUBPKT_PREF_COMPR:  
         fputs("pref-zip-algos:", stdout );  
         for( i=0; i < length; i++ )  
             printf(" %d", buffer[i] );  
         break;  
     case SIGSUBPKT_KS_FLAGS:  
         fputs("key server preferences:",stdout);  
         for(i=0;i<length;i++)  
             printf(" %02X", buffer[i]);  
         break;  
     case SIGSUBPKT_PREF_KS:  
         p = "preferred key server";  
         break;  
     case SIGSUBPKT_PRIMARY_UID:  
         p = "primary user ID";  
         break;  
     case SIGSUBPKT_POLICY:  
         fputs("policy: ", stdout );  
         print_string( stdout, buffer, length, ')' );  
         break;  
     case SIGSUBPKT_KEY_FLAGS:  
         fputs ( "key flags:", stdout );  
         for( i=0; i < length; i++ )  
             printf(" %02X", buffer[i] );  
         break;  
     case SIGSUBPKT_SIGNERS_UID:  
         p = "signer's user ID";  
         break;  
     case SIGSUBPKT_REVOC_REASON:  
         if( length ) {  
             printf("revocation reason 0x%02x (", *buffer );  
             print_string( stdout, buffer+1, length-1, ')' );  
             p = ")";  
         }  
         break;  
     case SIGSUBPKT_ARR:  
         fputs("Big Brother's key (ignored): ", stdout );  
         if( length < 22 )  
             p = "[too short]";  
         else {  
             printf("c=%02x a=%d f=", buffer[0], buffer[1] );  
             for( i=2; i < length; i++ )  
                 printf("%02X", buffer[i] );  
         }  
         break;  
     case SIGSUBPKT_FEATURES:  
         fputs ( "features:", stdout );  
         for( i=0; i < length; i++ )  
             printf(" %02x", buffer[i] );  
         break;  
     case SIGSUBPKT_PRIV_VERIFY_CACHE:  
         p = "obsolete verification cache";  
         break;  
     default: p = "?"; break;  
     }  
       
     printf("%s)\n", p? p: "");  
 }  
   
 /****************  
  * Returns: >= 0 offset into buffer  
  *          -1 unknown type  
  *          -2 unsupported type  
  *          -3 subpacket too short  
  */  
 int  
 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )  
 {  
     switch( type ) {  
     case SIGSUBPKT_REV_KEY:  
         if(n < 22)  
             break;  
         return 0;  
     case SIGSUBPKT_SIG_CREATED:  
     case SIGSUBPKT_SIG_EXPIRE:  
     case SIGSUBPKT_KEY_EXPIRE:  
         if( n < 4 )  
             break;  
         return 0;  
     case SIGSUBPKT_KEY_FLAGS:  
     case SIGSUBPKT_KS_FLAGS:  
     case SIGSUBPKT_PREF_SYM:  
     case SIGSUBPKT_PREF_HASH:  
     case SIGSUBPKT_PREF_COMPR:  
     case SIGSUBPKT_POLICY:  
     case SIGSUBPKT_FEATURES:  
         return 0;  
     case SIGSUBPKT_EXPORTABLE:  
     case SIGSUBPKT_REVOCABLE:  
         if( !n )  
             break;  
         return 0;  
     case SIGSUBPKT_ISSUER: /* issuer key ID */  
         if( n < 8 )  
             break;  
         return 0;  
     case SIGSUBPKT_NOTATION:  
         if( n < 8 ) /* minimum length needed */  
             break;  
         return 0;  
     case SIGSUBPKT_REVOC_REASON:  
         if( !n  )  
             break;  
         return 0;  
     case SIGSUBPKT_PRIMARY_UID:  
         if ( n != 1 )  
             break;  
         return 0;    
     case SIGSUBPKT_PRIV_VERIFY_CACHE:  
         /* We used this in gpg 1.0.5 and 1.0.6 to cache signature  
          * verification results - it is no longer used.  
          * "GPG" 0x00 <mode> <stat>  
          * where mode == 1: valid data, stat == 0: invalid signature  
          * stat == 1: valid signature  
          * (because we use private data, we check our marker) */  
         if( n < 6 )  
             break;  
         if( buffer[0] != 'G' || buffer[1] != 'P'  
             || buffer[2] != 'G' || buffer[3] )  
             return -2;  
         return 4;  
     default: return -1;  
     }  
     return -3;  
 }  
   
   
 static int  
 can_handle_critical( const byte *buffer, size_t n, int type )  
 {  
     switch( type ) {  
     case SIGSUBPKT_NOTATION:  
         if( n >= 8 && (*buffer & 0x80) )  
             return 1; /* human readable is handled */  
         return 0;  
           
     case SIGSUBPKT_SIG_CREATED:  
     case SIGSUBPKT_SIG_EXPIRE:  
     case SIGSUBPKT_KEY_EXPIRE:  
     case SIGSUBPKT_EXPORTABLE:  
     case SIGSUBPKT_REVOCABLE:  
     case SIGSUBPKT_REV_KEY:  
     case SIGSUBPKT_ISSUER:/* issuer key ID */  
     case SIGSUBPKT_PREF_SYM:  
     case SIGSUBPKT_PREF_HASH:  
     case SIGSUBPKT_PREF_COMPR:  
     case SIGSUBPKT_KEY_FLAGS:  
     case SIGSUBPKT_PRIMARY_UID:  
     case SIGSUBPKT_FEATURES:  
     case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */  
         return 1;  
           
     default:  
         return 0;  
     }  
 }  
   
   
 const byte *  
 enum_sig_subpkt( const subpktarea_t *pktbuf, sigsubpkttype_t reqtype,  
                  size_t *ret_n, int *start, int *critical )  
 {  
     const byte *buffer;  
     int buflen;  
     int type;  
     int critical_dummy;  
     int offset;  
     size_t n;  
     int seq = 0;  
     int reqseq = start? *start: 0;  
       
     if(!critical)  
         critical=&critical_dummy;  
       
     if( !pktbuf || reqseq == -1 ) {  
         /* return some value different from NULL to indicate that  
          * there is no critical bit we do not understand.  The caller  
          * will never use the value.  Yes I know, it is an ugly hack */  
         return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&pktbuf : NULL;  
     }  
     buffer = pktbuf->data;  
     buflen = pktbuf->len;  
     while( buflen ) {  
         n = *buffer++; buflen--;  
         if( n == 255 ) { /* 4 byte length header */  
             if( buflen < 4 )  
                 goto too_short;  
             n = (buffer[0] << 24) | (buffer[1] << 16)  
                 | (buffer[2] << 8) | buffer[3];  
             buffer += 4;  
             buflen -= 4;  
         }  
         else if( n >= 192 ) { /* 2 byte special encoded length header */  
             if( buflen < 2 )  
                 goto too_short;  
             n = (( n - 192 ) << 8) + *buffer + 192;  
             buffer++;  
             buflen--;  
         }  
         if( buflen < n )  
             goto too_short;  
         type = *buffer;  
         if( type & 0x80 ) {  
             type &= 0x7f;  
             *critical = 1;  
         }  
         else  
             *critical = 0;  
         if( !(++seq > reqseq) )  
             ;  
         else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {  
             if( *critical ) {  
                 if( n-1 > buflen+1 )  
                     goto too_short;  
                 if( !can_handle_critical(buffer+1, n-1, type ) ) {  
                     printf("subpacket of type %d has critical bit set\n",  
                            type);  
                     if( start )  
                         *start = seq;  
                     return NULL; /* this is an error */  
                 }  
             }  
         }  
         else if( reqtype < 0 ) /* list packets */  
             dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,  
                              type, *critical, buffer, buflen, n );  
         else if( type == reqtype ) { /* found */  
             buffer++;  
             n--;  
             if( n > buflen )  
                 goto too_short;  
             if( ret_n )  
                 *ret_n = n;  
             offset = parse_one_sig_subpkt(buffer, n, type );  
             switch( offset ) {  
             case -3:  
                 printf("subpacket of type %d too short\n", type);  
                 return NULL;  
             case -2:  
                 return NULL;  
             case -1:  
                 printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );  
                 exit( -1 );  
             default:  
                 break;  
             }  
             if( start )  
                 *start = seq;  
             return buffer+offset;  
         }  
         buffer += n; buflen -=n;  
     }  
     if( reqtype == SIGSUBPKT_TEST_CRITICAL )  
         return buffer; /* as value true to indicate that there is no */  
     /* critical bit we don't understand */  
     if( start )  
         *start = -1;  
     return NULL; /* end of packets; not found */  
       
 too_short:  
     printf("buffer shorter than subpacket\n");  
     if( start )  
         *start = -1;  
     return NULL;  
 }  
   
   
 const byte *  
 gpg_parse_sig_subpkt (const subpktarea_t *buffer, sigsubpkttype_t reqtype,  
                   size_t *ret_n)  
 {  
     return enum_sig_subpkt( buffer, reqtype, ret_n, NULL, NULL );  
 }  
   
 const byte *  
 gpg_parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype,  
                    size_t *ret_n )  
 {  
     const byte *p;  
       
     p = gpg_parse_sig_subpkt (sig->hashed, reqtype, ret_n );  
     if( !p )  
         p = gpg_parse_sig_subpkt (sig->unhashed, reqtype, ret_n );  
     return p;  
 }  
   
 /* Find all revocation keys. Look in hashed area only. */  
 void parse_revkeys(PKT_signature *sig)  
 {  
     struct revocation_key *revkey;  
     int seq=0;  
     size_t len;  
       
     if( sig->sig_class != 0x1F )  
         return;  
       
     while((revkey=  
            (struct revocation_key *)enum_sig_subpkt(sig->hashed,  
                                                     SIGSUBPKT_REV_KEY,  
                                                     &len,&seq,NULL))) {  
         if( len==sizeof(struct revocation_key) &&  
             (revkey->rclass&0x80)) /* 0x80 bit must be set */ {  
             sig->revkey=realloc(sig->revkey,  
                                   sizeof(struct revocation_key *)*(sig->numrevkeys+1));  
             sig->revkey[sig->numrevkeys]=revkey;  
             sig->numrevkeys++;  
         }  
     }  
 }  
   
 static int  
 parse_signature( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                                           PKT_signature *sig )  
 {  
     int md5_len=0;  
     unsigned n;  
     int is_v4=0;  
     int rc=0;  
     int i, ndata;  
       
     if( pktlen < 16 ) {  
         printf("packet(%d) too short\n", pkttype);  
         goto leave;  
     }  
     sig->version = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( sig->version == 4 )  
         is_v4=1;  
     else if( sig->version != 2 && sig->version != 3 ) {  
         printf("packet(%d) with unknown version %d\n", pkttype, sig->version);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
       
     if( !is_v4 ) {  
         md5_len = gpg_iobuf_get_noeof(inp); pktlen--;  
     }  
     sig->sig_class = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( !is_v4 ) {  
         sig->timestamp = read_32(inp); pktlen -= 4;  
         sig->keyid[0] = read_32(inp); pktlen -= 4;  
         sig->keyid[1] = read_32(inp); pktlen -= 4;  
     }  
     sig->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     sig->digest_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     sig->flags.exportable=1;  
     sig->flags.revocable=1;  
     if( is_v4 ) { /* read subpackets */  
         n = read_16(inp); pktlen -= 2; /* length of hashed data */  
         if( n > 10000 ) {  
             printf("signature packet: hashed data too long\n");  
             rc = G10ERR_INVALID_PACKET;  
             goto leave;  
         }  
         if( n ) {  
             sig->hashed = malloc (sizeof (*sig->hashed) + n - 1 );  
             sig->hashed->size = n;  
             sig->hashed->len = n;  
             if( gpg_iobuf_read (inp, sig->hashed->data, n ) != n ) {  
                 printf ("premature eof while reading "  
                         "hashed signature data\n");  
                 rc = -1;  
                 goto leave;  
             }  
             pktlen -= n;  
         }  
         n = read_16(inp); pktlen -= 2; /* length of unhashed data */  
         if( n > 10000 ) {  
             printf("signature packet: unhashed data too long\n");  
             rc = G10ERR_INVALID_PACKET;  
             goto leave;  
         }  
         if( n ) {  
             /* we add 8 extra bytes so that we have space for the signature  
              * status cache.  Well we are wastin this if there is a cache  
              * packet already, but in the other case it avoids an realloc */  
             sig->unhashed = malloc (sizeof(*sig->unhashed) + n + 8 - 1 );  
             sig->unhashed->size = n + 8;  
             sig->unhashed->len = n;  
             if( gpg_iobuf_read(inp, sig->unhashed->data, n ) != n ) {  
                 printf("premature eof while reading "  
                        "unhashed signature data\n");  
                 rc = -1;  
                 goto leave;  
             }  
             pktlen -= n;  
         }  
     }  
       
     if( pktlen < 5 ) { /* sanity check */  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
       
     sig->digest_start[0] = gpg_iobuf_get_noeof(inp); pktlen--;  
     sig->digest_start[1] = gpg_iobuf_get_noeof(inp); pktlen--;  
       
     if( is_v4 && sig->pubkey_algo ) { /*extract required information */  
         const byte *p;  
           
         /* set sig->flags.unknown_critical if there is a  
          * critical bit set for packets which we do not understand */  
         if( !gpg_parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)  
             || !gpg_parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL,  
                                   NULL) )  
         {  
             sig->flags.unknown_critical = 1;  
         }  
           
         p = gpg_parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL );  
         if( !p )  
             printf("signature packet without timestamp\n");  
         else  
             sig->timestamp = buffer_to_u32(p);  
         p = gpg_parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );  
         if( !p )  
             printf("signature packet without keyid\n");  
         else {  
             sig->keyid[0] = buffer_to_u32(p);  
             sig->keyid[1] = buffer_to_u32(p+4);  
         }  
           
         p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL);  
         if(p)  
             sig->expiredate=sig->timestamp+buffer_to_u32(p);  
         if(sig->expiredate && sig->expiredate<=time(NULL))  
             sig->flags.expired=1;  
           
         p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,NULL);  
         if(p)  
             sig->flags.policy_url=1;  
           
         p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL);  
         if(p)  
             sig->flags.notation=1;  
           
         p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_REVOCABLE,NULL);  
         if(p && *p==0)  
             sig->flags.revocable=0;  
           
         /* We accept the exportable subpacket from either the hashed  
            or unhashed areas as older versions of gpg put it in the  
            unhashed area.  In theory, anyway, we should never see this  
            packet off of a local keyring. */  
           
         p=gpg_parse_sig_subpkt2(sig,SIGSUBPKT_EXPORTABLE,NULL);  
         if(p && *p==0)  
             sig->flags.exportable=0;  
           
         /* Find all revocation keys. */  
         if(sig->sig_class==0x1F)  
             parse_revkeys(sig);  
     }  
       
     if( list_mode ) {  
         printf(":signature packet: algo %d, keyid %08lX%08lX\n"  
                "\tversion %d, created %lu, md5len %d, sigclass %02x\n"  
                "\tdigest algo %d, begin of digest %02x %02x\n",  
                sig->pubkey_algo,  
                (ulong)sig->keyid[0], (ulong)sig->keyid[1],  
                sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,  
                sig->digest_algo,  
                sig->digest_start[0], sig->digest_start[1] );  
         if( is_v4 ) {  
             gpg_parse_sig_subpkt (sig->hashed,   SIGSUBPKT_LIST_HASHED, NULL );  
             gpg_parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);  
         }  
     }  
       
     ndata = pubkey_get_nsig(sig->pubkey_algo);  
     if( !ndata ) {  
         if( list_mode )  
             printf("\tunknown algorithm %d\n", sig->pubkey_algo );  
         unknown_pubkey_warning( sig->pubkey_algo );  
         /* we store the plain material in data[0], so that we are able  
          * to write it back with build_packet() */  
         sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen );  
         pktlen = 0;  
     }  
     else {  
         for( i=0; i < ndata; i++ ) {  
             n = pktlen;  
             sig->data[i] = mpi_read(inp, &n, 0 );  
             pktlen -=n;  
             if( list_mode ) {  
                 printf("\tdata: ");  
                 mpi_print(stdout, sig->data[i], mpi_print_mode );  
                 putchar('\n');  
             }  
             if (!sig->data[i])  
                 rc = G10ERR_INVALID_PACKET;  
         }  
     }  
       
 leave:  
     skip_rest(inp, pktlen);  
     return rc;  
 }  
   
   
 static int  
 parse_onepass_sig( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                                              PKT_onepass_sig *ops )  
 {  
     int version;  
     int rc = 0;  
       
     if( pktlen < 13 ) {  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     version = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( version != 3 ) {  
         printf("onepass_sig with unknown version %d\n", version);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     ops->sig_class = gpg_iobuf_get_noeof(inp); pktlen--;  
     ops->digest_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     ops->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
     ops->keyid[0] = read_32(inp); pktlen -= 4;  
     ops->keyid[1] = read_32(inp); pktlen -= 4;  
     ops->last = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( list_mode )  
         printf(":onepass_sig packet: keyid %08lX%08lX\n"  
                "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",  
                (ulong)ops->keyid[0], (ulong)ops->keyid[1],  
                version, ops->sig_class,  
                ops->digest_algo, ops->pubkey_algo, ops->last );  
       
       
 leave:  
     skip_rest(inp, pktlen);  
     return rc;  
 }  
   
   
 static int  
 parse_key( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                               byte *hdr, int hdrlen, PACKET *pkt )  
 {  
     int i, version, algorithm;  
     unsigned n;  
     unsigned long timestamp, expiredate, max_expiredate;  
     int npkey, nskey;  
     int is_v4=0;  
     int rc=0;  
   
     version = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {  
         /* early versions of G10 use old PGP comments packets;  
          * luckily all those comments are started by a hash */  
         if( list_mode ) {  
             printf(":rfc1991 comment packet: \"" );  
             for( ; pktlen; pktlen-- ) {  
                 int c;  
                 c = gpg_iobuf_get_noeof(inp);  
                 if( c >= ' ' && c <= 'z' )  
                     putchar(c);  
                 else  
                     printf("\\x%02x", c );  
             }  
             printf("\"\n");  
         }  
         skip_rest(inp, pktlen);  
         return 0;  
     }  
     else if( version == 4 )  
         is_v4=1;  
     else if( version != 2 && version != 3 ) {  
         printf("packet(%d) with unknown version %d\n", pkttype, version);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
   
     if( pktlen < 11 ) {  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
   
     timestamp = read_32(inp); pktlen -= 4;  
     if( is_v4 ) {  
         expiredate = 0; /* have to get it from the selfsignature */  
         max_expiredate = 0;  
     }  
     else {  
         unsigned short ndays;  
         ndays = read_16(inp); pktlen -= 2;  
         if( ndays )  
             expiredate = timestamp + ndays * 86400L;  
         else  
             expiredate = 0;  
   
         max_expiredate=expiredate;  
     }  
     algorithm = gpg_iobuf_get_noeof(inp); pktlen--;  
     if( list_mode )  
         printf(":%s key packet:\n"  
                "\tversion %d, algo %d, created %lu, expires %lu\n",  
                 pkttype == PKT_PUBLIC_KEY? "public" :  
                 pkttype == PKT_SECRET_KEY? "secret" :  
                 pkttype == PKT_PUBLIC_SUBKEY? "public sub" :  
                 pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",  
                 version, algorithm, timestamp, expiredate );  
   
     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {  
         PKT_secret_key *sk = pkt->pkt.secret_key;  
   
         sk->timestamp = timestamp;  
         sk->expiredate = expiredate;  
         sk->max_expiredate = max_expiredate;  
         sk->hdrbytes = hdrlen;  
         sk->version = version;  
         sk->is_primary = pkttype == PKT_SECRET_KEY;  
         sk->pubkey_algo = algorithm;  
         sk->req_usage = 0;  
         sk->pubkey_usage = 0; /* not yet used */  
     }  
     else {  
         PKT_public_key *pk = pkt->pkt.public_key;  
   
         pk->timestamp = timestamp;  
         pk->expiredate = expiredate;  
         pk->max_expiredate = max_expiredate;  
         pk->hdrbytes    = hdrlen;  
         pk->version     = version;  
         pk->is_primary = pkttype == PKT_PUBLIC_KEY;  
         pk->pubkey_algo = algorithm;  
         pk->req_usage = 0;  
         pk->pubkey_usage = 0; /* not yet used */  
         pk->is_revoked = 0;      
         pk->keyid[0] = 0;  
         pk->keyid[1] = 0;  
     }  
     nskey = pubkey_get_nskey( algorithm );  
     npkey = pubkey_get_npkey( algorithm );  
     if( !npkey ) {  
         if( list_mode )  
             printf("\tunknown algorithm %d\n", algorithm );  
         unknown_pubkey_warning( algorithm );  
     }  
   
   
     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {  
         PKT_secret_key *sk = pkt->pkt.secret_key;  
         byte temp[16];  
         size_t snlen = 0;  
   
         if( !npkey ) {  
             sk->skey[0] = mpi_set_opaque( NULL,  
                                           read_rest(inp, pktlen), pktlen );  
             pktlen = 0;  
             goto leave;  
         }  
   
         for(i=0; i < npkey; i++ ) {  
             n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;  
             if( list_mode ) {  
                 printf(  "\tskey[%d]: ", i);  
                 mpi_print(stdout, sk->skey[i], mpi_print_mode  );  
                 putchar('\n');  
             }  
             if (!sk->skey[i])  
                 rc = G10ERR_INVALID_PACKET;  
         }  
         if (rc) /* one of the MPIs were bad */  
             goto leave;  
         sk->protect.algo = gpg_iobuf_get_noeof(inp); pktlen--;  
         sk->protect.sha1chk = 0;  
         if( sk->protect.algo ) {  
             sk->is_protected = 1;  
             sk->protect.s2k.count = 0;  
             if( sk->protect.algo == 254 || sk->protect.algo == 255 ) {  
                 if( pktlen < 3 ) {  
                     rc = G10ERR_INVALID_PACKET;  
                     goto leave;  
                 }  
                 sk->protect.sha1chk = (sk->protect.algo == 254);  
                 sk->protect.algo = gpg_iobuf_get_noeof(inp); pktlen--;  
                 /* Note that a sk->protect.algo > 110 is illegal, but  
                    I'm not erroring on it here as otherwise there  
                    would be no way to delete such a key. */  
                 sk->protect.s2k.mode  = gpg_iobuf_get_noeof(inp); pktlen--;  
                 sk->protect.s2k.hash_algo = gpg_iobuf_get_noeof(inp); pktlen--;  
                 /* check for the special GNU extension */  
                 if( is_v4 && sk->protect.s2k.mode == 101 ) {  
                     for(i=0; i < 4 && pktlen; i++, pktlen-- )  
                         temp[i] = gpg_iobuf_get_noeof(inp);  
                     if( i < 4 || memcmp( temp, "GNU", 3 ) ) {  
                         if( list_mode )  
                             printf(  "\tunknown S2K %d\n",  
                                                 sk->protect.s2k.mode );  
                         rc = G10ERR_INVALID_PACKET;  
                         goto leave;  
                     }  
                     /* here we know that it is a gnu extension  
                      * What follows is the GNU protection mode:  
                      * All values have special meanings  
                      * and they are mapped in the mode with a base of 1000.  
                      */  
                     sk->protect.s2k.mode = 1000 + temp[3];  
                 }  
                 switch( sk->protect.s2k.mode ) {  
                   case 1:  
                   case 3:  
                     for(i=0; i < 8 && pktlen; i++, pktlen-- )  
                         temp[i] = gpg_iobuf_get_noeof(inp);  
                     memcpy(sk->protect.s2k.salt, temp, 8 );  
                     break;  
                 }  
                 switch( sk->protect.s2k.mode ) {  
                   case 0: if( list_mode ) printf(  "\tsimple S2K" );  
                     break;  
                   case 1: if( list_mode ) printf(  "\tsalted S2K" );  
                     break;  
                   case 3: if( list_mode ) printf(  "\titer+salt S2K" );  
                     break;  
                   case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );  
                     break;  
                   case 1002: if (list_mode) printf("\tgnu-divert-to-card S2K");  
                     break;  
                   default:  
                     if( list_mode )  
                         printf(  "\tunknown %sS2K %d\n",  
                                  sk->protect.s2k.mode < 1000? "":"GNU ",  
                                                    sk->protect.s2k.mode );  
                     rc = G10ERR_INVALID_PACKET;  
                     goto leave;  
                 }  
   
                 if( list_mode ) {  
                     printf(", algo: %d,%s hash: %d",  
                                      sk->protect.algo,  
                                      sk->protect.sha1chk?" SHA1 protection,"  
                                                         :" simple checksum,",  
                                      sk->protect.s2k.hash_algo );  
                     if( sk->protect.s2k.mode == 1  
                         || sk->protect.s2k.mode == 3 ) {  
                         printf(", salt: ");  
                         for(i=0; i < 8; i++ )  
                             printf("%02x", sk->protect.s2k.salt[i]);  
                     }  
                     putchar('\n');  
                 }  
   
                 if( sk->protect.s2k.mode == 3 ) {  
                     if( pktlen < 1 ) {  
                         rc = G10ERR_INVALID_PACKET;  
                         goto leave;  
                     }  
                     sk->protect.s2k.count = gpg_iobuf_get(inp);  
                     pktlen--;  
                     if( list_mode )  
                         printf("\tprotect count: %lu\n",  
                                             (ulong)sk->protect.s2k.count);  
                 }  
                 else if( sk->protect.s2k.mode == 1002 ) {  
                     /* Read the serial number. */  
                     if (pktlen < 1) {  
                       rc = G10ERR_INVALID_PACKET;  
                         goto leave;  
                     }  
                     snlen = gpg_iobuf_get (inp);  
                     pktlen--;  
                     if (pktlen < snlen || snlen == -1) {  
                         rc = G10ERR_INVALID_PACKET;  
                         goto leave;  
                     }  
                 }  
             }  
             /* Note that a sk->protect.algo > 110 is illegal, but I'm  
                not erroring on it here as otherwise there would be no  
                way to delete such a key. */  
             else { /* old version; no S2K, so we set mode to 0, hash MD5 */  
                 sk->protect.s2k.mode = 0;  
                 sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5;  
                 if( list_mode )  
                     printf(  "\tprotect algo: %d  (hash algo: %d)\n",  
                          sk->protect.algo, sk->protect.s2k.hash_algo );  
             }  
             /* It is really ugly that we don't know the size  
              * of the IV here in cases we are not aware of the algorithm.  
              * so a  
              *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);  
              * won't work.  The only solution I see is to hardwire it here.  
              * NOTE: if you change the ivlen above 16, don't forget to  
              * enlarge temp.  
              */  
             switch( sk->protect.algo ) {  
               case 7: case 8: case 9: /* reserved for AES */  
               case 10: /* Twofish */  
                 sk->protect.ivlen = 16;  
                 break;  
               default:  
                 sk->protect.ivlen = 8;  
             }  
             if( sk->protect.s2k.mode == 1001 )  
                 sk->protect.ivlen = 0;  
             else if( sk->protect.s2k.mode == 1002 )  
                 sk->protect.ivlen = snlen < 16? snlen : 16;  
   
             if( pktlen < sk->protect.ivlen ) {  
                 rc = G10ERR_INVALID_PACKET;  
                 goto leave;  
             }  
             for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )  
                 temp[i] = gpg_iobuf_get_noeof(inp);  
             if( list_mode ) {  
                 printf( sk->protect.s2k.mode == 1002? "\tserial-number: "  
                                                     : "\tprotect IV: ");  
                 for(i=0; i < sk->protect.ivlen; i++ )  
                     printf(" %02x", temp[i] );  
                 putchar('\n');  
             }  
             memcpy( sk->protect.iv, temp, sk->protect.ivlen );  
         }  
         else  
             sk->is_protected = 0;  
         /* It does not make sense to read it into secure memory.  
          * If the user is so careless, not to protect his secret key,  
          * we can assume, that he operates an open system :=(.  
          * So we put the key into secure memory when we unprotect it. */  
         if( sk->protect.s2k.mode == 1001  
             || sk->protect.s2k.mode == 1002 ) {  
             /* better set some dummy stuff here */  
             sk->skey[npkey] = mpi_set_opaque(NULL, strdup("dummydata"), 10);  
             pktlen = 0;  
         }  
         else if( is_v4 && sk->is_protected ) {  
             /* ugly; the length is encrypted too, so we read all  
              * stuff up to the end of the packet into the first  
              * skey element */  
             sk->skey[npkey] = mpi_set_opaque(NULL,  
                                              read_rest(inp, pktlen), pktlen );  
             pktlen = 0;  
             if( list_mode ) {  
                 printf("\tencrypted stuff follows\n");  
             }  
         }  
         else { /* v3 method: the mpi length is not encrypted */  
             for(i=npkey; i < nskey; i++ ) {  
                 n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;  
                 if( sk->is_protected && sk->skey[i] )  
                     mpi_set_protect_flag(sk->skey[i]);  
                 if( list_mode ) {  
                     printf(  "\tskey[%d]: ", i);  
                     if( sk->is_protected )  
                         printf(  "[encrypted]\n");  
                     else {  
                         mpi_print(stdout, sk->skey[i], mpi_print_mode  );  
                         putchar('\n');  
                     }  
                 }  
                 if (!sk->skey[i])  
                     rc = G10ERR_INVALID_PACKET;  
             }  
             if (rc)  
                 goto leave;  
               
             sk->csum = read_16(inp); pktlen -= 2;  
             if( list_mode ) {  
                 printf("\tchecksum: %04hx\n", sk->csum);  
             }  
         }  
     }  
     else {  
         PKT_public_key *pk = pkt->pkt.public_key;  
   
         if( !npkey ) {  
             pk->pkey[0] = mpi_set_opaque( NULL,  
                                           read_rest(inp, pktlen), pktlen );  
             pktlen = 0;  
             goto leave;  
         }  
   
         for(i=0; i < npkey; i++ ) {  
             n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;  
             if( list_mode ) {  
                 printf(  "\tpkey[%d]: ", i);  
                 mpi_print(stdout, pk->pkey[i], mpi_print_mode  );  
                 putchar('\n');  
             }  
             if (!pk->pkey[i])  
                 rc = G10ERR_INVALID_PACKET;  
         }  
         if (rc)  
             goto leave;  
     }  
   
   leave:  
     skip_rest(inp, pktlen);  
     return rc;  
 }  
   
 /* Attribute subpackets have the same format as v4 signature  
    subpackets.  This is not part of OpenPGP, but is done in several  
    versions of PGP nevertheless. */  
 int  
 parse_attribute_subpkts(PKT_user_id *uid)  
 {  
     size_t n;  
     int count=0;  
     struct user_attribute *attribs=NULL;  
     const byte *buffer=uid->attrib_data;  
     int buflen=uid->attrib_len;  
     byte type;  
       
     safe_free(uid->attribs);  
       
     while(buflen) {  
         n = *buffer++; buflen--;  
         if( n == 255 ) { /* 4 byte length header */  
             if( buflen < 4 )  
                 goto too_short;  
             n = (buffer[0] << 24) | (buffer[1] << 16)  
                 | (buffer[2] << 8) | buffer[3];  
             buffer += 4;  
             buflen -= 4;  
         }  
         else if( n >= 192 ) { /* 2 byte special encoded length header */  
             if( buflen < 2 )  
                 goto too_short;  
             n = (( n - 192 ) << 8) + *buffer + 192;  
             buffer++;  
             buflen--;  
         }  
         if( buflen < n )  
             goto too_short;  
           
         attribs=realloc(attribs,(count+1)*sizeof(struct user_attribute));  
         memset(&attribs[count],0,sizeof(struct user_attribute));  
           
         type=*buffer;  
         buffer++;  
         buflen--;  
         n--;  
           
         attribs[count].type=type;  
         attribs[count].data=buffer;  
         attribs[count].len=n;  
         buffer+=n;  
         buflen-=n;  
         count++;  
     }  
       
     uid->attribs=attribs;  
     uid->numattribs=count;  
     return count;  
       
 too_short:  
     printf("buffer shorter than attribute subpacket\n");  
     uid->attribs=attribs;  
     uid->numattribs=count;  
     return count;  
 }  
   
109  static void  static void
 setup_user_id(PACKET *packet)  
 {  
     packet->pkt.user_id->ref = 1;  
     packet->pkt.user_id->attribs = NULL;  
     packet->pkt.user_id->attrib_data = NULL;  
     packet->pkt.user_id->attrib_len = 0;  
     packet->pkt.user_id->is_primary = 0;  
     packet->pkt.user_id->is_revoked = 0;  
     packet->pkt.user_id->is_expired = 0;  
     packet->pkt.user_id->expiredate = 0;  
     packet->pkt.user_id->created = 0;  
     packet->pkt.user_id->help_key_usage = 0;  
     packet->pkt.user_id->help_key_expire = 0;  
     packet->pkt.user_id->prefs = NULL;  
 }  
   
 static int  
 parse_user_id( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     byte *p;  
       
     packet->pkt.user_id = malloc(sizeof *packet->pkt.user_id  + pktlen);  
     packet->pkt.user_id->len = pktlen;  
       
     setup_user_id(packet);  
       
     p = packet->pkt.user_id->name;  
     for( ; pktlen; pktlen--, p++ )  
         *p = gpg_iobuf_get_noeof(inp);  
     *p = 0;  
       
     if( list_mode ) {  
         int n = packet->pkt.user_id->len;  
         printf(":user ID packet: \"");  
         /* fixme: Hey why don't we replace this with print_string?? */  
         for(p=packet->pkt.user_id->name; n; p++, n-- ) {  
             if( *p >= ' ' && *p <= 'z' )  
                 putchar(*p);  
             else  
                 printf("\\x%02x", *p );  
         }  
         printf("\"\n");  
     }  
     return 0;  
 }  
   
 /* Returns 0 for error, 1 for valid */  
 int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)  
 {  
     u16 headerlen;  
       
     if(attr->len<3)  
         return 0;  
       
     /* For historical reasons (i.e. "oops!"), the header length is  
        little endian. */  
     headerlen=(attr->data[1]<<8) | attr->data[0];  
       
     if(headerlen>attr->len)  
         return 0;  
       
     if(type && attr->len>=4)  
     {  
         if(attr->data[2]==1) /* header version 1 */  
             *type=attr->data[3];  
         else  
             *type=0;  
     }  
       
     *len=attr->len-headerlen;  
       
     if(*len==0)  
         return 0;  
       
     return 1;  
 }  
   
 /* style==0 for extension, 1 for name, 2 for MIME type.  Remember that  
    the "name" style string could be used in a user ID name field, so  
    make sure it is not too big (see  
    parse-packet.c:parse_attribute). */  
 char *image_type_to_string(byte type,int style)  
 {  
     char *string;  
       
     switch(type) {  
     case 1: /* jpeg */  
         if(style==0)  
             string="jpg";  
         else if(style==1)  
             string="jpeg";  
         else  
             string="image/jpeg";  
         break;  
           
     default:  
         if(style==0)  
             string="bin";  
         else if(style==1)  
             string="unknown";  
         else  
             string="image/x-unknown";  
         break;  
     }  
       
     return string;  
 }  
   
 void  
 make_attribute_uidname(PKT_user_id *uid)  
 {  
     if(uid->numattribs<=0)  
         sprintf(uid->name,"[bad attribute packet of size %lu]",uid->attrib_len);  
     else if(uid->numattribs>1)  
         sprintf(uid->name,"[%d attributes of size %lu]",  
                 uid->numattribs,uid->attrib_len);  
     else {  
         /* Only one attribute, so list it as the "user id" */  
           
         if(uid->attribs->type==ATTRIB_IMAGE) {  
             u32 len;  
             byte type;  
               
             if(parse_image_header(uid->attribs,&type,&len))  
                 sprintf(uid->name,"[%s image of size %lu]",  
                         image_type_to_string(type,1),(ulong)len);  
             else  
                 sprintf(uid->name,"[invalid image]");  
         }  
         else  
             sprintf(uid->name,"[unknown attribute of size %lu]",  
                     (ulong)uid->attribs->len);  
     }  
       
     uid->len = strlen(uid->name);  
 }  
   
 static int  
 parse_attribute( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     byte *p;  
       
     packet->pkt.user_id = malloc(sizeof *packet->pkt.user_id + 70);  
       
     setup_user_id(packet);  
       
     packet->pkt.user_id->attrib_data = malloc(pktlen);  
     packet->pkt.user_id->attrib_len = pktlen;  
     p = packet->pkt.user_id->attrib_data;  
     for( ; pktlen; pktlen--, p++ )  
         *p = gpg_iobuf_get_noeof(inp);  
       
     /* Now parse out the individual attribute subpackets.  This is  
        somewhat pointless since there is only one currently defined  
        attribute type (jpeg), but it is correct by the spec. */  
     parse_attribute_subpkts(packet->pkt.user_id);  
       
     make_attribute_uidname(packet->pkt.user_id);  
       
     if( list_mode ) {  
         printf(":attribute packet: %s\n", packet->pkt.user_id->name );  
     }  
     return 0;  
 }  
   
   
 static int  
 parse_comment( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     byte *p;  
       
     packet->pkt.comment = malloc(sizeof *packet->pkt.comment + pktlen - 1);  
     packet->pkt.comment->len = pktlen;  
     p = packet->pkt.comment->data;  
     for( ; pktlen; pktlen--, p++ )  
         *p = gpg_iobuf_get_noeof(inp);  
       
     if( list_mode ) {  
         int n = packet->pkt.comment->len;  
         printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?  
                "OpenPGP draft " : "" );  
         for(p=packet->pkt.comment->data; n; p++, n-- ) {  
             if( *p >= ' ' && *p <= 'z' )  
                 putchar(*p);  
             else  
                 printf("\\x%02x", *p );  
         }  
         printf("\"\n");  
     }  
     return 0;  
 }  
   
   
 static void  
 parse_trust( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *pkt )  
 {  
     int c;  
       
     if (pktlen) {  
         c = gpg_iobuf_get_noeof(inp);  
         pktlen--;  
         pkt->pkt.ring_trust = malloc( sizeof *pkt->pkt.ring_trust );  
         pkt->pkt.ring_trust->trustval = c;  
         pkt->pkt.ring_trust->sigcache = 0;  
         if (!c && pktlen==1) {  
             c = gpg_iobuf_get_noeof (inp);  
             pktlen--;  
             /* we require that bit 7 of the sigcache is 0 (easier eof handling)*/  
             if ( !(c & 0x80) )  
                 pkt->pkt.ring_trust->sigcache = c;  
         }  
         if( list_mode )  
             printf(":trust packet: flag=%02x sigcache=%02x\n",  
                    pkt->pkt.ring_trust->trustval,  
                    pkt->pkt.ring_trust->sigcache);  
     }  
     else {  
         if( list_mode )  
             printf(":trust packet: empty\n");  
     }  
     skip_rest (inp, pktlen);  
 }  
   
   
 static int  
 parse_plaintext( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                                         PACKET *pkt, int new_ctb )  
 {  
     int rc = 0;  
     int mode, namelen, partial=0;  
     PKT_plaintext *pt;  
     byte *p;  
     int c, i;  
       
     if( pktlen && pktlen < 6 ) {  
         printf("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     /* A packet length of zero indicates partial body length.  A zero  
        data length isn't a zero length packet due to the header (mode,  
        name, etc), so this is accurate. */  
     if(pktlen==0)  
         partial=1;  
     mode = gpg_iobuf_get_noeof(inp); if( pktlen ) pktlen--;  
     namelen = gpg_iobuf_get_noeof(inp); if( pktlen ) pktlen--;  
     pt = pkt->pkt.plaintext = malloc(sizeof *pkt->pkt.plaintext + namelen -1);  
     pt->new_ctb = new_ctb;  
     pt->mode = mode;  
     pt->namelen = namelen;  
     pt->is_partial = partial;  
     if( pktlen ) {  
         for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )  
             pt->name[i] = gpg_iobuf_get_noeof(inp);  
     }  
     else {  
         for( i=0; i < namelen; i++ )  
             if( (c=gpg_iobuf_get(inp)) == -1 )  
                 break;  
             else  
                 pt->name[i] = c;  
     }  
     pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;  
     pt->len = pktlen;  
     pt->buf = inp;  
     pktlen = 0;  
       
     if( list_mode ) {  
         printf(":literal data packet:\n"  
                "\tmode %c, created %lu, name=\"",  
                mode >= ' ' && mode <'z'? mode : '?',  
                (ulong)pt->timestamp );  
         for(p=pt->name,i=0; i < namelen; p++, i++ ) {  
             if( *p >= ' ' && *p <= 'z' )  
                 putchar(*p);  
             else  
                 printf("\\x%02x", *p );  
         }  
         printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );  
     }  
       
 leave:  
     return rc;  
 }  
   
   
 static int  
 parse_compressed( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                   PACKET *pkt, int new_ctb )  
 {  
     PKT_compressed *zd;  
       
     /* pktlen is here 0, but data follows  
      * (this should be the last object in a file or  
      *  the compress algorithm should know the length)  
      */  
     zd = pkt->pkt.compressed =  malloc(sizeof *pkt->pkt.compressed );  
     zd->algorithm = gpg_iobuf_get_noeof(inp);  
     zd->len = 0; /* not used */  
     zd->new_ctb = new_ctb;  
     zd->buf = inp;  
     if( list_mode )  
         printf(":compressed packet: algo=%d\n", zd->algorithm);  
     return 0;  
 }  
   
   
 static int  
 parse_encrypted( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                                        PACKET *pkt, int new_ctb )  
 {  
     int rc = 0;  
     PKT_encrypted *ed;  
     unsigned long orig_pktlen = pktlen;  
       
     ed = pkt->pkt.encrypted =  malloc(sizeof *pkt->pkt.encrypted );  
     ed->len = pktlen;  
     /* we don't know the extralen which is (cipher_blocksize+2)  
        because the algorithm ist not specified in this packet.  
        However, it is only important to know this for some sanity  
        checks on the packet length - it doesn't matter that we can't  
        do it */  
     ed->extralen = 0;  
     ed->buf = NULL;  
     ed->new_ctb = new_ctb;  
     ed->mdc_method = 0;  
     if( pkttype == PKT_ENCRYPTED_MDC ) {  
         /* fixme: add some pktlen sanity checks */  
         int version;  
           
         version = gpg_iobuf_get_noeof(inp);  
         if (orig_pktlen)  
             pktlen--;  
         if( version != 1 ) {  
             printf("encrypted_mdc packet with unknown version %d\n",  
                    version);  
             /*skip_rest(inp, pktlen); should we really do this? */  
             rc = G10ERR_INVALID_PACKET;  
             goto leave;  
         }  
         ed->mdc_method = DIGEST_ALGO_SHA1;  
     }  
     if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */  
         printf("packet(%d) too short\n", pkttype);  
         rc = G10ERR_INVALID_PACKET;  
         skip_rest(inp, pktlen);  
         goto leave;  
     }  
     if( list_mode ) {  
         if( orig_pktlen )  
             printf(":encrypted data packet:\n\tlength: %lu\n", orig_pktlen);  
         else  
             printf(":encrypted data packet:\n\tlength: unknown\n");  
         if( ed->mdc_method )  
             printf("\tmdc_method: %d\n", ed->mdc_method );  
     }  
       
     ed->buf = inp;  
     pktlen = 0;  
       
 leave:  
     return rc;  
 }  
   
   
 static int  
 parse_mdc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,  
                                    PACKET *pkt, int new_ctb )  
 {  
     int rc = 0;  
     PKT_mdc *mdc;  
     byte *p;  
       
     mdc = pkt->pkt.mdc=  malloc(sizeof *pkt->pkt.mdc );  
     if( list_mode )  
         printf(":mdc packet: length=%lu\n", pktlen);  
     if( !new_ctb || pktlen != 20 ) {  
         printf("mdc_packet with invalid encoding\n");  
         rc = G10ERR_INVALID_PACKET;  
         goto leave;  
     }  
     p = mdc->hash;  
     for( ; pktlen; pktlen--, p++ )  
         *p = gpg_iobuf_get_noeof(inp);  
       
 leave:  
     return rc;  
 }  
   
   
 /*  
  * This packet is internally generated by PGG (by armor.c) to  
  * transfer some information to the lower layer.  To make sure that  
  * this packet is really a GPG faked one and not one comming from outside,  
  * we first check that tehre is a unique tag in it.  
  * The format of such a control packet is:  
  *   n byte  session marker  
  *   1 byte  control type CTRLPKT_xxxxx  
  *   m byte  control data  
  */  
   
 /* Return a string which is used as a kind of process ID */  
 const byte *  
 get_session_marker( size_t *rlen )  
 {  
     static byte marker[SIZEOF_UNSIGNED_LONG*2];  
     static int initialized;  
       
     if ( !initialized ) {  
         volatile ulong aa, bb; /* we really want the uninitialized value */  
         ulong a, b;  
           
         initialized = 1;  
         /* also this marker is guessable it is not easy to use this  
          * for a faked control packet because an attacker does not  
          * have enough control about the time the verification does  
          * take place.  Of course, we can add just more random but  
          * than we need the random generator even for verification  
          * tasks - which does not make sense. */  
         a = aa ^ (ulong)getpid();  
         b = bb ^ (ulong)time(NULL);  
         memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );  
         memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );  
     }  
     *rlen = sizeof(marker);  
     return marker;  
 }  
   
 static int  
 parse_gpg_control( gpg_iobuf_t inp,  
                    int pkttype, unsigned long pktlen, PACKET *packet )  
 {  
     byte *p;  
     const byte *sesmark;  
     size_t sesmarklen;  
     int i;  
       
     if ( list_mode )  
         printf(":packet 63: length %lu ",  pktlen);  
       
     sesmark = get_session_marker ( &sesmarklen );  
     if ( pktlen < sesmarklen+1 ) /* 1 is for the control bytes */  
         goto skipit;  
     for( i=0; i < sesmarklen; i++, pktlen-- ) {  
         if ( sesmark[i] != gpg_iobuf_get_noeof(inp) )  
             goto skipit;  
     }  
     if ( list_mode )  
         puts ("- gpg control packet");  
       
     packet->pkt.gpg_control = malloc(sizeof *packet->pkt.gpg_control  
                                       + pktlen - 1);  
     packet->pkt.gpg_control->control = gpg_iobuf_get_noeof(inp); pktlen--;  
     packet->pkt.gpg_control->datalen = pktlen;  
     p = packet->pkt.gpg_control->data;  
     for( ; pktlen; pktlen--, p++ )  
         *p = gpg_iobuf_get_noeof(inp);  
       
     return 0;  
       
 skipit:  
     if ( list_mode ) {  
         int c;  
           
         i=0;  
         printf("- private (rest length %lu)\n",  pktlen);  
         if( gpg_iobuf_in_block_mode(inp) ) {  
             while( (c=gpg_iobuf_get(inp)) != -1 )  
                 dump_hex_line(c, &i);  
         }  
         else {  
             for( ; pktlen; pktlen-- )  
                 dump_hex_line(gpg_iobuf_get(inp), &i);  
         }  
         putchar('\n');  
     }  
     skip_rest(inp,pktlen);  
     return G10ERR_INVALID_PACKET;  
 }  
   
   
 u32  
 gpg_keyid_from_pk( PKT_public_key * pk, byte *fprint )  
 {  
     gpg_md_t md;  
     int npkey, pktlen, i;  
     const byte *mdbuf;  
           
     if( pk->version == 3 && pk->pubkey_algo == PUBKEY_ALGO_RSA )  
         return pk->pkey[0]->d[0];  
     else {  
         md = gpg_md_open( DIGEST_ALGO_SHA1 );  
         gpg_md_putc( md, 0x99 );  
         npkey = pubkey_get_npkey( pk->pubkey_algo );  
         pktlen = 6;  
         for( i = 0 ; i <npkey; i++ )  
             pktlen = pktlen + 2 + pk->pkey[i]->alloced;  
         gpg_md_putc( md, pktlen>>8 );  
         gpg_md_putc( md, pktlen );  
         gpg_md_putc( md, 4 );  
         gpg_md_putc( md, pk->timestamp >> 24 );  
         gpg_md_putc( md, pk->timestamp >> 16 );  
         gpg_md_putc( md, pk->timestamp >>  8 );  
         gpg_md_putc( md, pk->timestamp       );  
         gpg_md_putc( md, pk->pubkey_algo );  
         for( i=0; i <npkey; i++ ) {  
             const u32 * d = pk->pkey[i]->d;  
             int nbits = pk->pkey[i]->nbits,  
                 n = pk->pkey[i]->alloced;  
             gpg_md_putc( md, nbits >> 8 );  
             gpg_md_putc( md, nbits );  
             n = n>4? n/4 : n;  
             while( n-- ) {  
                 if( pk->pkey[i]->alloced > 3 )  
                     gpg_md_putc( md, d[n] >> 24 );  
                 if( pk->pkey[i]->alloced > 2 )  
                     gpg_md_putc( md, d[n] >> 16 );  
                 if( pk->pkey[i]->alloced > 1 )  
                     gpg_md_putc( md, d[n] >>  8 );  
                 if( pk->pkey[i]->alloced > 0 )  
                     gpg_md_putc( md, d[n]       );  
             }        
         }        
         gpg_md_final( md );    
         mdbuf = gpg_md_read( md );  
     }  
     if( mdbuf && fprint )  
         memcpy( fprint, mdbuf, 20 );  
     return mdbuf? mdbuf[16] << 24 | mdbuf[17] << 16 | mdbuf[18] << 8 | mdbuf[19] : 0;  
 }  
   
   
 u32  
 gpg_keyid_from_sk( PKT_secret_key * sk, byte *fprint )  
 {  
     PKT_public_key pk;  
     int npkey = pubkey_get_npkey( sk->pubkey_algo );  
     int i;  
       
     pk.pubkey_algo = sk->pubkey_algo;  
     pk.version     = sk->version;  
     pk.timestamp = sk->timestamp;  
     pk.expiredate = sk->expiredate;  
     pk.pubkey_algo = sk->pubkey_algo;  
     for( i=0; i < npkey; i++ )  
         pk.pkey[i] = sk->skey[i];  
     return gpg_keyid_from_pk( &pk, fprint );  
 }  
   
   
 /****************  
  * Read the next keyblock from stream A.  
  * PENDING_PKT should be initialzed to NULL  
  * and not chnaged form the caller.  
  * Retunr: 0 = okay, -1 no more blocks or another errorcode.  
  */  
 int  
 gpg_read_keyblock( gpg_iobuf_t a, PACKET **pending_pkt, gpg_kbnode_t *ret_root )  
 {  
     int rc;  
     PACKET *pkt;  
     gpg_kbnode_t root = NULL;  
     int in_cert;  
   
     if( *pending_pkt ) {  
         root = gpg_new_kbnode( *pending_pkt );  
         *pending_pkt = NULL;  
         in_cert = 1;  
     }  
     else  
         in_cert = 0;  
     pkt = malloc( sizeof *pkt );  
     gpg_init_packet(pkt);  
     while( (rc=gpg_parse_packet(a, pkt)) != -1 ) {  
         if( rc ) {  /* ignore errors */  
             if( rc != G10ERR_UNKNOWN_PACKET ) {  
                 printf("read_block: read error: %d\n", rc );  
                 rc = G10ERR_INV_KEYRING;  
                 goto ready;  
             }  
             gpg_free_packet( pkt );  
             gpg_init_packet(pkt);  
             continue;  
         }  
   
         if( !root && pkt->pkttype == PKT_SIGNATURE  
                   && pkt->pkt.signature->sig_class == 0x20 ) {  
             /* this is a revocation certificate which is handled  
              * in a special way */  
             root = gpg_new_kbnode( pkt );  
             pkt = NULL;  
             goto ready;  
         }  
   
         /* make a linked list of all packets */  
         switch( pkt->pkttype ) {  
           case PKT_RING_TRUST:  
             /* skip those packets */  
             gpg_free_packet( pkt );  
             gpg_init_packet(pkt);  
             break;  
   
           case PKT_PUBLIC_KEY:  
           case PKT_SECRET_KEY:  
             if( in_cert ) { /* store this packet */  
                 *pending_pkt = pkt;  
                 pkt = NULL;  
                 goto ready;  
             }  
             in_cert = 1;  
           default:  
             if( in_cert ) {  
                 if( !root )  
                     root = gpg_new_kbnode( pkt );  
                 else  
                     gpg_add_kbnode( root, gpg_new_kbnode( pkt ) );  
                 pkt = malloc( sizeof *pkt );  
             }  
             gpg_init_packet(pkt);  
             break;  
         }  
     }  
   ready:  
     if( rc == -1 && root )  
         rc = 0;  
   
     if( rc )  
         gpg_release_kbnode( root );  
     else  
         *ret_root = root;  
     gpg_free_packet( pkt );  
     free( pkt );  
     return rc;  
 }  
110    unknown_pubkey_warning( int algo )
111    {
112        static byte unknown_pubkey_algos[256];
113        
114        algo &= 0xff;
115        if( !unknown_pubkey_algos[algo] ) {
116            unknown_pubkey_algos[algo] = 1;
117        }
118    }
119    
120    static const char *
121    strtimestamp( unsigned long stamp )
122    {
123        static char buffer[11+5];
124        struct tm *tp;
125        time_t atime = stamp;
126        
127        if (atime < 0) {
128            strcpy (buffer, "????" "-??" "-??");
129        }
130        else {
131            tp = gmtime( &atime );
132            sprintf(buffer,"%04d-%02d-%02d",
133                    1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
134        }
135        return buffer;
136    }
137    
138    static const char *
139    strtimevalue( unsigned long value )
140    {
141        static char buffer[30];
142        unsigned int years, days, hours, minutes;
143        
144        value /= 60;
145        minutes = value % 60;
146        value /= 60;
147        hours = value % 24;
148        value /= 24;
149        days = value % 365;
150        value /= 365;
151        years = value;
152        
153        sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
154        if( years )
155            return buffer;
156        if( days )
157            return strchr( buffer, 'y' ) + 1;
158        return strchr( buffer, 'd' ) + 1;
159    }
160    
161    
162    static gpg_mpi_t
163    mpi_read( gpg_iobuf_t inp, size_t *ret_n, int flags )
164    {
165        gpg_mpi_t a;
166        int i = 0, j = 0;
167        u32 t;
168        size_t n;
169        
170        a = calloc( 1, sizeof *a );
171        a->nbits = read_16( inp );
172        n = (a->nbits + 7) / 8;        
173        a->alloced = n;
174        a->d = calloc( n, 4 );
175        i = 4 - n % 4;
176        i %= 4;
177        j = (n+4-1) / 4;    
178        for( ; j > 0; j-- ) {
179            t = 0;
180            for( ; i < 4; i++ ) {
181                t <<= 8;
182                t |= gpg_iobuf_get( inp ) & 0xff;
183            }
184            i = 0;
185            a->d[j-1] = t;
186        }
187        if( *ret_n )
188            *ret_n = n + 2;
189        
190        return a;
191    }
192    
193    void
194    mpi_print( FILE *fp, gpg_mpi_t a, int mode )
195    {
196        int i;
197        for( i = 0; i < a->alloced / 4; i++ )
198            printf( "%08lx", a->d[i] );
199    }
200    
201    static void
202    mpi_set_protect_flag( gpg_mpi_t a )
203    {
204        a->flags = 1;
205    }
206    
207    static gpg_mpi_t
208    mpi_set_opaque( gpg_mpi_t a, void *p, int len )
209    {
210        if( !a ) {
211            a = calloc( 1, sizeof *a );
212        }
213        
214        if( a->flags & 4 )
215            safe_free( a->d );
216        else {
217            safe_free( a->d );
218        }
219        
220        a->d = p;
221        a->alloced = 0;
222        a->nlimbs = 0;
223        a->nbits = len;
224        a->flags = 4;
225        return a;
226    }
227    
228    void
229    free_symkey_enc( PKT_symkey_enc *enc )
230    {
231        safe_free(enc);
232    }
233    
234    void
235    free_pubkey_enc( PKT_pubkey_enc *enc )
236    {
237        int n, i;
238        n = pubkey_get_nenc( enc->pubkey_algo );
239        if( !n )
240            safe_free(enc->data[0]);
241        for(i=0; i < n; i++ )
242            safe_free( enc->data[i] );
243        safe_free(enc);
244    }
245    
246    void
247    free_seckey_enc( PKT_signature *sig )
248    {
249        int n, i;
250        
251        n = pubkey_get_nsig( sig->pubkey_algo );
252        if( !n )
253            safe_free(sig->data[0]);
254        for(i=0; i < n; i++ )
255            safe_free( sig->data[i] );
256        
257        safe_free(sig->revkey);
258        safe_free(sig->hashed);
259        safe_free(sig->unhashed);
260        safe_free(sig);
261    }
262    
263    
264    
265    void
266    release_public_key_parts( PKT_public_key *pk )
267    {
268        int n, i;
269        n = pubkey_get_npkey( pk->pubkey_algo );
270        if( !n )
271            safe_free(pk->pkey[0]);
272        for(i=0; i < n; i++ ) {
273            safe_free( pk->pkey[i] );
274            pk->pkey[i] = NULL;
275        }
276        if (pk->prefs) {
277            safe_free (pk->prefs);
278            pk->prefs = NULL;
279        }
280        if( pk->namehash ) {
281            safe_free(pk->namehash);
282            pk->namehash = NULL;
283        }
284        if (pk->user_id) {
285            free_user_id (pk->user_id);
286            pk->user_id = NULL;
287        }
288        if (pk->revkey) {
289            safe_free(pk->revkey);
290            pk->revkey=NULL;
291            pk->numrevkeys=0;
292        }
293    }
294    
295    
296    void
297    free_public_key( PKT_public_key *pk )
298    {
299        release_public_key_parts( pk );
300        safe_free(pk);
301    }
302    
303    
304    int
305    pubkey_get_nenc( int algo )
306    {
307        switch( algo ) {
308        case 1:
309        case 2:
310        case 3:  return 1;          
311        case 16:
312        case 20: return 2;
313        }
314        return 0;
315    }
316    
317    int
318    pubkey_get_nsig( algo )
319    {
320        switch( algo ) {
321        case  1:
322        case  2:
323        case  3: return 1;
324        case 17:
325        case 16:
326        case 20: return 2;
327        }
328        return 0;
329    }
330    
331    int
332    pubkey_get_npkey( int algo )
333    {      
334        if( is_ELGAMAL( algo ) )   return 3;        
335        else if ( algo == 17 )     return 4;
336        else if ( is_RSA( algo ) ) return 2;
337        return 0;
338    }
339    
340    int
341    pubkey_get_nskey( int algo )
342    {
343        if ( is_ELGAMAL( algo ) ) return 4;
344        else if ( algo == 17 )    return 5;
345        else if ( is_RSA( algo ) )return 6;
346        return 0;
347    }
348    
349    
350    
351    /*
352     * Return a copy of the preferences
353     */
354    prefitem_t *
355    copy_prefs (const prefitem_t *prefs)
356    {
357        size_t n;
358        prefitem_t *new;
359        
360        if (!prefs)
361            return NULL;
362        
363        for (n=0; prefs[n].type; n++)
364            ;
365        new = malloc ( sizeof (*new) * (n+1));
366        for (n=0; prefs[n].type; n++) {
367            new[n].type = prefs[n].type;
368            new[n].value = prefs[n].value;
369        }
370        new[n].type = PREFTYPE_NONE;
371        new[n].value = 0;
372        
373        return new;
374    }
375    
376    /****************
377     * Replace all common parts of a sk by the one from the public key.
378     * This is a hack and a better solution will be to just store the real secret
379     * parts somewhere and don't duplicate all the other stuff.
380     */
381    void
382    copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
383    {
384        sk->expiredate  = pk->expiredate;    
385        sk->pubkey_algo = pk->pubkey_algo;    
386        sk->pubkey_usage= pk->pubkey_usage;
387        sk->req_usage   = pk->req_usage;
388        sk->req_algo    = pk->req_algo;
389        sk->has_expired = pk->has_expired;    
390        sk->is_revoked  = pk->is_revoked;    
391        sk->is_valid    = pk->is_valid;    
392        sk->main_keyid[0]= pk->main_keyid[0];
393        sk->main_keyid[1]= pk->main_keyid[1];
394        sk->keyid[0]    = pk->keyid[0];
395        sk->keyid[1]    = pk->keyid[1];
396    }
397    
398    void
399    release_secret_key_parts( PKT_secret_key *sk )
400    {
401        int n, i;
402        
403        n = pubkey_get_nskey( sk->pubkey_algo );
404        if( !n )
405            safe_free(sk->skey[0]);
406        for(i=0; i < n; i++ ) {
407            safe_free( sk->skey[i] );
408            sk->skey[i] = NULL;
409        }
410    }
411    
412    void
413    free_secret_key( PKT_secret_key *sk )
414    {
415        release_secret_key_parts( sk );
416        safe_free(sk);
417    }
418    
419    void
420    free_comment( PKT_comment *rem )
421    {
422        safe_free(rem);
423    }
424    
425    void
426    free_attributes(PKT_user_id *uid)
427    {
428        safe_free(uid->attribs);
429        safe_free(uid->attrib_data);
430        
431        uid->attribs=NULL;
432        uid->attrib_data=NULL;
433        uid->attrib_len=0;
434    }
435    
436    void
437    free_user_id (PKT_user_id *uid)
438    {
439        assert (uid->ref > 0);
440        if (--uid->ref)
441            return;
442        
443        free_attributes(uid);
444        
445        if (uid->prefs)
446            safe_free (uid->prefs);
447        safe_free (uid);
448    }
449    
450    void
451    free_compressed( PKT_compressed *zd )
452    {
453        if( zd->buf ) { /* have to skip some bytes */
454            /* don't have any information about the length, so
455             * we assume this is the last packet */
456            while( gpg_iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
457                ;
458        }
459        safe_free(zd);
460    }
461    
462    void
463    free_encrypted( PKT_encrypted *ed )
464    {
465        if( ed->buf ) { /* have to skip some bytes */
466            if( gpg_iobuf_in_block_mode(ed->buf) ) {
467                while( gpg_iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
468                    ;
469            }
470            else {
471                while( ed->len ) { /* skip the packet */
472                    int n = gpg_iobuf_read( ed->buf, NULL, ed->len );
473                    if( n == -1 )
474                        ed->len = 0;
475                    else
476                        ed->len -= n;
477                }
478            }
479        }
480        safe_free(ed);
481    }
482    
483    
484    void
485    free_plaintext( PKT_plaintext *pt )
486    {
487        if( pt->buf ) { /* have to skip some bytes */
488            if( gpg_iobuf_in_block_mode(pt->buf) ) {
489                while( gpg_iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
490                    ;
491            }
492            else {
493                while( pt->len ) { /* skip the packet */
494                    int n = gpg_iobuf_read( pt->buf, NULL, pt->len );
495                    if( n == -1 )
496                        pt->len = 0;
497                    else
498                        pt->len -= n;
499                }
500            }
501        }
502        safe_free(pt);
503    }
504    
505    /****************
506     * Free the packet in pkt.
507     */
508    void
509    gpg_free_packet( PACKET *pkt )
510    {
511        if( !pkt || !pkt->pkt.generic )
512            return;
513        
514        switch( pkt->pkttype ) {
515        case PKT_SIGNATURE:
516            free_seckey_enc( pkt->pkt.signature );
517            break;
518        case PKT_PUBKEY_ENC:
519            free_pubkey_enc( pkt->pkt.pubkey_enc );
520            break;
521        case PKT_SYMKEY_ENC:
522            free_symkey_enc( pkt->pkt.symkey_enc );
523            break;
524        case PKT_PUBLIC_KEY:
525        case PKT_PUBLIC_SUBKEY:
526            free_public_key( pkt->pkt.public_key );
527            break;
528        case PKT_SECRET_KEY:
529        case PKT_SECRET_SUBKEY:
530            free_secret_key( pkt->pkt.secret_key );
531            break;
532        case PKT_COMMENT:
533            free_comment( pkt->pkt.comment );
534            break;
535        case PKT_USER_ID:
536            free_user_id( pkt->pkt.user_id );
537            break;
538        case PKT_COMPRESSED:
539            free_compressed( pkt->pkt.compressed);
540            break;
541        case PKT_ENCRYPTED:
542        case PKT_ENCRYPTED_MDC:
543            free_encrypted( pkt->pkt.encrypted );
544            break;
545        case PKT_PLAINTEXT:
546            free_plaintext( pkt->pkt.plaintext );
547            break;
548        default:
549            safe_free( pkt->pkt.generic );
550            break;
551        }
552        pkt->pkt.generic = NULL;
553    }
554    
555    
556    
557    /****************
558     * Parse a Packet and return it in packet
559     * Returns: 0 := valid packet in pkt
560     *         -1 := no more packets
561     *         >0 := error
562     * Note: The function may return an error and a partly valid packet;
563     * caller must free this packet.
564     */
565    int
566    gpg_parse_packet( gpg_iobuf_t inp, PACKET *pkt )
567    {
568        int skip, rc;
569        
570        do {
571            rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );
572        } while( skip );
573        return rc;
574    }
575    
576    /****************
577     * Like parse packet, but only return secret or public (sub)key packets.
578     */
579    int
580    search_packet( gpg_iobuf_t inp, PACKET *pkt, _off_t *retpos, int with_uid )
581    {
582        int skip, rc;
583        
584        do {
585            rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 );
586        } while( skip );
587        return rc;
588    }
589    
590    /****************
591     * Copy all packets from INP to OUT, thereby removing unused spaces.
592     */
593    int
594    copy_all_packets( gpg_iobuf_t inp, gpg_iobuf_t out )
595    {
596        PACKET pkt;
597        int skip, rc=0;
598        do {
599            gpg_init_packet(&pkt);
600        } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )));
601        return rc;
602    }
603    
604    /****************
605     * Copy some packets from INP to OUT, thereby removing unused spaces.
606     * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets)
607     */
608    int
609    copy_some_packets( gpg_iobuf_t inp, gpg_iobuf_t out, _off_t stopoff )
610    {
611        PACKET pkt;
612        int skip, rc=0;
613        do {
614            if( gpg_iobuf_tell(inp) >= stopoff )
615                return 0;
616            gpg_init_packet(&pkt);
617        } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) );
618        return rc;
619    }
620    
621    /****************
622     * Skip over N packets
623     */
624    int
625    skip_some_packets( gpg_iobuf_t inp, unsigned n )
626    {
627        int skip, rc=0;
628        PACKET pkt;
629        
630        for( ;n && !rc; n--) {
631            gpg_init_packet(&pkt);
632            rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 );
633        }
634        return rc;
635    }
636    
637    /****************
638     * Parse packet. Set the variable skip points to 1 if the packet
639     * should be skipped; this is the case if either ONLYKEYPKTS is set
640     * and the parsed packet isn't one or the
641     * packet-type is 0, indicating deleted stuff.
642     * if OUT is not NULL, a special copymode is used.
643     */
644    static int
645    parse( gpg_iobuf_t inp, PACKET *pkt, int onlykeypkts, _off_t *retpos,
646           int *skip, gpg_iobuf_t out, int do_skip
647         )
648    {
649        int rc=0, c, ctb, pkttype, lenbytes;
650        unsigned long pktlen;
651        byte hdr[8];
652        int hdrlen;
653        int new_ctb = 0;
654        int with_uid = (onlykeypkts == 2);
655        
656        *skip = 0;
657        /*assert( !pkt->pkt.generic );*/
658        if( retpos )
659            *retpos = gpg_iobuf_tell(inp);
660        
661        if( (ctb = gpg_iobuf_get(inp)) == -1 ) {
662            rc = -1;
663            goto leave;
664        }
665        hdrlen=0;
666        hdr[hdrlen++] = ctb;
667        if( !(ctb & 0x80) ) {
668            printf("%s: invalid packet (ctb=%02x)\n", gpg_iobuf_where(inp), ctb );
669            rc = G10ERR_INVALID_PACKET;
670            goto leave;
671        }
672        pktlen = 0;
673        new_ctb = !!(ctb & 0x40);
674        if( new_ctb ) {
675            pkttype = ctb & 0x3f;
676            if( (c = gpg_iobuf_get(inp)) == -1 ) {
677                printf("%s: 1st length byte missing\n", gpg_iobuf_where(inp) );
678                rc = G10ERR_INVALID_PACKET;
679                goto leave;
680            }
681            if (pkttype == PKT_COMPRESSED) {
682                gpg_iobuf_set_partial_block_mode(inp, c & 0xff);
683                pktlen = 0;/* to indicate partial length */
684            }
685            else {
686                hdr[hdrlen++] = c;
687                if( c < 192 )
688                    pktlen = c;
689                else if( c < 224 ) {
690                    pktlen = (c - 192) * 256;
691                    if( (c = gpg_iobuf_get(inp)) == -1 ) {
692                        printf("%s: 2nd length byte missing\n",
693                               gpg_iobuf_where(inp) );
694                        rc = G10ERR_INVALID_PACKET;
695                        goto leave;
696                    }
697                    hdr[hdrlen++] = c;
698                    pktlen += c + 192;
699                }
700                else if( c == 255 ) {
701                    pktlen  = (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 24;
702                    pktlen |= (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 16;
703                    pktlen |= (hdr[hdrlen++] = gpg_iobuf_get_noeof(inp)) << 8;
704                    if( (c = gpg_iobuf_get(inp)) == -1 ) {
705                        printf("%s: 4 byte length invalid\n",
706                               gpg_iobuf_where(inp) );
707                        rc = G10ERR_INVALID_PACKET;
708                        goto leave;
709                    }
710                    pktlen |= (hdr[hdrlen++] = c );
711                }
712                else { /* partial body length */
713                    gpg_iobuf_set_partial_block_mode(inp, c & 0xff);
714                    pktlen = 0;/* to indicate partial length */
715                }
716            }
717        }
718        else {
719            pkttype = (ctb>>2)&0xf;
720            lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
721            if( !lenbytes ) {
722                pktlen = 0; /* don't know the value */
723                if( pkttype != PKT_COMPRESSED )
724                    gpg_iobuf_set_block_mode(inp, 1);
725            }
726            else {
727                for( ; lenbytes; lenbytes-- ) {
728                    pktlen <<= 8;
729                    pktlen |= hdr[hdrlen++] = gpg_iobuf_get_noeof(inp);
730                }
731            }
732        }
733        
734        if (pktlen == 0xffffffff) {
735            /* with a some probability this is caused by a problem in the
736             * the uncompressing layer - in some error cases it just loops
737             * and spits out 0xff bytes. */
738            /*printf ("%s: garbled packet detected\n", gpg_iobuf_where(inp));*/
739            rc = G10ERR_INVALID_PACKET;
740            goto leave;
741        }
742        
743        if( out && pkttype  ) {
744            if( gpg_iobuf_write( out, hdr, hdrlen ) == -1 )
745                rc = G10ERR_WRITE_FILE;
746            else
747                rc = copy_packet(inp, out, pkttype, pktlen );
748            goto leave;
749        }
750        
751        if (with_uid && pkttype == PKT_USER_ID)
752            ;
753        else if( do_skip
754                 || !pkttype
755                 || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
756                     && pkttype != PKT_PUBLIC_KEY
757                     && pkttype != PKT_SECRET_SUBKEY
758                     && pkttype != PKT_SECRET_KEY  ) ) {
759            skip_rest(inp, pktlen);
760            *skip = 1;
761            rc = 0;
762            goto leave;
763        }
764        
765        pkt->pkttype = pkttype;
766        rc = G10ERR_UNKNOWN_PACKET; /* default error */
767        switch( pkttype ) {
768        case PKT_PUBLIC_KEY:
769        case PKT_PUBLIC_SUBKEY:
770            pkt->pkt.public_key = calloc(1, sizeof *pkt->pkt.public_key );
771            rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
772            break;
773        case PKT_SECRET_KEY:
774        case PKT_SECRET_SUBKEY:
775            pkt->pkt.secret_key = calloc(1,sizeof *pkt->pkt.secret_key );
776            rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
777            break;
778        case PKT_SYMKEY_ENC:
779            rc = parse_symkeyenc( inp, pkttype, pktlen, pkt );
780            break;
781        case PKT_PUBKEY_ENC:
782            rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );
783            break;
784        case PKT_SIGNATURE:
785            pkt->pkt.signature = calloc(1,sizeof *pkt->pkt.signature );
786            rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
787            break;
788        case PKT_ONEPASS_SIG:
789            pkt->pkt.onepass_sig = calloc(1,sizeof *pkt->pkt.onepass_sig );
790            rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
791            break;
792        case PKT_USER_ID:
793            rc = parse_user_id(inp, pkttype, pktlen, pkt );
794            break;
795        case PKT_ATTRIBUTE:
796            pkt->pkttype = pkttype = PKT_USER_ID;  /* we store it in the userID */
797            rc = parse_attribute(inp, pkttype, pktlen, pkt);
798            break;
799        case PKT_OLD_COMMENT:
800        case PKT_COMMENT:
801            rc = parse_comment(inp, pkttype, pktlen, pkt);
802            break;
803        case PKT_RING_TRUST:
804            parse_trust(inp, pkttype, pktlen, pkt);
805            rc = 0;
806            break;
807        case PKT_PLAINTEXT:
808            rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );
809            break;
810        case PKT_COMPRESSED:
811            rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );
812            break;
813        case PKT_ENCRYPTED:
814        case PKT_ENCRYPTED_MDC:
815            rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb );
816            break;
817        case PKT_MDC:
818            rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb );
819            break;
820        case PKT_GPG_CONTROL:
821            rc = parse_gpg_control(inp, pkttype, pktlen, pkt );
822            break;
823        default:
824            skip_packet(inp, pkttype, pktlen);
825            break;
826        }
827        
828    leave:
829        if( !rc && gpg_iobuf_error(inp) )
830            rc = G10ERR_INV_KEYRING;
831        return rc;
832    }
833    
834    static void
835    dump_hex_line( int c, int *i )
836    {
837        if( *i && !(*i%8) ) {
838            if( *i && !(*i%24) )
839                printf("\n%4d:", *i );
840            else
841                putchar(' ');
842        }
843        if( c == -1 )
844            printf(" EOF" );
845        else
846            printf(" %02x", c );
847        ++*i;
848    }
849    
850    
851    static int
852    copy_packet( gpg_iobuf_t inp, gpg_iobuf_t out, int pkttype, unsigned long pktlen )
853    {
854        int n;
855        char buf[100];
856        
857        if( gpg_iobuf_in_block_mode(inp) ) {
858            while( (n = gpg_iobuf_read( inp, buf, 100 )) != -1 )
859                if( gpg_iobuf_write(out, buf, n ) )
860                    return G10ERR_WRITE_FILE; /* write error */
861        }
862        else if( !pktlen && pkttype == PKT_COMPRESSED ) {
863            printf("copy_packet: compressed!\n");
864            /* compressed packet, copy till EOF */
865            while( (n = gpg_iobuf_read( inp, buf, 100 )) != -1 )
866                if( gpg_iobuf_write(out, buf, n ) )
867                    return G10ERR_WRITE_FILE; /* write error */
868        }
869        else {
870            for( ; pktlen; pktlen -= n ) {
871                n = pktlen > 100 ? 100 : pktlen;
872                n = gpg_iobuf_read( inp, buf, n );
873                if( n == -1 )
874                    return G10ERR_READ_FILE;
875                if( gpg_iobuf_write(out, buf, n ) )
876                    return G10ERR_WRITE_FILE; /* write error */
877            }
878        }
879        return 0;
880    }
881    
882    
883    static void
884    skip_packet( gpg_iobuf_t inp, int pkttype, unsigned long pktlen )
885    {
886        if( list_mode ) {
887            if( pkttype == PKT_MARKER )
888                fputs(":marker packet:\n", stdout );
889            else
890                printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
891            if( pkttype ) {
892                int c, i=0 ;
893                if( pkttype != PKT_MARKER )
894                    fputs("dump:", stdout );
895                if( gpg_iobuf_in_block_mode(inp) ) {
896                    while( (c=gpg_iobuf_get(inp)) != -1 )
897                        dump_hex_line(c, &i);
898                }
899                else {
900                    for( ; pktlen; pktlen-- )
901                        dump_hex_line(gpg_iobuf_get(inp), &i);
902                }
903                putchar('\n');
904                return;
905            }
906        }
907        skip_rest(inp,pktlen);
908    }
909    
910    static void
911    skip_rest( gpg_iobuf_t inp, unsigned long pktlen )
912    {
913        if( gpg_iobuf_in_block_mode(inp) ) {
914            while( gpg_iobuf_get(inp) != -1 )
915                ;
916        }
917        else {
918            for( ; pktlen; pktlen-- )
919                if( gpg_iobuf_get(inp) == -1 )
920                    break;
921        }
922    }
923    
924    
925    static void *
926    read_rest( gpg_iobuf_t inp, size_t pktlen )
927    {
928        byte *p;
929        int i;
930        
931        if( gpg_iobuf_in_block_mode(inp) ) {
932            printf("read_rest: can't store stream data\n");
933            p = NULL;
934        }
935        else {
936            p = malloc( pktlen );
937            for(i=0; pktlen; pktlen--, i++ )
938                p[i] = gpg_iobuf_get(inp);
939        }
940        return p;
941    }
942    
943    
944    
945    static int
946    parse_symkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )
947    {
948        PKT_symkey_enc *k;
949        int rc = 0;
950        int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
951        
952        if( pktlen < 4 ) {
953            printf("packet(%d) too short\n", pkttype);
954            rc = G10ERR_INVALID_PACKET;
955            goto leave;
956        }
957        version = gpg_iobuf_get_noeof(inp); pktlen--;
958        if( version != 4 ) {
959            printf("packet(%d) with unknown version %d\n", pkttype, version);
960            rc = G10ERR_INVALID_PACKET;
961            goto leave;
962        }
963        if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
964            printf("packet(%d) too large\n", pkttype);
965            rc = G10ERR_INVALID_PACKET;
966            goto leave;
967        }
968        cipher_algo = gpg_iobuf_get_noeof(inp); pktlen--;
969        s2kmode = gpg_iobuf_get_noeof(inp); pktlen--;
970        hash_algo = gpg_iobuf_get_noeof(inp); pktlen--;
971        switch( s2kmode ) {
972        case 0:  /* simple s2k */
973            minlen = 0;
974            break;
975        case 1:  /* salted s2k */
976            minlen = 8;
977            break;
978        case 3:  /* iterated+salted s2k */
979            minlen = 9;
980            break;
981        default:
982            printf("unknown S2K %d\n", s2kmode );
983            goto leave;
984        }
985        if( minlen > pktlen ) {
986            printf("packet with S2K %d too short\n", s2kmode );
987            rc = G10ERR_INVALID_PACKET;
988            goto leave;
989        }
990        seskeylen = pktlen - minlen;
991        k = packet->pkt.symkey_enc = calloc(1, sizeof *packet->pkt.symkey_enc
992                                                    + seskeylen - 1 );
993        k->version = version;
994        k->cipher_algo = cipher_algo;
995        k->s2k.mode = s2kmode;
996        k->s2k.hash_algo = hash_algo;
997        if( s2kmode == 1 || s2kmode == 3 ) {
998            for(i=0; i < 8 && pktlen; i++, pktlen-- )
999                k->s2k.salt[i] = gpg_iobuf_get_noeof(inp);
1000        }
1001        if( s2kmode == 3 ) {
1002            k->s2k.count = gpg_iobuf_get(inp); pktlen--;
1003        }
1004        k->seskeylen = seskeylen;
1005        for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
1006            k->seskey[i] = gpg_iobuf_get_noeof(inp);
1007        assert( !pktlen );
1008        
1009        if( list_mode ) {
1010            printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
1011                   version, cipher_algo, s2kmode, hash_algo);
1012            if( s2kmode == 1 || s2kmode == 3 ) {
1013                printf("\tsalt ");
1014                for(i=0; i < 8; i++ )
1015                    printf("%02x", k->s2k.salt[i]);
1016                if( s2kmode == 3 )
1017                    printf(", count %lu\n", (ulong)k->s2k.count );
1018                printf("\n");
1019            }
1020        }
1021        
1022    leave:
1023        skip_rest(inp, pktlen);
1024        return rc;
1025    }
1026    
1027    static int
1028    parse_pubkeyenc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )
1029    {
1030        unsigned int n;
1031        int rc = 0;
1032        int i, ndata;
1033        PKT_pubkey_enc *k;
1034        
1035        k = packet->pkt.pubkey_enc = calloc(1, sizeof *packet->pkt.pubkey_enc);
1036        if( pktlen < 12 ) {
1037            printf("packet(%d) too short\n", pkttype);
1038            rc = G10ERR_INVALID_PACKET;
1039            goto leave;
1040        }
1041        k->version = gpg_iobuf_get_noeof(inp); pktlen--;
1042        if( k->version != 2 && k->version != 3 ) {
1043            printf("packet(%d) with unknown version %d\n", pkttype, k->version);
1044            rc = G10ERR_INVALID_PACKET;
1045            goto leave;
1046        }
1047        k->keyid[0] = read_32(inp); pktlen -= 4;
1048        k->keyid[1] = read_32(inp); pktlen -= 4;
1049        k->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1050        k->throw_keyid = 0; /* only used as flag for build_packet */
1051        if( list_mode )
1052            printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
1053                   k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
1054        
1055        ndata = pubkey_get_nenc(k->pubkey_algo);
1056        if( !ndata ) {
1057            if( list_mode )
1058                printf("\tunsupported algorithm %d\n", k->pubkey_algo );
1059            unknown_pubkey_warning( k->pubkey_algo );
1060            k->data[0] = NULL;  /* no need to store the encrypted data */
1061        }
1062        else {
1063            for( i=0; i < ndata; i++ ) {
1064                n = pktlen;
1065                k->data[i] = mpi_read(inp, &n, 0); pktlen -=n;
1066                if( list_mode ) {
1067                    printf("\tdata: ");
1068                    mpi_print(stdout, k->data[i], mpi_print_mode );
1069                    putchar('\n');
1070                }
1071                if (!k->data[i])
1072                    rc = G10ERR_INVALID_PACKET;
1073            }
1074        }
1075        
1076    leave:
1077        skip_rest(inp, pktlen);
1078        return rc;
1079    }
1080    
1081    static void
1082    dump_sig_subpkt( int hashed, int type, int critical,
1083                     const byte *buffer, size_t buflen, size_t length )
1084    {
1085        const char *p=NULL;
1086        int i;
1087        
1088        /* The CERT has warning out with explains how to use GNUPG to
1089         * detect the ARRs - we print our old message here when it is a faked
1090         * ARR and add an additional notice */
1091        if ( type == SIGSUBPKT_ARR && !hashed ) {
1092            printf("\tsubpkt %d len %u (additional recipient request)\n"
1093                   "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
1094                   "encrypt to this key and thereby reveal the plaintext to "
1095                   "the owner of this ARR key. Detailed info follows:\n",
1096                   type, (unsigned)length );
1097        }
1098        
1099        
1100        printf("\t%s%ssubpkt %d len %u (", /*)*/
1101               critical ? "critical ":"",
1102               hashed ? "hashed ":"", type, (unsigned)length );
1103        buffer++;
1104        length--;
1105        if( length > buflen ) {
1106            printf("too short: buffer is only %u)\n", (unsigned)buflen );
1107            return;
1108        }
1109        switch( type ) {
1110        case SIGSUBPKT_SIG_CREATED:
1111            if( length >= 4 )
1112                printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
1113            break;
1114        case SIGSUBPKT_SIG_EXPIRE:
1115            if( length >= 4 )
1116                printf("sig expires after %s",
1117                       strtimevalue( buffer_to_u32(buffer) ) );
1118            break;
1119        case SIGSUBPKT_EXPORTABLE:
1120            if( length )
1121                printf("%sexportable", *buffer? "":"not ");
1122            break;
1123        case SIGSUBPKT_TRUST:
1124            if(length!=2)
1125                p="[invalid trust signature]";
1126            else
1127                printf("trust signature of level %d, amount %d",buffer[0],buffer[1]);
1128            break;
1129        case SIGSUBPKT_REGEXP:
1130            if(!length)
1131                p="[invalid regexp]";
1132            else
1133                printf("regular expression: \"%s\"",buffer);
1134            break;
1135        case SIGSUBPKT_REVOCABLE:
1136            if( length )
1137                printf("%srevocable", *buffer? "":"not ");
1138            break;
1139        case SIGSUBPKT_KEY_EXPIRE:
1140            if( length >= 4 )
1141                printf("key expires after %s",
1142                       strtimevalue( buffer_to_u32(buffer) ) );
1143            break;
1144        case SIGSUBPKT_PREF_SYM:
1145            fputs("pref-sym-algos:", stdout );
1146            for( i=0; i < length; i++ )
1147                printf(" %d", buffer[i] );
1148            break;
1149        case SIGSUBPKT_REV_KEY:
1150            fputs("revocation key: ", stdout );
1151            if( length < 22 )
1152                p = "[too short]";
1153            else {
1154                printf("c=%02x a=%d f=", buffer[0], buffer[1] );
1155                for( i=2; i < length; i++ )
1156                    printf("%02X", buffer[i] );
1157            }
1158            break;
1159        case SIGSUBPKT_ISSUER:
1160            if( length >= 8 )
1161                printf("issuer key ID %08lX%08lX",
1162                       (ulong)buffer_to_u32(buffer),
1163                       (ulong)buffer_to_u32(buffer+4) );
1164            break;
1165        case SIGSUBPKT_NOTATION:
1166        {
1167            fputs("notation: ", stdout );
1168            if( length < 8 )
1169                p = "[too short]";
1170            else if( !(*buffer & 0x80) )
1171                p = "[not human readable]";
1172            else {
1173                const byte *s = buffer;
1174                size_t n1, n2;
1175                
1176                n1 = (s[4] << 8) | s[5];
1177                n2 = (s[6] << 8) | s[7];
1178                s += 8;
1179                if( 8+n1+n2 != length )
1180                    p = "[error]";
1181                else {
1182                    print_string( stdout, s, n1, ')' );
1183                    putc( '=', stdout );
1184                    print_string( stdout, s+n1, n2, ')' );
1185                }
1186            }
1187        }
1188        break;
1189        case SIGSUBPKT_PREF_HASH:
1190            fputs("pref-hash-algos:", stdout );
1191            for( i=0; i < length; i++ )
1192                printf(" %d", buffer[i] );
1193            break;
1194        case SIGSUBPKT_PREF_COMPR:
1195            fputs("pref-zip-algos:", stdout );
1196            for( i=0; i < length; i++ )
1197                printf(" %d", buffer[i] );
1198            break;
1199        case SIGSUBPKT_KS_FLAGS:
1200            fputs("key server preferences:",stdout);
1201            for(i=0;i<length;i++)
1202                printf(" %02X", buffer[i]);
1203            break;
1204        case SIGSUBPKT_PREF_KS:
1205            p = "preferred key server";
1206            break;
1207        case SIGSUBPKT_PRIMARY_UID:
1208            p = "primary user ID";
1209            break;
1210        case SIGSUBPKT_POLICY:
1211            fputs("policy: ", stdout );
1212            print_string( stdout, buffer, length, ')' );
1213            break;
1214        case SIGSUBPKT_KEY_FLAGS:
1215            fputs ( "key flags:", stdout );
1216            for( i=0; i < length; i++ )
1217                printf(" %02X", buffer[i] );
1218            break;
1219        case SIGSUBPKT_SIGNERS_UID:
1220            p = "signer's user ID";
1221            break;
1222        case SIGSUBPKT_REVOC_REASON:
1223            if( length ) {
1224                printf("revocation reason 0x%02x (", *buffer );
1225                print_string( stdout, buffer+1, length-1, ')' );
1226                p = ")";
1227            }
1228            break;
1229        case SIGSUBPKT_ARR:
1230            fputs("Big Brother's key (ignored): ", stdout );
1231            if( length < 22 )
1232                p = "[too short]";
1233            else {
1234                printf("c=%02x a=%d f=", buffer[0], buffer[1] );
1235                for( i=2; i < length; i++ )
1236                    printf("%02X", buffer[i] );
1237            }
1238            break;
1239        case SIGSUBPKT_FEATURES:
1240            fputs ( "features:", stdout );
1241            for( i=0; i < length; i++ )
1242                printf(" %02x", buffer[i] );
1243            break;
1244        case SIGSUBPKT_PRIV_VERIFY_CACHE:
1245            p = "obsolete verification cache";
1246            break;
1247        default: p = "?"; break;
1248        }
1249        
1250        printf("%s)\n", p? p: "");
1251    }
1252    
1253    /****************
1254     * Returns: >= 0 offset into buffer
1255     *          -1 unknown type
1256     *          -2 unsupported type
1257     *          -3 subpacket too short
1258     */
1259    int
1260    parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
1261    {
1262        switch( type ) {
1263        case SIGSUBPKT_REV_KEY:
1264            if(n < 22)
1265                break;
1266            return 0;
1267        case SIGSUBPKT_SIG_CREATED:
1268        case SIGSUBPKT_SIG_EXPIRE:
1269        case SIGSUBPKT_KEY_EXPIRE:
1270            if( n < 4 )
1271                break;
1272            return 0;
1273        case SIGSUBPKT_KEY_FLAGS:
1274        case SIGSUBPKT_KS_FLAGS:
1275        case SIGSUBPKT_PREF_SYM:
1276        case SIGSUBPKT_PREF_HASH:
1277        case SIGSUBPKT_PREF_COMPR:
1278        case SIGSUBPKT_POLICY:
1279        case SIGSUBPKT_FEATURES:
1280            return 0;
1281        case SIGSUBPKT_EXPORTABLE:
1282        case SIGSUBPKT_REVOCABLE:
1283            if( !n )
1284                break;
1285            return 0;
1286        case SIGSUBPKT_ISSUER: /* issuer key ID */
1287            if( n < 8 )
1288                break;
1289            return 0;
1290        case SIGSUBPKT_NOTATION:
1291            if( n < 8 ) /* minimum length needed */
1292                break;
1293            return 0;
1294        case SIGSUBPKT_REVOC_REASON:
1295            if( !n  )
1296                break;
1297            return 0;
1298        case SIGSUBPKT_PRIMARY_UID:
1299            if ( n != 1 )
1300                break;
1301            return 0;  
1302        case SIGSUBPKT_PRIV_VERIFY_CACHE:
1303            /* We used this in gpg 1.0.5 and 1.0.6 to cache signature
1304             * verification results - it is no longer used.
1305             * "GPG" 0x00 <mode> <stat>
1306             * where mode == 1: valid data, stat == 0: invalid signature
1307             * stat == 1: valid signature
1308             * (because we use private data, we check our marker) */
1309            if( n < 6 )
1310                break;
1311            if( buffer[0] != 'G' || buffer[1] != 'P'
1312                || buffer[2] != 'G' || buffer[3] )
1313                return -2;
1314            return 4;
1315        default: return -1;
1316        }
1317        return -3;
1318    }
1319    
1320    
1321    static int
1322    can_handle_critical( const byte *buffer, size_t n, int type )
1323    {
1324        switch( type ) {
1325        case SIGSUBPKT_NOTATION:
1326            if( n >= 8 && (*buffer & 0x80) )
1327                return 1; /* human readable is handled */
1328            return 0;
1329            
1330        case SIGSUBPKT_SIG_CREATED:
1331        case SIGSUBPKT_SIG_EXPIRE:
1332        case SIGSUBPKT_KEY_EXPIRE:
1333        case SIGSUBPKT_EXPORTABLE:
1334        case SIGSUBPKT_REVOCABLE:
1335        case SIGSUBPKT_REV_KEY:
1336        case SIGSUBPKT_ISSUER:/* issuer key ID */
1337        case SIGSUBPKT_PREF_SYM:
1338        case SIGSUBPKT_PREF_HASH:
1339        case SIGSUBPKT_PREF_COMPR:
1340        case SIGSUBPKT_KEY_FLAGS:
1341        case SIGSUBPKT_PRIMARY_UID:
1342        case SIGSUBPKT_FEATURES:
1343        case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
1344            return 1;
1345            
1346        default:
1347            return 0;
1348        }
1349    }
1350    
1351    
1352    const byte *
1353    enum_sig_subpkt( const subpktarea_t *pktbuf, sigsubpkttype_t reqtype,
1354                     size_t *ret_n, int *start, int *critical )
1355    {
1356        const byte *buffer;
1357        int buflen;
1358        int type;
1359        int critical_dummy;
1360        int offset;
1361        size_t n;
1362        int seq = 0;
1363        int reqseq = start? *start: 0;
1364        
1365        if(!critical)
1366            critical=&critical_dummy;
1367        
1368        if( !pktbuf || reqseq == -1 ) {
1369            /* return some value different from NULL to indicate that
1370             * there is no critical bit we do not understand.  The caller
1371             * will never use the value.  Yes I know, it is an ugly hack */
1372            return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&pktbuf : NULL;
1373        }
1374        buffer = pktbuf->data;
1375        buflen = pktbuf->len;
1376        while( buflen ) {
1377            n = *buffer++; buflen--;
1378            if( n == 255 ) { /* 4 byte length header */
1379                if( buflen < 4 )
1380                    goto too_short;
1381                n = (buffer[0] << 24) | (buffer[1] << 16)
1382                    | (buffer[2] << 8) | buffer[3];
1383                buffer += 4;
1384                buflen -= 4;
1385            }
1386            else if( n >= 192 ) { /* 2 byte special encoded length header */
1387                if( buflen < 2 )
1388                    goto too_short;
1389                n = (( n - 192 ) << 8) + *buffer + 192;
1390                buffer++;
1391                buflen--;
1392            }
1393            if( buflen < n )
1394                goto too_short;
1395            type = *buffer;
1396            if( type & 0x80 ) {
1397                type &= 0x7f;
1398                *critical = 1;
1399            }
1400            else
1401                *critical = 0;
1402            if( !(++seq > reqseq) )
1403                ;
1404            else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
1405                if( *critical ) {
1406                    if( n-1 > buflen+1 )
1407                        goto too_short;
1408                    if( !can_handle_critical(buffer+1, n-1, type ) ) {
1409                        printf("subpacket of type %d has critical bit set\n",
1410                               type);
1411                        if( start )
1412                            *start = seq;
1413                        return NULL; /* this is an error */
1414                    }
1415                }
1416            }
1417            else if( reqtype < 0 ) /* list packets */
1418                dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
1419                                 type, *critical, buffer, buflen, n );
1420            else if( type == reqtype ) { /* found */
1421                buffer++;
1422                n--;
1423                if( n > buflen )
1424                    goto too_short;
1425                if( ret_n )
1426                    *ret_n = n;
1427                offset = parse_one_sig_subpkt(buffer, n, type );
1428                switch( offset ) {
1429                case -3:
1430                    printf("subpacket of type %d too short\n", type);
1431                    return NULL;
1432                case -2:
1433                    return NULL;
1434                case -1:
1435                    printf( "This is a BUG.\n%s:%d\n", __FILE__, __LINE__ );
1436                    exit( -1 );
1437                default:
1438                    break;
1439                }
1440                if( start )
1441                    *start = seq;
1442                return buffer+offset;
1443            }
1444            buffer += n; buflen -=n;
1445        }
1446        if( reqtype == SIGSUBPKT_TEST_CRITICAL )
1447            return buffer; /* as value true to indicate that there is no */
1448        /* critical bit we don't understand */
1449        if( start )
1450            *start = -1;
1451        return NULL; /* end of packets; not found */
1452        
1453    too_short:
1454        printf("buffer shorter than subpacket\n");
1455        if( start )
1456            *start = -1;
1457        return NULL;
1458    }
1459    
1460    
1461    const byte *
1462    gpg_parse_sig_subpkt (const subpktarea_t *buffer, sigsubpkttype_t reqtype,
1463                      size_t *ret_n)
1464    {
1465        return enum_sig_subpkt( buffer, reqtype, ret_n, NULL, NULL );
1466    }
1467    
1468    const byte *
1469    gpg_parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype,
1470                       size_t *ret_n )
1471    {
1472        const byte *p;
1473        
1474        p = gpg_parse_sig_subpkt (sig->hashed, reqtype, ret_n );
1475        if( !p )
1476            p = gpg_parse_sig_subpkt (sig->unhashed, reqtype, ret_n );
1477        return p;
1478    }
1479    
1480    /* Find all revocation keys. Look in hashed area only. */
1481    void parse_revkeys(PKT_signature *sig)
1482    {
1483        struct revocation_key *revkey;
1484        int seq=0;
1485        size_t len;
1486        
1487        if( sig->sig_class != 0x1F )
1488            return;
1489        
1490        while((revkey=
1491               (struct revocation_key *)enum_sig_subpkt(sig->hashed,
1492                                                        SIGSUBPKT_REV_KEY,
1493                                                        &len,&seq,NULL))) {
1494            if( len==sizeof(struct revocation_key) &&
1495                (revkey->rclass&0x80)) /* 0x80 bit must be set */ {
1496                sig->revkey=realloc(sig->revkey,
1497                                      sizeof(struct revocation_key *)*(sig->numrevkeys+1));
1498                sig->revkey[sig->numrevkeys]=revkey;
1499                sig->numrevkeys++;
1500            }
1501        }
1502    }
1503    
1504    static int
1505    parse_signature( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
1506                                              PKT_signature *sig )
1507    {
1508        int md5_len=0;
1509        unsigned n;
1510        int is_v4=0;
1511        int rc=0;
1512        int i, ndata;
1513        
1514        if( pktlen < 16 ) {
1515            printf("packet(%d) too short\n", pkttype);
1516            goto leave;
1517        }
1518        sig->version = gpg_iobuf_get_noeof(inp); pktlen--;
1519        if( sig->version == 4 )
1520            is_v4=1;
1521        else if( sig->version != 2 && sig->version != 3 ) {
1522            printf("packet(%d) with unknown version %d\n", pkttype, sig->version);
1523            rc = G10ERR_INVALID_PACKET;
1524            goto leave;
1525        }
1526        
1527        if( !is_v4 ) {
1528            md5_len = gpg_iobuf_get_noeof(inp); pktlen--;
1529        }
1530        sig->sig_class = gpg_iobuf_get_noeof(inp); pktlen--;
1531        if( !is_v4 ) {
1532            sig->timestamp = read_32(inp); pktlen -= 4;
1533            sig->keyid[0] = read_32(inp); pktlen -= 4;
1534            sig->keyid[1] = read_32(inp); pktlen -= 4;
1535        }
1536        sig->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1537        sig->digest_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1538        sig->flags.exportable=1;
1539        sig->flags.revocable=1;
1540        if( is_v4 ) { /* read subpackets */
1541            n = read_16(inp); pktlen -= 2; /* length of hashed data */
1542            if( n > 10000 ) {
1543                printf("signature packet: hashed data too long\n");
1544                rc = G10ERR_INVALID_PACKET;
1545                goto leave;
1546            }
1547            if( n ) {
1548                sig->hashed = malloc (sizeof (*sig->hashed) + n - 1 );
1549                sig->hashed->size = n;
1550                sig->hashed->len = n;
1551                if( gpg_iobuf_read (inp, sig->hashed->data, n ) != n ) {
1552                    printf ("premature eof while reading "
1553                            "hashed signature data\n");
1554                    rc = -1;
1555                    goto leave;
1556                }
1557                pktlen -= n;
1558            }
1559            n = read_16(inp); pktlen -= 2; /* length of unhashed data */
1560            if( n > 10000 ) {
1561                printf("signature packet: unhashed data too long\n");
1562                rc = G10ERR_INVALID_PACKET;
1563                goto leave;
1564            }
1565            if( n ) {
1566                /* we add 8 extra bytes so that we have space for the signature
1567                 * status cache.  Well we are wastin this if there is a cache
1568                 * packet already, but in the other case it avoids an realloc */
1569                sig->unhashed = malloc (sizeof(*sig->unhashed) + n + 8 - 1 );
1570                sig->unhashed->size = n + 8;
1571                sig->unhashed->len = n;
1572                if( gpg_iobuf_read(inp, sig->unhashed->data, n ) != n ) {
1573                    printf("premature eof while reading "
1574                           "unhashed signature data\n");
1575                    rc = -1;
1576                    goto leave;
1577                }
1578                pktlen -= n;
1579            }
1580        }
1581        
1582        if( pktlen < 5 ) { /* sanity check */
1583            printf("packet(%d) too short\n", pkttype);
1584            rc = G10ERR_INVALID_PACKET;
1585            goto leave;
1586        }
1587        
1588        sig->digest_start[0] = gpg_iobuf_get_noeof(inp); pktlen--;
1589        sig->digest_start[1] = gpg_iobuf_get_noeof(inp); pktlen--;
1590        
1591        if( is_v4 && sig->pubkey_algo ) { /*extract required information */
1592            const byte *p;
1593            
1594            /* set sig->flags.unknown_critical if there is a
1595             * critical bit set for packets which we do not understand */
1596            if( !gpg_parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)
1597                || !gpg_parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL,
1598                                      NULL) )
1599            {
1600                sig->flags.unknown_critical = 1;
1601            }
1602            
1603            p = gpg_parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL );
1604            if( !p )
1605                printf("signature packet without timestamp\n");
1606            else
1607                sig->timestamp = buffer_to_u32(p);
1608            p = gpg_parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
1609            if( !p )
1610                printf("signature packet without keyid\n");
1611            else {
1612                sig->keyid[0] = buffer_to_u32(p);
1613                sig->keyid[1] = buffer_to_u32(p+4);
1614            }
1615            
1616            p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL);
1617            if(p)
1618                sig->expiredate=sig->timestamp+buffer_to_u32(p);
1619            if(sig->expiredate && sig->expiredate<=time(NULL))
1620                sig->flags.expired=1;
1621            
1622            p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,NULL);
1623            if(p)
1624                sig->flags.policy_url=1;
1625            
1626            p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL);
1627            if(p)
1628                sig->flags.notation=1;
1629            
1630            p=gpg_parse_sig_subpkt(sig->hashed,SIGSUBPKT_REVOCABLE,NULL);
1631            if(p && *p==0)
1632                sig->flags.revocable=0;
1633            
1634            /* We accept the exportable subpacket from either the hashed
1635               or unhashed areas as older versions of gpg put it in the
1636               unhashed area.  In theory, anyway, we should never see this
1637               packet off of a local keyring. */
1638            
1639            p=gpg_parse_sig_subpkt2(sig,SIGSUBPKT_EXPORTABLE,NULL);
1640            if(p && *p==0)
1641                sig->flags.exportable=0;
1642            
1643            /* Find all revocation keys. */
1644            if(sig->sig_class==0x1F)
1645                parse_revkeys(sig);
1646        }
1647        
1648        if( list_mode ) {
1649            printf(":signature packet: algo %d, keyid %08lX%08lX\n"
1650                   "\tversion %d, created %lu, md5len %d, sigclass %02x\n"
1651                   "\tdigest algo %d, begin of digest %02x %02x\n",
1652                   sig->pubkey_algo,
1653                   (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1654                   sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class,
1655                   sig->digest_algo,
1656                   sig->digest_start[0], sig->digest_start[1] );
1657            if( is_v4 ) {
1658                gpg_parse_sig_subpkt (sig->hashed,   SIGSUBPKT_LIST_HASHED, NULL );
1659                gpg_parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
1660            }
1661        }
1662        
1663        ndata = pubkey_get_nsig(sig->pubkey_algo);
1664        if( !ndata ) {
1665            if( list_mode )
1666                printf("\tunknown algorithm %d\n", sig->pubkey_algo );
1667            unknown_pubkey_warning( sig->pubkey_algo );
1668            /* we store the plain material in data[0], so that we are able
1669             * to write it back with build_packet() */
1670            sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen );
1671            pktlen = 0;
1672        }
1673        else {
1674            for( i=0; i < ndata; i++ ) {
1675                n = pktlen;
1676                sig->data[i] = mpi_read(inp, &n, 0 );
1677                pktlen -=n;
1678                if( list_mode ) {
1679                    printf("\tdata: ");
1680                    mpi_print(stdout, sig->data[i], mpi_print_mode );
1681                    putchar('\n');
1682                }
1683                if (!sig->data[i])
1684                    rc = G10ERR_INVALID_PACKET;
1685            }
1686        }
1687        
1688    leave:
1689        skip_rest(inp, pktlen);
1690        return rc;
1691    }
1692    
1693    
1694    static int
1695    parse_onepass_sig( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
1696                                                 PKT_onepass_sig *ops )
1697    {
1698        int version;
1699        int rc = 0;
1700        
1701        if( pktlen < 13 ) {
1702            printf("packet(%d) too short\n", pkttype);
1703            rc = G10ERR_INVALID_PACKET;
1704            goto leave;
1705        }
1706        version = gpg_iobuf_get_noeof(inp); pktlen--;
1707        if( version != 3 ) {
1708            printf("onepass_sig with unknown version %d\n", version);
1709            rc = G10ERR_INVALID_PACKET;
1710            goto leave;
1711        }
1712        ops->sig_class = gpg_iobuf_get_noeof(inp); pktlen--;
1713        ops->digest_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1714        ops->pubkey_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1715        ops->keyid[0] = read_32(inp); pktlen -= 4;
1716        ops->keyid[1] = read_32(inp); pktlen -= 4;
1717        ops->last = gpg_iobuf_get_noeof(inp); pktlen--;
1718        if( list_mode )
1719            printf(":onepass_sig packet: keyid %08lX%08lX\n"
1720                   "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n",
1721                   (ulong)ops->keyid[0], (ulong)ops->keyid[1],
1722                   version, ops->sig_class,
1723                   ops->digest_algo, ops->pubkey_algo, ops->last );
1724        
1725        
1726    leave:
1727        skip_rest(inp, pktlen);
1728        return rc;
1729    }
1730    
1731    
1732    static int
1733    parse_key( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
1734                                  byte *hdr, int hdrlen, PACKET *pkt )
1735    {
1736        int i, version, algorithm;
1737        unsigned n;
1738        unsigned long timestamp, expiredate, max_expiredate;
1739        int npkey, nskey;
1740        int is_v4=0;
1741        int rc=0;
1742    
1743        version = gpg_iobuf_get_noeof(inp); pktlen--;
1744        if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
1745            /* early versions of G10 use old PGP comments packets;
1746             * luckily all those comments are started by a hash */
1747            if( list_mode ) {
1748                printf(":rfc1991 comment packet: \"" );
1749                for( ; pktlen; pktlen-- ) {
1750                    int c;
1751                    c = gpg_iobuf_get_noeof(inp);
1752                    if( c >= ' ' && c <= 'z' )
1753                        putchar(c);
1754                    else
1755                        printf("\\x%02x", c );
1756                }
1757                printf("\"\n");
1758            }
1759            skip_rest(inp, pktlen);
1760            return 0;
1761        }
1762        else if( version == 4 )
1763            is_v4=1;
1764        else if( version != 2 && version != 3 ) {
1765            printf("packet(%d) with unknown version %d\n", pkttype, version);
1766            rc = G10ERR_INVALID_PACKET;
1767            goto leave;
1768        }
1769    
1770        if( pktlen < 11 ) {
1771            printf("packet(%d) too short\n", pkttype);
1772            rc = G10ERR_INVALID_PACKET;
1773            goto leave;
1774        }
1775    
1776        timestamp = read_32(inp); pktlen -= 4;
1777        if( is_v4 ) {
1778            expiredate = 0; /* have to get it from the selfsignature */
1779            max_expiredate = 0;
1780        }
1781        else {
1782            unsigned short ndays;
1783            ndays = read_16(inp); pktlen -= 2;
1784            if( ndays )
1785                expiredate = timestamp + ndays * 86400L;
1786            else
1787                expiredate = 0;
1788    
1789            max_expiredate=expiredate;
1790        }
1791        algorithm = gpg_iobuf_get_noeof(inp); pktlen--;
1792        if( list_mode )
1793            printf(":%s key packet:\n"
1794                   "\tversion %d, algo %d, created %lu, expires %lu\n",
1795                    pkttype == PKT_PUBLIC_KEY? "public" :
1796                    pkttype == PKT_SECRET_KEY? "secret" :
1797                    pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
1798                    pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
1799                    version, algorithm, timestamp, expiredate );
1800    
1801        if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
1802            PKT_secret_key *sk = pkt->pkt.secret_key;
1803    
1804            sk->timestamp = timestamp;
1805            sk->expiredate = expiredate;
1806            sk->max_expiredate = max_expiredate;
1807            sk->hdrbytes = hdrlen;
1808            sk->version = version;
1809            sk->is_primary = pkttype == PKT_SECRET_KEY;
1810            sk->pubkey_algo = algorithm;
1811            sk->req_usage = 0;
1812            sk->pubkey_usage = 0; /* not yet used */
1813        }
1814        else {
1815            PKT_public_key *pk = pkt->pkt.public_key;
1816    
1817            pk->timestamp = timestamp;
1818            pk->expiredate = expiredate;
1819            pk->max_expiredate = max_expiredate;
1820            pk->hdrbytes    = hdrlen;
1821            pk->version     = version;
1822            pk->is_primary = pkttype == PKT_PUBLIC_KEY;
1823            pk->pubkey_algo = algorithm;
1824            pk->req_usage = 0;
1825            pk->pubkey_usage = 0; /* not yet used */
1826            pk->is_revoked = 0;    
1827            pk->keyid[0] = 0;
1828            pk->keyid[1] = 0;
1829        }
1830        nskey = pubkey_get_nskey( algorithm );
1831        npkey = pubkey_get_npkey( algorithm );
1832        if( !npkey ) {
1833            if( list_mode )
1834                printf("\tunknown algorithm %d\n", algorithm );
1835            unknown_pubkey_warning( algorithm );
1836        }
1837    
1838    
1839        if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
1840            PKT_secret_key *sk = pkt->pkt.secret_key;
1841            byte temp[16];
1842            size_t snlen = 0;
1843    
1844            if( !npkey ) {
1845                sk->skey[0] = mpi_set_opaque( NULL,
1846                                              read_rest(inp, pktlen), pktlen );
1847                pktlen = 0;
1848                goto leave;
1849            }
1850    
1851            for(i=0; i < npkey; i++ ) {
1852                n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
1853                if( list_mode ) {
1854                    printf(  "\tskey[%d]: ", i);
1855                    mpi_print(stdout, sk->skey[i], mpi_print_mode  );
1856                    putchar('\n');
1857                }
1858                if (!sk->skey[i])
1859                    rc = G10ERR_INVALID_PACKET;
1860            }
1861            if (rc) /* one of the MPIs were bad */
1862                goto leave;
1863            sk->protect.algo = gpg_iobuf_get_noeof(inp); pktlen--;
1864            sk->protect.sha1chk = 0;
1865            if( sk->protect.algo ) {
1866                sk->is_protected = 1;
1867                sk->protect.s2k.count = 0;
1868                if( sk->protect.algo == 254 || sk->protect.algo == 255 ) {
1869                    if( pktlen < 3 ) {
1870                        rc = G10ERR_INVALID_PACKET;
1871                        goto leave;
1872                    }
1873                    sk->protect.sha1chk = (sk->protect.algo == 254);
1874                    sk->protect.algo = gpg_iobuf_get_noeof(inp); pktlen--;
1875                    /* Note that a sk->protect.algo > 110 is illegal, but
1876                       I'm not erroring on it here as otherwise there
1877                       would be no way to delete such a key. */
1878                    sk->protect.s2k.mode  = gpg_iobuf_get_noeof(inp); pktlen--;
1879                    sk->protect.s2k.hash_algo = gpg_iobuf_get_noeof(inp); pktlen--;
1880                    /* check for the special GNU extension */
1881                    if( is_v4 && sk->protect.s2k.mode == 101 ) {
1882                        for(i=0; i < 4 && pktlen; i++, pktlen-- )
1883                            temp[i] = gpg_iobuf_get_noeof(inp);
1884                        if( i < 4 || memcmp( temp, "GNU", 3 ) ) {
1885                            if( list_mode )
1886                                printf(  "\tunknown S2K %d\n",
1887                                                    sk->protect.s2k.mode );
1888                            rc = G10ERR_INVALID_PACKET;
1889                            goto leave;
1890                        }
1891                        /* here we know that it is a gnu extension
1892                         * What follows is the GNU protection mode:
1893                         * All values have special meanings
1894                         * and they are mapped in the mode with a base of 1000.
1895                         */
1896                        sk->protect.s2k.mode = 1000 + temp[3];
1897                    }
1898                    switch( sk->protect.s2k.mode ) {
1899                      case 1:
1900                      case 3:
1901                        for(i=0; i < 8 && pktlen; i++, pktlen-- )
1902                            temp[i] = gpg_iobuf_get_noeof(inp);
1903                        memcpy(sk->protect.s2k.salt, temp, 8 );
1904                        break;
1905                    }
1906                    switch( sk->protect.s2k.mode ) {
1907                      case 0: if( list_mode ) printf(  "\tsimple S2K" );
1908                        break;
1909                      case 1: if( list_mode ) printf(  "\tsalted S2K" );
1910                        break;
1911                      case 3: if( list_mode ) printf(  "\titer+salt S2K" );
1912                        break;
1913                      case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );
1914                        break;
1915                      case 1002: if (list_mode) printf("\tgnu-divert-to-card S2K");
1916                        break;
1917                      default:
1918                        if( list_mode )
1919                            printf(  "\tunknown %sS2K %d\n",
1920                                     sk->protect.s2k.mode < 1000? "":"GNU ",
1921                                                       sk->protect.s2k.mode );
1922                        rc = G10ERR_INVALID_PACKET;
1923                        goto leave;
1924                    }
1925    
1926                    if( list_mode ) {
1927                        printf(", algo: %d,%s hash: %d",
1928                                         sk->protect.algo,
1929                                         sk->protect.sha1chk?" SHA1 protection,"
1930                                                            :" simple checksum,",
1931                                         sk->protect.s2k.hash_algo );
1932                        if( sk->protect.s2k.mode == 1
1933                            || sk->protect.s2k.mode == 3 ) {
1934                            printf(", salt: ");
1935                            for(i=0; i < 8; i++ )
1936                                printf("%02x", sk->protect.s2k.salt[i]);
1937                        }
1938                        putchar('\n');
1939                    }
1940    
1941                    if( sk->protect.s2k.mode == 3 ) {
1942                        if( pktlen < 1 ) {
1943                            rc = G10ERR_INVALID_PACKET;
1944                            goto leave;
1945                        }
1946                        sk->protect.s2k.count = gpg_iobuf_get(inp);
1947                        pktlen--;
1948                        if( list_mode )
1949                            printf("\tprotect count: %lu\n",
1950                                                (ulong)sk->protect.s2k.count);
1951                    }
1952                    else if( sk->protect.s2k.mode == 1002 ) {
1953                        /* Read the serial number. */
1954                        if (pktlen < 1) {
1955                          rc = G10ERR_INVALID_PACKET;
1956                            goto leave;
1957                        }
1958                        snlen = gpg_iobuf_get (inp);
1959                        pktlen--;
1960                        if (pktlen < snlen || snlen == -1) {
1961                            rc = G10ERR_INVALID_PACKET;
1962                            goto leave;
1963                        }
1964                    }
1965                }
1966                /* Note that a sk->protect.algo > 110 is illegal, but I'm
1967                   not erroring on it here as otherwise there would be no
1968                   way to delete such a key. */
1969                else { /* old version; no S2K, so we set mode to 0, hash MD5 */
1970                    sk->protect.s2k.mode = 0;
1971                    sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5;
1972                    if( list_mode )
1973                        printf(  "\tprotect algo: %d  (hash algo: %d)\n",
1974                             sk->protect.algo, sk->protect.s2k.hash_algo );
1975                }
1976                /* It is really ugly that we don't know the size
1977                 * of the IV here in cases we are not aware of the algorithm.
1978                 * so a
1979                 *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);
1980                 * won't work.  The only solution I see is to hardwire it here.
1981                 * NOTE: if you change the ivlen above 16, don't forget to
1982                 * enlarge temp.
1983                 */
1984                switch( sk->protect.algo ) {
1985                  case 7: case 8: case 9: /* reserved for AES */
1986                  case 10: /* Twofish */
1987                    sk->protect.ivlen = 16;
1988                    break;
1989                  default:
1990                    sk->protect.ivlen = 8;
1991                }
1992                if( sk->protect.s2k.mode == 1001 )
1993                    sk->protect.ivlen = 0;
1994                else if( sk->protect.s2k.mode == 1002 )
1995                    sk->protect.ivlen = snlen < 16? snlen : 16;
1996    
1997                if( pktlen < sk->protect.ivlen ) {
1998                    rc = G10ERR_INVALID_PACKET;
1999                    goto leave;
2000                }
2001                for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
2002                    temp[i] = gpg_iobuf_get_noeof(inp);
2003                if( list_mode ) {
2004                    printf( sk->protect.s2k.mode == 1002? "\tserial-number: "
2005                                                        : "\tprotect IV: ");
2006                    for(i=0; i < sk->protect.ivlen; i++ )
2007                        printf(" %02x", temp[i] );
2008                    putchar('\n');
2009                }
2010                memcpy( sk->protect.iv, temp, sk->protect.ivlen );
2011            }
2012            else
2013                sk->is_protected = 0;
2014            /* It does not make sense to read it into secure memory.
2015             * If the user is so careless, not to protect his secret key,
2016             * we can assume, that he operates an open system :=(.
2017             * So we put the key into secure memory when we unprotect it. */
2018            if( sk->protect.s2k.mode == 1001
2019                || sk->protect.s2k.mode == 1002 ) {
2020                /* better set some dummy stuff here */
2021                sk->skey[npkey] = mpi_set_opaque(NULL, strdup("dummydata"), 10);
2022                pktlen = 0;
2023            }
2024            else if( is_v4 && sk->is_protected ) {
2025                /* ugly; the length is encrypted too, so we read all
2026                 * stuff up to the end of the packet into the first
2027                 * skey element */
2028                sk->skey[npkey] = mpi_set_opaque(NULL,
2029                                                 read_rest(inp, pktlen), pktlen );
2030                pktlen = 0;
2031                if( list_mode ) {
2032                    printf("\tencrypted stuff follows\n");
2033                }
2034            }
2035            else { /* v3 method: the mpi length is not encrypted */
2036                for(i=npkey; i < nskey; i++ ) {
2037                    n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
2038                    if( sk->is_protected && sk->skey[i] )
2039                        mpi_set_protect_flag(sk->skey[i]);
2040                    if( list_mode ) {
2041                        printf(  "\tskey[%d]: ", i);
2042                        if( sk->is_protected )
2043                            printf(  "[encrypted]\n");
2044                        else {
2045                            mpi_print(stdout, sk->skey[i], mpi_print_mode  );
2046                            putchar('\n');
2047                        }
2048                    }
2049                    if (!sk->skey[i])
2050                        rc = G10ERR_INVALID_PACKET;
2051                }
2052                if (rc)
2053                    goto leave;
2054                
2055                sk->csum = read_16(inp); pktlen -= 2;
2056                if( list_mode ) {
2057                    printf("\tchecksum: %04hx\n", sk->csum);
2058                }
2059            }
2060        }
2061        else {
2062            PKT_public_key *pk = pkt->pkt.public_key;
2063    
2064            if( !npkey ) {
2065                pk->pkey[0] = mpi_set_opaque( NULL,
2066                                              read_rest(inp, pktlen), pktlen );
2067                pktlen = 0;
2068                goto leave;
2069            }
2070    
2071            for(i=0; i < npkey; i++ ) {
2072                n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
2073                if( list_mode ) {
2074                    printf(  "\tpkey[%d]: ", i);
2075                    mpi_print(stdout, pk->pkey[i], mpi_print_mode  );
2076                    putchar('\n');
2077                }
2078                if (!pk->pkey[i])
2079                    rc = G10ERR_INVALID_PACKET;
2080            }
2081            if (rc)
2082                goto leave;
2083        }
2084    
2085      leave:
2086        skip_rest(inp, pktlen);
2087        return rc;
2088    }
2089    
2090    /* Attribute subpackets have the same format as v4 signature
2091       subpackets.  This is not part of OpenPGP, but is done in several
2092       versions of PGP nevertheless. */
2093    int
2094    parse_attribute_subpkts(PKT_user_id *uid)
2095    {
2096        size_t n;
2097        int count=0;
2098        struct user_attribute *attribs=NULL;
2099        const byte *buffer=uid->attrib_data;
2100        int buflen=uid->attrib_len;
2101        byte type;
2102        
2103        safe_free(uid->attribs);
2104        
2105        while(buflen) {
2106            n = *buffer++; buflen--;
2107            if( n == 255 ) { /* 4 byte length header */
2108                if( buflen < 4 )
2109                    goto too_short;
2110                n = (buffer[0] << 24) | (buffer[1] << 16)
2111                    | (buffer[2] << 8) | buffer[3];
2112                buffer += 4;
2113                buflen -= 4;
2114            }
2115            else if( n >= 192 ) { /* 2 byte special encoded length header */
2116                if( buflen < 2 )
2117                    goto too_short;
2118                n = (( n - 192 ) << 8) + *buffer + 192;
2119                buffer++;
2120                buflen--;
2121            }
2122            if( buflen < n )
2123                goto too_short;
2124            
2125            attribs=realloc(attribs,(count+1)*sizeof(struct user_attribute));
2126            memset(&attribs[count],0,sizeof(struct user_attribute));
2127            
2128            type=*buffer;
2129            buffer++;
2130            buflen--;
2131            n--;
2132            
2133            attribs[count].type=type;
2134            attribs[count].data=buffer;
2135            attribs[count].len=n;
2136            buffer+=n;
2137            buflen-=n;
2138            count++;
2139        }
2140        
2141        uid->attribs=attribs;
2142        uid->numattribs=count;
2143        return count;
2144        
2145    too_short:
2146        printf("buffer shorter than attribute subpacket\n");
2147        uid->attribs=attribs;
2148        uid->numattribs=count;
2149        return count;
2150    }
2151    
2152    static void
2153    setup_user_id(PACKET *packet)
2154    {
2155        packet->pkt.user_id->ref = 1;
2156        packet->pkt.user_id->attribs = NULL;
2157        packet->pkt.user_id->attrib_data = NULL;
2158        packet->pkt.user_id->attrib_len = 0;
2159        packet->pkt.user_id->is_primary = 0;
2160        packet->pkt.user_id->is_revoked = 0;
2161        packet->pkt.user_id->is_expired = 0;
2162        packet->pkt.user_id->expiredate = 0;
2163        packet->pkt.user_id->created = 0;
2164        packet->pkt.user_id->help_key_usage = 0;
2165        packet->pkt.user_id->help_key_expire = 0;
2166        packet->pkt.user_id->prefs = NULL;
2167    }
2168    
2169    static int
2170    parse_user_id( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )
2171    {
2172        byte *p;
2173        
2174        packet->pkt.user_id = malloc(sizeof *packet->pkt.user_id  + pktlen);
2175        packet->pkt.user_id->len = pktlen;
2176        
2177        setup_user_id(packet);
2178        
2179        p = packet->pkt.user_id->name;
2180        for( ; pktlen; pktlen--, p++ )
2181            *p = gpg_iobuf_get_noeof(inp);
2182        *p = 0;
2183        
2184        if( list_mode ) {
2185            int n = packet->pkt.user_id->len;
2186            printf(":user ID packet: \"");
2187            /* fixme: Hey why don't we replace this with print_string?? */
2188            for(p=packet->pkt.user_id->name; n; p++, n-- ) {
2189                if( *p >= ' ' && *p <= 'z' )
2190                    putchar(*p);
2191                else
2192                    printf("\\x%02x", *p );
2193            }
2194            printf("\"\n");
2195        }
2196        return 0;
2197    }
2198    
2199    /* Returns 0 for error, 1 for valid */
2200    int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
2201    {
2202        u16 headerlen;
2203        
2204        if(attr->len<3)
2205            return 0;
2206        
2207        /* For historical reasons (i.e. "oops!"), the header length is
2208           little endian. */
2209        headerlen=(attr->data[1]<<8) | attr->data[0];
2210        
2211        if(headerlen>attr->len)
2212            return 0;
2213        
2214        if(type && attr->len>=4)
2215        {
2216            if(attr->data[2]==1) /* header version 1 */
2217                *type=attr->data[3];
2218            else
2219                *type=0;
2220        }
2221        
2222        *len=attr->len-headerlen;
2223        
2224        if(*len==0)
2225            return 0;
2226        
2227        return 1;
2228    }
2229    
2230    /* style==0 for extension, 1 for name, 2 for MIME type.  Remember that
2231       the "name" style string could be used in a user ID name field, so
2232       make sure it is not too big (see
2233       parse-packet.c:parse_attribute). */
2234    char *image_type_to_string(byte type,int style)
2235    {
2236        char *string;
2237        
2238        switch(type) {
2239        case 1: /* jpeg */
2240            if(style==0)
2241                string="jpg";
2242            else if(style==1)
2243                string="jpeg";
2244            else
2245                string="image/jpeg";
2246            break;
2247            
2248        default:
2249            if(style==0)
2250                string="bin";
2251            else if(style==1)
2252                string="unknown";
2253            else
2254                string="image/x-unknown";
2255            break;
2256        }
2257        
2258        return string;
2259    }
2260    
2261    void
2262    make_attribute_uidname(PKT_user_id *uid)
2263    {
2264        if(uid->numattribs<=0)
2265            sprintf(uid->name,"[bad attribute packet of size %lu]",uid->attrib_len);
2266        else if(uid->numattribs>1)
2267            sprintf(uid->name,"[%d attributes of size %lu]",
2268                    uid->numattribs,uid->attrib_len);
2269        else {
2270            /* Only one attribute, so list it as the "user id" */
2271            
2272            if(uid->attribs->type==ATTRIB_IMAGE) {
2273                u32 len;
2274                byte type;
2275                
2276                if(parse_image_header(uid->attribs,&type,&len))
2277                    sprintf(uid->name,"[%s image of size %lu]",
2278                            image_type_to_string(type,1),(ulong)len);
2279                else
2280                    sprintf(uid->name,"[invalid image]");
2281            }
2282            else
2283                sprintf(uid->name,"[unknown attribute of size %lu]",
2284                        (ulong)uid->attribs->len);
2285        }
2286        
2287        uid->len = strlen(uid->name);
2288    }
2289    
2290    static int
2291    parse_attribute( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )
2292    {
2293        byte *p;
2294        
2295        packet->pkt.user_id = malloc(sizeof *packet->pkt.user_id + 70);
2296        
2297        setup_user_id(packet);
2298        
2299        packet->pkt.user_id->attrib_data = malloc(pktlen);
2300        packet->pkt.user_id->attrib_len = pktlen;
2301        p = packet->pkt.user_id->attrib_data;
2302        for( ; pktlen; pktlen--, p++ )
2303            *p = gpg_iobuf_get_noeof(inp);
2304        
2305        /* Now parse out the individual attribute subpackets.  This is
2306           somewhat pointless since there is only one currently defined
2307           attribute type (jpeg), but it is correct by the spec. */
2308        parse_attribute_subpkts(packet->pkt.user_id);
2309        
2310        make_attribute_uidname(packet->pkt.user_id);
2311        
2312        if( list_mode ) {
2313            printf(":attribute packet: %s\n", packet->pkt.user_id->name );
2314        }
2315        return 0;
2316    }
2317    
2318    
2319    static int
2320    parse_comment( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *packet )
2321    {
2322        byte *p;
2323        
2324        packet->pkt.comment = malloc(sizeof *packet->pkt.comment + pktlen - 1);
2325        packet->pkt.comment->len = pktlen;
2326        p = packet->pkt.comment->data;
2327        for( ; pktlen; pktlen--, p++ )
2328            *p = gpg_iobuf_get_noeof(inp);
2329        
2330        if( list_mode ) {
2331            int n = packet->pkt.comment->len;
2332            printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT?
2333                   "OpenPGP draft " : "" );
2334            for(p=packet->pkt.comment->data; n; p++, n-- ) {
2335                if( *p >= ' ' && *p <= 'z' )
2336                    putchar(*p);
2337                else
2338                    printf("\\x%02x", *p );
2339            }
2340            printf("\"\n");
2341        }
2342        return 0;
2343    }
2344    
2345    
2346    static void
2347    parse_trust( gpg_iobuf_t inp, int pkttype, unsigned long pktlen, PACKET *pkt )
2348    {
2349        int c;
2350        
2351        if (pktlen) {
2352            c = gpg_iobuf_get_noeof(inp);
2353            pktlen--;
2354            pkt->pkt.ring_trust = malloc( sizeof *pkt->pkt.ring_trust );
2355            pkt->pkt.ring_trust->trustval = c;
2356            pkt->pkt.ring_trust->sigcache = 0;
2357            if (!c && pktlen==1) {
2358                c = gpg_iobuf_get_noeof (inp);
2359                pktlen--;
2360                /* we require that bit 7 of the sigcache is 0 (easier eof handling)*/
2361                if ( !(c & 0x80) )
2362                    pkt->pkt.ring_trust->sigcache = c;
2363            }
2364            if( list_mode )
2365                printf(":trust packet: flag=%02x sigcache=%02x\n",
2366                       pkt->pkt.ring_trust->trustval,
2367                       pkt->pkt.ring_trust->sigcache);
2368        }
2369        else {
2370            if( list_mode )
2371                printf(":trust packet: empty\n");
2372        }
2373        skip_rest (inp, pktlen);
2374    }
2375    
2376    
2377    static int
2378    parse_plaintext( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
2379                                            PACKET *pkt, int new_ctb )
2380    {
2381        int rc = 0;
2382        int mode, namelen, partial=0;
2383        PKT_plaintext *pt;
2384        byte *p;
2385        int c, i;
2386        
2387        if( pktlen && pktlen < 6 ) {
2388            printf("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
2389            rc = G10ERR_INVALID_PACKET;
2390            goto leave;
2391        }
2392        /* A packet length of zero indicates partial body length.  A zero
2393           data length isn't a zero length packet due to the header (mode,
2394           name, etc), so this is accurate. */
2395        if(pktlen==0)
2396            partial=1;
2397        mode = gpg_iobuf_get_noeof(inp); if( pktlen ) pktlen--;
2398        namelen = gpg_iobuf_get_noeof(inp); if( pktlen ) pktlen--;
2399        pt = pkt->pkt.plaintext = malloc(sizeof *pkt->pkt.plaintext + namelen -1);
2400        pt->new_ctb = new_ctb;
2401        pt->mode = mode;
2402        pt->namelen = namelen;
2403        pt->is_partial = partial;
2404        if( pktlen ) {
2405            for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
2406                pt->name[i] = gpg_iobuf_get_noeof(inp);
2407        }
2408        else {
2409            for( i=0; i < namelen; i++ )
2410                if( (c=gpg_iobuf_get(inp)) == -1 )
2411                    break;
2412                else
2413                    pt->name[i] = c;
2414        }
2415        pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
2416        pt->len = pktlen;
2417        pt->buf = inp;
2418        pktlen = 0;
2419        
2420        if( list_mode ) {
2421            printf(":literal data packet:\n"
2422                   "\tmode %c, created %lu, name=\"",
2423                   mode >= ' ' && mode <'z'? mode : '?',
2424                   (ulong)pt->timestamp );
2425            for(p=pt->name,i=0; i < namelen; p++, i++ ) {
2426                if( *p >= ' ' && *p <= 'z' )
2427                    putchar(*p);
2428                else
2429                    printf("\\x%02x", *p );
2430            }
2431            printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
2432        }
2433        
2434    leave:
2435        return rc;
2436    }
2437    
2438    
2439    static int
2440    parse_compressed( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
2441                      PACKET *pkt, int new_ctb )
2442    {
2443        PKT_compressed *zd;
2444        
2445        /* pktlen is here 0, but data follows
2446         * (this should be the last object in a file or
2447         *  the compress algorithm should know the length)
2448         */
2449        zd = pkt->pkt.compressed =  malloc(sizeof *pkt->pkt.compressed );
2450        zd->algorithm = gpg_iobuf_get_noeof(inp);
2451        zd->len = 0; /* not used */
2452        zd->new_ctb = new_ctb;
2453        zd->buf = inp;
2454        if( list_mode )
2455            printf(":compressed packet: algo=%d\n", zd->algorithm);
2456        return 0;
2457    }
2458    
2459    
2460    static int
2461    parse_encrypted( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
2462                                           PACKET *pkt, int new_ctb )
2463    {
2464        int rc = 0;
2465        PKT_encrypted *ed;
2466        unsigned long orig_pktlen = pktlen;
2467        
2468        ed = pkt->pkt.encrypted =  malloc(sizeof *pkt->pkt.encrypted );
2469        ed->len = pktlen;
2470        /* we don't know the extralen which is (cipher_blocksize+2)
2471           because the algorithm ist not specified in this packet.
2472           However, it is only important to know this for some sanity
2473           checks on the packet length - it doesn't matter that we can't
2474           do it */
2475        ed->extralen = 0;
2476        ed->buf = NULL;
2477        ed->new_ctb = new_ctb;
2478        ed->mdc_method = 0;
2479        if( pkttype == PKT_ENCRYPTED_MDC ) {
2480            /* fixme: add some pktlen sanity checks */
2481            int version;
2482            
2483            version = gpg_iobuf_get_noeof(inp);
2484            if (orig_pktlen)
2485                pktlen--;
2486            if( version != 1 ) {
2487                printf("encrypted_mdc packet with unknown version %d\n",
2488                       version);
2489                /*skip_rest(inp, pktlen); should we really do this? */
2490                rc = G10ERR_INVALID_PACKET;
2491                goto leave;
2492            }
2493            ed->mdc_method = DIGEST_ALGO_SHA1;
2494        }
2495        if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
2496            printf("packet(%d) too short\n", pkttype);
2497            rc = G10ERR_INVALID_PACKET;
2498            skip_rest(inp, pktlen);
2499            goto leave;
2500        }
2501        if( list_mode ) {
2502            if( orig_pktlen )
2503                printf(":encrypted data packet:\n\tlength: %lu\n", orig_pktlen);
2504            else
2505                printf(":encrypted data packet:\n\tlength: unknown\n");
2506            if( ed->mdc_method )
2507                printf("\tmdc_method: %d\n", ed->mdc_method );
2508        }
2509        
2510        ed->buf = inp;
2511        pktlen = 0;
2512        
2513    leave:
2514        return rc;
2515    }
2516    
2517    
2518    static int
2519    parse_mdc( gpg_iobuf_t inp, int pkttype, unsigned long pktlen,
2520                                       PACKET *pkt, int new_ctb )
2521    {
2522        int rc = 0;
2523        PKT_mdc *mdc;
2524        byte *p;
2525        
2526        mdc = pkt->pkt.mdc=  malloc(sizeof *pkt->pkt.mdc );
2527        if( list_mode )
2528            printf(":mdc packet: length=%lu\n", pktlen);
2529        if( !new_ctb || pktlen != 20 ) {
2530            printf("mdc_packet with invalid encoding\n");
2531            rc = G10ERR_INVALID_PACKET;
2532            goto leave;
2533        }
2534        p = mdc->hash;
2535        for( ; pktlen; pktlen--, p++ )
2536            *p = gpg_iobuf_get_noeof(inp);
2537        
2538    leave:
2539        return rc;
2540    }
2541    
2542    
2543    /*
2544     * This packet is internally generated by PGG (by armor.c) to
2545     * transfer some information to the lower layer.  To make sure that
2546     * this packet is really a GPG faked one and not one comming from outside,
2547     * we first check that tehre is a unique tag in it.
2548     * The format of such a control packet is:
2549     *   n byte  session marker
2550     *   1 byte  control type CTRLPKT_xxxxx
2551     *   m byte  control data
2552     */
2553    
2554    /* Return a string which is used as a kind of process ID */
2555    const byte *
2556    get_session_marker( size_t *rlen )
2557    {
2558        static byte marker[SIZEOF_UNSIGNED_LONG*2];
2559        static int initialized;
2560        
2561        if ( !initialized ) {
2562            volatile ulong aa, bb; /* we really want the uninitialized value */
2563            ulong a, b;
2564            
2565            initialized = 1;
2566            /* also this marker is guessable it is not easy to use this
2567             * for a faked control packet because an attacker does not
2568             * have enough control about the time the verification does
2569             * take place.  Of course, we can add just more random but
2570             * than we need the random generator even for verification
2571             * tasks - which does not make sense. */
2572            a = aa ^ (ulong)getpid();
2573            b = bb ^ (ulong)time(NULL);
2574            memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
2575            memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
2576        }
2577        *rlen = sizeof(marker);
2578        return marker;
2579    }
2580    
2581    static int
2582    parse_gpg_control( gpg_iobuf_t inp,
2583                       int pkttype, unsigned long pktlen, PACKET *packet )
2584    {
2585        byte *p;
2586        const byte *sesmark;
2587        size_t sesmarklen;
2588        int i;
2589        
2590        if ( list_mode )
2591            printf(":packet 63: length %lu ",  pktlen);
2592        
2593        sesmark = get_session_marker ( &sesmarklen );
2594        if ( pktlen < sesmarklen+1 ) /* 1 is for the control bytes */
2595            goto skipit;
2596        for( i=0; i < sesmarklen; i++, pktlen-- ) {
2597            if ( sesmark[i] != gpg_iobuf_get_noeof(inp) )
2598                goto skipit;
2599        }
2600        if ( list_mode )
2601            puts ("- gpg control packet");
2602        
2603        packet->pkt.gpg_control = malloc(sizeof *packet->pkt.gpg_control
2604                                          + pktlen - 1);
2605        packet->pkt.gpg_control->control = gpg_iobuf_get_noeof(inp); pktlen--;
2606        packet->pkt.gpg_control->datalen = pktlen;
2607        p = packet->pkt.gpg_control->data;
2608        for( ; pktlen; pktlen--, p++ )
2609            *p = gpg_iobuf_get_noeof(inp);
2610        
2611        return 0;
2612        
2613    skipit:
2614        if ( list_mode ) {
2615            int c;
2616            
2617            i=0;
2618            printf("- private (rest length %lu)\n",  pktlen);
2619            if( gpg_iobuf_in_block_mode(inp) ) {
2620                while( (c=gpg_iobuf_get(inp)) != -1 )
2621                    dump_hex_line(c, &i);
2622            }
2623            else {
2624                for( ; pktlen; pktlen-- )
2625                    dump_hex_line(gpg_iobuf_get(inp), &i);
2626            }
2627            putchar('\n');
2628        }
2629        skip_rest(inp,pktlen);
2630        return G10ERR_INVALID_PACKET;
2631    }
2632    
2633    
2634    u32
2635    gpg_keyid_from_pk( PKT_public_key * pk, byte *fprint )
2636    {
2637        gpg_md_t md;
2638        int npkey, pktlen, i;
2639        const byte *mdbuf;
2640            
2641        if( pk->version == 3 && pk->pubkey_algo == PUBKEY_ALGO_RSA )
2642            return pk->pkey[0]->d[0];
2643        else {
2644            md = gpg_md_open( DIGEST_ALGO_SHA1 );
2645            gpg_md_putc( md, 0x99 );
2646            npkey = pubkey_get_npkey( pk->pubkey_algo );
2647            pktlen = 6;
2648            for( i = 0 ; i <npkey; i++ )
2649                pktlen = pktlen + 2 + pk->pkey[i]->alloced;
2650            gpg_md_putc( md, pktlen>>8 );
2651            gpg_md_putc( md, pktlen );
2652            gpg_md_putc( md, 4 );
2653            gpg_md_putc( md, pk->timestamp >> 24 );
2654            gpg_md_putc( md, pk->timestamp >> 16 );
2655            gpg_md_putc( md, pk->timestamp >>  8 );
2656            gpg_md_putc( md, pk->timestamp       );
2657            gpg_md_putc( md, pk->pubkey_algo );
2658            for( i=0; i <npkey; i++ ) {
2659                const u32 * d = pk->pkey[i]->d;
2660                int nbits = pk->pkey[i]->nbits,
2661                    n = pk->pkey[i]->alloced;
2662                gpg_md_putc( md, nbits >> 8 );
2663                gpg_md_putc( md, nbits );
2664                n = n>4? n/4 : n;
2665                while( n-- ) {
2666                    if( pk->pkey[i]->alloced > 3 )
2667                        gpg_md_putc( md, d[n] >> 24 );
2668                    if( pk->pkey[i]->alloced > 2 )
2669                        gpg_md_putc( md, d[n] >> 16 );
2670                    if( pk->pkey[i]->alloced > 1 )
2671                        gpg_md_putc( md, d[n] >>  8 );
2672                    if( pk->pkey[i]->alloced > 0 )
2673                        gpg_md_putc( md, d[n]       );
2674                }      
2675            }      
2676            gpg_md_final( md );  
2677            mdbuf = gpg_md_read( md );
2678        }
2679        if( mdbuf && fprint )
2680            memcpy( fprint, mdbuf, 20 );
2681        return mdbuf? mdbuf[16] << 24 | mdbuf[17] << 16 | mdbuf[18] << 8 | mdbuf[19] : 0;
2682    }
2683    
2684    
2685    u32
2686    gpg_keyid_from_sk( PKT_secret_key * sk, byte *fprint )
2687    {
2688        PKT_public_key pk;
2689        int npkey = pubkey_get_npkey( sk->pubkey_algo );
2690        int i;
2691        
2692        pk.pubkey_algo = sk->pubkey_algo;
2693        pk.version     = sk->version;
2694        pk.timestamp = sk->timestamp;
2695        pk.expiredate = sk->expiredate;
2696        pk.pubkey_algo = sk->pubkey_algo;
2697        for( i=0; i < npkey; i++ )
2698            pk.pkey[i] = sk->skey[i];
2699        return gpg_keyid_from_pk( &pk, fprint );
2700    }
2701    
2702    
2703    /****************
2704     * Read the next keyblock from stream A.
2705     * PENDING_PKT should be initialzed to NULL
2706     * and not chnaged form the caller.
2707     * Retunr: 0 = okay, -1 no more blocks or another errorcode.
2708     */
2709    int
2710    gpg_read_keyblock( gpg_iobuf_t a, PACKET **pending_pkt, gpg_kbnode_t *ret_root )
2711    {
2712        int rc;
2713        PACKET *pkt;
2714        gpg_kbnode_t root = NULL;
2715        int in_cert;
2716    
2717        if( *pending_pkt ) {
2718            root = gpg_new_kbnode( *pending_pkt );
2719            *pending_pkt = NULL;
2720            in_cert = 1;
2721        }
2722        else
2723            in_cert = 0;
2724        pkt = malloc( sizeof *pkt );
2725        gpg_init_packet(pkt);
2726        while( (rc=gpg_parse_packet(a, pkt)) != -1 ) {
2727            if( rc ) {  /* ignore errors */
2728                if( rc != G10ERR_UNKNOWN_PACKET ) {
2729                    printf("read_block: read error: %d\n", rc );
2730                    rc = G10ERR_INV_KEYRING;
2731                    goto ready;
2732                }
2733                gpg_free_packet( pkt );
2734                gpg_init_packet(pkt);
2735                continue;
2736            }
2737    
2738            if( !root && pkt->pkttype == PKT_SIGNATURE
2739                      && pkt->pkt.signature->sig_class == 0x20 ) {
2740                /* this is a revocation certificate which is handled
2741                 * in a special way */
2742                root = gpg_new_kbnode( pkt );
2743                pkt = NULL;
2744                goto ready;
2745            }
2746    
2747            /* make a linked list of all packets */
2748            switch( pkt->pkttype ) {
2749              case PKT_RING_TRUST:
2750                /* skip those packets */
2751                gpg_free_packet( pkt );
2752                gpg_init_packet(pkt);
2753                break;
2754    
2755              case PKT_PUBLIC_KEY:
2756              case PKT_SECRET_KEY:
2757                if( in_cert ) { /* store this packet */
2758                    *pending_pkt = pkt;
2759                    pkt = NULL;
2760                    goto ready;
2761                }
2762                in_cert = 1;
2763              default:
2764                if( in_cert ) {
2765                    if( !root )
2766                        root = gpg_new_kbnode( pkt );
2767                    else
2768                        gpg_add_kbnode( root, gpg_new_kbnode( pkt ) );
2769                    pkt = malloc( sizeof *pkt );
2770                }
2771                gpg_init_packet(pkt);
2772                break;
2773            }
2774        }
2775      ready:
2776        if( rc == -1 && root )
2777            rc = 0;
2778    
2779        if( rc )
2780            gpg_release_kbnode( root );
2781        else
2782            *ret_root = root;
2783        gpg_free_packet( pkt );
2784        free( pkt );
2785        return rc;
2786    }

Legend:
Removed from v.2  
changed lines
  Added in v.309

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26