g10: If iobuf_seek fails when reading from the cache, do a hard read.
[gnupg.git] / g10 / sign.c
index 0e8be71..7a8d697 100644 (file)
@@ -1,12 +1,12 @@
 /* sign.c - sign data
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ *               2007, 2010, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
-#include <unistd.h> /* need sleep() */
 
+#include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "errors.h"
+#include "status.h"
 #include "iobuf.h"
 #include "keydb.h"
-#include "memory.h"
 #include "util.h"
 #include "main.h"
 #include "filter.h"
 #include "trustdb.h"
 #include "status.h"
 #include "i18n.h"
-#include "cardglue.h"
+#include "pkglue.h"
+#include "sysutils.h"
+#include "call-agent.h"
 
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
-void __stdcall Sleep(ulong);
-#define sleep(a)  Sleep((a)*1000)
 #else
 #define LF "\n"
 #endif
@@ -55,100 +52,58 @@ void __stdcall Sleep(ulong);
 static int recipient_digest_algo=0;
 
 /****************
- * Create a notation.  It is assumed that the stings in STRLIST
- * are already checked to contain only printable data and have a valid
- * NAME=VALUE format.
+ * Create notations and other stuff.  It is assumed that the stings in
+ * STRLIST are already checked to contain only printable data and have
+ * a valid NAME=VALUE format.
  */
 static void
-mk_notation_policy_etcPKT_signature *sig,
-                       PKT_public_key *pk, PKT_secret_key *sk )
+mk_notation_policy_etc (PKT_signature *sig,
+                       PKT_public_key *pk, PKT_public_key *pksk)
 {
     const char *string;
     char *s=NULL;
-    byte *buf;
-    unsigned n1, n2;
-    STRLIST nd=NULL,pu=NULL;
+    strlist_t pu=NULL;
+    struct notation *nd=NULL;
     struct expando_args args;
 
+    assert(sig->version>=4);
+
     memset(&args,0,sizeof(args));
     args.pk=pk;
-    args.sk=sk;
-
-    /* It is actually impossible to get here when making a v3 key
-       signature since keyedit.c:sign_uids will automatically bump a
-       signature with a notation or policy url up to v4, but it is
-       good to do these checks anyway. */
+    args.pksk=pksk;
 
     /* notation data */
-    if(IS_SIG(sig) && opt.sig_notation_data)
-      {
-       if(sig->version<4)
-         log_error(_("can't put notation data into v3 (PGP 2.x style) "
-                     "signatures\n"));
-       else
-         nd=opt.sig_notation_data;
-      }
-    else if( IS_CERT(sig) && opt.cert_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)
       {
-       if(sig->version<4)
-         log_error(_("can't put notation data into v3 (PGP 2.x style) "
-                     "key signatures\n"));
-       else
-         nd=opt.cert_notation_data;
-      }
+       struct notation *i;
 
-    for( ; nd; nd = nd->next ) {
-        char *expanded;
+       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"));
+         }
 
-        string = nd->d;
-       s = strchr( string, '=' );
-       if( !s )
-         BUG(); /* we have already parsed this */
-       n1 = s - string;
-       s++;
+       keygen_add_notations(sig,nd);
 
-       expanded=pct_expando(s,&args);
-       if(!expanded)
+       for(i=nd;i;i=i->next)
          {
-           log_error(_("WARNING: unable to %%-expand notation "
-                       "(too large).  Using unexpanded.\n"));
-           expanded=xstrdup(s);
+           xfree(i->altvalue);
+           i->altvalue=NULL;
          }
-
-       n2 = strlen(expanded);
-       buf = xmalloc( 8 + n1 + n2 );
-       buf[0] = 0x80; /* human readable */
-       buf[1] = buf[2] = buf[3] = 0;
-       buf[4] = n1 >> 8;
-       buf[5] = n1;
-       buf[6] = n2 >> 8;
-       buf[7] = n2;
-       memcpy(buf+8, string, n1 );
-       memcpy(buf+8+n1, expanded, n2 );
-       build_sig_subpkt( sig, SIGSUBPKT_NOTATION
-                         | ((nd->flags & 1)? SIGSUBPKT_FLAG_CRITICAL:0),
-                         buf, 8+n1+n2 );
-       xfree(expanded);
-       xfree(buf);
-    }
+      }
 
     /* set policy URL */
     if( IS_SIG(sig) && opt.sig_policy_url )
-      {
-       if(sig->version<4)
-         log_error(_("can't put a policy URL into v3 (PGP 2.x style) "
-                     "signatures\n"));
-       else
-         pu=opt.sig_policy_url;
-      }
+      pu=opt.sig_policy_url;
     else if( IS_CERT(sig) && opt.cert_policy_url )
-      {
-       if(sig->version<4)
-         log_error(_("can't put a policy URL into v3 key (PGP 2.x style) "
-                     "signatures\n"));
-       else
-         pu=opt.cert_policy_url;
-      }
+      pu=opt.cert_policy_url;
 
     for(;pu;pu=pu->next)
       {
@@ -171,12 +126,7 @@ mk_notation_policy_etc( PKT_signature *sig,
 
     /* preferred keyserver URL */
     if( IS_SIG(sig) && opt.sig_keyserver_url )
-      {
-       if(sig->version<4)
-         log_info("can't put a preferred keyserver URL into v3 signatures\n");
-       else
-         pu=opt.sig_keyserver_url;
-      }
+      pu=opt.sig_keyserver_url;
 
     for(;pu;pu=pu->next)
       {
@@ -200,35 +150,37 @@ mk_notation_policy_etc( PKT_signature *sig,
 
 
 /*
- * Helper to hash a user ID packet.  
+ * Helper to hash a user ID packet.
  */
 static void
-hash_uid (MD_HANDLE md, int sigversion, const PKT_user_id *uid)
+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;
-       }
-        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)
-      md_write (md, uid->attrib_data, uid->attrib_len );
-    else
-      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 );
 }
 
 
