common: Fix -Wswitch warning.
[gnupg.git] / g10 / parse-packet.c
index 012d373..dbb7af8 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2007, 2009, 2010 Free Software Foundation, Inc.
  * Copyright (C) 2014 Werner Koch
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2007, 2009, 2010 Free Software Foundation, Inc.
  * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2015 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  *
  * This file is part of GnuPG.
  *
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 
 #include "gpg.h"
-#include "util.h"
+#include "../common/util.h"
 #include "packet.h"
 #include "packet.h"
-#include "iobuf.h"
+#include "../common/iobuf.h"
 #include "filter.h"
 #include "photoid.h"
 #include "options.h"
 #include "main.h"
 #include "filter.h"
 #include "photoid.h"
 #include "options.h"
 #include "main.h"
-#include "i18n.h"
+#include "../common/i18n.h"
+#include "../common/host2net.h"
 
 
 /* Maximum length of packets to avoid excessive memory allocation.  */
 
 
 /* Maximum length of packets to avoid excessive memory allocation.  */
@@ -47,9 +48,9 @@ static int mpi_print_mode;
 static int list_mode;
 static estream_t listfp;
 
 static int list_mode;
 static estream_t listfp;
 
-static int parse (IOBUF inp, PACKET * pkt, int onlykeypkts,
+static int parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts,
                  off_t * retpos, int *skip, IOBUF out, int do_skip
                  off_t * retpos, int *skip, IOBUF out, int do_skip
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
                  , const char *dbg_w, const char *dbg_f, int dbg_l
 #endif
   );
                  , const char *dbg_w, const char *dbg_f, int dbg_l
 #endif
   );
@@ -73,8 +74,8 @@ static int parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
                            PACKET * packet);
 static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen,
                          PACKET * packet);
                            PACKET * packet);
 static int parse_comment (IOBUF inp, int pkttype, unsigned long pktlen,
                          PACKET * packet);
-static void parse_trust (IOBUF inp, int pkttype, unsigned long pktlen,
-                        PACKET * packet);
+static gpg_error_t parse_ring_trust (parse_packet_ctx_t ctx,
+                                     unsigned long pktlen);
 static int parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
                            PACKET * packet, int new_ctb, int partial);
 static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
 static int parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
                            PACKET * packet, int new_ctb, int partial);
 static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
@@ -86,21 +87,23 @@ static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
 static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
                              PACKET * packet, int partial);
 
 static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
                              PACKET * packet, int partial);
 
+/* Read a 16-bit value in MSB order (big endian) from an iobuf.  */
 static unsigned short
 read_16 (IOBUF inp)
 {
   unsigned short a;
 static unsigned short
 read_16 (IOBUF inp)
 {
   unsigned short a;
-  a = iobuf_get_noeof (inp) << 8;
+  a = (unsigned short)iobuf_get_noeof (inp) << 8;
   a |= iobuf_get_noeof (inp);
   return a;
 }
 
 
   a |= iobuf_get_noeof (inp);
   return a;
 }
 
 
+/* Read a 32-bit value in MSB order (big endian) from an iobuf.  */
 static unsigned long
 read_32 (IOBUF inp)
 {
   unsigned long a;
 static unsigned long
 read_32 (IOBUF inp)
 {
   unsigned long a;
-  a = iobuf_get_noeof (inp) << 24;
+  a = (unsigned long)iobuf_get_noeof (inp) << 24;
   a |= iobuf_get_noeof (inp) << 16;
   a |= iobuf_get_noeof (inp) << 8;
   a |= iobuf_get_noeof (inp);
   a |= iobuf_get_noeof (inp) << 16;
   a |= iobuf_get_noeof (inp) << 8;
   a |= iobuf_get_noeof (inp);
@@ -108,11 +111,18 @@ read_32 (IOBUF inp)
 }
 
 
 }
 
 
