* export.c (do_export_stream) [ENABLE_SELINUX_HACKS]: Don't allow
[gnupg.git] / g10 / parse-packet.c
index 7e390ae..48035ad 100644 (file)
@@ -1,5 +1,6 @@
 /* parse-packet.c  - read packets
 /* parse-packet.c  - read packets
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  *
  * This file is part of GnuPG.
  *
@@ -41,21 +42,19 @@ static int list_mode = 0;
 
 static int  parse( IOBUF inp, PACKET *pkt, int onlykeypkts,
                   off_t *retpos, int *skip, IOBUF out, int do_skip
 
 static int  parse( IOBUF inp, PACKET *pkt, int onlykeypkts,
                   off_t *retpos, int *skip, IOBUF out, int do_skip
-           #ifdef DEBUG_PARSE_PACKET
+#ifdef DEBUG_PARSE_PACKET
                   ,const char *dbg_w, const char *dbg_f, int dbg_l
                   ,const char *dbg_w, const char *dbg_f, int dbg_l
-           #endif
+#endif
                 );
 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
                 );
 static int  copy_packet( IOBUF inp, IOBUF out, int pkttype,
-                                              unsigned long pktlen );
-static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
-static void skip_rest( IOBUF inp, unsigned long pktlen );
-static void *read_rest( IOBUF inp, size_t pktlen );
+                        unsigned long pktlen, int partial );
+static void skip_packet( IOBUF inp, int pkttype,
+                        unsigned long pktlen, int partial );
+static void *read_rest( IOBUF inp, size_t pktlen, int partial );
 static int  parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
                                                             PACKET *packet );
 static int  parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
                                                             PACKET *packet );
 static int  parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
                                                             PACKET *packet );
 static int  parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen,
                                                             PACKET *packet );
-static int  parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
-                                                        PKT_signature *sig );
 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
                                                        PKT_onepass_sig *ops );
 static int  parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
 static int  parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
                                                        PKT_onepass_sig *ops );
 static int  parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
@@ -69,15 +68,15 @@ static int  parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen,
                                                           PACKET *packet );
 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
 static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen,
                                                           PACKET *packet );
 static int  parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
-                                              PACKET *packet, int new_ctb);
+                            PACKET *packet, int new_ctb, int partial);
 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
                                               PACKET *packet, int new_ctb );
 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
 static int  parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
                                               PACKET *packet, int new_ctb );
 static int  parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
-                                              PACKET *packet, int new_ctb);
+                            PACKET *packet, int new_ctb, int partial);
 static int  parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
                                               PACKET *packet, int new_ctb);
 static int  parse_gpg_control( IOBUF inp, int pkttype, unsigned long pktlen,
 static int  parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
                                               PACKET *packet, int new_ctb);
 static int  parse_gpg_control( IOBUF inp, int pkttype, unsigned long pktlen,
-                               PACKET *packet );
+                               PACKET *packet, int partial );
 
 static unsigned short
 read_16(IOBUF inp)
 
 static unsigned short
 read_16(IOBUF inp)
@@ -296,7 +295,7 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
     unsigned long pktlen;
     byte hdr[8];
     int hdrlen;
     unsigned long pktlen;
     byte hdr[8];
     int hdrlen;
-    int new_ctb = 0;
+    int new_ctb = 0, partial=0;
     int with_uid = (onlykeypkts == 2);
 
     *skip = 0;
     int with_uid = (onlykeypkts == 2);
 
     *skip = 0;
@@ -327,55 +326,88 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
         if (pkttype == PKT_COMPRESSED) {
              iobuf_set_partial_block_mode(inp, c & 0xff);
              pktlen = 0;/* to indicate partial length */
         if (pkttype == PKT_COMPRESSED) {
              iobuf_set_partial_block_mode(inp, c & 0xff);
              pktlen = 0;/* to indicate partial length */
+            partial=1;
         }
         else {
              hdr[hdrlen++] = c;
              if( c < 192 )
         }
         else {
              hdr[hdrlen++] = c;
              if( c < 192 )
-                  pktlen = c;
-             else if( c < 224 ) {
-                  pktlen = (c - 192) * 256;
-                  if( (c = iobuf_get(inp)) == -1 ) {
-                       log_error("%s: 2nd length byte missing\n",
-                                 iobuf_where(inp) );
-                       rc = G10ERR_INVALID_PACKET;
-                       goto leave;
-                  }
-                  hdr[hdrlen++] = c;
-                  pktlen += c + 192;
-             }
-             else if( c == 255 ) {
-                  pktlen  = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24;
-                  pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16;
-                  pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
-                  if( (c = iobuf_get(inp)) == -1 ) {
-                       log_error("%s: 4 byte length invalid\n",
-                                 iobuf_where(inp) );
-                       rc = G10ERR_INVALID_PACKET;
-                       goto leave;
-                  }
-                  pktlen |= (hdr[hdrlen++] = c );
-             }
-             else { /* partial body length */
-                  iobuf_set_partial_block_mode(inp, c & 0xff);
-                  pktlen = 0;/* to indicate partial length */
-             }
+              pktlen = c;
+             else if( c < 224 )
+              {
+                pktlen = (c - 192) * 256;
+                if( (c = iobuf_get(inp)) == -1 )
+                  {
+                    log_error("%s: 2nd length byte missing\n",
+                              iobuf_where(inp) );
+                    rc = G10ERR_INVALID_PACKET;
+                    goto leave;
+                  }
+                hdr[hdrlen++] = c;
+                pktlen += c + 192;
+              }
+             else if( c == 255 )
+              {
+                pktlen  = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24;
+                pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16;
+                pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
+                if( (c = iobuf_get(inp)) == -1 )
+                  {
+                    log_error("%s: 4 byte length invalid\n",
+                              iobuf_where(inp) );
+                    rc = G10ERR_INVALID_PACKET;
+                    goto leave;
+                  }
+                pktlen |= (hdr[hdrlen++] = c );
+              }
+             else
+              {
+                /* Partial body length.  Note that we handled
+                   PKT_COMPRESSED earlier. */
+                if(pkttype==PKT_PLAINTEXT || pkttype==PKT_ENCRYPTED
+                   || pkttype==PKT_ENCRYPTED_MDC)
+                  {
+                    iobuf_set_partial_block_mode(inp, c & 0xff);
+                    pktlen = 0;/* to indicate partial length */
+                    partial=1;
+                  }
+                else
+                  {
+                    log_error("%s: partial length for invalid"
+                              " packet type %d\n",iobuf_where(inp),pkttype);
+                    rc=G10ERR_INVALID_PACKET;
+                    goto leave;
+                  }
+              }
        }
     }
        }
     }