@@ -236,205 +188,328 @@ hash_uid (MD_HANDLE md, int sigversion, const PKT_user_id *uid)
  * Helper to hash some parts from the signature
  */
 static void
-hash_sigversion_to_magic (MD_HANDLE md, const PKT_signature *sig)
+hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
 {
-    if (sig->version >= 4) 
-        md_putc (md, sig->version);
-    md_putc (md, sig->sig_class);
-    if (sig->version < 4) {
-        u32 a = sig->timestamp;
-        md_putc (md, (a >> 24) & 0xff );
-        md_putc (md, (a >> 16) & 0xff );
-        md_putc (md, (a >>  8) & 0xff );
-        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;
-        
-        md_putc (md, sig->pubkey_algo);
-        md_putc (md, sig->digest_algo);
-        if (sig->hashed) {
-            n = sig->hashed->len;
-            md_putc (md, (n >> 8) );
-            md_putc (md,  n       );
-            md_write (md, sig->hashed->data, n );
-            n += 6;
-        }
-        else {
-            md_putc (md, 0);  /* always hash the length of the subpacket*/
-            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;
-        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
-do_sign( PKT_secret_key *sk, PKT_signature *sig,
-        MD_HANDLE md, int digest_algo )
+do_sign (PKT_public_key *pksk, PKT_signature *sig,
+        gcry_md_hd_t md, int mdalgo, const char *cache_nonce)
 {
-    MPI frame;
-    byte *dp;
-    int rc;
-
-    if( sk->timestamp > sig->timestamp ) {
-       ulong d = sk->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 );
-       if( !opt.ignore_time_conflict )
-           return G10ERR_TIME_CONFLICT;
+  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 );
+      if (!opt.ignore_time_conflict)
+        return gpg_error (GPG_ERR_TIME_CONFLICT);
     }
 
 
-    print_pubkey_algo_note(sk->pubkey_algo);
+  print_pubkey_algo_note (pksk->pubkey_algo);
 
-    if( !digest_algo )
-       digest_algo = md_get_algo(md);
+  if (!mdalgo)
+    mdalgo = gcry_md_get_algo (md);
 
-    print_digest_algo_note( digest_algo );
-    dp = md_read( md, digest_algo );
-    sig->digest_algo = digest_algo;
-    sig->digest_start[0] = dp[0];
-    sig->digest_start[1] = dp[1];
-    if (sk->is_protected && sk->protect.s2k.mode == 1002) 
-      { 
-#ifdef ENABLE_CARD_SUPPORT
-        unsigned char *rbuf;
-        size_t rbuflen;
-        char *snbuf;
-        
-        snbuf = serialno_and_fpr_from_sk (sk->protect.iv,
-                                          sk->protect.ivlen, sk);
-        rc = agent_scd_pksign (snbuf, digest_algo,
-                               md_read (md, digest_algo),
-                               md_digest_length (digest_algo),
-                               &rbuf, &rbuflen);
-        xfree (snbuf);
-        if (!rc)
-          {
-            sig->data[0] = mpi_alloc ( (rbuflen+BYTES_PER_MPI_LIMB-1)
-                                       / BYTES_PER_MPI_LIMB );
-            mpi_set_buffer (sig->data[0], rbuf, rbuflen, 0);
-            xfree (rbuf);
-          }
-#else
-        return G10ERR_UNSUPPORTED;
-#endif /* ENABLE_CARD_SUPPORT */
-      }
-    else 
-      {
-        frame = encode_md_value( sk->pubkey_algo, md,
-                                 digest_algo, mpi_get_nbits(sk->skey[0]) );
-        if (!frame)
-          return G10ERR_GENERAL;
-        rc = pubkey_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
-        mpi_free(frame);
-      }
+  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];
+  sig->data[0] = NULL;
+  sig->data[1] = NULL;
 
-    if (!rc && !opt.no_sig_create_check) {
-        /* 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. */
-        PKT_public_key *pk = xmalloc_clear (sizeof *pk);
-
-        if( get_pubkey( pk, sig->keyid ) )
-            rc = G10ERR_NO_PUBKEY;
-        else {
-            frame = encode_md_value (pk->pubkey_algo, md,
-                                     sig->digest_algo,
-                                     mpi_get_nbits(pk->pkey[0]) );
-            if (!frame)
-                rc = G10ERR_GENERAL;
-            else
-                rc = pubkey_verify (pk->pubkey_algo, frame,
-                                    sig->data, pk->pkey );
-            mpi_free (frame);
+
+  err = hexkeygrip_from_pk (pksk, &hexgrip);
+  if (!err)
+    {
+      char *desc;
+      gcry_sexp_t s_sigval;
+
+      desc = gpg_format_keydesc (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] = 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);
         }
-        if (rc)
-            log_error (_("checking created signature failed: %s\n"),
-                         g10_errstr (rc));
-        free_public_key (pk);
+      else
+        {
+          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);
     }
-    if( rc )
-       log_error(_("signing failed: %s\n"), g10_errstr(rc) );
-    else {
-       if( opt.verbose ) {
-           char *ustr = get_user_id_string_native (sig->keyid);
-           log_info(_("%s/%s signature from: \"%s\"\n"),
-                    pubkey_algo_to_string(sk->pubkey_algo),
-                    digest_algo_to_string(sig->digest_algo),
-                    ustr );
-           xfree(ustr);
+  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.  Because Libgcrypt 1.7 does this
+   * for RSA internally there is no need to do it here again.  */
+  if (!err
+#if GCRYPT_VERSION_NUMBER >= 0x010700 /* Libgcrypt >= 1.7 */
+        && !is_RSA (pksk->pubkey_algo)
+#endif /* Libgcrypt >= 1.7 */
+      )
+    {
+      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"),
+                   gpg_strerror (err));
+      free_public_key (pk);
+    }
+
+  if (err)
+    log_error (_("signing failed: %s\n"), gpg_strerror (err));
+  else
+    {
+      if (opt.verbose)
+        {
+          char *ustr = get_user_id_string_native (sig->keyid);
+          log_info (_("%s/%s signature from: \"%s\"\n"),
+                    openpgp_pk_algo_name (pksk->pubkey_algo),
+                    openpgp_md_algo_name (sig->digest_algo),
+                    ustr);
+          xfree (ustr);
        }
     }
-    return rc;
+  return err;
 }
 
 
 int
-complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md )
+complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
+              const char *cache_nonce)
 {
-    int rc=0;
+  int rc;
 
-    if( !(rc=check_secret_key( sk, 0 )) )
-       rc = do_sign( sk, sig, md, 0 );
-    return rc;
+  /* if (!(rc = check_secret_key (pksk, 0))) */
+  rc = do_sign (pksk, sig, md, 0, cache_nonce);
+  return rc;
 }
 
