po: auto update
[gnupg.git] / g10 / sign.c
index ccf7964..095fa11 100644 (file)
@@ -1,6 +1,6 @@
 /* sign.c - sign data
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007, 2010 Free Software Foundation, Inc.
+ *               2007, 2010, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +15,7 @@
  * 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 <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "status.h"
-#include "iobuf.h"
+#include "../common/status.h"
+#include "../common/iobuf.h"
 #include "keydb.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
 #include "filter.h"
-#include "ttyio.h"
+#include "../common/ttyio.h"
 #include "trustdb.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
 #include "pkglue.h"
-#include "sysutils.h"
+#include "../common/sysutils.h"
 #include "call-agent.h"
-
+#include "../common/mbox-util.h"
+#include "../common/compliance.h"
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
@@ -60,125 +60,156 @@ static void
 mk_notation_policy_etc (PKT_signature *sig,
                        PKT_public_key *pk, PKT_public_key *pksk)
 {
-    const char *string;
-    char *s=NULL;
-    strlist_t pu=NULL;
-    struct notation *nd=NULL;
-    struct expando_args args;
+  const char *string;
+  char *p = NULL;
+  strlist_t pu = NULL;
+  struct notation *nd = NULL;
+  struct expando_args args;
 
-    assert(sig->version>=4);
+  log_assert (sig->version >= 4);
 
-    memset(&args,0,sizeof(args));
-    args.pk=pk;
-    args.pksk=pksk;
+  memset (&args, 0, sizeof(args));
+  args.pk = pk;
+  args.pksk = pksk;
 
-    /* notation data */
-    if(IS_SIG(sig) && opt.sig_notations)
-      nd=opt.sig_notations;
-    else if( IS_CERT(sig) && opt.cert_notations )
-      nd=opt.cert_notations;
+  /* Notation data. */
+  if (IS_SIG(sig) && opt.sig_notations)
+    nd = opt.sig_notations;
+  else if (IS_CERT(sig) && opt.cert_notations)
+    nd = opt.cert_notations;
 
-    if(nd)
-      {
-       struct notation *i;
+  if (nd)
+    {
+      struct notation *item;
 
-       for(i=nd;i;i=i->next)
-         {
-           i->altvalue=pct_expando(i->value,&args);
-           if(!i->altvalue)
-             log_error(_("WARNING: unable to %%-expand notation "
-                         "(too large).  Using unexpanded.\n"));
-         }
+      for (item = nd; item; item = item->next)
+        {
+          item->altvalue = pct_expando (item->value,&args);
+          if (!item->altvalue)
+            log_error (_("WARNING: unable to %%-expand notation "
+                         "(too large).  Using unexpanded.\n"));
+        }
 
-       keygen_add_notations(sig,nd);
+      keygen_add_notations (sig, nd);
 
-       for(i=nd;i;i=i->next)
-         {
-           xfree(i->altvalue);
-           i->altvalue=NULL;
-         }
-      }
+      for (item = nd; item; item = item->next)
+        {
+          xfree (item->altvalue);
+          item->altvalue = NULL;
+        }
+    }
 
-    /* set policy URL */
-    if( IS_SIG(sig) && opt.sig_policy_url )
-      pu=opt.sig_policy_url;
-    else if( IS_CERT(sig) && opt.cert_policy_url )
-      pu=opt.cert_policy_url;
+  /* Set policy URL. */
+  if (IS_SIG(sig) && opt.sig_policy_url)
+    pu = opt.sig_policy_url;
+  else if (IS_CERT(sig) && opt.cert_policy_url)
+    pu = opt.cert_policy_url;
 
-    for(;pu;pu=pu->next)
-      {
-        string = pu->d;
+  for (; pu; pu = pu->next)
+    {
+      string = pu->d;
 
-       s=pct_expando(string,&args);
-       if(!s)
-         {
-           log_error(_("WARNING: unable to %%-expand policy URL "
-                       "(too large).  Using unexpanded.\n"));
-           s=xstrdup(string);
-         }
+      p = pct_expando (string, &args);
+      if (!p)
+        {
+          log_error(_("WARNING: unable to %%-expand policy URL "
+                      "(too large).  Using unexpanded.\n"));
+          p = xstrdup(string);
+        }
 
-       build_sig_subpkt(sig,SIGSUBPKT_POLICY|
-                        ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
-                        s,strlen(s));
+      build_sig_subpkt (sig, (SIGSUBPKT_POLICY
+                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
+                        p, strlen (p));
 
-       xfree(s);
-      }
+      xfree (p);
+    }
 
-    /* preferred keyserver URL */
-    if( IS_SIG(sig) && opt.sig_keyserver_url )
-      pu=opt.sig_keyserver_url;
+  /* Preferred keyserver URL. */
+  if (IS_SIG(sig) && opt.sig_keyserver_url)
+    pu = opt.sig_keyserver_url;
 
-    for(;pu;pu=pu->next)
-      {
-        string = pu->d;
+  for (; pu; pu = pu->next)
+    {
+      string = pu->d;
 
-       s=pct_expando(string,&args);
-       if(!s)
-         {
-           log_error(_("WARNING: unable to %%-expand preferred keyserver URL"
-                       " (too large).  Using unexpanded.\n"));
-           s=xstrdup(string);
-         }
+      p = pct_expando (string, &args);
+      if (!p)
+        {
+          log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
+                       " (too large).  Using unexpanded.\n"));
+          p = xstrdup (string);
+        }
 
-       build_sig_subpkt(sig,SIGSUBPKT_PREF_KS|
-                        ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
-                        s,strlen(s));
+      build_sig_subpkt (sig, (SIGSUBPKT_PREF_KS
+                              | ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0)),
+                        p, strlen (p));
+      xfree (p);
+    }
 
