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

Legend:
Removed from v.45  
changed lines
  Added in v.46

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26