+
+/* Return true if the key seems to be on a version 1 OpenPGP card.
+   This works by asking the agent and may fail if the card has not yet
+   been used with the agent.  */
+static int
+openpgp_card_v1_p (PKT_public_key *pk)
+{
+  gpg_error_t err;
+  int result;
+
+  /* Shortcut if we are not using RSA: The v1 cards only support RSA
+     thus there is no point in looking any further.  */
+  if (!is_RSA (pk->pubkey_algo))
+    return 0;
+
+  if (!pk->flags.serialno_valid)
+    {
+      char *hexgrip;
+
+      err = hexkeygrip_from_pk (pk, &hexgrip);
+      if (err)
+        {
+          log_error ("error computing a keygrip: %s\n", gpg_strerror (err));
+          return 0; /* Ooops.  */
+        }
+
+      xfree (pk->serialno);
+      agent_get_keyinfo (NULL, hexgrip, &pk->serialno);
+      xfree (hexgrip);
+      pk->flags.serialno_valid = 1;
+    }
+
+  if (!pk->serialno)
+    result = 0; /* Error from a past agent_get_keyinfo or no card.  */
+  else
+    {
+      /* The version number of the card is included in the serialno.  */
+      result = !strncmp (pk->serialno, "D2760001240101", 14);
+    }
+  return result;
+}
+
+
+
+static int
+match_dsa_hash (unsigned int qbytes)
+{
+  if (qbytes <= 20)
+    return DIGEST_ALGO_SHA1;
+
+  if (qbytes <= 28)
+    return DIGEST_ALGO_SHA224;
+
+  if (qbytes <= 32)
+    return DIGEST_ALGO_SHA256;
+
+  if (qbytes <= 48)
+    return DIGEST_ALGO_SHA384;
+
+  if (qbytes <= 66 )   /* 66 corresponds to 521 (64 to 512) */
+    return DIGEST_ALGO_SHA512;
+
+  return DEFAULT_DIGEST_ALGO;
+  /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong
+     answer we have if a digest larger than 512 bits is requested.  */
+}
+
+
 /*
   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?
 */
-
 static int
-hash_for(int pubkey_algo, int packet_version )
+hash_for (PKT_public_key *pk)
 {
-  if( opt.def_digest_algo )
-    return opt.def_digest_algo;
-  else if( recipient_digest_algo )
-    return recipient_digest_algo;
-  else if(PGP2 && pubkey_algo == PUBKEY_ALGO_RSA && packet_version < 4 )
+  if (opt.def_digest_algo)
+    {
+      return opt.def_digest_algo;
+    }
+  else if (recipient_digest_algo)
     {
-      /* Old-style PGP only understands MD5 */
-      return DIGEST_ALGO_MD5;
+      return recipient_digest_algo;
     }
-  else if( pubkey_algo == PUBKEY_ALGO_DSA )
+  else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+           && openpgp_oid_is_ed25519 (pk->pkey[0]))
     {
-      /* We need a 160-bit hash for DSA, so we can't just take the first
-        in the pref list */
+      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);
+      qbytes = qbytes/8;
 
+      /* It's a DSA key, so find a hash that is the same size as q or
+        larger.  If q is 160, assume it is an old DSA key and use a
+        160-bit hash unless --enable-dsa2 is set, in which case act
+        like a new DSA key that just happens to have a 160-bit q
+        (i.e. allow truncation).  If q is not 160, by definition it
+        must be a new DSA key. */
+
+      if (opt.personal_digest_prefs)
+       {
+         prefitem_t *prefs;
+
+         if (qbytes != 20 || opt.flags.dsa2)
+           {
+             for (prefs=opt.personal_digest_prefs; prefs->type; prefs++)
+               if (gcry_md_get_algo_dlen (prefs->value) >= qbytes)
+                 return prefs->value;
+           }
+         else
+           {
+             for (prefs=opt.personal_digest_prefs; prefs->type; prefs++)
+               if (gcry_md_get_algo_dlen (prefs->value) == qbytes)
+                 return prefs->value;
+           }
+       }
+
+      return match_dsa_hash(qbytes);
+    }
+  else if (openpgp_card_v1_p (pk))
+    {
+      /* The sk lives on a smartcard, and old smartcards only handle
+        SHA-1 and RIPEMD/160.  Newer smartcards (v2.0) don't have
+        this restriction anymore.  Fortunately the serial number
+        encodes the version of the card and thus we know that this
+        key is on a v1 card. */
       if(opt.personal_digest_prefs)
        {
          prefitem_t *prefs;
 
-         for(prefs=opt.personal_digest_prefs;prefs->type;prefs++)
-           if(md_digest_length(prefs->value)==20)
+         for (prefs=opt.personal_digest_prefs;prefs->type;prefs++)
+           if (prefs->value==DIGEST_ALGO_SHA1
+                || prefs->value==DIGEST_ALGO_RMD160)
              return prefs->value;
        }
 
       return DIGEST_ALGO_SHA1;
     }
