Reworked the ECC changes to better fit into the Libgcrypt API.
[gnupg.git] / g10 / parse-packet.c
index 0b05cfb..83be15d 100644 (file)
@@ -1,6 +1,6 @@
 /* parse-packet.c  - read packets
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007, 2009 Free Software Foundation, Inc.
+ *               2007, 2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -25,9 +25,9 @@
 #include <assert.h>
 
 #include "gpg.h"
+#include "util.h"
 #include "packet.h"
 #include "iobuf.h"
-#include "util.h"
 #include "cipher.h"
 #include "filter.h"
 #include "photoid.h"
@@ -37,7 +37,7 @@
 
 static int mpi_print_mode;
 static int list_mode;
-static FILE *listfp;
+static estream_t listfp;
 
 static int parse (IOBUF inp, PACKET * pkt, int onlykeypkts,
                  off_t * retpos, int *skip, IOBUF out, int do_skip
@@ -169,7 +169,7 @@ set_packet_list_mode (int mode)
   list_mode = mode;
   /* FIXME(gcrypt) mpi_print_mode = DBG_MPI; */
   /* We use stdout print only if invoked by the --list-packets command
-     but switch to stderr in all otehr cases.  This breaks the
+     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
@@ -180,11 +180,11 @@ set_packet_list_mode (int mode)
      stream.
 
      Using stderr is not actually very clean because it bypasses the
-     logging code but it is a special thing anyay.  I am not sure
+     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. */
   if (!listfp)
-    listfp = opt.list_packets == 2 ? stdout : stderr;
+    listfp = opt.list_packets == 2 ? es_stdout : es_stderr;
   return old;
 }
 
@@ -565,12 +565,9 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
     {
     case PKT_PUBLIC_KEY:
     case PKT_PUBLIC_SUBKEY:
-      pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key);
-      rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt);
-      break;
     case PKT_SECRET_KEY:
     case PKT_SECRET_SUBKEY:
-      pkt->pkt.secret_key = xmalloc_clear (sizeof *pkt->pkt.secret_key);
+      pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key);
       rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt);
       break;
     case PKT_SYMKEY_ENC:
@@ -627,6 +624,7 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
     }
 
  leave:
+  /* FIXME: Do we leak in case of an error?  */
   if (!rc && iobuf_error (inp))
     rc = G10ERR_INV_KEYRING;
   return rc;
@@ -639,14 +637,14 @@ dump_hex_line (int c, int *i)
   if (*i && !(*i % 8))
     {
       if (*i && !(*i % 24))
-       fprintf (listfp, "\n%4d:", *i);
+       es_fprintf (listfp, "\n%4d:", *i);
       else
-       putc (' ', listfp);
+       es_putc (' ', listfp);
     }
   if (c == -1)
-    fprintf (listfp, " EOF");
+    es_fprintf (listfp, " EOF");
   else
-    fprintf (listfp, " %02x", c);
+    es_fprintf (listfp, " %02x", c);
   ++*i;
 }
 
@@ -694,12 +692,12 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
 {
   if (list_mode)
     {
-      fprintf (listfp, ":unknown packet: type %2d, length %lu\n",
-              pkttype, pktlen);
+      es_fprintf (listfp, ":unknown packet: type %2d, length %lu\n",
+                  pkttype, pktlen);
       if (pkttype)
        {
          int c, i = 0;
-         fputs ("dump:", listfp);
+         es_fputs ("dump:", listfp);
          if (partial)
            {
              while ((c = iobuf_get (inp)) != -1)
@@ -714,7 +712,7 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
                    break;
                }
            }
-         putc ('\n', listfp);
+         es_putc ('\n', listfp);
          return;
        }
     }
@@ -743,6 +741,61 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
 }
 
 