-    else {
+    else
+      {
        pkttype = (ctb>>2)&0xf;
        lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
        pkttype = (ctb>>2)&0xf;
        lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
-       if( !lenbytes ) {
+       if( !lenbytes )
+         {
            pktlen = 0; /* don't know the value */
            pktlen = 0; /* don't know the value */
-           if( pkttype != PKT_COMPRESSED )
-               iobuf_set_block_mode(inp, 1);
-       }
-       else {
-           for( ; lenbytes; lenbytes-- ) {
+           /* This isn't really partial, but we can treat it the same
+              in a "read until the end" sort of way. */
+           partial=1;
+           if(pkttype!=PKT_ENCRYPTED && pkttype!=PKT_PLAINTEXT
+              && pkttype!=PKT_COMPRESSED)
+             {
+               log_error ("%s: indeterminate length for invalid"
+                          " packet type %d\n", iobuf_where(inp), pkttype );
+               rc = G10ERR_INVALID_PACKET;
+               goto leave;
+             }
+         }
+       else
+         {
+           for( ; lenbytes; lenbytes-- )
+             {
                pktlen <<= 8;
                pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
                pktlen <<= 8;
                pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
-           }
-       }
-    }
+             }
+         }
+      }
 
     if (pktlen == 0xffffffff) {
         /* with a some probability this is caused by a problem in the
 
     if (pktlen == 0xffffffff) {
         /* with a some probability this is caused by a problem in the
@@ -389,7 +421,7 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
        if( iobuf_write( out, hdr, hdrlen ) == -1 )
            rc = G10ERR_WRITE_FILE;
        else
        if( iobuf_write( out, hdr, hdrlen ) == -1 )
            rc = G10ERR_WRITE_FILE;
        else
-           rc = copy_packet(inp, out, pkttype, pktlen );
+           rc = copy_packet(inp, out, pkttype, pktlen, partial );
        goto leave;
     }
 
        goto leave;
     }
 
@@ -401,7 +433,7 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
                         && pkttype != PKT_PUBLIC_KEY
                         && pkttype != PKT_SECRET_SUBKEY
                         && pkttype != PKT_SECRET_KEY  ) ) {
                         && pkttype != PKT_PUBLIC_KEY
                         && pkttype != PKT_SECRET_SUBKEY
                         && pkttype != PKT_SECRET_KEY  ) ) {
-       skip_rest(inp, pktlen);
+       iobuf_skip_rest(inp, pktlen, partial);
        *skip = 1;
        rc = 0;
        goto leave;
        *skip = 1;
        rc = 0;
        goto leave;
@@ -460,23 +492,23 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
        rc = 0;
        break;
       case PKT_PLAINTEXT:
        rc = 0;
        break;
       case PKT_PLAINTEXT:
-       rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb );
+       rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb, partial );
        break;
       case PKT_COMPRESSED:
        rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb );
        break;
       case PKT_ENCRYPTED:
       case PKT_ENCRYPTED_MDC:
        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 );
+       rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb, partial );
        break;
       case PKT_MDC:
        rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb );
        break;
       case PKT_GPG_CONTROL:
        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 );
+        rc = parse_gpg_control(inp, pkttype, pktlen, pkt, partial );
         break;
       default:
         break;
       default:
-       skip_packet(inp, pkttype, pktlen);
+       skip_packet(inp, pkttype, pktlen, partial);
        break;
     }
 
        break;
     }
 
@@ -504,12 +536,13 @@ dump_hex_line( int c, int *i )
 
 
 static int
 
 
 static int
-copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
+copy_packet( IOBUF inp, IOBUF out, int pkttype,
+            unsigned long pktlen, int partial )
 {
     int n;
     char buf[100];
 
 {
     int n;
     char buf[100];
 
-    if( iobuf_in_block_mode(inp) ) {
+    if( partial ) {
        while( (n = iobuf_read( inp, buf, 100 )) != -1 )
            if( iobuf_write(out, buf, n ) )
                return G10ERR_WRITE_FILE; /* write error */
        while( (n = iobuf_read( inp, buf, 100 )) != -1 )
            if( iobuf_write(out, buf, n ) )
                return G10ERR_WRITE_FILE; /* write error */
@@ -536,7 +569,7 @@ copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
 
 
 static void
 
 
 static void
-skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
+skip_packet( IOBUF inp, int pkttype, unsigned long pktlen, int partial )
 {
     if( list_mode ) {
        if( pkttype == PKT_MARKER )
 {
     if( list_mode ) {
        if( pkttype == PKT_MARKER )
@@ -547,7 +580,7 @@ skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
            int c, i=0 ;
            if( pkttype != PKT_MARKER )
                fputs("dump:", stdout );
            int c, i=0 ;
            if( pkttype != PKT_MARKER )
                fputs("dump:", stdout );
-           if( iobuf_in_block_mode(inp) ) {
+           if( partial ) {
                while( (c=iobuf_get(inp)) != -1 )
                    dump_hex_line(c, &i);
            }
                while( (c=iobuf_get(inp)) != -1 )
                    dump_hex_line(c, &i);
            }
@@ -559,31 +592,17 @@ skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
            return;
        }
     }
            return;
        }
     }
-    skip_rest(inp,pktlen);
-}
-
-static void
-skip_rest( IOBUF inp, unsigned long pktlen )
-{
-    if( iobuf_in_block_mode(inp) ) {
-       while( iobuf_get(inp) != -1 )
-               ;
-    }
-    else {
-       for( ; pktlen; pktlen-- )
-           if( iobuf_get(inp) == -1 )
-               break;
-    }
+    iobuf_skip_rest(inp,pktlen,partial);
 }
 
 
 static void *
 }
 
 
 static void *