-  else if( opt.personal_digest_prefs )
+  else if (opt.personal_digest_prefs)
     {
       /* It's not DSA, so we can use whatever the first hash algorithm
         is in the pref list */
@@ -444,41 +519,21 @@ hash_for(int pubkey_algo, int packet_version )
     return DEFAULT_DIGEST_ALGO;
 }
 
-static int
-only_old_style( SK_LIST sk_list )
-{
-    SK_LIST sk_rover = NULL;
-    int old_style = 0;
-
-    /* if there are only old style capable key we use the old sytle */
-    for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
-       PKT_secret_key *sk = sk_rover->sk;
-       if( sk->pubkey_algo == PUBKEY_ALGO_RSA && sk->version < 4 )
-           old_style = 1;
-       else
-           return 0;
-    }
-    return old_style;
-}
-
 
 static void
-print_status_sig_created ( PKT_secret_key *sk, PKT_signature *sig, int what )
+print_status_sig_created (PKT_public_key *pk, PKT_signature *sig, int what)
 {
-    byte array[MAX_FINGERPRINT_LEN], *p;
-    char buf[100+MAX_FINGERPRINT_LEN*2];
-    size_t i, n;
+  byte array[MAX_FINGERPRINT_LEN];
+  char buf[100+MAX_FINGERPRINT_LEN*2];
+  size_t n;
 
-    sprintf(buf, "%c %d %d %02x %lu ",
-           what, sig->pubkey_algo, sig->digest_algo, sig->sig_class,
-           (ulong)sig->timestamp );
+  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));
 
-    fingerprint_from_sk( sk, array, &n );
-    p = buf + strlen(buf);
-    for(i=0; i < n ; i++ )
-       sprintf(p+2*i, "%02X", array[i] );
-
-    write_status_text( STATUS_SIG_CREATED, buf );
+  write_status_text( STATUS_SIG_CREATED, buf );
 }
 
 
@@ -486,7 +541,7 @@ print_status_sig_created ( PKT_secret_key *sk, 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 )
@@ -498,24 +553,24 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         skcount++;
 
     for (; skcount; skcount--) {
-        PKT_secret_key *sk;
+        PKT_public_key *pk;
         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;
         }
 
-        sk = sk_rover->sk;
+        pk = sk_rover->pk;
         ops = xmalloc_clear (sizeof *ops);
         ops->sig_class = sigclass;
-        ops->digest_algo = hash_for (sk->pubkey_algo, sk->version);
-        ops->pubkey_algo = sk->pubkey_algo;
-        keyid_from_sk (sk, ops->keyid);
+        ops->digest_algo = hash_for (pk);
+        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;
@@ -523,7 +578,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;
         }
     }
@@ -541,29 +596,18 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
     u32 filesize;
     int rc = 0;
 
-    if (!opt.no_literal) {
-        if (fname || opt.set_filename) {
-            char *s = make_basename (opt.set_filename? opt.set_filename
-                                                     : fname,
-                                     iobuf_get_real_fname(inp));
-            pt = xmalloc (sizeof *pt + strlen(s) - 1);
-            pt->namelen = strlen (s);
-            memcpy (pt->name, s, pt->namelen);
-            xfree (s);
-        }
-        else { /* no filename */
-            pt = xmalloc (sizeof *pt - 1);
-            pt->namelen = 0;
-        }
-    }
+    if (!opt.no_literal)
+      pt=setup_plaintext_name(fname,inp);
 
     /* try to calculate the length of the data */
     if ( !iobuf_is_pipe_filename (fname) && *fname )
       {
         off_t tmpsize;
-       
-        if( !(tmpsize = iobuf_get_filelength(inp)) )
-         log_info (_("WARNING: `%s' is an empty file\n"), fname);
+        int overflow;
+
+        if( !(tmpsize = iobuf_get_filelength(inp, &overflow))
+            && !overflow && opt.verbose)
+         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
@@ -590,7 +634,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
         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;
@@ -598,7 +642,7 @@ 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;
     }
     else {
@@ -606,16 +650,15 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
         int  bytes_copied;
 
         while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
-            if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
-                rc = G10ERR_WRITE_FILE;
+            if ( (rc=iobuf_write(out, copy_buffer, bytes_copied)) ) {
                 log_error ("copying input to output failed: %s\n",
-                           g10_errstr(rc));
+                           gpg_strerror (rc));
                 break;
             }
         wipememory(copy_buffer,4096); /* burn buffer */
     }
     /* fixme: it seems that we never freed pt/pkt */
-    
+
     return rc;
 }
 
@@ -624,75 +667,78 @@ 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, MD_HANDLE hash,
+write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
                          int sigclass, u32 timestamp, u32 duration,
