gpg: Copy the correct digest for use by TOFU.
[gnupg.git] / g10 / sign.c
index bd78c17..e5fbd9d 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -41,7 +40,7 @@
 #include "pkglue.h"
 #include "sysutils.h"
 #include "call-agent.h"
-
+#include "mbox-util.h"
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
@@ -60,92 +59,121 @@ 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));
+        }
+    }
 }
 
 
@@ -155,30 +183,32 @@ mk_notation_policy_etc (PKT_signature *sig,
 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,45 +218,38 @@ 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.  */
 static int
@@ -234,22 +257,21 @@ do_sign (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)
@@ -297,32 +319,8 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
     }
   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);
-    }
-
   if (err)
-    log_error (_("signing failed: %s\n"), g10_errstr (err));
+    log_error (_("signing failed: %s\n"), gpg_strerror (err));
   else
     {
       if (opt.verbose)
@@ -377,7 +375,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;
     }
@@ -520,26 +518,6 @@ 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)
 {
@@ -598,7 +576,7 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         free_packet (&pkt);
         if (rc) {
             log_error ("build onepass_sig packet failed: %s\n",
-                       g10_errstr(rc));
+                       gpg_strerror (rc));
             return rc;
         }
     }
@@ -642,7 +620,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
@@ -651,6 +629,7 @@ 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;
@@ -662,8 +641,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);
     }
     else {
         byte copy_buffer[4096];
@@ -705,10 +685,8 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
 
       /* Build the signature packet.  */
       sig = xmalloc_clear (sizeof *sig);
-      if (opt.force_v3_sigs)
-        sig->version = 3;
-      else if (duration || opt.sig_policy_url
-               || opt.sig_notations || opt.sig_keyserver_url)
+      if (duration || opt.sig_policy_url
+          || opt.sig_notations || opt.sig_keyserver_url)
         sig->version = 4;
       else
         sig->version = pk->version;
@@ -729,8 +707,8 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
 
       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);
@@ -814,21 +792,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)
-      {
-       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 (encryptflag
-        && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
+        && (rc=build_pk_list (ctrl, remusr, &pk_list)))
       goto leave;
 
     /* prepare iobufs */
@@ -932,13 +907,12 @@ 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_EDDSA
-                        && !openpgp_oid_is_ed25519 (sk_rover->pk->pkey[1])))
+                    || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
                  {
                    int temp_hashlen = (gcry_mpi_get_nbits
                                         (sk_rover->pk->pkey[1]));
 
-                   if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
+                   if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
                      temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen);
                    temp_hashlen = (temp_hashlen+7)/8;
 
@@ -948,7 +922,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;  */
@@ -1052,7 +1026,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
                  }
                 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);
@@ -1064,7 +1038,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 */
@@ -1074,7 +1048,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 */
@@ -1113,7 +1088,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;
@@ -1123,30 +1099,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 = 0;
-    int only_md5 = 0;
     u32 duration=0;
 
     pfx = new_progress_context ();
     afx = new_armor_context ();
     init_packet( &pkt );
 
-    if(!opt.force_v3_sigs)
-      {
-       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(!duration )
-       old_style = only_old_style( sk_list );
-
     /* prepare iobufs */
     inp = iobuf_open(fname);
     if (inp && is_secured_file (iobuf_get_fd (inp)))
@@ -1184,18 +1152,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
 
     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];
@@ -1216,7 +1173,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
                }
            }
        }
-       assert(any);
+       log_assert(any);
        iobuf_writestr(out, LF );
     }
 
@@ -1234,8 +1191,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     if ( DBG_HASHING )
       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 */
@@ -1266,7 +1223,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;
@@ -1292,17 +1249,14 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
     memset( &cfx, 0, sizeof cfx);
     init_packet( &pkt );
 
-    if(!opt.force_v3_sigs)
-      {
-       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);
+    rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG);
     if (rc)
        goto leave;
 
@@ -1331,7 +1285,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
     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);
@@ -1339,12 +1293,7 @@ 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 (-1, fname, opt.armor? 1:0, 0, &out);
@@ -1378,7 +1327,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);
     }
 
@@ -1387,7 +1336,11 @@ 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)*/
@@ -1400,7 +1353,8 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* 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;
 
@@ -1441,52 +1395,39 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
  * applied (actually: dropped) when a v3 key is used.  TIMESTAMP is
  * the timestamp to use for the signature. 0 means "now" */
 int
-make_keysig_packetPKT_signature **ret_sig, PKT_public_key *pk,
+make_keysig_packet (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
@@ -1533,16 +1474,14 @@ 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 ) {
@@ -1570,7 +1509,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
  *
  * TODO: Merge this with make_keysig_packet.
  */
-int
+gpg_error_t
 update_keysig_packet( PKT_signature **ret_sig,
                       PKT_signature *orig_sig,
                       PKT_public_key *pk,
@@ -1581,14 +1520,14 @@ update_keysig_packet( PKT_signature **ret_sig,
                       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;
@@ -1617,27 +1556,32 @@ update_keysig_packet( PKT_signature **ret_sig,
 
     /* ... 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);
@@ -1646,6 +1590,7 @@ update_keysig_packet( PKT_signature **ret_sig,
        rc = complete_sig (sig, pksk, md, NULL);
     }
 
+ leave:
     gcry_md_close (md);
     if( rc )
        free_seckey_enc (sig);