-       xfree(s);
-      }
+  /* Set signer's user id.  */
+  if (IS_SIG (sig) && !opt.flags.disable_signer_uid)
+    {
+      char *mbox;
+
+      /* For now we use the uid which was used to locate the key.  */
+      if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name)))
+        {
+          if (DBG_LOOKUP)
+            log_debug ("setting Signer's UID to '%s'\n", mbox);
+          build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
+          xfree (mbox);
+        }
+      else if (opt.sender_list)
+        {
+          /* If a list of --sender was given we scan that list and use
+           * the first one matching a user id of the current key.  */
+
+          /* FIXME: We need to get the list of user ids for the PKSK
+           * packet.  That requires either a function to look it up
+           * again or we need to extend the key packet struct to link
+           * to the primary key which in turn could link to the user
+           * ids.  Too much of a change right now.  Let's take just
+           * one from the supplied list and hope that the caller
+           * passed a matching one.  */
+          build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID,
+                            opt.sender_list->d, strlen (opt.sender_list->d));
+        }
+    }
 }
 
 
 /*
- * Helper to hash a user ID packet.  
+ * Helper to hash a user ID packet.
  */
 static void
 hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid)
 {
-    if ( sigversion >= 4 ) {
-        byte buf[5];
-
-       if(uid->attrib_data) {
-         buf[0] = 0xd1;                   /* indicates an attribute packet */
-         buf[1] = uid->attrib_len >> 24;  /* always use 4 length bytes */
-         buf[2] = uid->attrib_len >> 16;
-         buf[3] = uid->attrib_len >>  8;
-         buf[4] = uid->attrib_len;
-       }
-       else {
-         buf[0] = 0xb4;            /* indicates a userid packet */
-         buf[1] = uid->len >> 24;  /* always use 4 length bytes */
-         buf[2] = uid->len >> 16;
-         buf[3] = uid->len >>  8;
-         buf[4] = uid->len;
-       }
-        gcry_md_write( md, buf, 5 );
+  byte buf[5];
+
+  (void)sigversion;
+
+  if (uid->attrib_data)
+    {
+      buf[0] = 0xd1;                  /* Indicates an attribute packet.  */
+      buf[1] = uid->attrib_len >> 24;  /* Always use 4 length bytes.  */
+      buf[2] = uid->attrib_len >> 16;
+      buf[3] = uid->attrib_len >>  8;
+      buf[4] = uid->attrib_len;
     }
+  else
+    {
+      buf[0] = 0xb4;                  /* Indicates a userid packet.  */
+      buf[1] = uid->len >> 24;         /* Always use 4 length bytes.  */
+      buf[2] = uid->len >> 16;
+      buf[3] = uid->len >>  8;
+      buf[4] = uid->len;
+    }
+  gcry_md_write( md, buf, 5 );
 
-    if(uid->attrib_data)
-      gcry_md_write (md, uid->attrib_data, uid->attrib_len );
-    else
-      gcry_md_write (md, uid->name, uid->len );
+  if (uid->attrib_data)
+    gcry_md_write (md, uid->attrib_data, uid->attrib_len );
+  else
+    gcry_md_write (md, uid->name, uid->len );
 }
 
 
@@ -188,143 +219,150 @@ hash_uid (gcry_md_hd_t md, int sigversion, const PKT_user_id *uid)
 static void
 hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
 {
-    if (sig->version >= 4) 
-        gcry_md_putc (md, sig->version);
-    gcry_md_putc (md, sig->sig_class);
-    if (sig->version < 4) {
-        u32 a = sig->timestamp;
-        gcry_md_putc (md, (a >> 24) & 0xff );
-        gcry_md_putc (md, (a >> 16) & 0xff );
-        gcry_md_putc (md, (a >>  8) & 0xff );
-        gcry_md_putc (md,  a          & 0xff );
+  byte buf[6];
+  size_t n;
+
+  gcry_md_putc (md, sig->version);
+  gcry_md_putc (md, sig->sig_class);
+  gcry_md_putc (md, sig->pubkey_algo);
+  gcry_md_putc (md, sig->digest_algo);
+  if (sig->hashed)
+    {
+      n = sig->hashed->len;
+      gcry_md_putc (md, (n >> 8) );
+      gcry_md_putc (md,  n       );
+      gcry_md_write (md, sig->hashed->data, n );
+      n += 6;
     }
-    else {
-        byte buf[6];
-        size_t n;
-        
-        gcry_md_putc (md, sig->pubkey_algo);
-        gcry_md_putc (md, sig->digest_algo);
-        if (sig->hashed) {
-            n = sig->hashed->len;
-            gcry_md_putc (md, (n >> 8) );
-            gcry_md_putc (md,  n       );
-            gcry_md_write (md, sig->hashed->data, n );
-            n += 6;
-        }
-        else {
-            gcry_md_putc (md, 0);  /* always hash the length of the subpacket*/
-            gcry_md_putc (md, 0);
-            n = 6;
-        }
-        /* add some magic */
-        buf[0] = sig->version;
-        buf[1] = 0xff;
-        buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
-        buf[3] = n >> 16;
-        buf[4] = n >>  8;
-        buf[5] = n;
-        gcry_md_write (md, buf, 6);
+  else
+    {
+      gcry_md_putc (md, 0);  /* Always hash the length of the subpacket.  */
+      gcry_md_putc (md, 0);
+      n = 6;
     }
+  /* Add some magic.  */
+  buf[0] = sig->version;
+  buf[1] = 0xff;
+  buf[2] = n >> 24;         /* (n is only 16 bit, so this is always 0) */
+  buf[3] = n >> 16;
+  buf[4] = n >>  8;
+  buf[5] = n;
+  gcry_md_write (md, buf, 6);
 }
 
+
 /* Perform the sign operation.  If CACHE_NONCE is given the agent is
-   advised to use that cached passphrase fro the key.  */
+   advised to use that cached passphrase for the key.  */
 static int
-do_sign (PKT_public_key *pksk, PKT_signature *sig,
+do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
         gcry_md_hd_t md, int mdalgo, const char *cache_nonce)
 {
   gpg_error_t err;
-  gcry_mpi_t frame;
   byte *dp;
   char *hexgrip;
 
   if (pksk->timestamp > sig->timestamp )
     {
       ulong d = pksk->timestamp - sig->timestamp;
-      log_info (d==1 ? _("key has been created %lu second "
-                         "in future (time warp or clock problem)\n")
-                : _("key has been created %lu seconds "
-                    "in future (time warp or clock problem)\n"), d );
+      log_info (ngettext("key %s was created %lu second"
+                         " in the future (time warp or clock problem)\n",
+                         "key %s was created %lu seconds"
+                         " in the future (time warp or clock problem)\n",
+                         d), keystr_from_pk (pksk), d);
       if (!opt.ignore_time_conflict)
         return gpg_error (GPG_ERR_TIME_CONFLICT);
     }
 
-  
   print_pubkey_algo_note (pksk->pubkey_algo);
 
   if (!mdalgo)
     mdalgo = gcry_md_get_algo (md);
 
+  /* Check compliance.  */
+  if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo))
+    {
+      log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+                gcry_md_algo_name (mdalgo),
+                gnupg_compliance_option_string (opt.compliance));
+      err = gpg_error (GPG_ERR_DIGEST_ALGO);
+      goto leave;
+    }
+
+  if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo,
+                             pksk->pkey, nbits_from_pk (pksk), NULL))
+    {
+      log_error (_("key %s may not be used for signing in %s mode\n"),
+                 keystr_from_pk (pksk),
+                 gnupg_compliance_option_string (opt.compliance));
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      goto leave;
+    }
+
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      err = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      write_status_error ("random-compliance", err);
+      goto leave;
+    }
+
   print_digest_algo_note (mdalgo);
   dp = gcry_md_read  (md, mdalgo);
   sig->digest_algo = mdalgo;
   sig->digest_start[0] = dp[0];
   sig->digest_start[1] = dp[1];