-/* Read an external representation of an mpi and return the MPI.  The
- * external format is a 16 bit unsigned value stored in network byte
- * order, giving the number of bits for the following integer. The
- * integer is stored with MSB first (left padded with zeroes to align
- * on a byte boundary).  */
+/* Read an external representation of an MPI and return the MPI.  The
+   external format is a 16-bit unsigned value stored in network byte
+   order giving the number of bits for the following integer.  The
+   integer is stored MSB first and is left padded with zero bits to
+   align on a byte boundary.
+
+   The caller must set *RET_NREAD to the maximum number of bytes to
+   read from the pipeline INP.  This function sets *RET_NREAD to be
+   the number of bytes actually read from the pipeline.
+
+   If SECURE is true, the integer is stored in secure memory
+   (allocated using gcry_xmalloc_secure).  */
 static gcry_mpi_t
 mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
 {
 static gcry_mpi_t
 mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
 {
@@ -149,10 +159,15 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
   p[1] = c2;
   for (i = 0; i < nbytes; i++)
     {
   p[1] = c2;
   for (i = 0; i < nbytes; i++)
     {
-      p[i + 2] = iobuf_get (inp) & 0xff;
       if (nread == nmax)
       if (nread == nmax)
-        goto overflow;
-      nread++;
+       goto overflow;
+
+      c = iobuf_get (inp);
+      if (c == -1)
+       goto leave;
+
+      p[i + 2] = c;
+      nread ++;
     }
 
   if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
     }
 
   if (gcry_mpi_scan (&a, GCRYMPI_FMT_PGP, buf, nread, &nread))
@@ -176,28 +191,44 @@ set_packet_list_mode (int mode)
 {
   int old = list_mode;
   list_mode = mode;
 {
   int old = list_mode;
   list_mode = mode;
-  /* FIXME(gcrypt) mpi_print_mode = DBG_MPI; */
-  /* We use stdout print only if invoked by the --list-packets command
+
+  /* We use stdout only if invoked by the --list-packets command
      but switch to stderr in all other cases.  This breaks the
      previous behaviour but that seems to be more of a bug than
      intentional.  I don't believe that any application makes use of
      this long standing annoying way of printing to stdout except when
      doing a --list-packets. If this assumption fails, it will be easy
      to add an option for the listing stream.  Note that we initialize
      but switch to stderr in all other cases.  This breaks the
      previous behaviour but that seems to be more of a bug than
      intentional.  I don't believe that any application makes use of
      this long standing annoying way of printing to stdout except when
      doing a --list-packets. If this assumption fails, it will be easy
      to add an option for the listing stream.  Note that we initialize
-     it only once; mainly because some code may switch the option
-     value later back to 1 and we want to have all output to the same
-     stream.
+     it only once; mainly because there is code which switches
+     opt.list_mode back to 1 and we want to have all output to the
+     same stream.  The MPI_PRINT_MODE will be enabled if the
+     corresponding debug flag is set or if we are in --list-packets
+     and --verbose is given.
 
      Using stderr is not actually very clean because it bypasses the
      logging code but it is a special thing anyway.  I am not sure
      whether using log_stream() would be better.  Perhaps we should
 
      Using stderr is not actually very clean because it bypasses the
      logging code but it is a special thing anyway.  I am not sure
      whether using log_stream() would be better.  Perhaps we should
-     enable the list mdoe only with a special option. */
+     enable the list mode only with a special option. */
   if (!listfp)
   if (!listfp)
-    listfp = opt.list_packets == 2 ? es_stdout : es_stderr;
+    {
+      if (opt.list_packets)
+        {
+          listfp = es_stdout;
+          if (opt.verbose)
+            mpi_print_mode = 1;
+        }
+      else
+        listfp = es_stderr;
+
+      if (DBG_MPI)
+        mpi_print_mode = 1;
+    }
   return old;
 }
 
 
   return old;
 }
 
 
+/* If OPT.VERBOSE is set, print a warning that the algorithm ALGO is
+   not suitable for signing and encryption.  */
 static void
 unknown_pubkey_warning (int algo)
 {
 static void
 unknown_pubkey_warning (int algo)
 {
@@ -230,36 +261,31 @@ unknown_pubkey_warning (int algo)
 }
 
 
 }
 
 
-/* Parse a packet and return it in packet structure.
- * 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.   */
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
 int
 int
-dbg_parse_packet (IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l)
+dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *pkt,
+                  const char *dbg_f, int dbg_l)
 {
   int skip, rc;
 
   do
     {
 {
   int skip, rc;
 
   do
     {
-      rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l);
+      rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l);
     }
     }
-  while (skip);
+  while (skip && ! rc);
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
-parse_packet (IOBUF inp, PACKET * pkt)
+parse_packet (parse_packet_ctx_t ctx, PACKET *pkt)
 {
   int skip, rc;
 
   do
     {
 {
   int skip, rc;
 
   do
     {
-      rc = parse (inp, pkt, 0, NULL, &skip, NULL, 0);
+      rc = parse (ctx, pkt, 0, NULL, &skip, NULL, 0);
     }
     }
-  while (skip);
+  while (skip && ! rc);
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -269,33 +295,34 @@ parse_packet (IOBUF inp, PACKET * pkt)
  * Like parse packet, but only return secret or public (sub)key
  * packets.
  */
  * Like parse packet, but only return secret or public (sub)key
  * packets.
  */
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
 int
 int
-dbg_search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid,
+dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
+                   off_t * retpos, int with_uid,
                   const char *dbg_f, int dbg_l)
 {
   int skip, rc;
 
   do
     {
                   const char *dbg_f, int dbg_l)
 {
   int skip, rc;
 
   do
     {
-      rc =
-       parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search",
-              dbg_f, dbg_l);
+      rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0, "search",
+                  dbg_f, dbg_l);
     }
     }
-  while (skip);
+  while (skip && ! rc);
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
-search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid)
+search_packet (parse_packet_ctx_t ctx, PACKET *pkt,
+               off_t * retpos, int with_uid)
 {
   int skip, rc;
 
   do
     {
 {
   int skip, rc;
 
   do
     {
-      rc = parse (inp, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0);
+      rc = parse (ctx, pkt, with_uid ? 2 : 1, retpos, &skip, NULL, 0);
     }
     }
-  while (skip);
+  while (skip && ! rc);
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -304,32 +331,53 @@ search_packet (IOBUF inp, PACKET * pkt, off_t * retpos, int with_uid)
 /*
  * Copy all packets from INP to OUT, thereby removing unused spaces.
  */
 /*
  * Copy all packets from INP to OUT, thereby removing unused spaces.
  */
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
 int
 int
-dbg_copy_all_packets (IOBUF inp, IOBUF out, const char *dbg_f, int dbg_l)
+dbg_copy_all_packets (iobuf_t inp, iobuf_t out, const char *dbg_f, int dbg_l)
 {
   PACKET pkt;
 {
   PACKET pkt;
+  struct parse_packet_ctx_s parsectx;
   int skip, rc = 0;
   int skip, rc = 0;
+
+  if (! out)
+    log_bug ("copy_all_packets: OUT may not be NULL.\n");
+
+  init_parse_packet (&parsectx, inp);
+
   do
     {
       init_packet (&pkt);
     }
   while (!
         (rc =
   do
     {
       init_packet (&pkt);
     }
   while (!
         (rc =
-         parse (inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l)));
+         parse (&parsectx, &pkt, 0, NULL, &skip, out, 0, "copy",
+                 dbg_f, dbg_l)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
-copy_all_packets (IOBUF inp, IOBUF out)
+copy_all_packets (iobuf_t inp, iobuf_t out)
 {
   PACKET pkt;
 {
   PACKET pkt;
+  struct parse_packet_ctx_s parsectx;
   int skip, rc = 0;
   int skip, rc = 0;
+
+  if (! out)
+    log_bug ("copy_all_packets: OUT may not be NULL.\n");
+
+  init_parse_packet (&parsectx, inp);
+
   do
     {
       init_packet (&pkt);
     }
   do
     {
       init_packet (&pkt);
     }
-  while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0)));
+  while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -340,36 +388,58 @@ copy_all_packets (IOBUF inp, IOBUF out)
  * Stop at offset STOPoff (i.e. don't copy packets at this or later
  * offsets)
  */
  * Stop at offset STOPoff (i.e. don't copy packets at this or later
  * offsets)
  */
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
 int
 int
-dbg_copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff,
+dbg_copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff,
                       const char *dbg_f, int dbg_l)
 {
                       const char *dbg_f, int dbg_l)
 {
+  int rc = 0;
   PACKET pkt;
   PACKET pkt;
-  int skip, rc = 0;
+  int skip;
+  struct parse_packet_ctx_s parsectx;
+
+  init_parse_packet (&parsectx, inp);
+
   do
     {
       if (iobuf_tell (inp) >= stopoff)
   do
     {
       if (iobuf_tell (inp) >= stopoff)
-       return 0;
+        {
+          deinit_parse_packet (&parsectx);
+          return 0;
+        }
       init_packet (&pkt);
     }
       init_packet (&pkt);
     }
-  while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0,
+  while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0,
                       "some", dbg_f, dbg_l)));
                       "some", dbg_f, dbg_l)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
-copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff)
+copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff)
 {
 {
+  int rc = 0;
   PACKET pkt;
   PACKET pkt;
-  int skip, rc = 0;
+  struct parse_packet_ctx_s parsectx;
+  int skip;
+
+  init_parse_packet (&parsectx, inp);
+
   do
     {
       if (iobuf_tell (inp) >= stopoff)
   do
     {
       if (iobuf_tell (inp) >= stopoff)
-       return 0;
+        {
+          deinit_parse_packet (&parsectx);
+          return 0;
+        }
       init_packet (&pkt);
     }
       init_packet (&pkt);
     }
-  while (!(rc = parse (inp, &pkt, 0, NULL, &skip, out, 0)));
+  while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -378,52 +448,90 @@ copy_some_packets (IOBUF inp, IOBUF out, off_t stopoff)
 /*
  * Skip over N packets
  */
 /*
  * Skip over N packets
  */
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
 int
 int
-dbg_skip_some_packets (IOBUF inp, unsigned n, const char *dbg_f, int dbg_l)
+dbg_skip_some_packets (iobuf_t inp, unsigned n, const char *dbg_f, int dbg_l)
 {
 {
-  int skip, rc = 0;
+  int rc = 0;
+  int skip;
   PACKET pkt;
   PACKET pkt;
+  struct parse_packet_ctx_s parsectx;
+
+  init_parse_packet (&parsectx, inp);
 
   for (; n && !rc; n--)
     {
       init_packet (&pkt);
 
   for (; n && !rc; n--)
     {
       init_packet (&pkt);
-      rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l);
+      rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1, "skip",
+                  dbg_f, dbg_l);
     }
     }
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
 int
-skip_some_packets (IOBUF inp, unsigned n)
+skip_some_packets (iobuf_t inp, unsigned int n)
 {
 {
-  int skip, rc = 0;
+  int rc = 0;
+  int skip;
   PACKET pkt;
   PACKET pkt;
+  struct parse_packet_ctx_s parsectx;
+
+  init_parse_packet (&parsectx, inp);
 
   for (; n && !rc; n--)
     {
       init_packet (&pkt);
 
   for (; n && !rc; n--)
     {
       init_packet (&pkt);
-      rc = parse (inp, &pkt, 0, NULL, &skip, NULL, 1);
+      rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1);
     }
     }
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
 
 
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
 
 
-/*
- * Parse packet.  Stores 1 at SKIP 1 if the packet should be skipped;
- * this is the case if either ONLYKEYPKTS is set and the parsed packet
- * isn't a key packet or the packet-type is 0, indicating deleted
- * stuff.  If OUT is not NULL, a special copymode is used.
- */
+/* Parse a packet and save it in *PKT.
+
+   If OUT is not NULL and the packet is valid (its type is not 0),
+   then the header, the initial length field and the packet's contents
+   are written to OUT.  In this case, the packet is not saved in *PKT.
+
+   ONLYKEYPKTS is a simple packet filter.  If ONLYKEYPKTS is set to 1,
+   then only public subkey packets, public key packets, private subkey
+   packets and private key packets are parsed.  The rest are skipped
+   (i.e., the header and the contents are read from the pipeline and
+   discarded).  If ONLYKEYPKTS is set to 2, then in addition to the
+   above 4 types of packets, user id packets are also accepted.
+
+   DO_SKIP is a more coarse grained filter.  Unless ONLYKEYPKTS is set
+   to 2 and the packet is a user id packet, all packets are skipped.
+
+   Finally, if a packet is invalid (it's type is 0), it is skipped.
+
+   If a packet is skipped and SKIP is not NULL, then *SKIP is set to
+   1.
+
+   Note: ONLYKEYPKTS and DO_SKIP are only respected if OUT is NULL,
+   i.e., the packets are not simply being copied.
+
+   If RETPOS is not NULL, then the position of CTX->INP (as returned by
+   iobuf_tell) is saved there before any data is read from CTX->INP.
+  */
 static int
 static int
-parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
+parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
        int *skip, IOBUF out, int do_skip
        int *skip, IOBUF out, int do_skip
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
        , const char *dbg_w, const char *dbg_f, int dbg_l
 #endif
        )
 {
        , const char *dbg_w, const char *dbg_f, int dbg_l
 #endif
        )
 {
-  int rc = 0, c, ctb, pkttype, lenbytes;
+  int rc = 0;
+  iobuf_t inp;
+  int c, ctb, pkttype, lenbytes;
   unsigned long pktlen;
   byte hdr[8];
   int hdrlen;
   unsigned long pktlen;
   byte hdr[8];
   int hdrlen;
@@ -432,7 +540,10 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
   off_t pos;
 
   *skip = 0;
   off_t pos;
 
   *skip = 0;
-  assert (!pkt->pkt.generic);
+  inp = ctx->inp;
+
+ again:
+  log_assert (!pkt->pkt.generic);
   if (retpos || list_mode)
     {
       pos = iobuf_tell (inp);
   if (retpos || list_mode)
     {
       pos = iobuf_tell (inp);
@@ -442,6 +553,8 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
   else
     pos = 0; /* (silence compiler warning) */
 
   else
     pos = 0; /* (silence compiler warning) */
 
+  /* The first byte of a packet is the so-called tag.  The highest bit
+     must be set.  */
   if ((ctb = iobuf_get (inp)) == -1)
     {
       rc = -1;
   if ((ctb = iobuf_get (inp)) == -1)
     {
       rc = -1;
@@ -449,17 +562,31 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
     }
   hdrlen = 0;
   hdr[hdrlen++] = ctb;
     }
   hdrlen = 0;
   hdr[hdrlen++] = ctb;
+
   if (!(ctb & 0x80))
     {
       log_error ("%s: invalid packet (ctb=%02x)\n", iobuf_where (inp), ctb);
       rc = gpg_error (GPG_ERR_INV_PACKET);
       goto leave;
     }
   if (!(ctb & 0x80))
     {
       log_error ("%s: invalid packet (ctb=%02x)\n", iobuf_where (inp), ctb);
       rc = gpg_error (GPG_ERR_INV_PACKET);
       goto leave;
     }
+
+  /* Immediately following the header is the length.  There are two
+     formats: the old format and the new format.  If bit 6 (where the
+     least significant bit is bit 0) is set in the tag, then we are
+     dealing with a new format packet.  Otherwise, it is an old format
+     packet.  */
   pktlen = 0;
   new_ctb = !!(ctb & 0x40);
   if (new_ctb)
     {
   pktlen = 0;
   new_ctb = !!(ctb & 0x40);
   if (new_ctb)
     {
+      /* Get the packet's type.  This is encoded in the 6 least
+        significant bits of the tag.  */
       pkttype = ctb & 0x3f;
       pkttype = ctb & 0x3f;
+
+      /* Extract the packet's length.  New format packets have 4 ways
+        to encode the packet length.  The value of the first byte
+        determines the encoding and partially determines the length.
+        See section 4.2.2 of RFC 4880 for details.  */
       if ((c = iobuf_get (inp)) == -1)
        {
          log_error ("%s: 1st length byte missing\n", iobuf_where (inp));
       if ((c = iobuf_get (inp)) == -1)
        {
          log_error ("%s: 1st length byte missing\n", iobuf_where (inp));
@@ -486,16 +613,21 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
         }
       else if (c == 255)
         {
         }
       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)
+         int i;
+         char value[4];
+
+         for (i = 0; i < 4; i ++)
             {
             {
-              log_error ("%s: 4 byte length invalid\n", iobuf_where (inp));
-              rc = gpg_error (GPG_ERR_INV_PACKET);
-              goto leave;
+              if ((c = iobuf_get (inp)) == -1)
+                {
+                  log_error ("%s: 4 byte length invalid\n", iobuf_where (inp));
+                  rc = gpg_error (GPG_ERR_INV_PACKET);
+                  goto leave;
+                }
+              value[i] = hdr[hdrlen++] = c;
             }
             }
-          pktlen |= (hdr[hdrlen++] = c);
+
+         pktlen = buf32_to_ulong (value);
         }
       else /* Partial body length.  */
         {
         }
       else /* Partial body length.  */
         {
@@ -505,13 +637,13 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC:
             case PKT_COMPRESSED:
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC:
             case PKT_COMPRESSED:
-              iobuf_set_partial_block_mode (inp, c & 0xff);
+              iobuf_set_partial_body_length_mode (inp, c & 0xff);
               pktlen = 0;      /* To indicate partial length.  */
               partial = 1;
               break;
 
             default:
               pktlen = 0;      /* To indicate partial length.  */
               partial = 1;
               break;
 
             default:
-              log_error ("%s: partial length for invalid"
+              log_error ("%s: partial length invalid for"
                          " packet type %d\n", iobuf_where (inp), pkttype);
               rc = gpg_error (GPG_ERR_INV_PACKET);
               goto leave;
                          " packet type %d\n", iobuf_where (inp), pkttype);
               rc = gpg_error (GPG_ERR_INV_PACKET);
               goto leave;
@@ -520,8 +652,13 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
 
     }
   else
 
     }
   else
+    /* This is an old format packet.  */
     {
     {
+      /* Extract the packet's type.  This is encoded in bits 2-5.  */
       pkttype = (ctb >> 2) & 0xf;
       pkttype = (ctb >> 2) & 0xf;
+
+      /* The type of length encoding is encoded in bits 0-1 of the
+        tag.  */
       lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3));
       if (!lenbytes)
        {
       lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3));
       if (!lenbytes)
        {
@@ -543,12 +680,26 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
          for (; lenbytes; lenbytes--)
            {
              pktlen <<= 8;
          for (; lenbytes; lenbytes--)
            {
              pktlen <<= 8;
-             pktlen |= hdr[hdrlen++] = iobuf_get_noeof (inp);
+             c = iobuf_get (inp);
+             if (c == -1)
+               {
+                 log_error ("%s: length invalid\n", iobuf_where (inp));
+                 rc = gpg_error (GPG_ERR_INV_PACKET);
+                 goto leave;
+               }
+             pktlen |= hdr[hdrlen++] = c;
            }
        }
     }
 
            }
        }
     }
 
-  if (pktlen == (unsigned long) (-1))
+  /* Sometimes the decompressing layer enters an error state in which
+     it simply outputs 0xff for every byte read.  If we have a stream
+     of 0xff bytes, then it will be detected as a new format packet
+     with type 63 and a 4-byte encoded length that is 4G-1.  Since
+     packets with type 63 are private and we use them as a control
+     packet, which won't be 4 GB, we reject such packets as
+     invalid.  */
+  if (pkttype == 63 && pktlen == 0xFFFFFFFF)
     {
       /* With some probability this is caused by a problem in the
        * the uncompressing layer - in some error cases it just loops
     {
       /* With some probability this is caused by a problem in the
        * the uncompressing layer - in some error cases it just loops
@@ -559,6 +710,17 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
 
   if (out && pkttype)
     {
 
   if (out && pkttype)
     {
+      /* This type of copying won't work if the packet uses a partial
+        body length.  (In other words, this only works if HDR is
+        actually the length.)  Currently, no callers require this
+        functionality so we just log this as an error.  */
+      if (partial)
+       {
+         log_error ("parse: Can't copy partial packet.  Aborting.\n");
+         rc = gpg_error (GPG_ERR_INV_PACKET);
+         goto leave;
+       }
+
       rc = iobuf_write (out, hdr, hdrlen);
       if (!rc)
        rc = copy_packet (inp, out, pkttype, pktlen, partial);
       rc = iobuf_write (out, hdr, hdrlen);
       if (!rc)
        rc = copy_packet (inp, out, pkttype, pktlen, partial);
@@ -566,9 +728,13 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
     }
 
   if (with_uid && pkttype == PKT_USER_ID)
     }
 
   if (with_uid && pkttype == PKT_USER_ID)