-                        int status_letter)
+                        int status_letter, const char *cache_nonce)
 {
-    SK_LIST sk_rover;
+  SK_LIST sk_rover;
 
-    /* loop over the secret certificates */
-    for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) {
-       PKT_secret_key *sk;
-       PKT_signature *sig;
-       MD_HANDLE md;
-        int rc;
-
-       sk = sk_rover->sk;
-
-       /* 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_notation_data || opt.sig_keyserver_url)
-         sig->version=4;
-       else
-         sig->version=sk->version;
-       keyid_from_sk (sk, sig->keyid);
-       sig->digest_algo = hash_for (sk->pubkey_algo, sk->version);
-       sig->pubkey_algo = sk->pubkey_algo;
-       if(timestamp)
-         sig->timestamp = timestamp;
-       else
-         sig->timestamp = make_timestamp();
-       if(duration)
-         sig->expiredate = sig->timestamp+duration;
-       sig->sig_class = sigclass;
-
-       md = md_copy (hash);
-
-       if (sig->version >= 4)
-           build_sig_subpkt_from_sig (sig);
-       mk_notation_policy_etc (sig, NULL, sk);
-
-        hash_sigversion_to_magic (md, sig);
-       md_final (md);
-
-       rc = do_sign( sk, sig, md, hash_for (sig->pubkey_algo, sk->version) );
-       md_close (md);
+  /* Loop over the certificates with secret keys. */
+  for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
+    {
+      PKT_public_key *pk;
+      PKT_signature *sig;
+      gcry_md_hd_t md;
+      int rc;
+
+      pk = sk_rover->pk;
+
+      /* Build the signature packet.  */
+      sig = xmalloc_clear (sizeof *sig);
+      if (duration || opt.sig_policy_url
+          || opt.sig_notations || opt.sig_keyserver_url)
+        sig->version = 4;
+      else
+        sig->version = pk->version;
+
+      keyid_from_pk (pk, sig->keyid);
+      sig->digest_algo = hash_for (pk);
+      sig->pubkey_algo = pk->pubkey_algo;
+      if (timestamp)
+        sig->timestamp = timestamp;
+      else
+        sig->timestamp = make_timestamp();
+      if (duration)
+        sig->expiredate = sig->timestamp + duration;
+      sig->sig_class = sigclass;
+
+      if (gcry_md_copy (&md, hash))
+        BUG ();
+
+      if (sig->version >= 4)
+        {
+          build_sig_subpkt_from_sig (sig);
+          mk_notation_policy_etc (sig, NULL, pk);
+        }
 
-       if( !rc ) { /* and write it */
-            PACKET pkt;
+      hash_sigversion_to_magic (md, sig);
+      gcry_md_final (md);
 
-           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 ( sk, sig, status_letter);
-           }
-           free_packet (&pkt);
-           if (rc)
-               log_error ("build signature packet failed: %s\n",
-                           g10_errstr(rc) );
+      rc = do_sign (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);
+          if (rc)
+            log_error ("build signature packet failed: %s\n", gpg_strerror (rc));
        }
-       if( rc )
-           return rc;;
+      if (rc)
+        return rc;
     }
 
-    return 0;
+  return 0;
 }
 
+
 /****************
  * Sign the files whose names are in FILENAME.
  * If DETACHED has the value true,
@@ -706,15 +752,15 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, MD_HANDLE hash,
  * uncompressed, non-armored and in binary mode.
  */
 int
-sign_file( STRLIST filenames, int detached, STRLIST locusr,
-          int encryptflag, STRLIST remusr, const char *outfile )
+sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
+          int encryptflag, strlist_t remusr, const char *outfile )
 {
     const char *fname;
-    armor_filter_context_t afx;
+    armor_filter_context_t *afx;
     compress_filter_context_t zfx;
     md_filter_context_t mfx;
     text_filter_context_t tfx;
-    progress_filter_context_t pfx;
+    progress_filter_context_t *pfx;
     encrypt_filter_context_t efx;
     IOBUF inp = NULL, out = NULL;
     PACKET pkt;
@@ -725,7 +771,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     int multifile = 0;
     u32 duration=0;
 
-    memset( &afx, 0, sizeof afx);
+    pfx = new_progress_context ();
+    afx = new_armor_context ();
     memset( &zfx, 0, sizeof zfx);
     memset( &mfx, 0, sizeof mfx);
     memset( &efx, 0, sizeof efx);
@@ -745,25 +792,18 @@ sign_file( STRLIST filenames, int detached, STRLIST 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);
 
-    if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
+    /* 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 )) )
        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( remusr, &pk_list, PUBKEY_USAGE_ENC )))
+    if (encryptflag
+        && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
       goto leave;
 
     /* prepare iobufs */
@@ -775,35 +815,37 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
         {
           iobuf_close (inp);
           inp = NULL;
-          errno = EPERM;
+          gpg_err_set_errno (EPERM);
         }
-      if( !inp ) {
-           log_error(_("can't open `%s': %s\n"), fname? fname: "[stdin]",
-                     strerror(errno) );
-           rc = G10ERR_OPEN_FILE;
-           goto leave;
+      if( !inp )
+        {
+          rc = gpg_error_from_syserror ();
+          log_error (_("can't open '%s': %s\n"), fname? fname: "[stdin]",
+                     strerror(errno) );
+          goto leave;
        }
 
-        handle_progress (&pfx, inp, fname);
+        handle_progress (pfx, inp, fname);
     }
 
     if( outfile ) {
         if (is_secured_filename ( outfile )) {
             out = NULL;
-            errno = EPERM;
+            gpg_err_set_errno (EPERM);
         }
         else
-            out = iobuf_create( outfile );
+          out = iobuf_create (outfile, 0);
        if( !out )
          {
-           log_error(_("can't create `%s': %s\n"), outfile, strerror(errno) );
-           rc = G10ERR_CREATE_FILE;
+            rc = gpg_error_from_syserror ();
+           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( 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 */
@@ -813,12 +855,18 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
        iobuf_push_filter( inp, text_filter, &tfx );
       }
 
-    mfx.md = md_open(0, 0);
+    if ( gcry_md_open (&mfx.md, 0, 0) )
+      BUG ();
     if (DBG_HASHING)
-       md_start_debug (mfx.md, "sign");
-
-   /* If we're encrypting and signing, it is reasonable to pick the
-       hash algorithm to use out of the recepient key prefs. */
+      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
+       best effort only, as in a DSA2 and smartcard world there are
+       cases where we cannot please everyone with a single hash (DSA2
+       wants >160 and smartcards want =160).  In the future this could
+       be more complex with different hashes for each sk, but the
+       current design requires a single hash for all SKs. */
     if(pk_list)
       {
        if(opt.def_digest_algo)
@@ -829,45 +877,82 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
                                      NULL)!=opt.def_digest_algo)
          log_info(_("WARNING: forcing digest algorithm %s (%d)"
                     " violates recipient preferences\n"),
-                  digest_algo_to_string(opt.def_digest_algo),
-                  opt.def_digest_algo);
+                  gcry_md_algo_name (opt.def_digest_algo),
+                  opt.def_digest_algo );
          }
        else
          {
-           int hashlen=0,algo;
+           int algo, smartcard=0;
+           union pref_hint hint;
+
+            hint.digest_length = 0;
 
            /* Of course, if the recipient asks for something
-              unreasonable (like a non-160-bit hash for DSA, for
-              example), then don't do it.  Check all sk's - if any
-              are DSA, then the hash must be 160-bit.  In the future
-              this can be more complex with different hashes for each
-              sk, but so long as there is only one signing algorithm
-              with hash restrictions, this is ok. -dms */
-
-           for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
-             if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA)
-               hashlen=20;
-
-           if((algo=
-               select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,
-                                      hashlen?&hashlen:NULL))>0)
-             recipient_digest_algo=algo;
+              unreasonable (like the wrong hash for a DSA key) then
+              don't do it.  Check all sk's - if any are DSA or live
+              on a smartcard, then the hash has restrictions and we
+              may not be able to give the recipient what they want.
+              For DSA, pass a hint for the largest q we have.  Note
+              that this means that a q>160 key will override a q=160
+              key and force the use of truncation for the q=160 key.
+              The alternative would be to ignore the recipient prefs
+              completely and get a different hash for each DSA key in
+              hash_for().  The override behavior here is more or less
+              reasonable as it is under the control of the user which
+              keys they sign with for a given message and the fact
+              that the message with multiple signatures won't be
+              usable on an implementation that doesn't understand
+              DSA2 anyway. */
+
+           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)
+                 {
+                   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);
+                   temp_hashlen = (temp_hashlen+7)/8;
+
+                   /* Pick a hash that is large enough for our
+                      largest q */
+
+                   if (hint.digest_length<temp_hashlen)
+                     hint.digest_length=temp_hashlen;
+                 }
+                /* FIXME: need to check gpg-agent for this. */
+               /* else if (sk_rover->pk->is_protected */
+                /*          && sk_rover->pk->protect.s2k.mode == 1002) */
+               /*   smartcard = 1;  */
+             }
+
+           /* Current smartcards only do 160-bit hashes.  If we have
+              to have a >160-bit hash, then we can't use the
+              recipient prefs as we'd need both =160 and >160 at the
+              same time and recipient prefs currently require a
+              single hash for all signatures.  All this may well have
+              to change as the cards add algorithms. */
+
+           if (!smartcard || (smartcard && hint.digest_length==20))
+             if ( (algo=
+                   select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,&hint)) > 0)
+               recipient_digest_algo=algo;
          }
       }
 