-read_rest( IOBUF inp, size_t pktlen )
+read_rest( IOBUF inp, size_t pktlen, int partial )
 {
     byte *p;
     int i;
 
 {
     byte *p;
     int i;
 
-    if( iobuf_in_block_mode(inp) ) {
+    if( partial ) {
        log_error("read_rest: can't store stream data\n");
        p = NULL;
     }
        log_error("read_rest: can't store stream data\n");
        p = NULL;
     }
@@ -657,25 +676,38 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
        k->s2k.count = iobuf_get(inp); pktlen--;
     }
     k->seskeylen = seskeylen;
        k->s2k.count = iobuf_get(inp); pktlen--;
     }
     k->seskeylen = seskeylen;
-    for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
-       k->seskey[i] = iobuf_get_noeof(inp);
+    if(k->seskeylen)
+      {
+       for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
+         k->seskey[i] = iobuf_get_noeof(inp);
+
+       /* What we're watching out for here is a session key decryptor
+          with no salt.  The RFC says that using salt for this is a
+          MUST. */
+       if(s2kmode!=1 && s2kmode!=3)
+         log_info(_("WARNING: potentially insecure symmetrically"
+                    " encrypted session key\n"));
+      }
     assert( !pktlen );
 
     if( list_mode ) {
     assert( !pktlen );
 
     if( list_mode ) {
-       printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
-                           version, cipher_algo, s2kmode, hash_algo);
+       printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
+              version, cipher_algo, s2kmode, hash_algo);
+       if(seskeylen)
+         printf(", seskey %d bits",(seskeylen-1)*8);
+       printf("\n");
        if( s2kmode == 1 || s2kmode == 3 ) {
            printf("\tsalt ");
            for(i=0; i < 8; i++ )
                printf("%02x", k->s2k.salt[i]);
            if( s2kmode == 3 )
        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(", count %lu", (ulong)k->s2k.count );
            printf("\n");
        }
     }
 
   leave:
            printf("\n");
        }
     }
 
   leave:
-    skip_rest(inp, pktlen);
+    iobuf_skip_rest(inp, pktlen, 0);
     return rc;
 }
 
     return rc;
 }
 
@@ -729,7 +761,7 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
     }
 
   leave:
     }
 
   leave:
-    skip_rest(inp, pktlen);
+    iobuf_skip_rest(inp, pktlen, 0);
     return rc;
 }
 
     return rc;
 }
 
@@ -860,7 +892,8 @@ dump_sig_subpkt( int hashed, int type, int critical,
          printf(" %02X", buffer[i]);
        break;
       case SIGSUBPKT_PREF_KS:
          printf(" %02X", buffer[i]);
        break;
       case SIGSUBPKT_PREF_KS:
-       p = "preferred key server";
+       fputs("preferred key server: ", stdout );
+       print_string( stdout, buffer, length, ')' );
        break;
       case SIGSUBPKT_PRIMARY_UID:
        p = "primary user ID";
        break;
       case SIGSUBPKT_PRIMARY_UID:
        p = "primary user ID";
@@ -899,10 +932,23 @@ dump_sig_subpkt( int hashed, int type, int critical,
         for( i=0; i < length; i++ )
             printf(" %02x", buffer[i] );
        break;
         for( i=0; i < length; i++ )
             printf(" %02x", buffer[i] );
        break;
-      case SIGSUBPKT_PRIV_VERIFY_CACHE:
-       p = "obsolete verification cache";
+      case SIGSUBPKT_SIGNATURE:
+       fputs("signature: ",stdout);
+       if(length<17)
+         p="[too short]";
+       else
+         printf("v%d, class 0x%02X, algo %d, digest algo %d",
+                buffer[0],
+                buffer[0]==3?buffer[2]:buffer[1],
+                buffer[0]==3?buffer[15]:buffer[2],
+                buffer[0]==3?buffer[16]:buffer[3]);
+       break;
+      default:
+       if(type>=100 && type<=110)
+         p="experimental / private subpacket";
+       else
+         p = "?";
        break;
        break;
-      default: p = "?"; break;
     }
 
     printf("%s)\n", p? p: "");
     }
 
     printf("%s)\n", p? p: "");