+    /* If ONLYKEYPKTS is set to 2, then we never skip user id packets,
+       even if DO_SKIP is set.  */
     ;
   else if (do_skip
     ;
   else if (do_skip
+          /* type==0 is not allowed.  This is an invalid packet.  */
           || !pkttype
           || !pkttype
+          /* When ONLYKEYPKTS is set, we don't skip keys.  */
           || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
               && pkttype != PKT_PUBLIC_KEY
               && pkttype != PKT_SECRET_SUBKEY && pkttype != PKT_SECRET_KEY))
           || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
               && pkttype != PKT_PUBLIC_KEY
               && pkttype != PKT_SECRET_SUBKEY && pkttype != PKT_SECRET_KEY))
@@ -581,7 +747,7 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
 
   if (DBG_PACKET)
     {
 
   if (DBG_PACKET)
     {
-#ifdef DEBUG_PARSE_PACKET
+#if DEBUG_PARSE_PACKET
       log_debug ("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n",
                 iobuf_id (inp), pkttype, pktlen, new_ctb ? " (new_ctb)" : "",
                 dbg_w, dbg_f, dbg_l);
       log_debug ("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n",
                 iobuf_id (inp), pkttype, pktlen, new_ctb ? " (new_ctb)" : "",
                 dbg_w, dbg_f, dbg_l);
@@ -595,9 +761,12 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
   if (list_mode)
     es_fprintf (listfp, "# off=%lu ctb=%02x tag=%d hlen=%d plen=%lu%s%s\n",
                 (unsigned long)pos, ctb, pkttype, hdrlen, pktlen,
   if (list_mode)
     es_fprintf (listfp, "# off=%lu ctb=%02x tag=%d hlen=%d plen=%lu%s%s\n",
                 (unsigned long)pos, ctb, pkttype, hdrlen, pktlen,
-                partial? " partial":"",
+                partial? (new_ctb ? " partial" : " indeterminate") :"",
                 new_ctb? " new-ctb":"");
 
                 new_ctb? " new-ctb":"");
 
+  /* Count it.  */
+  ctx->n_parsed_packets++;
+
   pkt->pkttype = pkttype;
   rc = GPG_ERR_UNKNOWN_PACKET; /* default error */
   switch (pkttype)
   pkt->pkttype = pkttype;
   rc = GPG_ERR_UNKNOWN_PACKET; /* default error */
   switch (pkttype)
@@ -635,8 +804,11 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
       rc = parse_comment (inp, pkttype, pktlen, pkt);
       break;
     case PKT_RING_TRUST:
       rc = parse_comment (inp, pkttype, pktlen, pkt);
       break;
     case PKT_RING_TRUST:
-      parse_trust (inp, pkttype, pktlen, pkt);
-      rc = 0;
+      {
+        rc = parse_ring_trust (ctx, pktlen);
+        if (!rc)
+          goto again; /* Directly read the next packet.  */
+      }
       break;
     case PKT_PLAINTEXT:
       rc = parse_plaintext (inp, pkttype, pktlen, pkt, new_ctb, partial);
       break;
     case PKT_PLAINTEXT:
       rc = parse_plaintext (inp, pkttype, pktlen, pkt, new_ctb, partial);
@@ -658,12 +830,24 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
       rc = parse_marker (inp, pkttype, pktlen);
       break;
     default:
       rc = parse_marker (inp, pkttype, pktlen);
       break;
     default:
+      /* Unknown packet.  Skip it.  */
       skip_packet (inp, pkttype, pktlen, partial);
       break;
     }
 
       skip_packet (inp, pkttype, pktlen, partial);
       break;
     }
 