+  mpi_release (sig->data[0]);
   sig->data[0] = NULL;
+  mpi_release (sig->data[1]);
   sig->data[1] = NULL;
 
-  
+
   err = hexkeygrip_from_pk (pksk, &hexgrip);
   if (!err)
     {
       char *desc;
       gcry_sexp_t s_sigval;
-      
-      desc = gpg_format_keydesc (pksk, 0, 1);
-      err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, 
+
+      desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1);
+      err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc,
+                          pksk->keyid, pksk->main_keyid, pksk->pubkey_algo,
                           dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,
                           &s_sigval);
       xfree (desc);
-      
+
       if (err)
         ;
       else if (pksk->pubkey_algo == GCRY_PK_RSA
                || pksk->pubkey_algo == GCRY_PK_RSA_S)
-        sig->data[0] = mpi_from_sexp (s_sigval, "s");
+        sig->data[0] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
+      else if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
+        {
+          sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_OPAQUE);
+          sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_OPAQUE);
+        }
       else
         {
-          sig->data[0] = mpi_from_sexp (s_sigval, "r");
-          sig->data[1] = mpi_from_sexp (s_sigval, "s");
+          sig->data[0] = get_mpi_from_sexp (s_sigval, "r", GCRYMPI_FMT_USG);
+          sig->data[1] = get_mpi_from_sexp (s_sigval, "s", GCRYMPI_FMT_USG);
         }
-      
+
       gcry_sexp_release (s_sigval);
     }
   xfree (hexgrip);
 
-  /* Check that the signature verification worked and nothing is
-   * fooling us e.g. by a bug in the signature create code or by
-   * deliberately introduced faults.  */
-  if (!err && !opt.no_sig_create_check)
-    {
-      PKT_public_key *pk = xmalloc_clear (sizeof *pk);
-
-      if (get_pubkey (pk, sig->keyid ))
-        err = gpg_error (GPG_ERR_NO_PUBKEY);
-      else 
-        {
-          frame = encode_md_value (pk, md, sig->digest_algo );
-          if (!frame)
-            err = gpg_error (GPG_ERR_GENERAL);
-          else
-            err = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey);
-          gcry_mpi_release (frame);
-        }
-      if (err)
-        log_error (_("checking created signature failed: %s\n"),
-                   g10_errstr (err));
-      free_public_key (pk);
-    }
-
+ leave:
   if (err)
-    log_error (_("signing failed: %s\n"), g10_errstr (err));
-  else 
+    log_error (_("signing failed: %s\n"), gpg_strerror (err));
+  else
     {
       if (opt.verbose)
         {
-          char *ustr = get_user_id_string_native (sig->keyid);
+          char *ustr = get_user_id_string_native (ctrl, sig->keyid);
           log_info (_("%s/%s signature from: \"%s\"\n"),
-                    gcry_pk_algo_name (pksk->pubkey_algo),
-                    gcry_md_algo_name (sig->digest_algo),
+                    openpgp_pk_algo_name (pksk->pubkey_algo),
+                    openpgp_md_algo_name (sig->digest_algo),
                     ustr);
           xfree (ustr);
        }
@@ -333,14 +371,15 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
 }
 
 
-int
-complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
+static int
+complete_sig (ctrl_t ctrl,
+              PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
               const char *cache_nonce)
 {
   int rc;
 
   /* if (!(rc = check_secret_key (pksk, 0))) */
-  rc = do_sign (pksk, sig, md, 0, cache_nonce);
+  rc = do_sign (ctrl, pksk, sig, md, 0, cache_nonce);
   return rc;
 }
 
@@ -371,7 +410,7 @@ openpgp_card_v1_p (PKT_public_key *pk)
         }
 
       xfree (pk->serialno);
-      agent_get_keyinfo (NULL, hexgrip, &pk->serialno);
+      agent_get_keyinfo (NULL, hexgrip, &pk->serialno, NULL);
       xfree (hexgrip);
       pk->flags.serialno_valid = 1;
     }
@@ -415,12 +454,16 @@ match_dsa_hash (unsigned int qbytes)
 /*
   First try --digest-algo.  If that isn't set, see if the recipient
   has a preferred algorithm (which is also filtered through
-  --preferred-digest-prefs).  If we're making a signature without a
+  --personal-digest-prefs).  If we're making a signature without a
   particular recipient (i.e. signing, rather than signing+encrypting)
-  then take the first algorithm in --preferred-digest-prefs that is
-  usable for the pubkey algorithm.  If --preferred-digest-prefs isn't
+  then take the first algorithm in --personal-digest-prefs that is
+  usable for the pubkey algorithm.  If --personal-digest-prefs isn't
   set, then take the OpenPGP default (i.e. SHA-1).
 
+  Note that Ed25519+EdDSA takes an input of arbitrary length and thus
+  we don't enforce any particular algorithm like we do for standard
+  ECDSA. However, we use SHA256 as the default algorithm.
+
   Possible improvement: Use the highest-ranked usable algorithm from
   the signing key prefs either before or after using the personal
   list?
@@ -436,12 +479,21 @@ hash_for (PKT_public_key *pk)
     {
       return recipient_digest_algo;
     }
-  else if(pk->pubkey_algo==PUBKEY_ALGO_DSA || pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
+  else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+           && openpgp_oid_is_ed25519 (pk->pkey[0]))
+    {
+      if (opt.personal_digest_prefs)
+        return opt.personal_digest_prefs[0].value;
+      else
+        return DIGEST_ALGO_SHA256;
+    }
+  else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
+           || pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
     {
       unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
 
-      if( pk->pubkey_algo==PUBKEY_ALGO_ECDSA )
-        qbytes = ecdsa_qbits_from_Q(qbytes);
+      if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
+        qbytes = ecdsa_qbits_from_Q (qbytes);
       qbytes = qbytes/8;
 
       /* It's a DSA key, so find a hash that is the same size as q or
@@ -490,11 +542,6 @@ hash_for (PKT_public_key *pk)
 
       return DIGEST_ALGO_SHA1;
     }
-  else if (PGP2 && pk->pubkey_algo == PUBKEY_ALGO_RSA && pk->version < 4 )
-    {
-      /* Old-style PGP only understands MD5 */
-      return DIGEST_ALGO_MD5;
-    }
   else if (opt.personal_digest_prefs)
     {
       /* It's not DSA, so we can use whatever the first hash algorithm
@@ -506,39 +553,19 @@ hash_for (PKT_public_key *pk)
 }
 
 
-/* Return true iff all keys in SK_LIST are old style (v3 RSA).  */
-static int
-only_old_style (SK_LIST sk_list)
-{
-  SK_LIST sk_rover = NULL;
-  int old_style = 0;
-  
-  for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
-    {
-      PKT_public_key *pk = sk_rover->pk;
-
-      if (pk->pubkey_algo == PUBKEY_ALGO_RSA && pk->version < 4)
-        old_style = 1;
-      else
-        return 0;
-    }
-  return old_style;
-}
-
-
 static void
 print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what)
 {
   byte array[MAX_FINGERPRINT_LEN];
   char buf[100+MAX_FINGERPRINT_LEN*2];
   size_t n;
-  
+
   snprintf (buf, sizeof buf - 2*MAX_FINGERPRINT_LEN, "%c %d %d %02x %lu ",
             what, sig->pubkey_algo, sig->digest_algo, sig->sig_class,
             (ulong)sig->timestamp );
   fingerprint_from_pk (pk, array, &n);
   bin2hex (array, n, buf + strlen (buf));
-  
+
   write_status_text( STATUS_SIG_CREATED, buf );
 }
 