@@ -917,99 +963,90 @@ dump_sig_subpkt( int hashed, int type, int critical,
 int
 parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
 {
 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:
-      case SIGSUBPKT_REGEXP:
-       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_TRUST:
-         if ( n != 2 )
-             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;
+  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_PREF_KS:
+    case SIGSUBPKT_FEATURES:
+    case SIGSUBPKT_REGEXP:
+      return 0;
+    case SIGSUBPKT_SIGNATURE:
+    case SIGSUBPKT_EXPORTABLE:
+    case SIGSUBPKT_REVOCABLE:
+    case SIGSUBPKT_REVOC_REASON:
+      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_PRIMARY_UID:
+      if ( n != 1 )
+       break;
+      return 0;
+    case SIGSUBPKT_TRUST:
+      if ( n != 2 )
+       break;
+      return 0;
+    default: return -1;
+    }
+  return -3;
 }
 
 
 static int
 can_handle_critical( const byte *buffer, size_t n, int type )
 {
 }
 
 
 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? */
-      case SIGSUBPKT_TRUST:
-      case SIGSUBPKT_REGEXP:
-       return 1;
-
-      default:
-       return 0;
+  switch( type )
+    {
+    case SIGSUBPKT_NOTATION:
+      if( n >= 8 && (*buffer & 0x80) )
+       return 1; /* human readable is handled */
+      return 0;
+
+    case SIGSUBPKT_SIGNATURE:
+    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_TRUST:
+    case SIGSUBPKT_REGEXP:
+      /* Is it enough to show the policy or keyserver? */
+    case SIGSUBPKT_POLICY:
+    case SIGSUBPKT_PREF_KS:
+      return 1;
+
+    default:
+      return 0;
     }
 }
 
     }
 }
 
@@ -1070,13 +1107,15 @@ enum_sig_subpkt( const subpktarea_t *pktbuf, sigsubpkttype_t reqtype,
            if( *critical ) {
                if( n-1 > buflen+1 )
                    goto too_short;
            if( *critical ) {
                if( n-1 > buflen+1 )
                    goto too_short;
-               if( !can_handle_critical(buffer+1, n-1, type ) ) {
-                   log_info(_("subpacket of type %d has critical bit set\n"),
-                                                                       type);
+               if( !can_handle_critical(buffer+1, n-1, type ) )
+                 {
+                   if(opt.verbose)
+                     log_info(_("subpacket of type %d has "
+                                "critical bit set\n"),type);
                    if( start )
                    if( start )
-                       *start = seq;
+                     *start = seq;
                    return NULL; /* this is an error */
                    return NULL; /* this is an error */
-               }
+                 }
            }
        }
        else if( reqtype < 0 ) /* list packets */
            }
        }
        else if( reqtype < 0 ) /* list packets */
@@ -1167,7 +1206,7 @@ void parse_revkeys(PKT_signature *sig)
     }
 }
 
     }
 }
 