+/* Read a special size+body from INP.  On success store an opaque MPI
+   with it at R_DATA.  On error return an error code and store NULL at
+   R_DATA.  Even in the error case store the number of read bytes at
+   R_NREAD.  The caller shall pass the remaining size of the packet in
+   PKTLEN.  */
+static gpg_error_t
+read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
+                gcry_mpi_t *r_data)
+{
+  char buffer[256];
+  char *tmpbuf;
+  int i, c, nbytes;
+
+  *r_nread = 0;
+  *r_data = NULL;
+
+  if (!pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  c = iobuf_readbyte (inp);
+  if (c < 0)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  pktlen--;
+  ++*r_nread;
+  nbytes = c;
+  if (nbytes < 2 || nbytes > 254)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  if (nbytes > pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
+
+  buffer[0] = nbytes;
+
+  for (i = 0; i < nbytes; i++)
+    {
+      c = iobuf_get (inp);
+      if (c < 0)
+        return gpg_error (GPG_ERR_INV_PACKET);
+      ++*r_nread;
+      buffer[1+i] = c;
+    }
+
+  tmpbuf = xtrymalloc (1 + nbytes);
+  if (!tmpbuf)
+    return gpg_error_from_syserror ();
+  memcpy (tmpbuf, buffer, 1 + nbytes);
+  *r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
+  if (!*r_data)
+    {
+      xfree (tmpbuf);
+      return gpg_error_from_syserror ();
+    }
+  return 0;
+}
+
+
+/* Parse a marker packet.  */
 static int
 parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
 {
@@ -770,7 +823,7 @@ parse_marker (IOBUF inp, int pkttype, unsigned long pktlen)
     }
 
   if (list_mode)
-    fputs (":marker packet: PGP\n", listfp);
+    es_fputs (":marker packet: PGP\n", listfp);
 
   return 0;
 
@@ -870,22 +923,21 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
 
   if (list_mode)
     {
-      fprintf (listfp,
-              ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
-              version, cipher_algo, s2kmode, hash_algo);
+      es_fprintf (listfp,
+                  ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
+                  version, cipher_algo, s2kmode, hash_algo);
       if (seskeylen)
-       fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
-      fprintf (listfp, "\n");
+       es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
+      es_fprintf (listfp, "\n");
       if (s2kmode == 1 || s2kmode == 3)
        {
-         fprintf (listfp, "\tsalt ");
-         for (i = 0; i < 8; i++)
-           fprintf (listfp, "%02x", k->s2k.salt[i]);
+         es_fprintf (listfp, "\tsalt ");
+          es_write_hexstring (listfp, k->s2k.salt, 8, 0, NULL);
          if (s2kmode == 3)
-           fprintf (listfp, ", count %lu (%lu)",
-                    S2K_DECODE_COUNT ((ulong) k->s2k.count),
-                    (ulong) k->s2k.count);
-         fprintf (listfp, "\n");
+           es_fprintf (listfp, ", count %lu (%lu)",
+                        S2K_DECODE_COUNT ((ulong) k->s2k.count),
+                        (ulong) k->s2k.count);
+         es_fprintf (listfp, "\n");
        }
     }
 
@@ -927,35 +979,45 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
   pktlen--;
   k->throw_keyid = 0;  /* Only used as flag for build_packet.  */
   if (list_mode)
-    fprintf (listfp,
-            ":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
-            k->version, k->pubkey_algo, (ulong) k->keyid[0],
-            (ulong) k->keyid[1]);
+    es_fprintf (listfp,
+                ":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
+                k->version, k->pubkey_algo, (ulong) k->keyid[0],
+                (ulong) k->keyid[1]);
 
   ndata = pubkey_get_nenc (k->pubkey_algo);
   if (!ndata)
     {
       if (list_mode)
-       fprintf (listfp, "\tunsupported algorithm %d\n", k->pubkey_algo);
+       es_fprintf (listfp, "\tunsupported algorithm %d\n", k->pubkey_algo);
       unknown_pubkey_warning (k->pubkey_algo);
       k->data[0] = NULL; /* No need to store the encrypted data.  */
     }
   else
     {
       for (i = 0; i < ndata; i++)
-       {
-         n = pktlen;
-         k->data[i] = mpi_read (inp, &n, 0);
-         pktlen -= n;
-         if (list_mode)
-           {
-             fprintf (listfp, "\tdata: ");
-             mpi_print (listfp, k->data[i], mpi_print_mode);
-             putc ('\n', listfp);
-           }
-         if (!k->data[i])
-           rc = gpg_error (GPG_ERR_INV_PACKET);
-       }
+        {
+          if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
+            {
+              rc = read_size_body (inp, pktlen, &n, k->data+i);
+              pktlen -= n;
+            }
+          else
+            {
+              n = pktlen;
+              k->data[i] = mpi_read (inp, &n, 0);
+              pktlen -= n;
+              if (!k->data[i])
+                rc = gpg_error (GPG_ERR_INV_PACKET);
+            }
+          if (rc)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tdata: ");
+              mpi_print (listfp, k->data[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
+        }
     }
 
  leave:
@@ -976,98 +1038,98 @@ dump_sig_subpkt (int hashed, int type, int critical,
    * and add an additional notice.  */
   if (type == SIGSUBPKT_ARR && !hashed)
     {
-      fprintf (listfp,
-              "\tsubpkt %d len %u (additional recipient request)\n"
-              "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
-              "encrypt to this key and thereby reveal the plaintext to "
-              "the owner of this ARR key. Detailed info follows:\n",
-              type, (unsigned) length);
+      es_fprintf (listfp,
+                  "\tsubpkt %d len %u (additional recipient request)\n"
+                  "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
+                  "encrypt to this key and thereby reveal the plaintext to "
+                  "the owner of this ARR key. Detailed info follows:\n",
+                  type, (unsigned) length);
     }
 
   buffer++;
   length--;
 
-  fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
-          critical ? "critical " : "",
-          hashed ? "hashed " : "", type, (unsigned) length);
+  es_fprintf (listfp, "\t%s%ssubpkt %d len %u (",      /*) */
+              critical ? "critical " : "",
+              hashed ? "hashed " : "", type, (unsigned) length);
   if (length > buflen)
     {
-      fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
+      es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
       return;
     }
   switch (type)
     {
     case SIGSUBPKT_SIG_CREATED:
       if (length >= 4)
-       fprintf (listfp, "sig created %s",
-                strtimestamp (buffer_to_u32 (buffer)));
+       es_fprintf (listfp, "sig created %s",
+                    strtimestamp (buffer_to_u32 (buffer)));
       break;
     case SIGSUBPKT_SIG_EXPIRE:
       if (length >= 4)
        {
          if (buffer_to_u32 (buffer))
-           fprintf (listfp, "sig expires after %s",
-                    strtimevalue (buffer_to_u32 (buffer)));
+           es_fprintf (listfp, "sig expires after %s",
+                        strtimevalue (buffer_to_u32 (buffer)));
          else
-           fprintf (listfp, "sig does not expire");
+           es_fprintf (listfp, "sig does not expire");
        }
       break;
     case SIGSUBPKT_EXPORTABLE:
       if (length)
-       fprintf (listfp, "%sexportable", *buffer ? "" : "not ");
+       es_fprintf (listfp, "%sexportable", *buffer ? "" : "not ");
       break;
     case SIGSUBPKT_TRUST:
       if (length != 2)
        p = "[invalid trust subpacket]";
       else
-       fprintf (listfp, "trust signature of depth %d, value %d", buffer[0],
-                buffer[1]);
+       es_fprintf (listfp, "trust signature of depth %d, value %d", buffer[0],
+                    buffer[1]);
       break;
     case SIGSUBPKT_REGEXP:
       if (!length)
        p = "[invalid regexp subpacket]";
       else
-       fprintf (listfp, "regular expression: \"%s\"", buffer);
+       es_fprintf (listfp, "regular expression: \"%s\"", buffer);
       break;
     case SIGSUBPKT_REVOCABLE:
       if (length)
-       fprintf (listfp, "%srevocable", *buffer ? "" : "not ");
+       es_fprintf (listfp, "%srevocable", *buffer ? "" : "not ");
       break;
     case SIGSUBPKT_KEY_EXPIRE:
       if (length >= 4)
        {
          if (buffer_to_u32 (buffer))
-           fprintf (listfp, "key expires after %s",
-                    strtimevalue (buffer_to_u32 (buffer)));
+           es_fprintf (listfp, "key expires after %s",
+                        strtimevalue (buffer_to_u32 (buffer)));
          else
-           fprintf (listfp, "key does not expire");
+           es_fprintf (listfp, "key does not expire");
        }
       break;
     case SIGSUBPKT_PREF_SYM:
-      fputs ("pref-sym-algos:", listfp);
+      es_fputs ("pref-sym-algos:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %d", buffer[i]);
+       es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_REV_KEY:
-      fputs ("revocation key: ", listfp);
+      es_fputs ("revocation key: ", listfp);
       if (length < 22)
        p = "[too short]";
       else
        {
-         fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
+         es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
          for (i = 2; i < length; i++)
-           fprintf (listfp, "%02X", buffer[i]);
+           es_fprintf (listfp, "%02X", buffer[i]);
        }
       break;
     case SIGSUBPKT_ISSUER:
       if (length >= 8)
-       fprintf (listfp, "issuer key ID %08lX%08lX",
-                (ulong) buffer_to_u32 (buffer),
-                (ulong) buffer_to_u32 (buffer + 4));
+       es_fprintf (listfp, "issuer key ID %08lX%08lX",
+                    (ulong) buffer_to_u32 (buffer),
+                    (ulong) buffer_to_u32 (buffer + 4));
       break;
     case SIGSUBPKT_NOTATION:
       {
-       fputs ("notation: ", listfp);
+       es_fputs ("notation: ", listfp);
        if (length < 8)
          p = "[too short]";
        else
@@ -1082,11 +1144,11 @@ dump_sig_subpkt (int hashed, int type, int critical,
              p = "[error]";
            else
              {
-               print_string (listfp, s, n1, ')');
-               putc ('=', listfp);
+               es_write_sanitized (listfp, s, n1, ")", NULL);
+               es_putc ('=', listfp);
 
                if (*buffer & 0x80)
-                 print_string (listfp, s + n1, n2, ')');
+                 es_write_sanitized (listfp, s + n1, n2, ")", NULL);
                else
                  p = "[not human readable]";
              }
@@ -1094,35 +1156,35 @@ dump_sig_subpkt (int hashed, int type, int critical,
       }
       break;
     case SIGSUBPKT_PREF_HASH:
-      fputs ("pref-hash-algos:", listfp);
+      es_fputs ("pref-hash-algos:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %d", buffer[i]);
+       es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_PREF_COMPR:
-      fputs ("pref-zip-algos:", listfp);
+      es_fputs ("pref-zip-algos:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %d", buffer[i]);
+       es_fprintf (listfp, " %d", buffer[i]);
       break;
     case SIGSUBPKT_KS_FLAGS:
-      fputs ("key server preferences:", listfp);
+      es_fputs ("key server preferences:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %02X", buffer[i]);
+       es_fprintf (listfp, " %02X", buffer[i]);
       break;
     case SIGSUBPKT_PREF_KS:
-      fputs ("preferred key server: ", listfp);
-      print_string (listfp, buffer, length, ')');
+      es_fputs ("preferred key server: ", listfp);
+      es_write_sanitized (listfp, buffer, length, ")", NULL);
       break;
     case SIGSUBPKT_PRIMARY_UID:
       p = "primary user ID";
       break;
     case SIGSUBPKT_POLICY:
-      fputs ("policy: ", listfp);
-      print_string (listfp, buffer, length, ')');
+      es_fputs ("policy: ", listfp);
+      es_write_sanitized (listfp, buffer, length, ")", NULL);
       break;
     case SIGSUBPKT_KEY_FLAGS:
-      fputs ("key flags:", listfp);
+      es_fputs ("key flags:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %02X", buffer[i]);
+       es_fprintf (listfp, " %02X", buffer[i]);
       break;
     case SIGSUBPKT_SIGNERS_UID:
       p = "signer's user ID";
@@ -1130,37 +1192,37 @@ dump_sig_subpkt (int hashed, int type, int critical,
     case SIGSUBPKT_REVOC_REASON:
       if (length)
        {
-         fprintf (listfp, "revocation reason 0x%02x (", *buffer);
-         print_string (listfp, buffer + 1, length - 1, ')');
+         es_fprintf (listfp, "revocation reason 0x%02x (", *buffer);
+         es_write_sanitized (listfp, buffer + 1, length - 1, ")", NULL);
          p = ")";
        }
       break;
     case SIGSUBPKT_ARR:
-      fputs ("Big Brother's key (ignored): ", listfp);
+      es_fputs ("Big Brother's key (ignored): ", listfp);
       if (length < 22)
        p = "[too short]";
       else
        {
-         fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
-         for (i = 2; i < length; i++)
-           fprintf (listfp, "%02X", buffer[i]);
+         es_fprintf (listfp, "c=%02x a=%d f=", buffer[0], buffer[1]);
+          if (length > 2)
+            es_write_hexstring (listfp, buffer+2, length-2, 0, NULL);
        }
       break;
     case SIGSUBPKT_FEATURES:
-      fputs ("features:", listfp);
+      es_fputs ("features:", listfp);
       for (i = 0; i < length; i++)
-       fprintf (listfp, " %02x", buffer[i]);
+       es_fprintf (listfp, " %02x", buffer[i]);
       break;
     case SIGSUBPKT_SIGNATURE:
-      fputs ("signature: ", listfp);
+      es_fputs ("signature: ", listfp);
       if (length < 17)
        p = "[too short]";
       else
-       fprintf (listfp, "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]);
+       es_fprintf (listfp, "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)
@@ -1170,7 +1232,7 @@ dump_sig_subpkt (int hashed, int type, int critical,
       break;
     }
 
-  fprintf (listfp, "%s)\n", p ? p : "");
+  es_fprintf (listfp, "%s)\n", p ? p : "");
 }
 
 
@@ -1654,13 +1716,13 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
 
   if (list_mode)
     {
-      fprintf (listfp, ":signature packet: algo %d, keyid %08lX%08lX\n"
-              "\tversion %d, created %lu, md5len %d, sigclass 0x%02x\n"
-              "\tdigest algo %d, begin of digest %02x %02x\n",
-              sig->pubkey_algo,
-              (ulong) sig->keyid[0], (ulong) sig->keyid[1],
-              sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class,
-              sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
+      es_fprintf (listfp, ":signature packet: algo %d, keyid %08lX%08lX\n"
+                  "\tversion %d, created %lu, md5len %d, sigclass 0x%02x\n"
+                  "\tdigest algo %d, begin of digest %02x %02x\n",
+                  sig->pubkey_algo,
+                  (ulong) sig->keyid[0], (ulong) sig->keyid[1],
+                  sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class,
+                  sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
       if (is_v4)
        {
          parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
@@ -1672,7 +1734,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
   if (!ndata)
     {
       if (list_mode)
-       fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo);
+       es_fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo);
       unknown_pubkey_warning (sig->pubkey_algo);
 
       /* We store the plain material in data[0], so that we are able
@@ -1701,9 +1763,9 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
          pktlen -= n;
          if (list_mode)
            {
-             fprintf (listfp, "\tdata: ");
+             es_fprintf (listfp, "\tdata: ");
              mpi_print (listfp, sig->data[i], mpi_print_mode);
-             putc ('\n', listfp);
+             es_putc ('\n', listfp);
            }
          if (!sig->data[i])
            rc = G10ERR_INVALID_PACKET;
@@ -1750,13 +1812,13 @@ parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen,
   ops->last = iobuf_get_noeof (inp);
   pktlen--;
   if (list_mode)
-    fprintf (listfp,
-            ":onepass_sig packet: keyid %08lX%08lX\n"
-            "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, "
-            "last=%d\n",
-            (ulong) ops->keyid[0], (ulong) ops->keyid[1],
-            version, ops->sig_class,
-            ops->digest_algo, ops->pubkey_algo, ops->last);
+    es_fprintf (listfp,
+                ":onepass_sig packet: keyid %08lX%08lX\n"
+                "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, "
+                "last=%d\n",
+                (ulong) ops->keyid[0], (ulong) ops->keyid[1],
+                version, ops->sig_class,
+                ops->digest_algo, ops->pubkey_algo, ops->last);
 
 
  leave:
@@ -1816,6 +1878,7 @@ static int
 parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           byte * hdr, int hdrlen, PACKET * pkt)
 {
+  gpg_error_t err = 0;
   int i, version, algorithm;
   unsigned n;
   unsigned long timestamp, expiredate, max_expiredate;
@@ -1823,9 +1886,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
   int is_v4 = 0;
   int rc = 0;
   u32 keyid[2];
+  PKT_public_key *pk;
 
   (void) hdr;
 
+  pk = pkt->pkt.public_key; /* PK has been cleared. */
+
   version = iobuf_get_noeof (inp);
   pktlen--;
   if (pkttype == PKT_PUBLIC_SUBKEY && version == '#')
@@ -1834,17 +1900,17 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
        * luckily all those comments are started by a hash.  */
       if (list_mode)
        {
-         fprintf (listfp, ":rfc1991 comment packet: \"");
+         es_fprintf (listfp, ":rfc1991 comment packet: \"");
          for (; pktlen; pktlen--)
            {
              int c;
              c = iobuf_get_noeof (inp);
              if (c >= ' ' && c <= 'z')
-               putc (c, listfp);
+               es_putc (c, listfp);
              else
-               fprintf (listfp, "\\x%02x", c);
+               es_fprintf (listfp, "\\x%02x", c);
            }
-         fprintf (listfp, "\"\n");
+         es_fprintf (listfp, "\"\n");
        }
       iobuf_skip_rest (inp, pktlen, 0);
       return 0;
@@ -1854,14 +1920,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
   else if (version != 2 && version != 3)
     {
       log_error ("packet(%d) with unknown version %d\n", pkttype, version);
-      rc = gpg_error (GPG_ERR_INV_PACKET);
+      err = gpg_error (GPG_ERR_INV_PACKET);
       goto leave;
     }
 
   if (pktlen < 11)
     {
       log_error ("packet(%d) too short\n", pkttype);
-      rc = gpg_error (GPG_ERR_INV_PACKET);
+      err = gpg_error (GPG_ERR_INV_PACKET);
       goto leave;
     }
 
@@ -1887,364 +1953,326 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
   algorithm = iobuf_get_noeof (inp);
   pktlen--;
   if (list_mode)
-    fprintf (listfp, ":%s key packet:\n"
-            "\tversion %d, algo %d, created %lu, expires %lu\n",
-            pkttype == PKT_PUBLIC_KEY ? "public" :
-            pkttype == PKT_SECRET_KEY ? "secret" :
-            pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
-            pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
-            version, algorithm, timestamp, expiredate);
-
-  if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY)
-    {
-      PKT_secret_key *sk = pkt->pkt.secret_key;
+    es_fprintf (listfp, ":%s key packet:\n"
+                "\tversion %d, algo %d, created %lu, expires %lu\n",
+                pkttype == PKT_PUBLIC_KEY ? "public" :
+                pkttype == PKT_SECRET_KEY ? "secret" :
+                pkttype == PKT_PUBLIC_SUBKEY ? "public sub" :
+                pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??",
+                version, algorithm, timestamp, expiredate);
+
+  pk->timestamp = timestamp;
+  pk->expiredate = expiredate;
+  pk->max_expiredate = max_expiredate;
+  pk->hdrbytes = hdrlen;
+  pk->version = version;
+  pk->flags.primary = (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY);
+  pk->pubkey_algo = algorithm;
 
-      sk->timestamp = timestamp;
-      sk->expiredate = expiredate;
-      sk->max_expiredate = max_expiredate;
-      sk->hdrbytes = hdrlen;
-      sk->version = version;
-      sk->is_primary = pkttype == PKT_SECRET_KEY;
-      sk->pubkey_algo = algorithm;
-      sk->req_usage = 0;
-      sk->pubkey_usage = 0;    /* not yet used */
-    }
-  else
-    {
-      PKT_public_key *pk = pkt->pkt.public_key;
-
-      pk->timestamp = timestamp;
-      pk->expiredate = expiredate;
-      pk->max_expiredate = max_expiredate;
-      pk->hdrbytes = hdrlen;
-      pk->version = version;
-      pk->is_primary = pkttype == PKT_PUBLIC_KEY;
-      pk->pubkey_algo = algorithm;
-      pk->req_usage = 0;
-      pk->pubkey_usage = 0;    /* not yet used */
-      pk->is_revoked = 0;
-      pk->is_disabled = 0;
-      pk->keyid[0] = 0;
-      pk->keyid[1] = 0;
-    }
   nskey = pubkey_get_nskey (algorithm);
   npkey = pubkey_get_npkey (algorithm);
   if (!npkey)
     {
       if (list_mode)
-       fprintf (listfp, "\tunknown algorithm %d\n", algorithm);
+       es_fprintf (listfp, "\tunknown algorithm %d\n", algorithm);
       unknown_pubkey_warning (algorithm);
     }
 
+  if (!npkey)
+    {
+      /* Unknown algorithm - put data into an opaque MPI.  */
+      pk->pkey[0] = gcry_mpi_set_opaque (NULL,
+                                         read_rest (inp, pktlen, 0),
+                                         pktlen * 8);
+      pktlen = 0;
+      goto leave;
+    }
+  else
+    {
+      for (i = 0; i < npkey; i++)
+        {
+          if ((algorithm == PUBKEY_ALGO_ECDSA
+               || algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
+            {
+              err = read_size_body (inp, pktlen, &n, pk->pkey+i);
+              pktlen -= n;
+            }
+          else
+            {
+              n = pktlen;
+              pk->pkey[i] = mpi_read (inp, &n, 0);
+              pktlen -= n;
+              if (!pk->pkey[i])
+                err = gpg_error (GPG_ERR_INV_PACKET);
+            }
+          if (err)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tpkey[%d]: ", i);
+              mpi_print (listfp, pk->pkey[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
+        }
+    }
+  if (list_mode)
+    keyid_from_pk (pk, keyid);
 
   if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY)
     {
-      PKT_secret_key *sk = pkt->pkt.secret_key;
+      struct seckey_info *ski;
       byte temp[16];
       size_t snlen = 0;
 
-      if (!npkey)
-       {
-         sk->skey[0] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen, 0),
-                                            pktlen * 8);
-         pktlen = 0;
-         goto leave;
-       }
+      pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
+      if (!pk->seckey_info)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
 
-      for (i = 0; i < npkey; i++)
-       {
-         n = pktlen;
-         sk->skey[i] = mpi_read (inp, &n, 0);
-         pktlen -= n;
-         if (list_mode)
-           {
-             fprintf (listfp, "\tskey[%d]: ", i);
-             mpi_print (listfp, sk->skey[i], mpi_print_mode);
-             putc ('\n', listfp);
-           }
-         if (!sk->skey[i])
-           rc = G10ERR_INVALID_PACKET;
-       }
-      if (rc)  /* One of the MPIs were bad.  */
-       goto leave;
-      sk->protect.algo = iobuf_get_noeof (inp);
+      ski->algo = iobuf_get_noeof (inp);
       pktlen--;
-      sk->protect.sha1chk = 0;
-      if (sk->protect.algo)
+      if (ski->algo)
        {
-         sk->is_protected = 1;
-         sk->protect.s2k.count = 0;
-         if (sk->protect.algo == 254 || sk->protect.algo == 255)
+         ski->is_protected = 1;
+         ski->s2k.count = 0;
+         if (ski->algo == 254 || ski->algo == 255)
            {
              if (pktlen < 3)
                {
-                 rc = G10ERR_INVALID_PACKET;
+                 err = gpg_error (GPG_ERR_INV_PACKET);
                  goto leave;
                }
-             sk->protect.sha1chk = (sk->protect.algo == 254);
-             sk->protect.algo = iobuf_get_noeof (inp);
+             ski->sha1chk = (ski->algo == 254);
+             ski->algo = iobuf_get_noeof (inp);
              pktlen--;
-             /* Note that a sk->protect.algo > 110 is illegal, but
-                I'm not erroring on it here as otherwise there would
-                be no way to delete such a key.  */
-             sk->protect.s2k.mode = iobuf_get_noeof (inp);
+             /* Note that a ski->algo > 110 is illegal, but I'm not
+                erroring on it here as otherwise there would be no
+                way to delete such a key.  */
+             ski->s2k.mode = iobuf_get_noeof (inp);
              pktlen--;
-             sk->protect.s2k.hash_algo = iobuf_get_noeof (inp);
+             ski->s2k.hash_algo = iobuf_get_noeof (inp);
              pktlen--;
-             /* check for the special GNU extension */
-             if (is_v4 && sk->protect.s2k.mode == 101)
+             /* Check for the special GNU extension.  */
+             if (is_v4 && ski->s2k.mode == 101)
                {
                  for (i = 0; i < 4 && pktlen; i++, pktlen--)
                    temp[i] = iobuf_get_noeof (inp);
                  if (i < 4 || memcmp (temp, "GNU", 3))
                    {
                      if (list_mode)
-                       fprintf (listfp, "\tunknown S2K %d\n",
-                                sk->protect.s2k.mode);
-                     rc = G10ERR_INVALID_PACKET;
+                       es_fprintf (listfp, "\tunknown S2K %d\n",
+                                    ski->s2k.mode);
+                     err = gpg_error (GPG_ERR_INV_PACKET);
                      goto leave;
                    }
                  /* Here we know that it is a GNU extension.  What
                   * follows is the GNU protection mode: All values
                   * have special meanings and they are mapped to MODE
                   * with a base of 1000.  */
-                 sk->protect.s2k.mode = 1000 + temp[3];
+                 ski->s2k.mode = 1000 + temp[3];
                }
-             switch (sk->protect.s2k.mode)
+
+              /* Read the salt.  */
+             switch (ski->s2k.mode)
                {
                case 1:
                case 3:
                  for (i = 0; i < 8 && pktlen; i++, pktlen--)
                    temp[i] = iobuf_get_noeof (inp);
-                 memcpy (sk->protect.s2k.salt, temp, 8);
+                 memcpy (ski->s2k.salt, temp, 8);
                  break;
                }
-             switch (sk->protect.s2k.mode)
+
+              /* Check the mode.  */
+             switch (ski->s2k.mode)
                {
                case 0:
                  if (list_mode)
-                   fprintf (listfp, "\tsimple S2K");
+                   es_fprintf (listfp, "\tsimple S2K");
                  break;
                case 1:
                  if (list_mode)
-                   fprintf (listfp, "\tsalted S2K");
+                   es_fprintf (listfp, "\tsalted S2K");
                  break;
                case 3:
                  if (list_mode)
-                   fprintf (listfp, "\titer+salt S2K");
+                   es_fprintf (listfp, "\titer+salt S2K");
                  break;
                case 1001:
                  if (list_mode)
-                   fprintf (listfp, "\tgnu-dummy S2K");
+                   es_fprintf (listfp, "\tgnu-dummy S2K");
                  break;
                case 1002:
                  if (list_mode)
-                   fprintf (listfp, "\tgnu-divert-to-card S2K");
+                   es_fprintf (listfp, "\tgnu-divert-to-card S2K");
                  break;
                default:
                  if (list_mode)
-                   fprintf (listfp, "\tunknown %sS2K %d\n",
-                            sk->protect.s2k.mode < 1000 ? "" : "GNU ",
-                            sk->protect.s2k.mode);
-                 rc = G10ERR_INVALID_PACKET;
+                   es_fprintf (listfp, "\tunknown %sS2K %d\n",
+                                ski->s2k.mode < 1000 ? "" : "GNU ",
+                                ski->s2k.mode);
+                 err = gpg_error (GPG_ERR_INV_PACKET);
                  goto leave;
                }
 
+              /* Print some info.  */
              if (list_mode)
                {
-                 fprintf (listfp, ", algo: %d,%s hash: %d",
-                          sk->protect.algo,
-                          sk->protect.sha1chk ? " SHA1 protection,"
-                          : " simple checksum,", sk->protect.s2k.hash_algo);
-                 if (sk->protect.s2k.mode == 1 || sk->protect.s2k.mode == 3)
+                 es_fprintf (listfp, ", algo: %d,%s hash: %d",
+                              ski->algo,
+                              ski->sha1chk ? " SHA1 protection,"
+                              : " simple checksum,", ski->s2k.hash_algo);
+                 if (ski->s2k.mode == 1 || ski->s2k.mode == 3)
                    {
-                     fprintf (listfp, ", salt: ");
-                     for (i = 0; i < 8; i++)
-                       fprintf (listfp, "%02x", sk->protect.s2k.salt[i]);
+                     es_fprintf (listfp, ", salt: ");
+                      es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL);
                    }
-                 putc ('\n', listfp);
+                 es_putc ('\n', listfp);
                }
 
-             if (sk->protect.s2k.mode == 3)
+              /* Read remaining protection parameters.  */
+             if (ski->s2k.mode == 3)
                {
                  if (pktlen < 1)
                    {
-                     rc = G10ERR_INVALID_PACKET;
+                     err = gpg_error (GPG_ERR_INV_PACKET);
                      goto leave;
                    }
-                 sk->protect.s2k.count = iobuf_get (inp);
+                 ski->s2k.count = iobuf_get (inp);
                  pktlen--;
                  if (list_mode)
-                   fprintf (listfp, "\tprotect count: %lu\n",
-                            (ulong) sk->protect.s2k.count);
+                   es_fprintf (listfp, "\tprotect count: %lu\n",
+                                (ulong) ski->s2k.count);
                }
-             else if (sk->protect.s2k.mode == 1002)
+             else if (ski->s2k.mode == 1002)
                {
                  /* Read the serial number. */
                  if (pktlen < 1)
                    {
-                     rc = G10ERR_INVALID_PACKET;
+                     err = gpg_error (GPG_ERR_INV_PACKET);
                      goto leave;
                    }
                  snlen = iobuf_get (inp);
                  pktlen--;
-                 if (pktlen < snlen || snlen == -1)
+                 if (pktlen < snlen || snlen == (size_t)(-1))
                    {
-                     rc = G10ERR_INVALID_PACKET;
+                     err = gpg_error (GPG_ERR_INV_PACKET);
                      goto leave;
                    }
                }
            }
          else /* Old version; no S2K, so we set mode to 0, hash MD5.  */
            { 
-              /* Note that a sk->protect.algo > 110 is illegal, but
-                 I'm not erroring on it here as otherwise there would
-                 be no way to delete such a key.  */
-             sk->protect.s2k.mode = 0;
-             sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5;
+              /* Note that a ski->algo > 110 is illegal, but I'm not
+                 erroring on it here as otherwise there would be no
+                 way to delete such a key.  */
+             ski->s2k.mode = 0;
+             ski->s2k.hash_algo = DIGEST_ALGO_MD5;
              if (list_mode)
-               fprintf (listfp, "\tprotect algo: %d  (hash algo: %d)\n",
-                        sk->protect.algo, sk->protect.s2k.hash_algo);
+               es_fprintf (listfp, "\tprotect algo: %d  (hash algo: %d)\n",
+                            ski->algo, ski->s2k.hash_algo);
            }
           
          /* It is really ugly that we don't know the size
           * of the IV here in cases we are not aware of the algorithm.
           * so a
-          *   sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo);
+          *   ski->ivlen = cipher_get_blocksize (ski->algo);
           * won't work.  The only solution I see is to hardwire it.
           * NOTE: if you change the ivlen above 16, don't forget to
           * enlarge temp.  */
-         sk->protect.ivlen = openpgp_cipher_blocklen (sk->protect.algo);
-         assert (sk->protect.ivlen <= sizeof (temp));
+         ski->ivlen = openpgp_cipher_blocklen (ski->algo);
+         assert (ski->ivlen <= sizeof (temp));
 
-         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 (ski->s2k.mode == 1001)
+           ski->ivlen = 0;
+         else if (ski->s2k.mode == 1002)
+           ski->ivlen = snlen < 16 ? snlen : 16;
 
-         if (pktlen < sk->protect.ivlen)
+         if (pktlen < ski->ivlen)
            {
-             rc = G10ERR_INVALID_PACKET;
+              err = gpg_error (GPG_ERR_INV_PACKET);
              goto leave;
            }
-         for (i = 0; i < sk->protect.ivlen && pktlen; i++, pktlen--)
+         for (i = 0; i < ski->ivlen && pktlen; i++, pktlen--)
            temp[i] = iobuf_get_noeof (inp);
          if (list_mode)
            {
-             fprintf (listfp,
-                      sk->protect.s2k.mode == 1002 ? "\tserial-number: "
-                      : "\tprotect IV: ");
-             for (i = 0; i < sk->protect.ivlen; i++)
-               fprintf (listfp, " %02x", temp[i]);
-             putc ('\n', listfp);
+             es_fprintf (listfp,
+                          ski->s2k.mode == 1002 ? "\tserial-number: "
+                          : "\tprotect IV: ");
+             for (i = 0; i < ski->ivlen; i++)
+               es_fprintf (listfp, " %02x", temp[i]);
+             es_putc ('\n', listfp);
            }
-         memcpy (sk->protect.iv, temp, sk->protect.ivlen);
+         memcpy (ski->iv, temp, ski->ivlen);
        }
-      else
-       sk->is_protected = 0;
 
       /* It does not make sense to read it into secure memory.
        * If the user is so careless, not to protect his secret key,
        * we can assume, that he operates an open system :=(.
        * So we put the key into secure memory when we unprotect it. */
-      if (sk->protect.s2k.mode == 1001 || sk->protect.s2k.mode == 1002)
+      if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
        {
          /* Better set some dummy stuff here.  */
-         sk->skey[npkey] = gcry_mpi_set_opaque (NULL,
+         pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
                                                 xstrdup ("dummydata"),
                                                 10 * 8);
          pktlen = 0;
        }
-      else if (is_v4 && sk->is_protected)
+      else if (is_v4 && ski->is_protected)
        {
          /* Ugly: The length is encrypted too, so we read all stuff
           * up to the end of the packet into the first SKEY
           * element.  */
-         sk->skey[npkey] = gcry_mpi_set_opaque (NULL,
+         pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
                                                 read_rest (inp, pktlen, 0),
                                                 pktlen * 8);
          pktlen = 0;
          if (list_mode)
-           {
-             fprintf (listfp, "\tencrypted stuff follows\n");
-           }
+            es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey);
        }
-      else /* The v3 method: The mpi length is not encrypted.  */
+      else 
        {       
+          /* The v3 method: The mpi length is not encrypted.  */
          for (i = npkey; i < nskey; i++)
            {
-             if (sk->is_protected)
+             if (ski->is_protected)
                {
-                 sk->skey[i] = read_protected_v3_mpi (inp, &pktlen);
+                 pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen);
                  if (list_mode)
-                   fprintf (listfp, "\tskey[%d]: [encrypted]\n", i);
+                   es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i);
                }
              else
                {
                  n = pktlen;
-                 sk->skey[i] = mpi_read (inp, &n, 0);
+                 pk->pkey[i] = mpi_read (inp, &n, 0);
                  pktlen -= n;
                  if (list_mode)
                    {
-                     fprintf (listfp, "\tskey[%d]: ", i);
-                     mpi_print (listfp, sk->skey[i], mpi_print_mode);
-                     putc ('\n', listfp);
+                     es_fprintf (listfp, "\tskey[%d]: ", i);
+                     mpi_print (listfp, pk->pkey[i], mpi_print_mode);
+                     es_putc ('\n', listfp);
                    }
                }
 
-             if (!sk->skey[i])
-               rc = G10ERR_INVALID_PACKET;
+             if (!pk->pkey[i])
+               err = gpg_error (GPG_ERR_INV_PACKET);
            }
-         if (rc)
+         if (err)
            goto leave;
 
-         sk->csum = read_16 (inp);
+         ski->csum = read_16 (inp);
          pktlen -= 2;
          if (list_mode)
-           {
-             fprintf (listfp, "\tchecksum: %04hx\n", sk->csum);
-           }
-       }
-
-      if (list_mode)
-       keyid_from_sk (sk, keyid);
-    }
-  else
-    {
-      PKT_public_key *pk = pkt->pkt.public_key;
-
-      if (!npkey)
-       {
-         pk->pkey[0] = gcry_mpi_set_opaque (NULL,
-                                            read_rest (inp, pktlen, 0),
-                                            pktlen * 8);
-         pktlen = 0;
-         goto leave;
-       }
-
-      for (i = 0; i < npkey; i++)
-       {
-         n = pktlen;
-         pk->pkey[i] = mpi_read (inp, &n, 0);
-         pktlen -= n;
-         if (list_mode)
-           {
-             fprintf (listfp, "\tpkey[%d]: ", i);
-             mpi_print (listfp, pk->pkey[i], mpi_print_mode);
-             putc ('\n', listfp);
-           }
-         if (!pk->pkey[i])
-           rc = G10ERR_INVALID_PACKET;
+            es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum);
        }
-      if (rc)
-       goto leave;
-      if (list_mode)
-       keyid_from_pk (pk, keyid);
     }
 
   if (list_mode)
-    fprintf (listfp, "\tkeyid: %08lX%08lX\n",
-            (ulong) keyid[0], (ulong) keyid[1]);
+    es_fprintf (listfp, "\tkeyid: %08lX%08lX\n",
+                (ulong) keyid[0], (ulong) keyid[1]);
 
  leave:
   iobuf_skip_rest (inp, pktlen, 0);
@@ -2352,16 +2380,16 @@ parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
   if (list_mode)
     {
       int n = packet->pkt.user_id->len;
-      fprintf (listfp, ":user ID packet: \"");
-      /* fixme: Hey why don't we replace this with print_string?? */
+      es_fprintf (listfp, ":user ID packet: \"");
+      /* fixme: Hey why don't we replace this with es_write_sanitized?? */
       for (p = packet->pkt.user_id->name; n; p++, n--)
        {
          if (*p >= ' ' && *p <= 'z')
-           putc (*p, listfp);
+           es_putc (*p, listfp);
          else
-           fprintf (listfp, "\\x%02x", *p);
+           es_fprintf (listfp, "\\x%02x", *p);
        }
-      fprintf (listfp, "\"\n");
+      es_fprintf (listfp, "\"\n");
     }
   return 0;
 }
@@ -2429,7 +2457,7 @@ parse_attribute (IOBUF inp, int pkttype, unsigned long pktlen,
 
   if (list_mode)
     {
-      fprintf (listfp, ":attribute packet: %s\n", packet->pkt.user_id->name);
+      es_fprintf (listfp, ":attribute packet: %s\n", packet->pkt.user_id->name);
     }
   return 0;
 }
@@ -2459,16 +2487,16 @@ parse_comment (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
   if (list_mode)
     {
       int n = packet->pkt.comment->len;
-      fprintf (listfp, ":%scomment packet: \"", pkttype == PKT_OLD_COMMENT ?
-              "OpenPGP draft " : "");
+      es_fprintf (listfp, ":%scomment packet: \"", pkttype == PKT_OLD_COMMENT ?
+                  "OpenPGP draft " : "");
       for (p = packet->pkt.comment->data; n; p++, n--)
        {
          if (*p >= ' ' && *p <= 'z')
-           putc (*p, listfp);
+           es_putc (*p, listfp);
          else
-           fprintf (listfp, "\\x%02x", *p);
+           es_fprintf (listfp, "\\x%02x", *p);
        }
-      fprintf (listfp, "\"\n");
+      es_fprintf (listfp, "\"\n");
     }
   return 0;
 }
@@ -2498,14 +2526,14 @@ parse_trust (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * pkt)
            pkt->pkt.ring_trust->sigcache = c;
        }
       if (list_mode)
-       fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n",
-                pkt->pkt.ring_trust->trustval,
-                pkt->pkt.ring_trust->sigcache);
+       es_fprintf (listfp, ":trust packet: flag=%02x sigcache=%02x\n",
+                    pkt->pkt.ring_trust->trustval,
+                    pkt->pkt.ring_trust->sigcache);
     }
   else
     {
       if (list_mode)
-       fprintf (listfp, ":trust packet: empty\n");
+       es_fprintf (listfp, ":trust packet: empty\n");
     }
   iobuf_skip_rest (inp, pktlen, 0);
 }
@@ -2562,22 +2590,22 @@ parse_plaintext (IOBUF inp, int pkttype, unsigned long pktlen,
 
   if (list_mode)
     {
-      fprintf (listfp, ":literal data packet:\n"
-              "\tmode %c (%X), created %lu, name=\"",
-              mode >= ' ' && mode < 'z' ? mode : '?', mode,
-              (ulong) pt->timestamp);
+      es_fprintf (listfp, ":literal data packet:\n"
+                  "\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')
-           putc (*p, listfp);
+           es_putc (*p, listfp);
          else
-           fprintf (listfp, "\\x%02x", *p);
+           es_fprintf (listfp, "\\x%02x", *p);
        }
-      fprintf (listfp, "\",\n\traw data: ");
+      es_fprintf (listfp, "\",\n\traw data: ");
       if (partial)
-       fprintf (listfp, "unknown length\n");
+       es_fprintf (listfp, "unknown length\n");
       else
-       fprintf (listfp, "%lu bytes\n", (ulong) pt->len);
+       es_fprintf (listfp, "%lu bytes\n", (ulong) pt->len);
     }
 
  leave:
@@ -2603,7 +2631,7 @@ parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen,
   zd->new_ctb = new_ctb;
   zd->buf = inp;
   if (list_mode)
-    fprintf (listfp, ":compressed packet: algo=%d\n", zd->algorithm);
+    es_fprintf (listfp, ":compressed packet: algo=%d\n", zd->algorithm);
   return 0;
 }
 
@@ -2617,16 +2645,11 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
   unsigned long orig_pktlen = pktlen;
 
   ed = pkt->pkt.encrypted = xmalloc (sizeof *pkt->pkt.encrypted);
-  ed->len = pktlen;
-  /* We don't know the extralen which is (cipher_blocksize+2) because
-     the algorithm ist not specified in this packet.  However, it is
-     only important to know this for some sanity checks on the packet
-     length - it doesn't matter that we can't do it.  */
-  ed->extralen = 0;
+  /* ed->len is set below.  */
+  ed->extralen = 0;  /* Unknown here; only used in build_packet.  */
   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.  */
@@ -2645,6 +2668,12 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
        }
       ed->mdc_method = DIGEST_ALGO_SHA1;
     }