+  /* Store a shallow copy of certain packets in the context.  */
+  free_packet (NULL, ctx);
+  if (!rc && (pkttype == PKT_PUBLIC_KEY
+              || pkttype == PKT_SECRET_KEY
+              || pkttype == PKT_USER_ID
+              || pkttype == PKT_ATTRIBUTE
+              || pkttype == PKT_SIGNATURE))
+    {
+      ctx->last_pkt = *pkt;
+    }
+
  leave:
  leave:
-  /* FIXME: Do we leak in case of an error?  */
+  /* FIXME: We leak in case of an error (see the xmalloc's above).  */
   if (!rc && iobuf_error (inp))
     rc = GPG_ERR_INV_KEYRING;
 
   if (!rc && iobuf_error (inp))
     rc = GPG_ERR_INV_KEYRING;
 
@@ -692,6 +876,20 @@ dump_hex_line (int c, int *i)
 }
 
 
 }
 
 
+/* Copy the contents of a packet from the pipeline IN to the pipeline
+   OUT.
+
+   The header and length have already been read from INP and the
+   decoded values are given as PKGTYPE and PKTLEN.
+
+   If the packet is a partial body length packet (RFC 4880, Section
+   4.2.2.4), then iobuf_set_partial_block_modeiobuf_set_partial_block_mode
+   should already have been called on INP and PARTIAL should be set.
+
+   If PARTIAL is set or PKTLEN is 0 and PKTTYPE is PKT_COMPRESSED,
+   copy until the first EOF is encountered on INP.
+
+   Returns 0 on success and an error code if an error occurs.  */
 static int
 copy_packet (IOBUF inp, IOBUF out, int pkttype,
             unsigned long pktlen, int partial)
 static int
 copy_packet (IOBUF inp, IOBUF out, int pkttype,
             unsigned long pktlen, int partial)