@@ -547,7 +574,7 @@ print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what)
  * Loop over the secret certificates in SK_LIST and build the one pass
  * signature packets.  OpenPGP says that the data should be bracket by
  * the onepass-sig and signature-packet; so we build these onepass
- * packet here in reverse order 
+ * packet here in reverse order
  */
 static int
 write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
@@ -563,7 +590,7 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         PKT_onepass_sig *ops;
         PACKET pkt;
         int i, rc;
-        
+
         for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
             if (++i == skcount)
                 break;
@@ -576,15 +603,15 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         ops->pubkey_algo = pk->pubkey_algo;
         keyid_from_pk (pk, ops->keyid);
         ops->last = (skcount == 1);
-        
+
         init_packet(&pkt);
         pkt.pkttype = PKT_ONEPASS_SIG;
         pkt.pkt.onepass_sig = ops;
         rc = build_packet (out, &pkt);
-        free_packet (&pkt);
+        free_packet (&pkt, NULL);
         if (rc) {
             log_error ("build onepass_sig packet failed: %s\n",
-                       g10_errstr(rc));
+                       gpg_strerror (rc));
             return rc;
         }
     }
@@ -613,7 +640,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
 
         if( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow && opt.verbose)
-         log_info (_("WARNING: `%s' is an empty file\n"), fname);
+         log_info (_("WARNING: '%s' is an empty file\n"), fname);
 
         /* We can't encode the length of very large files because
            OpenPGP uses only 32 bit for file sizes.  So if the size of
@@ -628,7 +655,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
          * data, it is not possible to know the used length
          * without a double read of the file - to avoid that
          * we simple use partial length packets. */
-        if ( ptmode == 't' )
+        if ( ptmode == 't' || ptmode == 'u' || ptmode == 'm')
          filesize = 0;
       }
     else
@@ -637,10 +664,11 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
     if (!opt.no_literal) {
         PACKET pkt;
 
+        /* Note that PT has been initialized above in no_literal mode.  */
         pt->timestamp = make_timestamp ();
         pt->mode = ptmode;
         pt->len = filesize;
-        pt->new_ctb = !pt->len && !RFC1991;
+        pt->new_ctb = !pt->len;
         pt->buf = inp;
         init_packet(&pkt);
         pkt.pkttype = PKT_PLAINTEXT;
@@ -648,8 +676,9 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
         /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
         if( (rc = build_packet (out, &pkt)) )
             log_error ("build_packet(PLAINTEXT) failed: %s\n",
-                       g10_errstr(rc) );
+                       gpg_strerror (rc) );
         pt->buf = NULL;
+        free_packet (&pkt, NULL);
     }
     else {
         byte copy_buffer[4096];
@@ -664,7 +693,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
         wipememory(copy_buffer,4096); /* burn buffer */
     }
     /* fixme: it seems that we never freed pt/pkt */
-    
+
     return rc;
 }
 
@@ -673,12 +702,13 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
  * hash which will not be changes here.
  */
 static int
-write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
+write_signature_packets (ctrl_t ctrl,
+                         SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
                          int sigclass, u32 timestamp, u32 duration,
                         int status_letter, const char *cache_nonce)
 {
   SK_LIST sk_rover;
-  
+
   /* Loop over the certificates with secret keys. */
   for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
     {
@@ -690,11 +720,12 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
       pk = sk_rover->pk;
 
       /* Build the signature packet.  */
-      sig = xmalloc_clear (sizeof *sig);
-      if (opt.force_v3_sigs || RFC1991)
-        sig->version = 3;
-      else if (duration || opt.sig_policy_url
-               || opt.sig_notations || opt.sig_keyserver_url)
+      sig = xtrycalloc (1, sizeof *sig);
+      if (!sig)
+        return gpg_error_from_syserror ();
+
+      if (duration || opt.sig_policy_url
+          || opt.sig_notations || opt.sig_keyserver_url)
         sig->version = 4;
       else
         sig->version = pk->version;
@@ -712,37 +743,41 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
 
       if (gcry_md_copy (&md, hash))
         BUG ();
-      
+
       if (sig->version >= 4)
         {
-          build_sig_subpkt_from_sig (sig);
-          mk_notation_policy_etc (sig, pk, NULL);
+          build_sig_subpkt_from_sig (sig, pk);
+          mk_notation_policy_etc (sig, NULL, pk);
         }
-      
+
       hash_sigversion_to_magic (md, sig);
       gcry_md_final (md);
 
-      rc = do_sign (pk, sig, md, hash_for (pk), cache_nonce);
+      rc = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce);
       gcry_md_close (md);
       if (!rc)
-        { 
+        {
           /* Write the packet.  */
           PACKET pkt;
-          
+
           init_packet (&pkt);
           pkt.pkttype = PKT_SIGNATURE;
           pkt.pkt.signature = sig;
           rc = build_packet (out, &pkt);
           if (!rc && is_status_enabled())
             print_status_sig_created (pk, sig, status_letter);
-          free_packet (&pkt);
+          free_packet (&pkt, NULL);
           if (rc)
-            log_error ("build signature packet failed: %s\n", gpg_strerror (rc));
+            log_error ("build signature packet failed: %s\n",
+                       gpg_strerror (rc));
        }
+      else
+        free_seckey_enc (sig);
+
       if (rc)
         return rc;
     }
-  
+
   return 0;
 }
 