+  else
+    ed->mdc_method = 0;
+
+  /* A basic sanity check.  We need at least an 8 byte IV plus the 2
+     detection bytes.  Note that we don't known the algorithm and thus
+     we may only check against the minimum blocksize.  */
   if (orig_pktlen && pktlen < 10)
     {
       /* Actually this is blocksize+2.  */
@@ -2653,15 +2682,21 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen,
       iobuf_skip_rest (inp, pktlen, partial);
       goto leave;
     }
+
+  /* Store the remaining length of the encrypted data (i.e. without
+     the MDC version number but with the IV etc.).  This value is
+     required during decryption.  */
+  ed->len = pktlen;
+
   if (list_mode)
     {
       if (orig_pktlen)
-       fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n",
-                orig_pktlen);
+       es_fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n",
+                    orig_pktlen);
       else
-       fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n");
+       es_fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n");
       if (ed->mdc_method)
-       fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method);
+       es_fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method);
     }
 
   ed->buf = inp;
@@ -2686,7 +2721,7 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen,
 
   mdc = pkt->pkt.mdc = xmalloc (sizeof *pkt->pkt.mdc);
   if (list_mode)
-    fprintf (listfp, ":mdc packet: length=%lu\n", pktlen);
+    es_fprintf (listfp, ":mdc packet: length=%lu\n", pktlen);
   if (!new_ctb || pktlen != 20)
     {
       log_error ("mdc_packet with invalid encoding\n");
@@ -2725,7 +2760,7 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
   (void) pkttype;
 
   if (list_mode)
-    fprintf (listfp, ":packet 63: length %lu ", pktlen);
+    es_fprintf (listfp, ":packet 63: length %lu ", pktlen);
 
   sesmark = get_session_marker (&sesmarklen);
   if (pktlen < sesmarklen + 1) /* 1 is for the control bytes */
@@ -2758,7 +2793,7 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
       int c;
 
       i = 0;
-      fprintf (listfp, "- private (rest length %lu)\n", pktlen);
+      es_fprintf (listfp, "- private (rest length %lu)\n", pktlen);
       if (partial)
        {
          while ((c = iobuf_get (inp)) != -1)
@@ -2773,7 +2808,7 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
                break;
            }
        }
-      putc ('\n', listfp);
+      es_putc ('\n', listfp);
     }
   iobuf_skip_rest (inp, pktlen, 0);
   return gpg_error (GPG_ERR_INV_PACKET);