@@ -702,7 +900,7 @@ copy_packet (IOBUF inp, IOBUF out, int pkttype,
 
   if (partial)
     {
 
   if (partial)
     {
-      while ((n = iobuf_read (inp, buf, 100)) != -1)
+      while ((n = iobuf_read (inp, buf, sizeof (buf))) != -1)
        if ((rc = iobuf_write (out, buf, n)))
          return rc;            /* write error */
     }
        if ((rc = iobuf_write (out, buf, n)))
          return rc;            /* write error */
     }
@@ -710,7 +908,7 @@ copy_packet (IOBUF inp, IOBUF out, int pkttype,
     {
       log_debug ("copy_packet: compressed!\n");
       /* compressed packet, copy till EOF */
     {
       log_debug ("copy_packet: compressed!\n");
       /* compressed packet, copy till EOF */
-      while ((n = iobuf_read (inp, buf, 100)) != -1)
+      while ((n = iobuf_read (inp, buf, sizeof (buf))) != -1)
        if ((rc = iobuf_write (out, buf, n)))
          return rc;            /* write error */
     }
        if ((rc = iobuf_write (out, buf, n)))
          return rc;            /* write error */
     }
@@ -718,7 +916,7 @@ copy_packet (IOBUF inp, IOBUF out, int pkttype,
     {
       for (; pktlen; pktlen -= n)
        {
     {
       for (; pktlen; pktlen -= n)
        {
-         n = pktlen > 100 ? 100 : pktlen;
+         n = pktlen > sizeof (buf) ? sizeof (buf) : pktlen;
          n = iobuf_read (inp, buf, n);
          if (n == -1)
            return gpg_error (GPG_ERR_EOF);
          n = iobuf_read (inp, buf, n);
          if (n == -1)
            return gpg_error (GPG_ERR_EOF);
@@ -730,6 +928,9 @@ copy_packet (IOBUF inp, IOBUF out, int pkttype,
 }
 
 
 }
 
 
+/* Skip an unknown packet.  PKTTYPE is the packet's type, PKTLEN is
+   the length of the packet's content and PARTIAL is whether partial
+   body length encoding in used (in this case PKTLEN is ignored).  */
 static void
 skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
 {
 static void
 skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
 {
@@ -764,8 +965,9 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
 
 
 /* Read PKTLEN bytes form INP and return them in a newly allocated
 
 
 /* Read PKTLEN bytes form INP and return them in a newly allocated
-   buffer.  In case of an error NULL is returned and a error messages
-   printed.  */
+   buffer.  In case of an error (including reading fewer than PKTLEN
+   bytes from INP before EOF is returned), NULL is returned and an
+   error message is logged.  */
 static void *
 read_rest (IOBUF inp, size_t pktlen)
 {
 static void *
 read_rest (IOBUF inp, size_t pktlen)
 {
@@ -985,7 +1187,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
        log_info (_("WARNING: potentially insecure symmetrically"
                    " encrypted session key\n"));
     }
        log_info (_("WARNING: potentially insecure symmetrically"
                    " encrypted session key\n"));
     }
-  assert (!pktlen);
+  log_assert (!pktlen);
 
   if (list_mode)
     {
 
   if (list_mode)
     {
@@ -1096,6 +1298,12 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
 }
 
 
 }
 
 
+/* Dump a subpacket to LISTFP.  BUFFER contains the subpacket in
+   question and points to the type field in the subpacket header (not
+   the start of the header).  TYPE is the subpacket's type with the
+   critical bit cleared.  CRITICAL is the value of the CRITICAL bit.
+   BUFLEN is the length of the buffer and LENGTH is the length of the
+   subpacket according to the subpacket's header.  */
 static void
 dump_sig_subpkt (int hashed, int type, int critical,
                 const byte * buffer, size_t buflen, size_t length)
 static void
 dump_sig_subpkt (int hashed, int type, int critical,
                 const byte * buffer, size_t buflen, size_t length)
@@ -1132,14 +1340,14 @@ dump_sig_subpkt (int hashed, int type, int critical,
     case SIGSUBPKT_SIG_CREATED:
       if (length >= 4)
        es_fprintf (listfp, "sig created %s",
     case SIGSUBPKT_SIG_CREATED:
       if (length >= 4)
        es_fprintf (listfp, "sig created %s",
-                    strtimestamp (buffer_to_u32 (buffer)));
+                    strtimestamp (buf32_to_u32 (buffer)));
       break;
     case SIGSUBPKT_SIG_EXPIRE:
       if (length >= 4)
        {
       break;
     case SIGSUBPKT_SIG_EXPIRE:
       if (length >= 4)
        {
-         if (buffer_to_u32 (buffer))
+         if (buf32_to_u32 (buffer))
            es_fprintf (listfp, "sig expires after %s",
            es_fprintf (listfp, "sig expires after %s",
-                        strtimevalue (buffer_to_u32 (buffer)));
+                        strtimevalue (buf32_to_u32 (buffer)));
          else
            es_fprintf (listfp, "sig does not expire");
        }
          else
            es_fprintf (listfp, "sig does not expire");
        }
@@ -1172,9 +1380,9 @@ dump_sig_subpkt (int hashed, int type, int critical,
     case SIGSUBPKT_KEY_EXPIRE:
       if (length >= 4)
        {
     case SIGSUBPKT_KEY_EXPIRE:
       if (length >= 4)
        {
-         if (buffer_to_u32 (buffer))
+         if (buf32_to_u32 (buffer))
            es_fprintf (listfp, "key expires after %s",
            es_fprintf (listfp, "key expires after %s",
-                        strtimevalue (buffer_to_u32 (buffer)));
+                        strtimevalue (buf32_to_u32 (buffer)));
          else
            es_fprintf (listfp, "key does not expire");
        }
          else
            es_fprintf (listfp, "key does not expire");
        }
@@ -1198,8 +1406,21 @@ dump_sig_subpkt (int hashed, int type, int critical,
     case SIGSUBPKT_ISSUER:
       if (length >= 8)
        es_fprintf (listfp, "issuer key ID %08lX%08lX",
     case SIGSUBPKT_ISSUER:
       if (length >= 8)
        es_fprintf (listfp, "issuer key ID %08lX%08lX",
-                    (ulong) buffer_to_u32 (buffer),
-                    (ulong) buffer_to_u32 (buffer + 4));
+                    (ulong) buf32_to_u32 (buffer),
+                    (ulong) buf32_to_u32 (buffer + 4));
+      break;
+    case SIGSUBPKT_ISSUER_FPR:
+      if (length >= 21)
+        {
+          char *tmp;
+          es_fprintf (listfp, "issuer fpr v%d ", buffer[0]);
+          tmp = bin2hex (buffer+1, length-1, NULL);
+          if (tmp)
+            {
+              es_fputs (tmp, listfp);
+              xfree (tmp);
+            }
+        }
       break;
     case SIGSUBPKT_NOTATION:
       {
       break;
     case SIGSUBPKT_NOTATION:
       {
@@ -1240,12 +1461,12 @@ dump_sig_subpkt (int hashed, int type, int critical,
        es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_KS_FLAGS:
        es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_KS_FLAGS:
-      es_fputs ("key server preferences:", listfp);
+      es_fputs ("keyserver preferences:", listfp);
       for (i = 0; i < length; i++)
        es_fprintf (listfp, " %02X", buffer[i]);
       break;
     case SIGSUBPKT_PREF_KS:
       for (i = 0; i < length; i++)
        es_fprintf (listfp, " %02X", buffer[i]);
       break;
     case SIGSUBPKT_PREF_KS:
-      es_fputs ("preferred key server: ", listfp);
+      es_fputs ("preferred keyserver: ", listfp);
       es_write_sanitized (listfp, buffer, length, ")", NULL);
       break;
     case SIGSUBPKT_PRIMARY_UID:
       es_write_sanitized (listfp, buffer, length, ")", NULL);
       break;
     case SIGSUBPKT_PRIMARY_UID:
@@ -1351,6 +1572,10 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
       if (n < 8)
        break;
       return 0;
       if (n < 8)
        break;
       return 0;
+    case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
+      if (n < 21)
+       break;
+      return 0;
     case SIGSUBPKT_NOTATION:
       /* minimum length needed, and the subpacket must be well-formed
          where the name length and value length all fit inside the
     case SIGSUBPKT_NOTATION:
       /* minimum length needed, and the subpacket must be well-formed
          where the name length and value length all fit inside the
@@ -1409,6 +1634,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
     case SIGSUBPKT_REVOCABLE:
     case SIGSUBPKT_REV_KEY:
     case SIGSUBPKT_ISSUER:     /* issuer key ID */
     case SIGSUBPKT_REVOCABLE:
     case SIGSUBPKT_REV_KEY:
     case SIGSUBPKT_ISSUER:     /* issuer key ID */
+    case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
     case SIGSUBPKT_PREF_SYM:
     case SIGSUBPKT_PREF_HASH:
     case SIGSUBPKT_PREF_COMPR:
     case SIGSUBPKT_PREF_SYM:
     case SIGSUBPKT_PREF_HASH:
     case SIGSUBPKT_PREF_COMPR:
@@ -1420,6 +1646,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
       /* Is it enough to show the policy or keyserver? */
     case SIGSUBPKT_POLICY:
     case SIGSUBPKT_PREF_KS:
       /* Is it enough to show the policy or keyserver? */
     case SIGSUBPKT_POLICY:
     case SIGSUBPKT_PREF_KS:
+    case SIGSUBPKT_REVOC_REASON: /* At least we know about it.  */
       return 1;
 
     default:
       return 1;
 
     default:
@@ -1461,8 +1688,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
        {
          if (buflen < 4)
            goto too_short;
        {
          if (buflen < 4)
            goto too_short;
-         n = (buffer[0] << 24) | (buffer[1] << 16)
-           | (buffer[2] << 8) | buffer[3];
+         n = buf32_to_size_t (buffer);
          buffer += 4;
          buflen -= 4;
        }
          buffer += 4;
          buflen -= 4;
        }
@@ -1533,7 +1759,11 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
       buflen -= n;
     }
   if (reqtype == SIGSUBPKT_TEST_CRITICAL)
       buflen -= n;
     }
   if (reqtype == SIGSUBPKT_TEST_CRITICAL)
-    return buffer;  /* Used as True to indicate that there is no. */
+    /* Returning NULL means we found a subpacket with the critical bit
+       set that we don't grok.  We've iterated over all the subpackets
+       and haven't found such a packet so we need to return a non-NULL
+       value.  */
+    return buffer;
 
   /* Critical bit we don't understand. */
   if (start)
 
   /* Critical bit we don't understand. */
   if (start)
@@ -1558,14 +1788,13 @@ parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype,
 
 
 const byte *
 
 
 const byte *
-parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype,
-                  size_t * ret_n)
+parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype)
 {
   const byte *p;
 
 {
   const byte *p;
 
-  p = parse_sig_subpkt (sig->hashed, reqtype, ret_n);
+  p = parse_sig_subpkt (sig->hashed, reqtype, NULL);
   if (!p)
   if (!p)
-    p = parse_sig_subpkt (sig->unhashed, reqtype, ret_n);
+    p = parse_sig_subpkt (sig->unhashed, reqtype, NULL);
   return p;
 }
 
   return p;
 }
 
@@ -1574,25 +1803,31 @@ parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype,
 void
 parse_revkeys (PKT_signature * sig)
 {
 void
 parse_revkeys (PKT_signature * sig)
 {
-  struct revocation_key *revkey;
+  const byte *revkey;
   int seq = 0;
   size_t len;
 
   if (sig->sig_class != 0x1F)
     return;
 
   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)))
+  while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY,
+                                   &len, &seq, NULL)))
     {
     {
-      if (len == sizeof (struct revocation_key)
-          && (revkey->class & 0x80))  /* 0x80 bit must be set.  */
+      if (/* The only valid length is 22 bytes.  See RFC 4880
+            5.2.3.15.  */
+         len == 22
+         /* 0x80 bit must be set on the class.  */
+          && (revkey[0] & 0x80))
        {
          sig->revkey = xrealloc (sig->revkey,
        {
          sig->revkey = xrealloc (sig->revkey,
-                                 sizeof (struct revocation_key *) *
+                                 sizeof (struct revocation_key) *
                                  (sig->numrevkeys + 1));
                                  (sig->numrevkeys + 1));
-         sig->revkey[sig->numrevkeys] = revkey;
+
+         /* Copy the individual fields.  */
+         sig->revkey[sig->numrevkeys].class = revkey[0];
+         sig->revkey[sig->numrevkeys].algid = revkey[1];
+         memcpy (sig->revkey[sig->numrevkeys].fpr, &revkey[2], 20);
+
          sig->numrevkeys++;
        }
     }
          sig->numrevkeys++;
        }
     }
@@ -1632,13 +1867,19 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
 
   if (!is_v4)
     {
 
   if (!is_v4)
     {
+      if (pktlen == 0)
+       goto underflow;
       md5_len = iobuf_get_noeof (inp);
       pktlen--;
     }
       md5_len = iobuf_get_noeof (inp);
       pktlen--;
     }
+  if (pktlen == 0)
+    goto underflow;
   sig->sig_class = iobuf_get_noeof (inp);
   pktlen--;
   if (!is_v4)
     {
   sig->sig_class = iobuf_get_noeof (inp);
   pktlen--;
   if (!is_v4)
     {
+      if (pktlen < 12)
+       goto underflow;
       sig->timestamp = read_32 (inp);
       pktlen -= 4;
       sig->keyid[0] = read_32 (inp);
       sig->timestamp = read_32 (inp);
       pktlen -= 4;
       sig->keyid[0] = read_32 (inp);
@@ -1646,6 +1887,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
       sig->keyid[1] = read_32 (inp);
       pktlen -= 4;
     }
       sig->keyid[1] = read_32 (inp);
       pktlen -= 4;
     }
+  if (pktlen < 2)
+    goto underflow;
   sig->pubkey_algo = iobuf_get_noeof (inp);
   pktlen--;
   sig->digest_algo = iobuf_get_noeof (inp);
   sig->pubkey_algo = iobuf_get_noeof (inp);
   pktlen--;
   sig->digest_algo = iobuf_get_noeof (inp);
@@ -1654,8 +1897,12 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
   sig->flags.revocable = 1;
   if (is_v4) /* Read subpackets.  */
     {
   sig->flags.revocable = 1;
   if (is_v4) /* Read subpackets.  */
     {
+      if (pktlen < 2)
+       goto underflow;
       n = read_16 (inp);
       pktlen -= 2;  /* Length of hashed data. */
       n = read_16 (inp);
       pktlen -= 2;  /* Length of hashed data. */
+      if (pktlen < n)
+       goto underflow;
       if (n > 10000)
        {
          log_error ("signature packet: hashed data too long\n");
       if (n > 10000)
        {
          log_error ("signature packet: hashed data too long\n");
@@ -1680,8 +1927,12 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
            }
          pktlen -= n;
        }
            }
          pktlen -= n;
        }
+      if (pktlen < 2)
+       goto underflow;
       n = read_16 (inp);
       pktlen -= 2;  /* Length of unhashed data.  */
       n = read_16 (inp);
       pktlen -= 2;  /* Length of unhashed data.  */
+      if (pktlen < n)
+       goto underflow;
       if (n > 10000)
        {
          log_error ("signature packet: unhashed data too long\n");
       if (n > 10000)
        {
          log_error ("signature packet: unhashed data too long\n");
@@ -1708,15 +1959,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
        }
     }
 
        }
     }
 
-  if (pktlen < 5)  /* Sanity check.  */
-    {
-      log_error ("packet(%d) too short\n", pkttype);
-      if (list_mode)
-        es_fputs (":signature packet: [too short]\n", listfp);
-      rc = GPG_ERR_INV_PACKET;
-      goto leave;
-    }
-
+  if (pktlen < 2)
+    goto underflow;
   sig->digest_start[0] = iobuf_get_noeof (inp);
   pktlen--;
   sig->digest_start[1] = iobuf_get_noeof (inp);
   sig->digest_start[0] = iobuf_get_noeof (inp);
   pktlen--;
   sig->digest_start[1] = iobuf_get_noeof (inp);
@@ -1735,24 +1979,24 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
 
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
       if (p)
 
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
       if (p)
-       sig->timestamp = buffer_to_u32 (p);
+       sig->timestamp = buf32_to_u32 (p);
       else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
               && opt.verbose)
        log_info ("signature packet without timestamp\n");
 
       else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
               && opt.verbose)
        log_info ("signature packet without timestamp\n");
 
-      p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER, NULL);
+      p = parse_sig_subpkt2 (sig, SIGSUBPKT_ISSUER);
       if (p)
        {
       if (p)
        {
-         sig->keyid[0] = buffer_to_u32 (p);
-         sig->keyid[1] = buffer_to_u32 (p + 4);
+         sig->keyid[0] = buf32_to_u32 (p);
+         sig->keyid[1] = buf32_to_u32 (p + 4);
        }
       else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
               && opt.verbose)
        log_info ("signature packet without keyid\n");
 
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL);
        }
       else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
               && opt.verbose)
        log_info ("signature packet without keyid\n");
 
       p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL);