-static int
+int
 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
                                          PKT_signature *sig )
 {
 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
                                          PKT_signature *sig )
 {
@@ -1229,11 +1268,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
            goto leave;
        }
        if( n ) {
            goto leave;
        }
        if( n ) {
-            /* we add 8 extra bytes so that we have space for the signature
-             * status cache.  Well we are wasting this if there is a cache
-             * packet already, but in the other case it avoids an realloc */
-           sig->unhashed = m_alloc (sizeof(*sig->unhashed) + n + 8 - 1 );
-            sig->unhashed->size = n + 8;
+           sig->unhashed = m_alloc (sizeof(*sig->unhashed) + n - 1 );
+            sig->unhashed->size = n;
            sig->unhashed->len = n;
            if( iobuf_read(inp, sig->unhashed->data, n ) != n ) {
                log_error("premature eof while reading "
            sig->unhashed->len = n;
            if( iobuf_read(inp, sig->unhashed->data, n ) != n ) {
                log_error("premature eof while reading "
@@ -1268,17 +1304,19 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
        }
 
        p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL );
        }
 
        p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL );
-       if( !p )
-           log_error("signature packet without timestamp\n");
-       else
-           sig->timestamp = buffer_to_u32(p);
+       if(p)
+         sig->timestamp = buffer_to_u32(p);
+       else if(!(sig->pubkey_algo>=100 && sig->pubkey_algo<=110))
+         log_error("signature packet without timestamp\n");
+
        p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
        p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
-       if( !p )
-           log_error("signature packet without keyid\n");
-       else {
+       if(p)
+         {
            sig->keyid[0] = buffer_to_u32(p);
            sig->keyid[1] = buffer_to_u32(p+4);
            sig->keyid[0] = buffer_to_u32(p);
            sig->keyid[1] = buffer_to_u32(p+4);
-       }
+         }
+       else if(!(sig->pubkey_algo>=100 && sig->pubkey_algo<=110))
+         log_error("signature packet without keyid\n");
 
        p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL);
        if(p)
 
        p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL);
        if(p)
@@ -1290,6 +1328,10 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
        if(p)
          sig->flags.policy_url=1;
 
        if(p)
          sig->flags.policy_url=1;
 
+       p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,NULL);
+       if(p)
+         sig->flags.pref_ks=1;
+
        p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL);
        if(p)
          sig->flags.notation=1;
        p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL);
        if(p)
          sig->flags.notation=1;
@@ -1351,7 +1393,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
        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() */
        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 );
+       sig->data[0]= mpi_set_opaque(NULL, read_rest(inp, pktlen, 0), pktlen );
        pktlen = 0;
     }
     else {
        pktlen = 0;
     }
     else {
@@ -1370,7 +1412,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
     }
 
   leave:
     }
 
   leave:
-    skip_rest(inp, pktlen);
+    iobuf_skip_rest(inp, pktlen, 0);
     return rc;
 }
 
     return rc;
 }
 
@@ -1408,7 +1450,7 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
 
 
   leave:
 
 
   leave:
-    skip_rest(inp, pktlen);
+    iobuf_skip_rest(inp, pktlen, 0);
     return rc;
 }
 
     return rc;
 }
 
@@ -1487,7 +1529,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
            }
            printf("\"\n");
        }
            }
            printf("\"\n");
        }
-       skip_rest(inp, pktlen);
+       iobuf_skip_rest(inp, pktlen, 0);
        return 0;
     }
     else if( version == 4 )
        return 0;
     }
     else if( version == 4 )
@@ -1555,6 +1597,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
        pk->req_usage = 0; 
        pk->pubkey_usage = 0; /* not yet used */
         pk->is_revoked = 0;
        pk->req_usage = 0; 
        pk->pubkey_usage = 0; /* not yet used */
         pk->is_revoked = 0;
+       pk->is_disabled = 0;
        pk->keyid[0] = 0;
        pk->keyid[1] = 0;
     }
        pk->keyid[0] = 0;
        pk->keyid[1] = 0;
     }
@@ -1570,10 +1613,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
        PKT_secret_key *sk = pkt->pkt.secret_key;
        byte temp[16];
     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,
 
        if( !npkey ) {
            sk->skey[0] = mpi_set_opaque( NULL,
-                                         read_rest(inp, pktlen), pktlen );
+                                         read_rest(inp, pktlen, 0), pktlen );
            pktlen = 0;
            goto leave;
        }
            pktlen = 0;
            goto leave;
        }