@@ -784,6 +819,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
     memset( &zfx, 0, sizeof zfx);
     memset( &mfx, 0, sizeof mfx);
     memset( &efx, 0, sizeof efx);
+    efx.ctrl = ctrl;
     init_packet( &pkt );
 
     if( filenames ) {
@@ -800,28 +836,18 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
        && (rc=setup_symkey(&efx.symkey_s2k,&efx.symkey_dek)))
       goto leave;
 
-    if(!opt.force_v3_sigs && !RFC1991)
-      {
-       if(opt.ask_sig_expire && !opt.batch)
-         duration=ask_expire_interval(1,opt.def_sig_expire);
-       else
-         duration=parse_expire_string(opt.def_sig_expire);
-      }
+    if (opt.ask_sig_expire && !opt.batch)
+      duration = ask_expire_interval(1,opt.def_sig_expire);
+    else
+      duration = parse_expire_string(opt.def_sig_expire);
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    if( (rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG )) )
+    if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
-    if(PGP2 && !only_old_style(sk_list))
-      {
-       log_info(_("you can only detach-sign with PGP 2.x style keys "
-                  "while in --pgp2 mode\n"));
-       compliance_failure();
-      }
-
     if (encryptflag
-        && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
+        && (rc=build_pk_list (ctrl, remusr, &pk_list)))
       goto leave;
 
     /* prepare iobufs */
@@ -835,10 +861,10 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
           inp = NULL;
           gpg_err_set_errno (EPERM);
         }
-      if( !inp ) 
+      if( !inp )
         {
           rc = gpg_error_from_syserror ();
-          log_error (_("can't open `%s': %s\n"), fname? fname: "[stdin]",
+          log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]",
                      strerror(errno) );
           goto leave;
        }
@@ -852,18 +878,18 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
             gpg_err_set_errno (EPERM);
         }
         else
-            out = iobuf_create( outfile );
+          out = iobuf_create (outfile, 0);
        if( !out )
          {
             rc = gpg_error_from_syserror ();
-           log_error(_("can't create `%s': %s\n"), outfile, strerror(errno) );
+           log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) );
            goto leave;
          }
        else if( opt.verbose )
-           log_info(_("writing to `%s'\n"), outfile );
+           log_info(_("writing to '%s'\n"), outfile );
     }
-    else if( (rc = open_outfile (GNUPG_INVALID_FD, fname,
-                                 opt.armor? 1: detached? 2:0, &out )))
+    else if( (rc = open_outfile (-1, fname,
+                                 opt.armor? 1: detached? 2:0, 0, &out)))
        goto leave;
 
     /* prepare to calculate the MD over the input */
@@ -876,7 +902,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
     if ( gcry_md_open (&mfx.md, 0, 0) )
       BUG ();
     if (DBG_HASHING)
-      gcry_md_start_debug (mfx.md, "sign");
+      gcry_md_debug (mfx.md, "sign");
 
     /* If we're encrypting and signing, it is reasonable to pick the
        hash algorithm to use out of the recipient key prefs.  This is
@@ -924,12 +950,14 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
 
            for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
              {
-               if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
+               if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA
+                    || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
                  {
-                   int temp_hashlen = gcry_mpi_get_nbits(sk_rover->pk->pkey[1]);
+                   int temp_hashlen = (gcry_mpi_get_nbits
+                                        (sk_rover->pk->pkey[1]));
 
-                   if( sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA )
-                     temp_hashlen = ecdsa_qbits_from_Q( temp_hashlen );
+                   if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
+                     temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen);
                    temp_hashlen = (temp_hashlen+7)/8;
 
                    /* Pick a hash that is large enough for our
@@ -938,7 +966,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
                    if (hint.digest_length<temp_hashlen)
                      hint.digest_length=temp_hashlen;
                  }
-                /* FIXME: need toall gpg-agent */
+                /* FIXME: need to check gpg-agent for this. */
                /* else if (sk_rover->pk->is_protected */
                 /*          && sk_rover->pk->protect.s2k.mode == 1002) */
                /*   smartcard = 1;  */
@@ -964,7 +992,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
     if( !multifile )
        iobuf_push_filter( inp, md_filter, &mfx );
 
-    if( detached && !encryptflag && !RFC1991 )
+    if( detached && !encryptflag)
        afx->what = 2;
 
     if( opt.armor && !outfile  )
@@ -976,7 +1004,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
        iobuf_push_filter( out, encrypt_filter, &efx );
     }
 