-      if (p && buffer_to_u32 (p))
-       sig->expiredate = sig->timestamp + buffer_to_u32 (p);
+      if (p && buf32_to_u32 (p))
+       sig->expiredate = sig->timestamp + buf32_to_u32 (p);
       if (sig->expiredate && sig->expiredate <= make_timestamp ())
        sig->flags.expired = 1;
 
       if (sig->expiredate && sig->expiredate <= make_timestamp ())
        sig->flags.expired = 1;
 
@@ -1764,6 +2008,17 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
       if (p)
        sig->flags.pref_ks = 1;
 
       if (p)
        sig->flags.pref_ks = 1;
 
+      p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
+      if (p && len)
+        {
+          sig->signers_uid = try_make_printable_string (p, len, 0);
+          if (!sig->signers_uid)
+            {
+              rc = gpg_error_from_syserror ();
+              goto leave;
+            }
+        }
+
       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;
@@ -1794,7 +2049,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
          unhashed area.  In theory, anyway, we should never see this
          packet off of a local keyring. */
 
          unhashed area.  In theory, anyway, we should never see this
          packet off of a local keyring. */
 
-      p = parse_sig_subpkt2 (sig, SIGSUBPKT_EXPORTABLE, NULL);
+      p = parse_sig_subpkt2 (sig, SIGSUBPKT_EXPORTABLE);
       if (p && *p == 0)
        sig->flags.exportable = 0;
 
       if (p && *p == 0)
        sig->flags.exportable = 0;
 