-    for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
-       PKT_secret_key *sk = sk_rover->sk;
-       md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version ));
-    }
+    for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
+      gcry_md_enable (mfx.md, hash_for (sk_rover->pk));
 
     if( !multifile )
        iobuf_push_filter( inp, md_filter, &mfx );
 
-    if( detached && !encryptflag && !RFC1991 )
-       afx.what = 2;
+    if( detached && !encryptflag)
+       afx->what = 2;
 
     if( opt.armor && !outfile  )
-       iobuf_push_filter( out, armor_filter, &afx );
+       push_armor_filter (afx, out);
 
     if( encryptflag ) {
        efx.pk_list = pk_list;
@@ -875,7 +960,7 @@ sign_file( STRLIST filenames, int detached, STRLIST 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;
 
@@ -888,7 +973,7 @@ sign_file( STRLIST filenames, int detached, STRLIST 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();
@@ -906,17 +991,19 @@ sign_file( STRLIST filenames, int detached, STRLIST 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)
             goto leave;
     }
 
-    /* setup the inner packet */
+    write_status_begin_signing (mfx.md);
+
+    /* Setup the inner packet. */
     if( detached ) {
        if( multifile ) {
-           STRLIST sl;
+           strlist_t sl;
 
            if( opt.verbose )
                log_info(_("signing:") );
@@ -928,18 +1015,18 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
                   {
                     iobuf_close (inp);
                     inp = NULL;
-                    errno = EPERM;
+                    gpg_err_set_errno (EPERM);
                   }
                if( !inp )
                  {
-                   log_error(_("can't open `%s': %s\n"),
+                    rc = gpg_error_from_syserror ();
+                   log_error(_("can't open '%s': %s\n"),
                              sl->d,strerror(errno));
-                   rc = G10ERR_OPEN_FILE;
                    goto leave;
                  }
-                handle_progress (&pfx, inp, sl->d);
+                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);
@@ -951,7 +1038,7 @@ sign_file( STRLIST filenames, int detached, STRLIST 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 */
@@ -971,7 +1058,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     /* write the signatures */
     rc = write_signature_packets (sk_list, out, mfx.md,
                                   opt.textmode && !outfile? 0x01 : 0x00,
-                                 0, duration, detached ? 'D':'S');
+                                 0, duration, detached ? 'D':'S', NULL);
     if( rc )
         goto leave;
 
@@ -985,10 +1072,12 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
             write_status( STATUS_END_ENCRYPTION );
     }
     iobuf_close(inp);
-    md_close( mfx.md );
+    gcry_md_close ( mfx.md );
     release_sk_list( sk_list );
     release_pk_list( pk_list );
     recipient_digest_algo=0;
+    release_progress_context (pfx);
+    release_armor_context (afx);
     return rc;
 }
 
@@ -998,92 +1087,70 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
  * make a clear signature. note that opt.armor is not needed
  */
 int
-clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
+clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
 {
-    armor_filter_context_t afx;
-    progress_filter_context_t pfx;
-    MD_HANDLE textmd = NULL;
+    armor_filter_context_t *afx;
+    progress_filter_context_t *pfx;
+    gcry_md_hd_t textmd = NULL;
     IOBUF inp = NULL, out = NULL;
     PACKET pkt;
     int rc = 0;
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
-    int old_style = RFC1991;
-    int only_md5 = 0;
     u32 duration=0;
 
-    memset( &afx, 0, sizeof afx);
+    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);
 
-    if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
+    /* 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 )) )
        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)))
       {
         iobuf_close (inp);
         inp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     if( !inp ) {
-       log_error(_("can't open `%s': %s\n"), fname? fname: "[stdin]",
-                                       strerror(errno) );
-       rc = G10ERR_OPEN_FILE;
+        rc = gpg_error_from_syserror ();
+       log_error (_("can't open '%s': %s\n"),
+                   fname? fname: "[stdin]", strerror(errno) );
        goto leave;
     }
-    handle_progress (&pfx, inp, fname);
+    handle_progress (pfx, inp, fname);
 
     if( outfile ) {
         if (is_secured_filename (outfile) ) {
             outfile = NULL;
-            errno = EPERM;
+            gpg_err_set_errno (EPERM);
         }
-        else 
-            out = iobuf_create( outfile );
+        else
+          out = iobuf_create (outfile, 0);
        if( !out )
          {
-           log_error(_("can't create `%s': %s\n"), outfile, strerror(errno) );
-           rc = G10ERR_CREATE_FILE;
+            rc = gpg_error_from_syserror ();
+           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( 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 ) {
-       PKT_secret_key *sk = sk_rover->sk;
-       if( hash_for(sk->pubkey_algo, sk->version) == 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];
@@ -1091,11 +1158,10 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
        memset( hashs_seen, 0, sizeof hashs_seen );
        iobuf_writestr(out, "Hash: " );
        for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
-           PKT_secret_key *sk = sk_rover->sk;
-           int i = hash_for(sk->pubkey_algo, sk->version);
+           int i = hash_for (sk_rover->pk);
 
            if( !hashs_seen[ i & 0xff ] ) {
-               s = digest_algo_to_string( i );
+               s = gcry_md_algo_name ( i );
                if( s ) {
                    hashs_seen[ i & 0xff ] = 1;
                    if( any )
@@ -1111,26 +1177,29 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
 
     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 );
 
-    textmd = md_open(0, 0);
-    for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
-       PKT_secret_key *sk = sk_rover->sk;
-       md_enable(textmd, hash_for(sk->pubkey_algo, sk->version));
-    }
+    if ( gcry_md_open (&textmd, 0, 0) )
+      BUG ();
+    for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
+      gcry_md_enable (textmd, hash_for(sk_rover->pk));
+
     if ( DBG_HASHING )
-       md_start_debug( textmd, "clearsign" );
-    copy_clearsig_text( out, inp, textmd, !opt.not_dash_escaped,
-                       opt.escape_from, (old_style && only_md5) );
+      gcry_md_debug ( textmd, "clearsign" );
+
+    copy_clearsig_text (out, inp, textmd, !opt.not_dash_escaped,
+                        opt.escape_from);
     /* fixme: check for read errors */
 
     /* now write the armor */
-    afx.what = 2;
-    iobuf_push_filter( out, armor_filter, &afx );
+    afx->what = 2;
+    push_armor_filter (afx, out);
 
-    /* write the signatures */
-    rc=write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C');
+    /* Write the signatures.  */
+    rc = write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C',
+                                  NULL);
     if( rc )
         goto leave;
 
@@ -1140,8 +1209,10 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
     else
        iobuf_close(out);
     iobuf_close(inp);
-    md_close( textmd );
+    gcry_md_close ( textmd );
     release_sk_list( sk_list );
+    release_progress_context (pfx);
+    release_armor_context (afx);
     return rc;
 }
 