@@ -1642,6 +1686,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                    break;
                  case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );
                    break;
                    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",
                  default:
                    if( list_mode )
                        printf(  "\tunknown %sS2K %d\n",
@@ -1677,6 +1723,19 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                        printf("\tprotect count: %lu\n",
                                            (ulong)sk->protect.s2k.count);
                }
                        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 = 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
            }
            /* Note that a sk->protect.algo > 110 is illegal, but I'm
               not erroring on it here as otherwise there would be no
@@ -1706,6 +1765,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
            }
            if( sk->protect.s2k.mode == 1001 )
                sk->protect.ivlen = 0;
            }
            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;
 
            if( pktlen < sk->protect.ivlen ) {
                rc = G10ERR_INVALID_PACKET;
@@ -1714,7 +1775,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
            for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
                temp[i] = iobuf_get_noeof(inp);
            if( list_mode ) {
            for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
                temp[i] = iobuf_get_noeof(inp);
            if( list_mode ) {
-               printf(  "\tprotect IV: ");
+               printf( sk->protect.s2k.mode == 1002? "\tserial-number: "
+                                                    : "\tprotect IV: ");
                for(i=0; i < sk->protect.ivlen; i++ )
                    printf(" %02x", temp[i] );
                putchar('\n');
                for(i=0; i < sk->protect.ivlen; i++ )
                    printf(" %02x", temp[i] );
                putchar('\n');
@@ -1727,7 +1789,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
         * 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 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 ) {
+       if( sk->protect.s2k.mode == 1001 
+            || sk->protect.s2k.mode == 1002 ) {
            /* better set some dummy stuff here */
            sk->skey[npkey] = mpi_set_opaque(NULL, m_strdup("dummydata"), 10);
            pktlen = 0;
            /* better set some dummy stuff here */
            sk->skey[npkey] = mpi_set_opaque(NULL, m_strdup("dummydata"), 10);
            pktlen = 0;
@@ -1737,7 +1800,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
             * stuff up to the end of the packet into the first
             * skey element */
            sk->skey[npkey] = mpi_set_opaque(NULL,
             * 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 );
+                                            read_rest(inp, pktlen, 0),pktlen);
            pktlen = 0;
            if( list_mode ) {
                printf("\tencrypted stuff follows\n");
            pktlen = 0;
            if( list_mode ) {
                printf("\tencrypted stuff follows\n");
@@ -1778,7 +1841,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
 
        if( !npkey ) {
            pk->pkey[0] = mpi_set_opaque( NULL,
 
        if( !npkey ) {
            pk->pkey[0] = mpi_set_opaque( NULL,
-                                         read_rest(inp, pktlen), pktlen );
+                                         read_rest(inp, pktlen, 0), pktlen );
            pktlen = 0;
            goto leave;
        }
            pktlen = 0;
            goto leave;
        }
@@ -1798,7 +1861,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
     }
 
   leave:
     }
 
   leave:
-    skip_rest(inp, pktlen);
+    iobuf_skip_rest(inp, pktlen, 0);
     return rc;
 }
 
     return rc;
 }
 
@@ -2033,30 +2096,25 @@ parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
       if( list_mode )
        printf(":trust packet: empty\n");
     }
       if( list_mode )
        printf(":trust packet: empty\n");
     }
-  skip_rest (inp, pktlen);
+  iobuf_skip_rest (inp, pktlen, 0);
 }
 
 
 static int
 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
 }
 
 
 static int
 parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