@@ -1863,6 +2118,15 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
  leave:
   iobuf_skip_rest (inp, pktlen, 0);
   return rc;
  leave:
   iobuf_skip_rest (inp, pktlen, 0);
   return rc;
+
+ underflow:
+  log_error ("packet(%d) too short\n", pkttype);
+  if (list_mode)
+    es_fputs (":signature packet: [too short]\n", listfp);
+
+  iobuf_skip_rest (inp, pktlen, 0);
+
+  return GPG_ERR_INV_PACKET;
 }
 
 
 }
 
 
@@ -2072,8 +2336,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
                    || algorithm == PUBKEY_ALGO_ECDH) && i==0)
                 {
                   char *curve = openpgp_oid_to_str (pk->pkey[0]);
                    || algorithm == PUBKEY_ALGO_ECDH) && i==0)
                 {
                   char *curve = openpgp_oid_to_str (pk->pkey[0]);
-                  es_fprintf (listfp, " %s (%s)",
-                              openpgp_oid_to_curve (curve), curve);
+                  const char *name = openpgp_oid_to_curve (curve, 0);
+                  es_fprintf (listfp, " %s (%s)", name?name:"", curve);
                   xfree (curve);
                 }
               es_putc ('\n', listfp);
                   xfree (curve);
                 }
               es_putc ('\n', listfp);
@@ -2089,6 +2353,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       byte temp[16];
       size_t snlen = 0;
 
       byte temp[16];
       size_t snlen = 0;
 
+      if (pktlen < 1)
+        {
+          err = gpg_error (GPG_ERR_INV_PACKET);
+          goto leave;
+        }
+
       pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
       if (!pk->seckey_info)
         {
       pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
       if (!pk->seckey_info)
         {
@@ -2146,6 +2416,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
                case 3:
                  for (i = 0; i < 8 && pktlen; i++, pktlen--)
                    temp[i] = iobuf_get_noeof (inp);
                case 3:
                  for (i = 0; i < 8 && pktlen; i++, pktlen--)
                    temp[i] = iobuf_get_noeof (inp);
+                  if (i < 8)
+                    {
+                     err = gpg_error (GPG_ERR_INV_PACKET);
+                     goto leave;
+                    }
                  memcpy (ski->s2k.salt, temp, 8);
                  break;
                }
                  memcpy (ski->s2k.salt, temp, 8);
                  break;
                }
@@ -2249,7 +2524,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           * NOTE: if you change the ivlen above 16, don't forget to
           * enlarge temp.  */
          ski->ivlen = openpgp_cipher_blocklen (ski->algo);
           * NOTE: if you change the ivlen above 16, don't forget to
           * enlarge temp.  */
          ski->ivlen = openpgp_cipher_blocklen (ski->algo);
-         assert (ski->ivlen <= sizeof (temp));
+         log_assert (ski->ivlen <= sizeof (temp));
 
          if (ski->s2k.mode == 1001)
            ski->ivlen = 0;
 
          if (ski->s2k.mode == 1001)
            ski->ivlen = 0;
@@ -2261,7 +2536,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
               err = gpg_error (GPG_ERR_INV_PACKET);
              goto leave;
            }
               err = gpg_error (GPG_ERR_INV_PACKET);
              goto leave;
            }
-         for (i = 0; i < ski->ivlen && pktlen; i++, pktlen--)
+         for (i = 0; i < ski->ivlen; i++, pktlen--)
            temp[i] = iobuf_get_noeof (inp);
          if (list_mode)
            {
            temp[i] = iobuf_get_noeof (inp);
          if (list_mode)
            {
@@ -2289,6 +2564,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
        }
       else if (ski->is_protected)
        {
        }
       else if (ski->is_protected)
        {
+         if (pktlen < 2) /* At least two bytes for the length.  */
+           {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+             goto leave;
+           }
+
          /* Ugly: The length is encrypted too, so we read all stuff
           * up to the end of the packet into the first SKEY
           * element.  */
          /* Ugly: The length is encrypted too, so we read all stuff
           * up to the end of the packet into the first SKEY
           * element.  */
@@ -2309,7 +2590,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           /* Not encrypted.  */
          for (i = npkey; i < nskey; i++)
            {
           /* Not encrypted.  */
          for (i = npkey; i < nskey; i++)
            {
-              unsigned int n = pktlen;
+              unsigned int n;
+
+              if (pktlen < 2) /* At least two bytes for the length.  */
+                {
+                  err = gpg_error (GPG_ERR_INV_PACKET);
+                  goto leave;
+                }
+              n = pktlen;
               pk->pkey[i] = mpi_read (inp, &n, 0);
               pktlen -= n;
               if (list_mode)
               pk->pkey[i] = mpi_read (inp, &n, 0);
               pktlen -= n;
               if (list_mode)
@@ -2325,6 +2613,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
          if (err)
            goto leave;
 
          if (err)
            goto leave;
 
+         if (pktlen < 2)
+           {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+             goto leave;
+           }
          ski->csum = read_16 (inp);
          pktlen -= 2;
          if (list_mode)
          ski->csum = read_16 (inp);
          pktlen -= 2;
          if (list_mode)
@@ -2332,6 +2625,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
        }
     }
 
        }
     }
 
+  /* Note that KEYID below has been initialized above in list_mode.  */
   if (list_mode)
     es_fprintf (listfp, "\tkeyid: %08lX%08lX\n",
                 (ulong) keyid[0], (ulong) keyid[1]);
   if (list_mode)
     es_fprintf (listfp, "\tkeyid: %08lX%08lX\n",
                 (ulong) keyid[0], (ulong) keyid[1]);
@@ -2365,8 +2659,7 @@ parse_attribute_subpkts (PKT_user_id * uid)
        {
          if (buflen < 4)
            goto too_short;
        {
          if (buflen < 4)
            goto too_short;
-         n = (buffer[0] << 24) | (buffer[1] << 16)
-           | (buffer[2] << 8) | buffer[3];
+         n = buf32_to_size_t (buffer);
          buffer += 4;
          buflen -= 4;
        }
          buffer += 4;
          buflen -= 4;
        }
@@ -2470,7 +2763,7 @@ parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
 void
 make_attribute_uidname (PKT_user_id * uid, size_t max_namelen)
 {
 void
 make_attribute_uidname (PKT_user_id * uid, size_t max_namelen)
 {
-  assert (max_namelen > 70);
+  log_assert (max_namelen > 70);
   if (uid->numattribs <= 0)
     sprintf (uid->name, "[bad attribute packet of size %lu]",
             uid->attrib_len);
   if (uid->numattribs <= 0)
     sprintf (uid->name, "[bad attribute packet of size %lu]",
             uid->attrib_len);
@@ -2589,42 +2882,164 @@ parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
 }
 
 
 }
 
 