@@ -1150,10 +1221,10 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
  * FIXME: Far too much code is duplicated - revamp the whole file.
  */
 int
-sign_symencrypt_file (const char *fname, STRLIST locusr)
+sign_symencrypt_file (const char *fname, strlist_t locusr)
 {
-    armor_filter_context_t afx;
-    progress_filter_context_t pfx;
+    armor_filter_context_t *afx;
+    progress_filter_context_t *pfx;
     compress_filter_context_t zfx;
     md_filter_context_t mfx;
     text_filter_context_t tfx;
@@ -1166,24 +1237,25 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     SK_LIST sk_rover = NULL;
     int algo;
     u32 duration=0;
+    int canceled;
 
-    memset( &afx, 0, sizeof afx);
+    pfx = new_progress_context ();
+    afx = new_armor_context ();
     memset( &zfx, 0, sizeof zfx);
     memset( &mfx, 0, sizeof mfx);
     memset( &tfx, 0, sizeof tfx);
     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);
 
-    rc = build_sk_list (locusr, &sk_list, 1, PUBKEY_USAGE_SIG);
-    if (rc) 
+    /* 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)
        goto leave;
 
     /* prepare iobufs */
@@ -1192,30 +1264,30 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
       {
         iobuf_close (inp);
         inp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     if( !inp ) {
-       log_error(_("can't open `%s': %s\n"), 
-                  fname? fname: "[stdin]", strerror(errno) );
-       rc = G10ERR_OPEN_FILE;
+        rc = gpg_error_from_syserror ();
+       log_error (_("can't open '%s': %s\n"),
+                   fname? fname: "[stdin]", strerror(errno) );
        goto leave;
     }
-    handle_progress (&pfx, inp, fname);
+    handle_progress (pfx, inp, fname);
 
     /* 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"),
-                   cipher_algo_to_string(algo) );
-    cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, NULL);
+                  openpgp_cipher_algo_name (algo) );
+    cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, &canceled);
 
     if (!cfx.dek || !cfx.dek->keylen) {
-        rc = G10ERR_PASSPHRASE;
-        log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
+        rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE);
+        log_error(_("error creating passphrase: %s\n"), gpg_strerror (rc) );
         goto leave;
     }
 
@@ -1227,31 +1299,30 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
       cfx.dek->use_mdc=1;
 
     /* now create the outfile */
-    rc = open_outfile (fname, opt.armor? 1:0, &out);
+    rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
     if (rc)
        goto leave;
 
     /* prepare to calculate the MD over the input */
     if (opt.textmode)
        iobuf_push_filter (inp, text_filter, &tfx);
-    mfx.md = md_open(0, 0);
+    if ( gcry_md_open (&mfx.md, 0, 0) )
+      BUG ();
     if ( DBG_HASHING )
-       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) {
-       PKT_secret_key *sk = sk_rover->sk;
-       md_enable (mfx.md, hash_for (sk->pubkey_algo, sk->version ));
-    }
+    for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
+      gcry_md_enable (mfx.md, hash_for (sk_rover->pk));
 
     iobuf_push_filter (inp, md_filter, &mfx);
 
     /* Push armor output filter */
     if (opt.armor)