-    if( opt.compress_algo && !outfile && ( !detached || opt.compress_sigs) )
+    if (opt.compress_algo && !outfile && !detached)
       {
         int compr_algo=opt.compress_algo;
 
@@ -989,7 +1017,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
               there is an assumed preference for uncompressed data.
               Still, if it did fail, we'll also end up with the
               default. */
+
            if((compr_algo=
                select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
              compr_algo=default_compress_algo();
@@ -1007,7 +1035,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
       }
 
     /* Write the one-pass signature packets if needed */
-    if (!detached && !RFC1991) {
+    if (!detached) {
         rc = write_onepass_sig_packets (sk_list, out,
                                         opt.textmode && !outfile ? 0x01:0x00);
         if (rc)
@@ -1036,13 +1064,13 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
                if( !inp )
                  {
                     rc = gpg_error_from_syserror ();
-                   log_error(_("can't open `%s': %s\n"),
+                   log_error(_("can't open '%s': %s\n"),
                              sl->d,strerror(errno));
                    goto leave;
                  }
                 handle_progress (pfx, inp, sl->d);
                if( opt.verbose )
-                   fprintf(stderr, " `%s'", sl->d );
+                  log_printf (" '%s'", sl->d );
                if(opt.textmode)
                  {
                    memset( &tfx, 0, sizeof tfx);
@@ -1054,7 +1082,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
                iobuf_close(inp); inp = NULL;
            }
            if( opt.verbose )
-               putc( '\n', stderr );
+              log_printf ("\n");
        }
        else {
            /* read, so that the filter can calculate the digest */
@@ -1064,7 +1092,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
     }
     else {
         rc = write_plaintext_packet (out, inp, fname,
-                                     opt.textmode && !outfile ? 't':'b');
+                                     opt.textmode && !outfile ?
+                                     (opt.mimemode? 'm':'t'):'b');
     }
 
     /* catch errors from above */
@@ -1072,7 +1101,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
        goto leave;
 
     /* write the signatures */
-    rc = write_signature_packets (sk_list, out, mfx.md,
+    rc = write_signature_packets (ctrl, sk_list, out, mfx.md,
                                   opt.textmode && !outfile? 0x01 : 0x00,
                                  0, duration, detached ? 'D':'S', NULL);
     if( rc )
@@ -1103,7 +1132,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
  * make a clear signature. note that opt.armor is not needed
  */
 int
-clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
+clearsign_file (ctrl_t ctrl,
+                const char *fname, strlist_t locusr, const char *outfile )
 {
     armor_filter_context_t *afx;
     progress_filter_context_t *pfx;
@@ -1113,37 +1143,22 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     int rc = 0;
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
-    int old_style = RFC1991;
-    int only_md5 = 0;
     u32 duration=0;
 
     pfx = new_progress_context ();
     afx = new_armor_context ();
     init_packet( &pkt );
 
-    if(!opt.force_v3_sigs && !RFC1991)
-      {
-       if(opt.ask_sig_expire && !opt.batch)
-         duration=ask_expire_interval(1,opt.def_sig_expire);
-       else
-         duration=parse_expire_string(opt.def_sig_expire);
-      }
+    if (opt.ask_sig_expire && !opt.batch)
+      duration = ask_expire_interval (1,opt.def_sig_expire);
+    else
+      duration = parse_expire_string (opt.def_sig_expire);
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    if( (rc=build_sk_list( locusr, &sk_list, PUBKEY_USAGE_SIG )) )
+    if( (rc=build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
-    if( !old_style && !duration )
-       old_style = only_old_style( sk_list );
-
-    if(PGP2 && !only_old_style(sk_list))
-      {
-       log_info(_("you can only clearsign with PGP 2.x style keys "
-                  "while in --pgp2 mode\n"));
-       compliance_failure();
-      }
-
     /* prepare iobufs */
     inp = iobuf_open(fname);
     if (inp && is_secured_file (iobuf_get_fd (inp)))
@@ -1154,7 +1169,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
       }
     if( !inp ) {
         rc = gpg_error_from_syserror ();
-       log_error (_("can't open `%s': %s\n"), 
+       log_error (_("can't open '%s': %s\n"),
                    fname? fname: "[stdin]", strerror(errno) );
        goto leave;
     }
@@ -1165,34 +1180,23 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
             outfile = NULL;
             gpg_err_set_errno (EPERM);
         }
-        else 
-            out = iobuf_create( outfile );
+        else
+          out = iobuf_create (outfile, 0);
        if( !out )
          {
             rc = gpg_error_from_syserror ();
-           log_error(_("can't create `%s': %s\n"), outfile, strerror(errno) );
+           log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) );
            goto leave;
          }
        else if( opt.verbose )
-           log_info(_("writing to `%s'\n"), outfile );
+           log_info(_("writing to '%s'\n"), outfile );
     }
-    else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, &out )) )
+    else if ((rc = open_outfile (-1, fname, 1, 0, &out)))
        goto leave;
 
     iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF );
 
-    for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
-      {
-       if (hash_for (sk_rover->pk) == DIGEST_ALGO_MD5)
-          only_md5 = 1;
-       else 
-          {
-           only_md5 = 0;
-           break;
-          }
-      }
-
-    if( !(old_style && only_md5) ) {
+    {
        const char *s;
        int any = 0;
        byte hashs_seen[256];
@@ -1213,13 +1217,14 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
                }
            }
        }
-       assert(any);
+       log_assert(any);
        iobuf_writestr(out, LF );
     }
 
     if( opt.not_dash_escaped )
       iobuf_writestr( out,
-                 "NotDashEscaped: You need GnuPG to verify this message" LF );
+                      "NotDashEscaped: You need "GPG_NAME
+                      " to verify this message" LF );
     iobuf_writestr(out, LF );
 
     if ( gcry_md_open (&textmd, 0, 0) )
@@ -1228,10 +1233,10 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
       gcry_md_enable (textmd, hash_for(sk_rover->pk));
 
     if ( DBG_HASHING )
-      gcry_md_start_debug ( textmd, "clearsign" );
+      gcry_md_debug ( textmd, "clearsign" );
 
-    copy_clearsig_textout, inp, textmd, !opt.not_dash_escaped,
-                       opt.escape_from, (old_style && only_md5) );
+    copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped,
+                        opt.escape_from);
     /* fixme: check for read errors */
 
     /* now write the armor */
@@ -1239,8 +1244,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     push_armor_filter (afx, out);
 
     /* Write the signatures.  */
-    rc = write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C',
-                                  NULL);
+    rc = write_signature_packets (ctrl, sk_list, out, textmd, 0x01, 0,
+                                  duration, 'C', NULL);
     if( rc )
         goto leave;
 
@@ -1253,7 +1258,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     gcry_md_close ( textmd );
     release_sk_list( sk_list );
     release_progress_context (pfx);
-    release_armor_context (afx); 
+    release_armor_context (afx);
     return rc;
 }
 
@@ -1262,7 +1267,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
  * FIXME: Far too much code is duplicated - revamp the whole file.
  */
 int
-sign_symencrypt_file (const char *fname, strlist_t locusr)
+sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
 {
     armor_filter_context_t *afx;
     progress_filter_context_t *pfx;
@@ -1288,18 +1293,15 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
     memset( &cfx, 0, sizeof cfx);
     init_packet( &pkt );
 
-    if(!opt.force_v3_sigs && !RFC1991)
-      {
-       if(opt.ask_sig_expire && !opt.batch)
-         duration=ask_expire_interval(1,opt.def_sig_expire);
-       else
-         duration=parse_expire_string(opt.def_sig_expire);
-      }
+    if (opt.ask_sig_expire && !opt.batch)
+      duration = ask_expire_interval (1, opt.def_sig_expire);
+    else
+      duration = parse_expire_string (opt.def_sig_expire);
 
     /* Note: In the old non-agent version the following call used to
        unprotect the secret key.  This is now done on demand by the agent.  */
-    rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG);
-    if (rc) 
+    rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG);
+    if (rc)
        goto leave;
 
     /* prepare iobufs */
