po: auto update
[gnupg.git] / g10 / sign.c
index 2724513..095fa11 100644 (file)
@@ -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,92 +60,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));
+        }
+    }
 }
 
 
@@ -223,39 +252,70 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
 
 
 /* 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;
 
 
@@ -265,7 +325,7 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
       char *desc;
       gcry_sexp_t s_sigval;
 
-      desc = gpg_format_keydesc (pksk, FORMAT_KEYDESC_NORMAL, 1);
+      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,
@@ -292,37 +352,14 @@ 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);
-    }
-
+ leave:
   if (err)
-    log_error (_("signing failed: %s\n"), g10_errstr (err));
+    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"),
                     openpgp_pk_algo_name (pksk->pubkey_algo),
                     openpgp_md_algo_name (sig->digest_algo),
@@ -334,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;
 }
 
@@ -372,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;
     }
@@ -570,10 +608,10 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         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;
         }
     }
@@ -617,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
@@ -626,6 +664,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;
@@ -637,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];
@@ -662,7 +702,8 @@ 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)
 {
@@ -679,7 +720,10 @@ 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);
+      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;
@@ -702,14 +746,14 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
 
       if (sig->version >= 4)
         {
-          build_sig_subpkt_from_sig (sig);
+          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)
         {
@@ -722,10 +766,14 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
           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;
     }
@@ -771,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 ) {
@@ -794,11 +843,11 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
 
     /* 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 */
@@ -1021,7 +1070,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);
@@ -1033,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 */
@@ -1043,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 */
@@ -1051,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 )
@@ -1082,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;
@@ -1105,7 +1156,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
 
     /* 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;
 
     /* prepare iobufs */
@@ -1166,7 +1217,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
                }
            }
        }
-       assert(any);
+       log_assert(any);
        iobuf_writestr(out, LF );
     }
 
@@ -1193,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;
 
@@ -1216,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;
@@ -1249,7 +1300,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
 
     /* 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;
 
@@ -1278,7 +1329,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);
@@ -1286,12 +1337,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);
@@ -1325,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);
     }
 
@@ -1334,7 +1380,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)*/
@@ -1347,13 +1397,14 @@ 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;
 
     /* 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 )
@@ -1379,16 +1430,33 @@ 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,
@@ -1401,9 +1469,9 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
     int sigversion;
     gcry_md_hd_t md;
 
-    assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
-           || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
-           || sigclass == 0x30 || sigclass == 0x28 );
+    log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
+                || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
+                || sigclass == 0x30 || sigclass == 0x28 );
 
     sigversion = 4;
     if (sigversion < pksk->version)
@@ -1468,7 +1536,7 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
       sig->expiredate=sig->timestamp+duration;
     sig->sig_class = sigclass;
 
-    build_sig_subpkt_from_sig( sig );
+    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
@@ -1481,7 +1549,7 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
         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);
@@ -1502,8 +1570,9 @@ 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,
@@ -1513,14 +1582,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;
@@ -1549,11 +1618,19 @@ 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
@@ -1563,7 +1640,7 @@ update_keysig_packet( PKT_signature **ret_sig,
        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 );
+    build_sig_subpkt_from_sig (sig, pksk);
 
     if (mksubpkt)
       rc = (*mksubpkt)(sig, opaque);
@@ -1572,9 +1649,10 @@ update_keysig_packet( PKT_signature **ret_sig,
         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);