-       iobuf_push_filter (out, armor_filter, &afx);
+       push_armor_filter (afx, out);
 
     /* 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;
@@ -1259,7 +1330,7 @@ sign_symencrypt_file (const char *fname, STRLIST 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);
     }
 
@@ -1272,24 +1343,24 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
 
     /* 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');
     if (rc)
        goto leave;
-    
+
     /* Write the signatures */
     /*(current filters: zip - encrypt - armor)*/
     rc = write_signature_packets (sk_list, out, mfx.md,
                                  opt.textmode? 0x01 : 0x00,
-                                 0, duration, 'S');
+                                 0, duration, 'S', NULL);
     if( rc )
         goto leave;
 
@@ -1303,9 +1374,11 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     }
     iobuf_close(inp);
     release_sk_list( sk_list );
-    md_close( mfx.md );
+    gcry_md_close( mfx.md );
     xfree(cfx.dek);
     xfree(s2k);
+    release_progress_context (pfx);
+    release_armor_context (afx);
     return rc;
 }
 
@@ -1320,59 +1393,58 @@ sign_symencrypt_file (const char *fname, STRLIST 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_secret_key *sk,
+                   PKT_public_key *pksk,
                    int sigclass, int digest_algo,
-                    int sigversion, u32 timestamp, u32 duration,
-                   int (*mksubpkt)(PKT_signature *, void *), void *opaque
-                  )
+                    u32 timestamp, u32 duration,
+                   int (*mksubpkt)(PKT_signature *, void *), void *opaque,
+                    const char *cache_nonce)
 {
     PKT_signature *sig;
     int rc=0;
-    MD_HANDLE md;
+    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;
-
-    if (sigversion < sk->version)
-        sigversion = sk->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;
+    sigversion = 4;
+    if (sigversion < pksk->version)
+        sigversion = pksk->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).  They still must use a
-          160-bit hash with 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((sk->pubkey_algo==PUBKEY_ALGO_RSA ||
-                sk->pubkey_algo==PUBKEY_ALGO_RSA_S) &&
-               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
+                 || 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;
       }
 
-    md = md_open( digest_algo, 0 );
+    if ( gcry_md_open (&md, digest_algo, 0 ) )
+      BUG ();
 
-    /* hash the public key certificate */
+    /* Hash the public key certificate. */
     hash_public_key( md, pk );
 
     if( sigclass == 0x18 || sigclass == 0x19 || sigclass == 0x28 )
@@ -1390,8 +1462,8 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
     sig->version = sigversion;
     sig->flags.exportable=1;
     sig->flags.revocable=1;
-    keyid_from_sk( sk, sig->keyid );
-    sig->pubkey_algo = sk->pubkey_algo;
+    keyid_from_pk (pksk, sig->keyid);
+    sig->pubkey_algo = pksk->pubkey_algo;
     sig->digest_algo = digest_algo;
     if(timestamp)
       sig->timestamp=timestamp;
@@ -1400,24 +1472,24 @@ 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, sk );
+
+    build_sig_subpkt_from_sig( sig );
+    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);
-       md_final(md);
+       gcry_md_final (md);
 
-       rc = complete_sig( sig, sk, md );
+       rc = complete_sig (sig, pksk, md, cache_nonce);
     }
 
-    md_close( md );
+    gcry_md_close (md);
     if( rc )
        free_seckey_enc( sig );
     else
@@ -1430,30 +1502,40 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
 /****************
  * Create a new signature packet based on an existing one.
  * Only user ID signatures are supported for now.
+ * PK is the public key to work on.
+ * PKSK is the key used to make the signature.
+ *
  * TODO: Merge this with make_keysig_packet.
  */
 int
 update_keysig_packet( 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_secret_key *sk,
+                      PKT_public_key *pksk,
                       int (*mksubpkt)(PKT_signature *, void *),
-                      void *opaque )
+                      void *opaque)
 {
     PKT_signature *sig;
-    int rc=0;
-    MD_HANDLE md;
+    int rc = 0;
+    int digest_algo;
+    gcry_md_hd_t md;
 
-    if ((!orig_sig || !pk || !sk)
+    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;
 
-    md = md_open( orig_sig->digest_algo, 0 );
+    if ( opt.cert_digest_algo )
+      digest_algo = opt.cert_digest_algo;
+    else
+      digest_algo = orig_sig->digest_algo;
 
-    /* hash the public key certificate and the user id */
+    if ( gcry_md_open (&md, digest_algo, 0 ) )
+      BUG ();
+
+    /* Hash the public key certificate and the user id. */
     hash_public_key( md, pk );
 
     if( orig_sig->sig_class == 0x18 )
@@ -1463,7 +1545,9 @@ 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();
@@ -1472,34 +1556,31 @@ update_keysig_packet( PKT_signature **ret_sig,
        one. */
     while(sig->timestamp<=orig_sig->timestamp)
       {
-       sleep(1);
+       gnupg_sleep (1);
        sig->timestamp=make_timestamp();
       }
 
     /* Note that already expired sigs will remain expired (with a
-       duration of 0) since build-packet.c:build_sig_subpkt_from_sig
+       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 );
+
+    if (mksubpkt)
+      rc = (*mksubpkt)(sig, opaque);
 
     if (!rc) {
         hash_sigversion_to_magic (md, sig);
-       md_final(md);
+       gcry_md_final (md);
 
-       rc = complete_sig( sig, sk, md );
+       rc = complete_sig (sig, pksk, md, NULL);
     }
 
-    md_close (md);
+    gcry_md_close (md);
     if( rc )
        free_seckey_enc (sig);
     else