@@ -1312,7 +1314,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
       }
     if( !inp ) {
         rc = gpg_error_from_syserror ();
-       log_error (_("can't open `%s': %s\n"), 
+       log_error (_("can't open '%s': %s\n"),
                    fname? fname: "[stdin]", strerror(errno) );
        goto leave;
     }
@@ -1320,14 +1322,14 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* prepare key */
     s2k = xmalloc_clear( sizeof *s2k );
-    s2k->mode = RFC1991? 0:opt.s2k_mode;
+    s2k->mode = opt.s2k_mode;
     s2k->hash_algo = S2K_DIGEST_ALGO;
 
     algo = default_cipher_algo();
     if (!opt.quiet || !opt.batch)
         log_info (_("%s encryption will be used\n"),
                   openpgp_cipher_algo_name (algo) );
-    cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, &canceled);
+    cfx.dek = passphrase_to_dek (algo, s2k, 1, 1, NULL, &canceled);
 
     if (!cfx.dek || !cfx.dek->keylen) {
         rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE);
@@ -1335,15 +1337,10 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
         goto leave;
     }
 
-    /* We have no way to tell if the recipient can handle messages
-       with an MDC, so this defaults to no.  Perhaps in a few years,
-       this can be defaulted to yes.  Note that like regular
-       encrypting, --force-mdc overrides --disable-mdc. */
-    if(opt.force_mdc)
-      cfx.dek->use_mdc=1;
+    cfx.dek->use_mdc = use_mdc (NULL, cfx.dek->algo);
 
     /* now create the outfile */
-    rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1:0, &out);
+    rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
     if (rc)
        goto leave;
 
@@ -1353,7 +1350,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
     if ( gcry_md_open (&mfx.md, 0, 0) )
       BUG ();
     if ( DBG_HASHING )
-      gcry_md_start_debug (mfx.md, "symc-sign");
+      gcry_md_debug (mfx.md, "symc-sign");
 
     for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
       gcry_md_enable (mfx.md, hash_for (sk_rover->pk));
@@ -1366,7 +1363,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* Write the symmetric key packet */
     /*(current filters: armor)*/
-    if (!RFC1991) {
+    {
        PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc );
        enc->version = 4;
        enc->cipher_algo = cfx.dek->algo;
@@ -1374,7 +1371,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
        pkt.pkttype = PKT_SYMKEY_ENC;
        pkt.pkt.symkey_enc = enc;
        if( (rc = build_packet( out, &pkt )) )
-           log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
+           log_error("build symkey packet failed: %s\n", gpg_strerror (rc) );
        xfree(enc);
     }
 
@@ -1383,28 +1380,31 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* Push the compress filter */
     if (default_compress_algo())
-      push_compress_filter(out,&zfx,default_compress_algo());
+      {
+        if (cfx.dek && cfx.dek->use_mdc)
+          zfx.new_ctb = 1;
+        push_compress_filter (out, &zfx,default_compress_algo() );
+      }
 
     /* Write the one-pass signature packets */
     /*(current filters: zip - encrypt - armor)*/
-    if (!RFC1991) {
-        rc = write_onepass_sig_packets (sk_list, out,
-                                        opt.textmode? 0x01:0x00);
-        if (rc)
-            goto leave;
-    }
+    rc = write_onepass_sig_packets (sk_list, out,
+                                    opt.textmode? 0x01:0x00);
+    if (rc)
+      goto leave;
 
     write_status_begin_signing (mfx.md);
 
     /* Pipe data through all filters; i.e. write the signed stuff */
     /*(current filters: zip - encrypt - armor)*/
-    rc = write_plaintext_packet (out, inp, fname, opt.textmode ? 't':'b');
+    rc = write_plaintext_packet (out, inp, fname,
+                                 opt.textmode ? (opt.mimemode?'m':'t'):'b');
     if (rc)
        goto leave;
-    
+
     /* Write the signatures */
     /*(current filters: zip - encrypt - armor)*/
-    rc = write_signature_packets (sk_list, out, mfx.md,
+    rc = write_signature_packets (ctrl, sk_list, out, mfx.md,
                                  opt.textmode? 0x01 : 0x00,
                                  0, duration, 'S', NULL);
     if( rc )
@@ -1430,67 +1430,78 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
 
 /****************
- * Create a signature packet for the given public key certificate and
- * the user id and return it in ret_sig. User signature class SIGCLASS
- * user-id is not used (and may be NULL if sigclass is 0x20) If
- * DIGEST_ALGO is 0 the function selects an appropriate one.
- * SIGVERSION gives the minimal required signature packet version;
- * this is needed so that special properties like local sign are not
- * applied (actually: dropped) when a v3 key is used.  TIMESTAMP is
- * the timestamp to use for the signature. 0 means "now" */
+ * Create a v4 signature in *RET_SIG.
+ *
+ * PK is the primary key to sign (required for all sigs)
+ * UID is the user id to sign (required for 0x10..0x13, 0x30)
+ * SUBPK is subkey to sign (required for 0x18, 0x19, 0x28)
+ *
+ * PKSK is the signing key
+ *
+ * SIGCLASS is the type of signature to create.
+ *
+ * DIGEST_ALGO is the digest algorithm.  If it is 0 the function
+ * selects an appropriate one.
+ *
+ * TIMESTAMP is the timestamp to use for the signature. 0 means "now"
+ *
+ * DURATION is the amount of time (in seconds) until the signature
+ * expires.
+ *
+ * This function creates the following subpackets: issuer, created,
+ * and expire (if duration is not 0).  Additional subpackets can be
+ * added using MKSUBPKT, which is called after these subpackets are
+ * added and before the signature is generated.  OPAQUE is passed to
+ * MKSUBPKT.
+ */
 int
-make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
+make_keysig_packet (ctrl_t ctrl,
+                    PKT_signature **ret_sig, PKT_public_key *pk,
                    PKT_user_id *uid, PKT_public_key *subpk,
                    PKT_public_key *pksk,
                    int sigclass, int digest_algo,
-                    int sigversion, u32 timestamp, u32 duration,
+                    u32 timestamp, u32 duration,
                    int (*mksubpkt)(PKT_signature *, void *), void *opaque,
                     const char *cache_nonce)
 {
     PKT_signature *sig;
     int rc=0;
+    int sigversion;
     gcry_md_hd_t md;
 
-    assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
-           || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
-           || sigclass == 0x30 || sigclass == 0x28 );
-
-    if (opt.force_v4_certs)
-        sigversion = 4;
+    log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
+                || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
+                || sigclass == 0x30 || sigclass == 0x28 );
 
+    sigversion = 4;
     if (sigversion < pksk->version)
         sigversion = pksk->version;
 