-static void
-parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt)
+/* Parse a ring trust packet RFC4880 (5.10).
+ *
+ * This parser is special in that the packet is not stored as a packet
+ * but its content is merged into the previous packet.  */
+static gpg_error_t
+parse_ring_trust (parse_packet_ctx_t ctx, unsigned long pktlen)
 {
 {
+  gpg_error_t err;
+  iobuf_t inp = ctx->inp;
+  PKT_ring_trust rt = {0};
   int c;
   int c;
+  int not_gpg = 0;
 
 
-  (void) pkttype;
+  if (!pktlen)
+    {
+      if (list_mode)
+       es_fprintf (listfp, ":trust packet: empty\n");
+      err = 0;
+      goto leave;
+    }
 
 
-  pkt->pkt.ring_trust = xmalloc (sizeof *pkt->pkt.ring_trust);
+  c = iobuf_get_noeof (inp);
+  pktlen--;
+  rt.trustval = c;
   if (pktlen)
     {
   if (pktlen)
     {
-      c = iobuf_get_noeof (inp);
+      if (!c)
+        {
+          c = iobuf_get_noeof (inp);
+          /* We require that bit 7 of the sigcache is 0 (easier
+           * eof handling).  */
+          if (!(c & 0x80))
+            rt.sigcache = c;
+        }
+      else
+        iobuf_get_noeof (inp);  /* Dummy read.  */
+      pktlen--;
+    }
+
+  /* Next is the optional subtype.  */
+  if (pktlen > 3)
+    {
+      char tmp[4];
+      tmp[0] = iobuf_get_noeof (inp);
+      tmp[1] = iobuf_get_noeof (inp);
+      tmp[2] = iobuf_get_noeof (inp);
+      tmp[3] = iobuf_get_noeof (inp);
+      pktlen -= 4;
+      if (!memcmp (tmp, "gpg", 3))
+        rt.subtype = tmp[3];
+      else
+        not_gpg = 1;
+    }
+  /* If it is a key or uid subtype read the remaining data.  */
+  if ((rt.subtype == RING_TRUST_KEY || rt.subtype == RING_TRUST_UID)
+      && pktlen >= 6 )
+    {
+      int i;
+      unsigned int namelen;
+
+      rt.keysrc = iobuf_get_noeof (inp);
       pktlen--;
       pktlen--;
-      pkt->pkt.ring_trust->trustval = c;
-      pkt->pkt.ring_trust->sigcache = 0;
-      if (!c && pktlen == 1)
-       {
-         c = 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)
-       es_fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n",
-                    pkt->pkt.ring_trust->trustval,
-                    pkt->pkt.ring_trust->sigcache);
+      rt.keyupdate = read_32 (inp);
+      pktlen -= 4;
+      namelen = iobuf_get_noeof (inp);
+      pktlen--;
+      if (namelen && pktlen)
+        {
+          rt.url = xtrymalloc (namelen + 1);
+          if (!rt.url)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          for (i = 0; pktlen && i < namelen; pktlen--, i++)
+            rt.url[i] = iobuf_get_noeof (inp);
+          rt.url[i] = 0;
+        }
     }
     }
-  else
+
+  if (list_mode)
     {
     {
-      pkt->pkt.ring_trust->trustval = 0;
-      pkt->pkt.ring_trust->sigcache = 0;
-      if (list_mode)
-       es_fprintf (listfp, ":trust packet: empty\n");
+      if (rt.subtype == RING_TRUST_SIG)
+        es_fprintf (listfp, ":trust packet: sig flag=%02x sigcache=%02x\n",
+                    rt.trustval, rt.sigcache);
+      else if (rt.subtype == RING_TRUST_UID || rt.subtype == RING_TRUST_KEY)
+        {
+          unsigned char *p;
+
+          es_fprintf (listfp, ":trust packet: %s upd=%lu src=%d%s",
+                      (rt.subtype == RING_TRUST_UID? "uid" : "key"),
+                      (unsigned long)rt.keyupdate,
+                      rt.keysrc,
+                      (rt.url? " url=":""));
+          if (rt.url)
+            {
+              for (p = rt.url; *p; p++)
+                {
+                  if (*p >= ' ' && *p <= 'z')
+                    es_putc (*p, listfp);
+                  else
+                    es_fprintf (listfp, "\\x%02x", *p);
+                }
+            }
+          es_putc ('\n', listfp);
+        }
+      else if (not_gpg)
+        es_fprintf (listfp, ":trust packet: not created by gpg\n");
+      else
+        es_fprintf (listfp, ":trust packet: subtype=%02x\n",
+                    rt.subtype);
     }
     }
+
+  /* Now transfer the data to the respective packet.  Do not do this
+   * if SKIP_META is set.  */
+  if (!ctx->last_pkt.pkt.generic || ctx->skip_meta)
+    ;
+  else if (rt.subtype == RING_TRUST_SIG
+           && ctx->last_pkt.pkttype == PKT_SIGNATURE)
+    {
+      PKT_signature *sig = ctx->last_pkt.pkt.signature;
+
+      if ((rt.sigcache & 1))
+        {
+          sig->flags.checked = 1;
+          sig->flags.valid = !!(rt.sigcache & 2);
+        }
+    }
+  else if (rt.subtype == RING_TRUST_UID
+           && (ctx->last_pkt.pkttype == PKT_USER_ID
+               || ctx->last_pkt.pkttype == PKT_ATTRIBUTE))
+    {
+      PKT_user_id *uid = ctx->last_pkt.pkt.user_id;
+
+      uid->keysrc = rt.keysrc;
+      uid->keyupdate = rt.keyupdate;
+      uid->updateurl = rt.url;
+      rt.url = NULL;
+    }
+  else if (rt.subtype == RING_TRUST_KEY
+           && (ctx->last_pkt.pkttype == PKT_PUBLIC_KEY
+               || ctx->last_pkt.pkttype == PKT_SECRET_KEY))
+    {
+      PKT_public_key *pk = ctx->last_pkt.pkt.public_key;
+
+      pk->keysrc = rt.keysrc;
+      pk->keyupdate = rt.keyupdate;
+      pk->updateurl = rt.url;
+      rt.url = NULL;
+    }
+
+  err = 0;
+
+ leave:
+  xfree (rt.url);
+  free_packet (NULL, ctx); /* This sets ctx->last_pkt to NULL.  */
   iobuf_skip_rest (inp, pktlen, 0);
   iobuf_skip_rest (inp, pktlen, 0);
+  return err;
 }
 
 
 }
 
 
@@ -2677,7 +3092,6 @@ parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
     pktlen -= 4;
   pt->len = pktlen;
   pt->buf = inp;
     pktlen -= 4;
   pt->len = pktlen;
   pt->buf = inp;
-  pktlen = 0;
 
   if (list_mode)
     {
 
   if (list_mode)
     {
@@ -2833,9 +3247,9 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
 
 
 /*
 
 
 /*
- * This packet is internally generated by us (ibn armor.c) to transfer
+ * This packet is internally generated by us (in armor.c) to transfer
  * some information to the lower layer.  To make sure that this packet
  * 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
+ * is really a GPG faked one and not one coming from outside, we
  * first check that there is a unique tag in it.
  *
  * The format of such a control packet is:
  * first check that there is a unique tag in it.
  *
  * The format of such a control packet is:
@@ -2869,7 +3283,7 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
     goto skipit;  /* Definitely too large.  We skip it to avoid an
                      overflow in the malloc.  */
   if (list_mode)
     goto skipit;  /* Definitely too large.  We skip it to avoid an
                      overflow in the malloc.  */
   if (list_mode)
-    puts ("- gpg control packet");
+    es_fputs ("- gpg control packet", listfp);
 
   packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
                                     + pktlen - 1);
 
   packet->pkt.gpg_control = xmalloc (sizeof *packet->pkt.gpg_control
                                     + pktlen - 1);