-                                       PACKET *pkt, int new_ctb )
+                PACKET *pkt, int new_ctb, int partial )
 {
     int rc = 0;
 {
     int rc = 0;
-    int mode, namelen, partial=0;
+    int mode, namelen;
     PKT_plaintext *pt;
     byte *p;
     int c, i;
 
     PKT_plaintext *pt;
     byte *p;
     int c, i;
 
-    if( pktlen && pktlen < 6 ) {
+    if( !partial && pktlen < 6 ) {
        log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
         rc = G10ERR_INVALID_PACKET;
        goto leave;
     }
        log_error("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 = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
     mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
     namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
     pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
@@ -2082,8 +2140,8 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
 
     if( list_mode ) {
        printf(":literal data packet:\n"
 
     if( list_mode ) {
        printf(":literal data packet:\n"
-              "\tmode %c, created %lu, name=\"",
-                   mode >= ' ' && mode <'z'? mode : '?',
+              "\tmode %c (%X), created %lu, name=\"",
+                   mode >= ' ' && mode <'z'? mode : '?', mode,
                    (ulong)pt->timestamp );
        for(p=pt->name,i=0; i < namelen; p++, i++ ) {
            if( *p >= ' ' && *p <= 'z' )
                    (ulong)pt->timestamp );
        for(p=pt->name,i=0; i < namelen; p++, i++ ) {
            if( *p >= ' ' && *p <= 'z' )
@@ -2091,7 +2149,11 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
            else
                printf("\\x%02x", *p );
        }
            else
                printf("\\x%02x", *p );
        }
-       printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len );
+       printf("\",\n\traw data: ");
+       if(partial)
+         printf("unknown length\n");
+       else
+         printf("%lu bytes\n", (ulong)pt->len );
     }
 
   leave:
     }
 
   leave:
@@ -2122,7 +2184,7 @@ parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
 
 static int
 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
 
 static int
 parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
-                                      PACKET *pkt, int new_ctb )
+                PACKET *pkt, int new_ctb, int partial )
 {
     int rc = 0;
     PKT_encrypted *ed;
 {
     int rc = 0;
     PKT_encrypted *ed;
@@ -2138,6 +2200,7 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
     ed->extralen = 0;
     ed->buf = NULL;
     ed->new_ctb = new_ctb;
     ed->extralen = 0;
     ed->buf = NULL;
     ed->new_ctb = new_ctb;
+    ed->is_partial = partial;
     ed->mdc_method = 0;
     if( pkttype == PKT_ENCRYPTED_MDC ) {
        /* fixme: add some pktlen sanity checks */
     ed->mdc_method = 0;
     if( pkttype == PKT_ENCRYPTED_MDC ) {
        /* fixme: add some pktlen sanity checks */
@@ -2158,7 +2221,7 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
     if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
        log_error("packet(%d) too short\n", pkttype);
         rc = G10ERR_INVALID_PACKET;
     if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
        log_error("packet(%d) too short\n", pkttype);
         rc = G10ERR_INVALID_PACKET;
-       skip_rest(inp, pktlen);
+       iobuf_skip_rest(inp, pktlen, partial);
        goto leave;
     }
     if( list_mode ) {
        goto leave;
     }
     if( list_mode ) {
@@ -2171,7 +2234,6 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
     }
 
     ed->buf = inp;
     }
 
     ed->buf = inp;
-    pktlen = 0;
 
   leave:
     return rc;
 
   leave:
     return rc;
@@ -2215,8 +2277,8 @@ parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
  */
 
 static int
  */
 
 static int
-parse_gpg_control( IOBUF inp,
-                   int pkttype, unsigned long pktlen, PACKET *packet )
+parse_gpg_control( IOBUF inp, int pkttype,
+                  unsigned long pktlen, PACKET *packet, int partial )
 {
     byte *p;
     const byte *sesmark;
 {
     byte *p;
     const byte *sesmark;
@@ -2252,7 +2314,7 @@ parse_gpg_control( IOBUF inp,
 
         i=0;
         printf("- private (rest length %lu)\n",  pktlen);
 
         i=0;
         printf("- private (rest length %lu)\n",  pktlen);
-        if( iobuf_in_block_mode(inp) ) {
+        if( partial ) {
             while( (c=iobuf_get(inp)) != -1 )
                 dump_hex_line(c, &i);
         }
             while( (c=iobuf_get(inp)) != -1 )
                 dump_hex_line(c, &i);
         }
@@ -2262,7 +2324,7 @@ parse_gpg_control( IOBUF inp,
         }
         putchar('\n');
     }
         }
         putchar('\n');
     }
-    skip_rest(inp,pktlen);
+    iobuf_skip_rest(inp,pktlen, 0);
     return G10ERR_INVALID_PACKET;
 }
 
     return G10ERR_INVALID_PACKET;
 }