-    /* If you are making a signature on a v4 key using your v3 key, it
-       doesn't make sense to generate a v3 sig.  After all, no v3-only
-       PGP implementation could understand the v4 key in the first
-       place.  Note that this implies that a signature on an attribute
-       uid is usually going to be v4 as well, since they are not
-       generally found on v3 keys. */
-    if (sigversion < pk->version)
-        sigversion = pk->version;
-
     if( !digest_algo )
       {
-       /* Basically, this means use SHA1 always unless it's a v3 RSA
-          key making a v3 cert (use MD5), or the user specified
-          something (use whatever they said), or it's DSA (use the
-          best match).  They still can't pick an inappropriate hash
-          for DSA or the signature will fail.  Note that this still
-          allows the caller of make_keysig_packet to override the
-          user setting if it must. */
+       /* Basically, this means use SHA1 always unless the user
+          specified something (use whatever they said), or it's DSA
+          (use the best match).  They still can't pick an
+          inappropriate hash for DSA or the signature will fail.
+          Note that this still allows the caller of
+          make_keysig_packet to override the user setting if it
+          must. */
 
        if(opt.cert_digest_algo)
          digest_algo=opt.cert_digest_algo;
-       else if(pksk->pubkey_algo==PUBKEY_ALGO_RSA
-               && pk->version<4 && sigversion<4)
-         digest_algo = DIGEST_ALGO_MD5;
-       else if(pksk->pubkey_algo==PUBKEY_ALGO_DSA)
-         digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8 );
-        else if(pksk->pubkey_algo==PUBKEY_ALGO_ECDSA )
-         digest_algo = match_dsa_hash (ecdsa_qbits_from_Q( gcry_mpi_get_nbits (pksk->pkey[1]) ) / 8);
+       else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
+         digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
+        else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
+                 || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
+          {
+            if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
+              digest_algo = DIGEST_ALGO_SHA256;
+            else
+              digest_algo = match_dsa_hash
+                (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
+          }
        else
-         digest_algo = DIGEST_ALGO_SHA1;
+         digest_algo = DEFAULT_DIGEST_ALGO;
       }
 
     if ( gcry_md_open (&md, digest_algo, 0 ) )
@@ -1524,23 +1535,21 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
     if(duration)
       sig->expiredate=sig->timestamp+duration;
     sig->sig_class = sigclass;
-    if( sig->version >= 4 )
-      {
-       build_sig_subpkt_from_sig( sig );
-       mk_notation_policy_etc (sig, pk, pksk);
-      }
+
+    build_sig_subpkt_from_sig (sig, pksk);
+    mk_notation_policy_etc (sig, pk, pksk);
 
     /* Crucial that the call to mksubpkt comes LAST before the calls
        to finalize the sig as that makes it possible for the mksubpkt
        function to get a reliable pointer to the subpacket area. */
-    if( sig->version >= 4 && mksubpkt )
+    if (mksubpkt)
        rc = (*mksubpkt)( sig, opaque );
 
     if( !rc ) {
         hash_sigversion_to_magic (md, sig);
        gcry_md_final (md);
 
-       rc = complete_sig (sig, pksk, md, cache_nonce);
+       rc = complete_sig (ctrl, sig, pksk, md, cache_nonce);
     }
 
     gcry_md_close (md);
@@ -1561,26 +1570,33 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
  *
  * TODO: Merge this with make_keysig_packet.
  */
-int
-update_keysig_packet( PKT_signature **ret_sig,
+gpg_error_t
+update_keysig_packet (ctrl_t ctrl,
+                      PKT_signature **ret_sig,
                       PKT_signature *orig_sig,
                       PKT_public_key *pk,
-                      PKT_user_id *uid, 
+                      PKT_user_id *uid,
                       PKT_public_key *subpk,
                       PKT_public_key *pksk,
                       int (*mksubpkt)(PKT_signature *, void *),
                       void *opaque)
 {
     PKT_signature *sig;
-    int rc=0;
+    gpg_error_t rc = 0;
+    int digest_algo;
     gcry_md_hd_t md;
 
     if ((!orig_sig || !pk || !pksk)
        || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid)
        || (orig_sig->sig_class == 0x18 && !subpk))
-      return G10ERR_GENERAL;
+      return GPG_ERR_GENERAL;
+
+    if ( opt.cert_digest_algo )
+      digest_algo = opt.cert_digest_algo;
+    else
+      digest_algo = orig_sig->digest_algo;
 
-    if ( gcry_md_open (&md, orig_sig->digest_algo, 0 ) )
+    if ( gcry_md_open (&md, digest_algo, 0 ) )
       BUG ();
 
     /* Hash the public key certificate and the user id. */
@@ -1593,42 +1609,50 @@ update_keysig_packet( PKT_signature **ret_sig,
 
     /* create a new signature packet */
     sig = copy_signature (NULL, orig_sig);
+
+    sig->digest_algo=digest_algo;
+
     /* We need to create a new timestamp so that new sig expiration
        calculations are done correctly... */
     sig->timestamp=make_timestamp();
 
     /* ... but we won't make a timestamp earlier than the existing
        one. */
-    while(sig->timestamp<=orig_sig->timestamp)
-      {
-       gnupg_sleep (1);
-       sig->timestamp=make_timestamp();
-      }
+    {
+      int tmout = 0;
+      while(sig->timestamp<=orig_sig->timestamp)
+        {
+          if (++tmout > 5 && !opt.ignore_time_conflict)
+            {
+              rc = gpg_error (GPG_ERR_TIME_CONFLICT);
+              goto leave;
+            }
+          gnupg_sleep (1);
+          sig->timestamp=make_timestamp();
+        }
+    }
 
     /* Note that already expired sigs will remain expired (with a
        duration of 1) since build-packet.c:build_sig_subpkt_from_sig
        detects this case. */
 
-    if( sig->version >= 4 )
-      {
-       /* Put the updated timestamp into the sig.  Note that this
-          will automagically lower any sig expiration dates to
-          correctly correspond to the differences in the timestamps
-          (i.e. the duration will shrink). */
-       build_sig_subpkt_from_sig( sig );
-
-       if (mksubpkt)
-         rc = (*mksubpkt)(sig, opaque);
-      }
+    /* Put the updated timestamp into the sig.  Note that this will
+       automagically lower any sig expiration dates to correctly
+       correspond to the differences in the timestamps (i.e. the
+       duration will shrink).  */
+    build_sig_subpkt_from_sig (sig, pksk);
+
+    if (mksubpkt)
+      rc = (*mksubpkt)(sig, opaque);
 
     if (!rc) {
         hash_sigversion_to_magic (md, sig);
        gcry_md_final (md);
 
-       rc = complete_sig (sig, pksk, md, NULL);
+       rc = complete_sig (ctrl, sig, pksk, md, NULL);
     }
 
+ leave:
     gcry_md_close (md);
     if( rc )
        free_seckey_enc (sig);