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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26