Fix minor compiler warnings.
[gnupg.git] / g10 / keygen.c
index 1335eaf..9c371bd 100644 (file)
@@ -1,12 +1,12 @@
 /* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ *               2007, 2009, 2010, 2011  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 "i18n.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
+#include "pkglue.h"
 
+/* The default algorithms.  If you change them remember to change them
+   also in gpg.c:gpgconf_list.  You should also check that the value
+   is inside the bounds enforced by ask_keysize and gen_xxx.  */
+#define DEFAULT_STD_ALGO    GCRY_PK_RSA
+#define DEFAULT_STD_KEYSIZE 2048
 
-#define MAX_PREFS 30 
+/* Flag bits used during key generation.  */
+#define KEYGEN_FLAG_NO_PROTECTION 1
+#define KEYGEN_FLAG_TRANSIENT_KEY 2
+
+/* Maximum number of supported algorithm preferences.  */
+#define MAX_PREFS 30
 
 enum para_name {
   pKEYTYPE,
   pKEYLENGTH,
+  pKEYCURVE,
   pKEYUSAGE,
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
+  pSUBKEYCURVE,
   pSUBKEYUSAGE,
   pAUTHKEYTYPE,
   pNAMEREAL,
@@ -62,6 +73,8 @@ enum para_name {
   pPREFERENCES,
   pREVOKER,
   pUSERID,
+  pCREATIONDATE,
+  pKEYCREATIONDATE, /* Same in seconds since epoch.  */
   pEXPIREDATE,
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
@@ -69,7 +82,7 @@ enum para_name {
   pPASSPHRASE_DEK,
   pPASSPHRASE_S2K,
   pSERIALNO,
-  pBACKUPENCDIR,
+  pCARDBACKUPKEY,
   pHANDLE,
   pKEYSERVER
 };
@@ -82,28 +95,26 @@ struct para_data_s {
         DEK *dek;
         STRING2KEY *s2k;
         u32 expire;
+        u32 creation;
         unsigned int usage;
         struct revocation_key revkey;
         char value[1];
     } u;
 };
 
-struct output_control_s {
-    int lnr;
-    int dryrun;
-    int use_files;
-    struct {
-       char  *fname;
-       char  *newfname;
-       IOBUF stream;
-       armor_filter_context_t *afx;
-    } pub;
-    struct {
-       char  *fname;
-       char  *newfname;
-       IOBUF stream;
-       armor_filter_context_t *afx;
-    } sec;
+struct output_control_s
+{
+  int lnr;
+  int dryrun;
+  int ask_passphrase;
+  unsigned int keygen_flags;
+  int use_files;
+  struct {
+    char  *fname;
+    char  *newfname;
+    IOBUF stream;
+    armor_filter_context_t *afx;
+  } pub;
 };
 
 
@@ -124,15 +135,13 @@ static int mdc_available,ks_modify;
 
 static void do_generate_keypair( struct para_data_s *para,
                                 struct output_control_s *outctrl, int card );
-static int  write_keyblock( IOBUF out, KBNODE node );
-static int gen_card_key (int algo, int keyno, int is_primary,
-                         KBNODE pub_root, KBNODE sec_root,
-                        PKT_secret_key **ret_sk,
-                         u32 expireval, struct para_data_s *para);
+static int write_keyblock (iobuf_t out, kbnode_t node);
+static gpg_error_t gen_card_key (int algo, int keyno, int is_primary,
+                                 kbnode_t pub_root,
+                                 u32 *timestamp, u32 expireval);
 static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
-                                     KBNODE pub_root, KBNODE sec_root,
-                                     u32 expireval, struct para_data_s *para,
-                                     const char *backup_dir);
+                                     kbnode_t pub_root, u32 timestamp,
+                                     u32 expireval, struct para_data_s *para);
 
 
 static void
@@ -141,7 +150,7 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
   byte array[MAX_FINGERPRINT_LEN], *s;
   char *buf, *p;
   size_t i, n;
-  
+
   if (!handle)
     handle = "";
 
@@ -209,51 +218,51 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
 
-    if (!buf[0]) 
-        return;
-
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
 
 int
-keygen_add_key_expire( PKT_signature *sig, void *opaque )
+keygen_add_key_expire (PKT_signature *sig, void *opaque)
 {
-    PKT_public_key *pk = opaque;
-    byte buf[8];
-    u32  u;
+  PKT_public_key *pk = opaque;
+  byte buf[8];
+  u32  u;
 
-    if( pk->expiredate ) {
-        if(pk->expiredate > pk->timestamp)
-         u= pk->expiredate - pk->timestamp;
-       else
-         u= 1;
+  if (pk->expiredate)
+    {
+      if (pk->expiredate > pk->timestamp)
+        u = pk->expiredate - pk->timestamp;
+      else
+        u = 1;
 
-       buf[0] = (u >> 24) & 0xff;
-       buf[1] = (u >> 16) & 0xff;
-       buf[2] = (u >>  8) & 0xff;
-       buf[3] = u & 0xff;
-       build_sig_subpkt( sig, SIGSUBPKT_KEY_EXPIRE, buf, 4 );
+      buf[0] = (u >> 24) & 0xff;
+      buf[1] = (u >> 16) & 0xff;
+      buf[2] = (u >>   8) & 0xff;
+      buf[3] = u & 0xff;
+      build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
+    }
+  else
+    {
+      /* Make sure we don't leave a key expiration subpacket lying
+         around */
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE);
     }
-    else
-      {
-       /* Make sure we don't leave a key expiration subpacket lying
-          around */
-       delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE);
-      }
 
-    return 0;
+  return 0;
 }
 
+
 static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
-    struct opaque_data_usage_and_pk *oduap = opaque;
+  struct opaque_data_usage_and_pk *oduap = opaque;
 
-    do_add_key_flags (sig, oduap->usage);
-    return keygen_add_key_expire (sig, oduap->pk);
+  do_add_key_flags (sig, oduap->usage);
+  return keygen_add_key_expire (sig, oduap->pk);
 }
 
+
 static int
 set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
 {
@@ -262,7 +271,7 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
     for (i=0; i < *nbuf; i++ )
       if (buf[i] == val)
        {
-         log_info (_("preference `%s' duplicated\n"), item);
+         log_info (_("preference '%s' duplicated\n"), item);
          return -1;
         }
 
@@ -297,7 +306,7 @@ keygen_set_std_prefs (const char *string,int personal)
     byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
     int nsym=0, nhash=0, nzip=0, val, rc=0;
     int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
-    char dummy_string[45+1]; /* Enough for 15 items. */
+    char dummy_string[20*4+1]; /* Enough for 20 items. */
 
     if (!string || !ascii_strcasecmp (string, "default"))
       {
@@ -305,6 +314,7 @@ keygen_set_std_prefs (const char *string,int personal)
          string=opt.def_preference_list;
        else
          {
+            int any_compress = 0;
            dummy_string[0]='\0';
 
             /* The rationale why we use the order AES256,192,128 is
@@ -314,7 +324,7 @@ keygen_set_std_prefs (const char *string,int personal)
 
                  gpg -r pgpkey -r gpgkey  ---gives--> AES256
                  gpg -r gpgkey -r pgpkey  ---gives--> AES
-                 
+
                Note that by using --personal-cipher-preferences it is
                possible to prefer AES128.
             */
@@ -338,26 +348,58 @@ keygen_set_std_prefs (const char *string,int personal)
               break PGP2, but that is difficult with the current
               code, and not really worth checking as a non-RSA <=2048
               bit key wouldn't be usable by PGP2 anyway. -dms */
-           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
+           if (PGP2 && !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
              strcat(dummy_string,"S1 ");
 
-           /* SHA-1 */
-           strcat(dummy_string,"H2 ");
 
-           if (!openpgp_md_test_algo(DIGEST_ALGO_SHA256))
-             strcat(dummy_string,"H8 ");
+            /* The default hash algo order is:
+                 SHA-256, SHA-1, SHA-384, SHA-512, SHA-224.
+               Ordering SHA-1 before SHA-384 might be viewed as a bit
+               strange; it is done because we expect that soon enough
+               SHA-3 will be available and at that point there should
+               be no more need for SHA-384 etc.  Anyway this order is
+               just a default and can easily be changed by a config
+               option.  */
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
+             strcat (dummy_string, "H8 ");
+
+           strcat (dummy_string, "H2 "); /* SHA-1 */
 
-           /* RIPEMD160 */
-           strcat(dummy_string,"H3 ");
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
+             strcat (dummy_string, "H9 ");
 
-           /* ZLIB */
-           strcat(dummy_string,"Z2 ");
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512))
+             strcat (dummy_string, "H10 ");
+
+           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224))
+             strcat (dummy_string, "H11 ");
+
+           if(!check_compress_algo(COMPRESS_ALGO_ZLIB))
+              {
+                strcat(dummy_string,"Z2 ");
+                any_compress = 1;
+              }
 
            if(!check_compress_algo(COMPRESS_ALGO_BZIP2))
-             strcat(dummy_string,"Z3 ");
+              {
+                strcat(dummy_string,"Z3 ");
+                any_compress = 1;
+              }
+
+           if(!check_compress_algo(COMPRESS_ALGO_ZIP))
+              {
+                strcat(dummy_string,"Z1 ");
+                any_compress = 1;
+              }
+
+            /* In case we have no compress algo at all, declare that
+               we prefer no compresssion.  */
+            if (!any_compress)
+              strcat(dummy_string,"Z0 ");
 
-           /* ZIP */
-           strcat(dummy_string,"Z1");
+            /* Remove the trailing space.  */
+            if (*dummy_string && dummy_string[strlen (dummy_string)-1] == ' ')
+              dummy_string[strlen (dummy_string)-1] = 0;
 
            string=dummy_string;
          }
@@ -398,13 +440,7 @@ keygen_set_std_prefs (const char *string,int personal)
              modify=0;
            else
              {
-               log_info (_("invalid item `%s' in preference string\n"),tok);
-
-               /* Complain if IDEA is not available. */
-               if(ascii_strcasecmp(tok,"s1")==0
-                  || ascii_strcasecmp(tok,"idea")==0)
-                 idea_cipher_warn(1);
-
+               log_info (_("invalid item '%s' in preference string\n"),tok);
                rc=-1;
              }
          }
@@ -502,7 +538,8 @@ keygen_set_std_prefs (const char *string,int personal)
 
 /* Return a fake user ID containing the preferences.  Caller must
    free. */
-PKT_user_id *keygen_get_std_prefs(void)
+PKT_user_id *
+keygen_get_std_prefs(void)
 {
   int i,j=0;
   PKT_user_id *uid=xmalloc_clear(sizeof(PKT_user_id));
@@ -627,61 +664,63 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
   xfree (buf);
 }
 
+
 int
-keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
+keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
 {
-    if (!prefs_initialized)
-        keygen_set_std_prefs (NULL, 0);
+  (void)opaque;
 
-    if (nsym_prefs) 
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
-    else
-      {
-        delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
-        delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
-      }
+  if (!prefs_initialized)
+    keygen_set_std_prefs (NULL, 0);
 
-    if (nhash_prefs)
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
-    else
-      {
-       delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
-       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
-      }
+  if (nsym_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
+    }
 
-    if (nzip_prefs)
-        build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
-    else
-      {
-        delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
-        delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
-      }
+  if (nhash_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
+    }
+
+  if (nzip_prefs)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
+  else
+    {
+      delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
+      delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
+    }
 
-    /* Make sure that the MDC feature flag is set if needed */
-    add_feature_mdc (sig,mdc_available);
-    add_keyserver_modify (sig,ks_modify);
-    keygen_add_keyserver_url(sig,NULL);
+  /* Make sure that the MDC feature flag is set if needed.  */
+  add_feature_mdc (sig,mdc_available);
+  add_keyserver_modify (sig,ks_modify);
+  keygen_add_keyserver_url(sig,NULL);
 
-    return 0;
+  return 0;
 }
 
 
 /****************
  * Add preference to the self signature packet.
  * This is only called for packets with version > 3.
-
  */
 int
-keygen_add_std_prefs( PKT_signature *sig, void *opaque )
+keygen_add_std_prefs (PKT_signature *sig, void *opaque)
 {
-    PKT_public_key *pk = opaque;
+  PKT_public_key *pk = opaque;
 
-    do_add_key_flags (sig, pk->pubkey_usage);
-    keygen_add_key_expire( sig, opaque );
-    keygen_upd_std_prefs (sig, opaque);
-    keygen_add_keyserver_url(sig,NULL);
+  do_add_key_flags (sig, pk->pubkey_usage);
+  keygen_add_key_expire (sig, opaque );
+  keygen_upd_std_prefs (sig, opaque);
+  keygen_add_keyserver_url (sig,NULL);
 
-    return 0;
+  return 0;
 }
 
 int
@@ -750,264 +789,380 @@ keygen_add_notations(PKT_signature *sig,void *opaque)
 }
 
 int
-keygen_add_revkey(PKT_signature *sig, void *opaque)
+keygen_add_revkey (PKT_signature *sig, void *opaque)
 {
-  struct revocation_key *revkey=opaque;
+  struct revocation_key *revkey = opaque;
   byte buf[2+MAX_FINGERPRINT_LEN];
 
-  buf[0]=revkey->class;
-  buf[1]=revkey->algid;
-  memcpy(&buf[2],revkey->fpr,MAX_FINGERPRINT_LEN);
+  buf[0] = revkey->class;
+  buf[1] = revkey->algid;
+  memcpy (&buf[2], revkey->fpr, MAX_FINGERPRINT_LEN);
 
-  build_sig_subpkt(sig,SIGSUBPKT_REV_KEY,buf,2+MAX_FINGERPRINT_LEN);
+  build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+MAX_FINGERPRINT_LEN);
 
-  /* All sigs with revocation keys set are nonrevocable */
-  sig->flags.revocable=0;
+  /* All sigs with revocation keys set are nonrevocable */
+  sig->flags.revocable = 0;
   buf[0] = 0;
-  build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
+  build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1);
 
-  parse_revkeys(sig);
+  parse_revkeys (sig);
 
   return 0;
 }
 
-int
-make_backsig(PKT_signature *sig,PKT_public_key *pk,
-            PKT_public_key *sub_pk,PKT_secret_key *sub_sk)
+
+
+/* Create a back-signature.  If TIMESTAMP is not NULL, use it for the
+   signature creation time.  */
+gpg_error_t
+make_backsig (PKT_signature *sig, PKT_public_key *pk,
+              PKT_public_key *sub_pk, PKT_public_key *sub_psk,
+              u32 timestamp, const char *cache_nonce)
 {
+  gpg_error_t err;
   PKT_signature *backsig;
-  int rc;
 
-  cache_public_key(sub_pk);
+  cache_public_key (sub_pk);
 
-  rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk,0x19,0,0,0,0,NULL,NULL);
-  if(rc)
-    log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc));
+  err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19,
+                            0, 0, timestamp, 0, NULL, NULL, cache_nonce);
+  if (err)
+    log_error ("make_keysig_packet failed for backsig: %s\n", g10_errstr(err));
   else
     {
-      /* get it into a binary packed form. */
-      IOBUF backsig_out=iobuf_temp();
+      /* Get it into a binary packed form. */
+      IOBUF backsig_out = iobuf_temp();
       PACKET backsig_pkt;
-      init_packet(&backsig_pkt);
-      backsig_pkt.pkttype=PKT_SIGNATURE;
-      backsig_pkt.pkt.signature=backsig;
-      rc=build_packet(backsig_out,&backsig_pkt);
-      free_packet(&backsig_pkt);
-      if(rc)
-       log_error("build_packet failed for backsig: %s\n",g10_errstr(rc));
+
+      init_packet (&backsig_pkt);
+      backsig_pkt.pkttype = PKT_SIGNATURE;
+      backsig_pkt.pkt.signature = backsig;
+      err = build_packet (backsig_out, &backsig_pkt);
+      free_packet (&backsig_pkt);
+      if (err)
+       log_error ("build_packet failed for backsig: %s\n", g10_errstr(err));
       else
        {
-         size_t pktlen=0;
-         byte *buf=iobuf_get_temp_buffer(backsig_out);
-         /* Remove the packet header */
+         size_t pktlen = 0;
+         byte *buf = iobuf_get_temp_buffer (backsig_out);
+
+         /* Remove the packet header. */
          if(buf[0]&0x40)
            {
-             if(buf[1]<192)
+             if (buf[1] < 192)
                {
-                 pktlen=buf[1];
-                 buf+=2;
+                 pktlen = buf[1];
+                 buf += 2;
                }
-             else if(buf[1]<224)
+             else if(buf[1] < 224)
                {
-                 pktlen=(buf[1]-192)*256;
-                 pktlen+=buf[2]+192;
-                 buf+=3;
+                 pktlen = (buf[1]-192)*256;
+                 pktlen += buf[2]+192;
+                 buf += 3;
                }
-             else if(buf[1]==255)
+             else if (buf[1] == 255)
                {
-                 pktlen =buf[2] << 24;
-                 pktlen|=buf[3] << 16;
-                 pktlen|=buf[4] << 8;
-                 pktlen|=buf[5];
-                 buf+=6;
+                 pktlen  = buf[2] << 24;
+                 pktlen |= buf[3] << 16;
+                 pktlen |= buf[4] << 8;
+                 pktlen |= buf[5];
+                 buf += 6;
                }
              else
-               BUG();
+               BUG ();
            }
          else
            {
-             int mark=1;
-             switch(buf[0]&3)
+             int mark = 1;
+
+             switch (buf[0]&3)
                {
                case 3:
-                 BUG();
+                 BUG ();
                  break;
+
                case 2:
-                 pktlen =buf[mark++] << 24;
-                 pktlen|=buf[mark++] << 16;
+                 pktlen  = buf[mark++] << 24;
+                 pktlen |= buf[mark++] << 16;
+
                case 1:
-                 pktlen|=buf[mark++] << 8;
+                 pktlen |= buf[mark++] << 8;
+
                case 0:
-                 pktlen|=buf[mark++];
+                 pktlen |= buf[mark++];
                }
-             buf+=mark;
+
+             buf += mark;
            }
-         /* now make the binary blob into a subpacket */
-         build_sig_subpkt(sig,SIGSUBPKT_SIGNATURE,buf,pktlen);
 
-         iobuf_close(backsig_out);
+         /* Now make the binary blob into a subpacket.  */
+         build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen);
+
+         iobuf_close (backsig_out);
        }
     }
-  return rc;
+
+  return err;
 }
 
 
-static int
-write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
-                 struct revocation_key *revkey )
+/* Write a direct key signature to the first key in ROOT using the key
+   PSK.  REVKEY is describes the direct key signature and TIMESTAMP is
+   the timestamp to set on the signature.  */
+static gpg_error_t
+write_direct_sig (KBNODE root, PKT_public_key *psk,
+                  struct revocation_key *revkey, u32 timestamp,
+                  const char *cache_nonce)
 {
-    PACKET *pkt;
-    PKT_signature *sig;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pk;
+  gpg_error_t err;
+  PACKET *pkt;
+  PKT_signature *sig;
+  KBNODE node;
+  PKT_public_key *pk;
 
-    if( opt.verbose )
-       log_info(_("writing direct signature\n"));
+  if (opt.verbose)
+    log_info (_("writing direct signature\n"));
 
-    /* get the pk packet from the pub_tree */
-    node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
-    if( !node )
-       BUG();
-    pk = node->pkt->pkt.public_key;
+  /* Get the pk packet from the pub_tree. */
+  node = find_kbnode (root, PKT_PUBLIC_KEY);
+  if (!node)
+    BUG ();
+  pk = node->pkt->pkt.public_key;
 
-    /* we have to cache the key, so that the verification of the signature
-     * creation is able to retrieve the public key */
-    cache_public_key (pk);
+  /* We have to cache the key, so that the verification of the
+     signature creation is able to retrieve the public key.  */
+  cache_public_key (pk);
 
-    /* and make the signature */
-    rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,0,0,
-                           keygen_add_revkey,revkey);
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
+  /* Make the signature.  */
+  err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F,
+                            0, 0, timestamp, 0,
+                            keygen_add_revkey, revkey, cache_nonce);
+  if (err)
+    {
+      log_error ("make_keysig_packet failed: %s\n", g10_errstr (err) );
+      return err;
     }
 
-    pkt = xmalloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
-    return rc;
+  pkt = xmalloc_clear (sizeof *pkt);
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode (root, new_kbnode (pkt));
+  return err;
 }
 
-static int
-write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
-               unsigned int use )
-{
-    PACKET *pkt;
-    PKT_signature *sig;
-    PKT_user_id *uid;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pk;
 
-    if( opt.verbose )
-       log_info(_("writing self signature\n"));
-
-    /* get the uid packet from the list */
-    node = find_kbnode( pub_root, PKT_USER_ID );
-    if( !node )
-       BUG(); /* no user id packet in tree */
-    uid = node->pkt->pkt.user_id;
-    /* get the pk packet from the pub_tree */
-    node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
-    if( !node )
-       BUG();
-    pk = node->pkt->pkt.public_key;
-    pk->pubkey_usage = use;
-    /* we have to cache the key, so that the verification of the signature
-     * creation is able to retrieve the public key */
-    cache_public_key (pk);
-
-    /* and make the signature */
-    rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
-                            keygen_add_std_prefs, pk );
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
-    }
-
-    pkt = xmalloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( sec_root, new_kbnode( pkt ) );
-
-    pkt = xmalloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = copy_signature(NULL,sig);
-    add_kbnode( pub_root, new_kbnode( pkt ) );
-    return rc;
+
+/* Write a self-signature to the first user id in ROOT using the key
+   PSK.  USE and TIMESTAMP give the extra data we need for the
+   signature.  */
+static gpg_error_t
+write_selfsigs (KBNODE root, PKT_public_key *psk,
+               unsigned int use, u32 timestamp, const char *cache_nonce)
+{
+  gpg_error_t err;
+  PACKET *pkt;
+  PKT_signature *sig;
+  PKT_user_id *uid;
+  KBNODE node;
+  PKT_public_key *pk;
+
+  if (opt.verbose)
+    log_info (_("writing self signature\n"));
+
+  /* Get the uid packet from the list. */
+  node = find_kbnode (root, PKT_USER_ID);
+  if (!node)
+    BUG(); /* No user id packet in tree.  */
+  uid = node->pkt->pkt.user_id;
+
+  /* Get the pk packet from the pub_tree. */
+  node = find_kbnode (root, PKT_PUBLIC_KEY);
+  if (!node)
+    BUG();
+  pk = node->pkt->pkt.public_key;
+
+  /* The usage has not yet been set - do it now. */
+  pk->pubkey_usage = use;
+
+  /* We have to cache the key, so that the verification of the
+     signature creation is able to retrieve the public key.  */
+  cache_public_key (pk);
+
+  /* Make the signature.  */
+  err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13,
+                            0, 0, timestamp, 0,
+                            keygen_add_std_prefs, pk, cache_nonce);
+  if (err)
+    {
+      log_error ("make_keysig_packet failed: %s\n", g10_errstr (err));
+      return err;
+    }
+
+  pkt = xmalloc_clear (sizeof *pkt);
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode (root, new_kbnode (pkt));
+
+  return err;
 }
 
+
+/* Write the key binding signature.  If TIMESTAMP is not NULL use the
+   signature creation time.  PRI_PSK is the key use for signing.
+   SUB_PSK is a key used to create a back-signature; that one is only
+   used if USE has the PUBKEY_USAGE_SIG capability.  */
 static int
-write_keybinding( KBNODE root, KBNODE pub_root,
-                 PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
-                  unsigned int use )
-{
-    PACKET *pkt;
-    PKT_signature *sig;
-    int rc=0;
-    KBNODE node;
-    PKT_public_key *pri_pk, *sub_pk;
-    struct opaque_data_usage_and_pk oduap;
-
-    if( opt.verbose )
-       log_info(_("writing key binding signature\n"));
-
-    /* get the pk packet from the pub_tree */
-    node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
-    if( !node )
-       BUG();
-    pri_pk = node->pkt->pkt.public_key;
-    /* we have to cache the key, so that the verification of the signature
-     * creation is able to retrieve the public key */
-    cache_public_key (pri_pk);
-    /* find the last subkey */
-    sub_pk = NULL;
-    for(node=pub_root; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-           sub_pk = node->pkt->pkt.public_key;
-    }
-    if( !sub_pk )
-       BUG();
+write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
+                  unsigned int use, u32 timestamp, const char *cache_nonce)
+{
+  gpg_error_t err;
+  PACKET *pkt;
+  PKT_signature *sig;
+  KBNODE node;
+  PKT_public_key *pri_pk, *sub_pk;
+  struct opaque_data_usage_and_pk oduap;
+
+  if (opt.verbose)
+    log_info(_("writing key binding signature\n"));
+
+  /* Get the primary pk packet from the tree.  */
+  node = find_kbnode (root, PKT_PUBLIC_KEY);
+  if (!node)
+    BUG();
+  pri_pk = node->pkt->pkt.public_key;
+
+  /* We have to cache the key, so that the verification of the
+   * signature creation is able to retrieve the public key.  */
+  cache_public_key (pri_pk);
 
-    /* and make the signature */
-    oduap.usage = use;
-    oduap.pk = sub_pk;
-    rc=make_keysig_packet(&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18, 0, 0, 0, 0,
-                         keygen_add_key_flags_and_expire, &oduap );
-    if( rc ) {
-       log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
-       return rc;
+  /* Find the last subkey. */
+  sub_pk = NULL;
+  for (node = root; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        sub_pk = node->pkt->pkt.public_key;
     }
+  if (!sub_pk)
+    BUG();
 
-    /* make a backsig */
-    if(use&PUBKEY_USAGE_SIG)
-      {
-       rc=make_backsig(sig,pri_pk,sub_pk,sub_sk);
-       if(rc)
-         return rc;
-      }
+  /* Make the signature.  */
+  oduap.usage = use;
+  oduap.pk = sub_pk;
+  err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
+                            0, 0, timestamp, 0,
+                            keygen_add_key_flags_and_expire, &oduap,
+                            cache_nonce);
+  if (err)
+    {
+      log_error ("make_keysig_packet failed: %s\n", g10_errstr (err));
+      return err;
+    }
 
-    pkt = xmalloc_clear( sizeof *pkt );
-    pkt->pkttype = PKT_SIGNATURE;
-    pkt->pkt.signature = sig;
-    add_kbnode( root, new_kbnode( pkt ) );
-    return rc;
+  /* Make a backsig.  */
+  if (use & PUBKEY_USAGE_SIG)
+    {
+      err = make_backsig (sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce);
+      if (err)
+        return err;
+    }
+
+  pkt = xmalloc_clear ( sizeof *pkt );
+  pkt->pkttype = PKT_SIGNATURE;
+  pkt->pkt.signature = sig;
+  add_kbnode (root, new_kbnode (pkt) );
+  return err;
 }
 
 
+static gpg_error_t
+ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
+{
+  gpg_error_t err;
+  gcry_sexp_t list, l2;
+  char *curve;
+  int i;
+  const char *oidstr;
+  unsigned int nbits;
+
+  array[0] = NULL;
+  array[1] = NULL;
+  array[2] = NULL;
+
+  list = gcry_sexp_find_token (sexp, "public-key", 0);
+  if (!list)
+    return gpg_error (GPG_ERR_INV_OBJ);
+  l2 = gcry_sexp_cadr (list);
+  gcry_sexp_release (list);
+  list = l2;
+  if (!list)
+    return gpg_error (GPG_ERR_NO_OBJ);
+
+  l2 = gcry_sexp_find_token (list, "curve", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  curve = gcry_sexp_nth_string (l2, 1);
+  if (!curve)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (l2);
+  oidstr = openpgp_curve_to_oid (curve, &nbits);
+  if (!oidstr)
+    {
+      /* That can't happen because we used one of the curves
+         gpg_curve_to_oid knows about.  */
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  err = openpgp_oid_from_str (oidstr, &array[0]);
+  if (err)
+    goto leave;
+
+  l2 = gcry_sexp_find_token (list, "q", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l2);
+  if (!array[1])
+    {
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (list);
 
+  if (algo == PUBKEY_ALGO_ECDH)
+    {
+      array[2] = pk_ecdh_default_params (nbits);
+      if (!array[2])
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
+ leave:
+  if (err)
+    {
+      for (i=0; i < 3; i++)
+        {
+          gcry_mpi_release (array[i]);
+          array[i] = NULL;
+        }
+    }
+  return err;
+}
+
+
+/* Extract key parameters from SEXP and store them in ARRAY.  ELEMS is
+   a string where each character denotes a parameter name.  TOPNAME is
+   the name of the top element above the elements.  */
 static int
 key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
                const char *topname, const char *elems)
@@ -1036,7 +1191,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
         }
       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
       gcry_sexp_release (l2);
-      if (!array[idx]) 
+      if (!array[idx])
         {
           rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
           goto leave;
@@ -1049,7 +1204,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
     {
       for (i=0; i<idx; i++)
         {
-          xfree (array[i]);
+          gcry_mpi_release (array[i]);
           array[i] = NULL;
         }
       gcry_sexp_release (list);
@@ -1058,402 +1213,373 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
 }
 
 
+/* Create a keyblock using the given KEYGRIP.  ALGO is the OpenPGP
+   algorithm of that keygrip.  */
 static int
-genhelp_protect (DEK *dek, STRING2KEY *s2k, PKT_secret_key *sk)
+do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
+                        kbnode_t pub_root, u32 timestamp, u32 expireval,
+                        int is_subkey)
 {
-  int rc = 0;
+  int err;
+  PACKET *pkt;
+  PKT_public_key *pk;
+  gcry_sexp_t s_key;
+  const char *algoelem;
 
-  if (dek)
+  if (hexkeygrip[0] == '&')
+    hexkeygrip++;
+
+  switch (algo)
     {
-      sk->protect.algo = dek->algo;
-      sk->protect.s2k = *s2k;
-      rc = protect_secret_key (sk, dek);
-      if (rc)
-        log_error ("protect_secret_key failed: %s\n", gpg_strerror (rc) );
+    case PUBKEY_ALGO_RSA:       algoelem = "ne"; break;
+    case PUBKEY_ALGO_DSA:       algoelem = "pqgy"; break;
+    case PUBKEY_ALGO_ELGAMAL_E: algoelem = "pgy"; break;
+    case PUBKEY_ALGO_ECDH:
+    case PUBKEY_ALGO_ECDSA:     algoelem = ""; break;
+    default: return gpg_error (GPG_ERR_INTERNAL);
     }
 
-  return rc;
-}
-
-static void
-genhelp_factors (gcry_sexp_t misc_key_info, KBNODE sec_root)
-{
-#if 0 /* Not used anymore */
-  size_t n;
-  char *buf;
-  
-  if (misc_key_info)
-    {
-      /* DSA: don't know whether it makes sense to have the factors, so for now
-         we store them in the secret keyring (but they are not secret)
-         p = 2 * q * f1 * f2 * ... * fn
-         We store only f1 to f_n-1;  fn can be calculated because p and q
-         are known. */
-      n = gcry_sexp_sprint (misc_key_info, 0, NULL, 0);
-      buf = xmalloc (n+4);
-      strcpy (buf, "#::");
-      n = gcry_sexp_sprint (misc_key_info, 0, buf+3, n);
-      if (n)
-        {
-          n += 3;
-          add_kbnode (sec_root, make_comment_node_from_buffer (buf, n));
-        }
-      xfree (buf);
-      gcry_sexp_release (misc_key_info);
-    }
-#endif
-}
 
+  /* Ask the agent for the public key matching HEXKEYGRIP.  */
+  {
+    unsigned char *public;
+
+    err = agent_readkey (ctrl, 0, hexkeygrip, &public);
+    if (err)
+      return err;
+    err = gcry_sexp_sscan (&s_key, NULL,
+                           public, gcry_sexp_canon_len (public, 0, NULL, NULL));
+    xfree (public);
+    if (err)
+      return err;
+  }
 
-static int
-gen_elg(int algo, unsigned int nbits,
-        KBNODE pub_root, KBNODE sec_root, DEK *dek,
-       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval,
-        int is_subkey)
-{
-    int rc;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    gcry_sexp_t s_parms, s_key;
-    gcry_sexp_t misc_key_info;
+  /* Build a public key packet.  */
+  pk = xtrycalloc (1, sizeof *pk);
+  if (!pk)
+    {
+      err = gpg_error_from_syserror ();
+      gcry_sexp_release (s_key);
+      return err;
+    }
 
-    assert( is_ELGAMAL(algo) );
+  pk->timestamp = timestamp;
+  pk->version = 4;
+  if (expireval)
+    pk->expiredate = pk->timestamp + expireval;
+  pk->pubkey_algo = algo;
 
-    if( nbits < 512 ) {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
+  if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
+  if (err)
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      gcry_sexp_release (s_key);
+      free_public_key (pk);
+      return err;
     }
+  gcry_sexp_release (s_key);
 
-    if( (nbits % 32) ) {
-       nbits = ((nbits + 31) / 32) * 32;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
+  pkt = xtrycalloc (1, sizeof *pkt);
+  if (!pkt)
+    {
+      err = gpg_error_from_syserror ();
+      free_public_key (pk);
+      return err;
     }
 
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode (pub_root, new_kbnode (pkt));
 
-    rc = gcry_sexp_build ( &s_parms, NULL,
-                           "(genkey(%s(nbits %d)))",
-                           algo == GCRY_PK_ELG_E ? "openpgp-elg" :
-                           algo == GCRY_PK_ELG  ? "elg" : "x-oops" ,
-                           (int)nbits);
-    if (rc)
-      log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
-  
-    rc = gcry_pk_genkey (&s_key, s_parms);
-    gcry_sexp_release (s_parms);
-    if (rc)
-      {
-        log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
-        return rc;
-      }
+  return 0;
+}
 
-    sk = xmalloc_clear( sizeof *sk );
-    pk = xmalloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    if( expireval ) {
-       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    }
-    sk->pubkey_algo = pk->pubkey_algo = algo;
-/*                    pk->pkey[0] = mpi_copy( skey[0] ); */
-/*                    pk->pkey[1] = mpi_copy( skey[1] ); */
-/*                    pk->pkey[2] = mpi_copy( skey[2] ); */
-/*     sk->skey[0] = skey[0]; */
-/*     sk->skey[1] = skey[1]; */
-/*     sk->skey[2] = skey[2]; */
-/*     sk->skey[3] = skey[3]; */
-
-    rc = key_from_sexp (pk->pkey, s_key, "public-key", "pgy");
-    if (rc) 
-      {
-        log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
-        gcry_sexp_release (s_key);
-        free_secret_key (sk);
-        free_public_key (pk);
-        return rc;
-      }
-    rc = key_from_sexp (sk->skey, s_key, "private-key", "pgyx");
-    if (rc)
-      {
-        log_error("key_from_sexp failed: %s\n", gpg_strerror (rc) );
-        gcry_sexp_release (s_key);
-        free_secret_key (sk);
-        free_public_key (pk);
-        return rc;
-      }
-    misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0);
-    gcry_sexp_release (s_key);
-  
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
 
-    sk->csum = checksum_mpi( sk->skey[3] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
+/* Common code for the key generation fucntion gen_xxx.  */
+static int
+common_gen (const char *keyparms, int algo, const char *algoelem,
+            kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
+            int keygen_flags, char **cache_nonce_addr)
+{
+  int err;
+  PACKET *pkt;
+  PKT_public_key *pk;
+  gcry_sexp_t s_key;
 
-    rc = genhelp_protect (dek, s2k, sk);
-    if (rc)
-      {
-        free_public_key (pk);
-        free_secret_key (sk);
-        gcry_sexp_release (misc_key_info);
-        return rc;
-      }
+  err = agent_genkey (NULL, cache_nonce_addr, keyparms,
+                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
+  if (err)
+    {
+      log_error ("agent_genkey failed: %s\n", gpg_strerror (err) );
+      return err;
+    }
+
+  pk = xtrycalloc (1, sizeof *pk);
+  if (!pk)
+    {
+      err = gpg_error_from_syserror ();
+      gcry_sexp_release (s_key);
+      return err;
+    }
 
-    pkt = xmalloc_clear (sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    pkt->pkt.public_key = pk;
-    add_kbnode(pub_root, new_kbnode( pkt ));
+  pk->timestamp = timestamp;
+  pk->version = 4;
+  if (expireval)
+    pk->expiredate = pk->timestamp + expireval;
+  pk->pubkey_algo = algo;
+
+  if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
+  if (err)
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      gcry_sexp_release (s_key);
+      free_public_key (pk);
+      return err;
+    }
+  gcry_sexp_release (s_key);
 
-    /* Don't know whether it makes sense to have the factors, so for now
-     * we store them in the secret keyring (but they are not secret). */
-    pkt = xmalloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
+  pkt = xtrycalloc (1, sizeof *pkt);
+  if (!pkt)
+    {
+      err = gpg_error_from_syserror ();
+      free_public_key (pk);
+      return err;
+    }
 
-    genhelp_factors (misc_key_info, sec_root);
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode (pub_root, new_kbnode (pkt));
 
-    return 0;
+  return 0;
 }
 
 
-/****************
- * Generate a DSA key
+/*
+ * Generate an Elgamal key.
  */
 static int
-gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
+gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
+         u32 timestamp, u32 expireval, int is_subkey,
+         int keygen_flags, char **cache_nonce_addr)
 {
-    int rc;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    gcry_sexp_t s_parms, s_key;
-    gcry_sexp_t misc_key_info;
-    unsigned int qbits;
+  int err;
+  char *keyparms;
+  char nbitsstr[35];
 
-    if ( nbits < 512 || (!opt.flags.dsa2 && nbits > 1024)) 
-      {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
-      }
-    else if ( nbits > 3072 )
-      {
-       nbits = 3072;
-        log_info(_("keysize invalid; using %u bits\n"), nbits );
-      }
+  assert (is_ELGAMAL (algo));
 
-    if( (nbits % 64) )
-      {
-       nbits = ((nbits + 63) / 64) * 64;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
-      }
+  if (nbits < 512)
+    {
+      nbits = 2048;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
+    }
 
-    /*
-      Figure out a q size based on the key size.  FIPS 180-3 says:
-      L = 1024, N = 160
-      L = 2048, N = 224
-      L = 2048, N = 256
-      L = 3072, N = 256
-      2048/256 is an odd pair since there is also a 2048/224 and
-      3072/256.  Matching sizes is not a very exact science.
-      
-      We'll do 256 qbits for nbits over 2048, 224 for nbits over 1024
-      but less than 2048, and 160 for 1024 (DSA1).
-    */
-    if (nbits > 2048)
-      qbits = 256;
-    else if ( nbits > 1024)
-      qbits = 224;
-    else
-      qbits = 160;
-    if (qbits != 160 )
-      log_info (_("WARNING: some OpenPGP programs can't"
-                  " handle a DSA key with this digest size\n"));
-
-    rc = gcry_sexp_build (&s_parms, NULL,
-                            "(genkey(dsa(nbits %d)(qbits %d)))",
-                            (int)nbits, (int)qbits);
-    if (rc)
-      log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
-  
-    rc = gcry_pk_genkey (&s_key, s_parms);
-    gcry_sexp_release (s_parms);
-    if (rc)
-      {
-        log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
-        return rc;
-      }
+  if ((nbits % 32))
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      log_info (_("keysize rounded up to %u bits\n"), nbits );
+    }
 
-    sk = xmalloc_clear( sizeof *sk );
-    pk = xmalloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    if (expireval) 
-      sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
+  /* Note that we use transient-key only if no-protection has also
+     been enabled.  */
+  snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits);
+  keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)%s))",
+                           algo == GCRY_PK_ELG_E ? "openpgp-elg" :
+                           algo == GCRY_PK_ELG  ? "elg" : "x-oops" ,
+                           strlen (nbitsstr), nbitsstr,
+                           ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                            && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                           "(transient-key)" : "" );
+  if (!keyparms)
+    err = gpg_error_from_syserror ();
+  else
+    {
+      err = common_gen (keyparms, algo, "pgy",
+                        pub_root, timestamp, expireval, is_subkey,
+                        keygen_flags, cache_nonce_addr);
+      xfree (keyparms);
+    }
 
-    rc = key_from_sexp (pk->pkey, s_key, "public-key", "pqgy");
-    if (rc) 
-      {
-        log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc));
-        gcry_sexp_release (s_key);
-        free_public_key(pk);
-        free_secret_key(sk);
-        return rc;
-      }
-    rc = key_from_sexp (sk->skey, s_key, "private-key", "pqgyx");
-    if (rc) 
-      {
-        log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
-        gcry_sexp_release (s_key);
-        free_public_key(pk);
-        free_secret_key(sk);
-        return rc;
-      }
-    misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0);
-    gcry_sexp_release (s_key);
-  
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
+  return err;
+}
 
-    sk->csum = checksum_mpi ( sk->skey[4] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
 
-    rc = genhelp_protect (dek, s2k, sk);
-    if (rc)
-      {
-        free_public_key (pk);
-        free_secret_key (sk);
-        gcry_sexp_release (misc_key_info);
-        return rc;
-      }
+/*
+ * Generate an DSA key
+ */
+static gpg_error_t
+gen_dsa (unsigned int nbits, KBNODE pub_root,
+         u32 timestamp, u32 expireval, int is_subkey,
+         int keygen_flags, char **cache_nonce_addr)
+{
+  int err;
+  unsigned int qbits;
+  char *keyparms;
+  char nbitsstr[35];
+  char qbitsstr[35];
 
-    pkt = xmalloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    pkt->pkt.public_key = pk;
-    add_kbnode(pub_root, new_kbnode( pkt ));
+  if ( nbits < 512)
+    {
+      nbits = 2048;
+      log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
+  else if ( nbits > 3072 )
+    {
+      nbits = 3072;
+      log_info(_("keysize invalid; using %u bits\n"), nbits );
+    }
 
-    /* Don't know whether it makes sense to have the factors, so for now
-     * we store them in the secret keyring (but they are not secret)
-     * p = 2 * q * f1 * f2 * ... * fn
-     * We store only f1 to f_n-1;  fn can be calculated because p and q
-     * are known.
-     */
-    pkt = xmalloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
+  if( (nbits % 64) )
+    {
+      nbits = ((nbits + 63) / 64) * 64;
+      log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
 
-    genhelp_factors (misc_key_info, sec_root);
+  /* To comply with FIPS rules we round up to the next value unless in
+     expert mode.  */
+  if (!opt.expert && nbits > 1024 && (nbits % 1024))
+    {
+      nbits = ((nbits + 1023) / 1024) * 1024;
+      log_info(_("keysize rounded up to %u bits\n"), nbits );
+    }
 
-    return 0;
-}
+  /*
+    Figure out a q size based on the key size.  FIPS 180-3 says:
 
+    L = 1024, N = 160
+    L = 2048, N = 224
+    L = 2048, N = 256
+    L = 3072, N = 256
 
-/* 
- * Generate an RSA key.
- */
-static int
-gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
-       STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval, int is_subkey)
-{
-    int rc;
-    PACKET *pkt;
-    PKT_secret_key *sk;
-    PKT_public_key *pk;
-    gcry_sexp_t s_parms, s_key;
+    2048/256 is an odd pair since there is also a 2048/224 and
+    3072/256.  Matching sizes is not a very exact science.
 
-    assert( is_RSA(algo) );
+    We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024
+    but less than 2048, and 160 for 1024 (DSA1).
+  */
 
-    if( nbits < 1024 ) {
-       nbits = 1024;
-       log_info(_("keysize invalid; using %u bits\n"), nbits );
+  if (nbits > 2047)
+    qbits = 256;
+  else if ( nbits > 1024)
+    qbits = 224;
+  else
+    qbits = 160;
+
+  if (qbits != 160 )
+    log_info (_("WARNING: some OpenPGP programs can't"
+                " handle a DSA key with this digest size\n"));
+
+  snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits);
+  snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits);
+  keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s))",
+                           strlen (nbitsstr), nbitsstr,
+                           strlen (qbitsstr), qbitsstr,
+                           ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                            && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                           "(transient-key)" : "" );
+  if (!keyparms)
+    err = gpg_error_from_syserror ();
+  else
+    {
+      err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
+                        pub_root, timestamp, expireval, is_subkey,
+                        keygen_flags, cache_nonce_addr);
+      xfree (keyparms);
     }
 
-    if( (nbits % 32) ) {
-       nbits = ((nbits + 31) / 32) * 32;
-       log_info(_("keysize rounded up to %u bits\n"), nbits );
-    }
+  return err;
+}
 
-    rc = gcry_sexp_build (&s_parms, NULL,
-                          "(genkey(rsa(nbits %d)))",
-                          (int)nbits);
-    if (rc)
-      log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
-  
-    rc = gcry_pk_genkey (&s_key, s_parms);
-    gcry_sexp_release (s_parms);
-    if (rc)
-      {
-        log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
-        return rc;
-      }
 
-    sk = xmalloc_clear( sizeof *sk );
-    pk = xmalloc_clear( sizeof *pk );
-    sk->timestamp = pk->timestamp = make_timestamp();
-    sk->version = pk->version = 4;
-    if( expireval ) {
-       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    }
-    sk->pubkey_algo = pk->pubkey_algo = algo;
 
-    rc = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
-    if (rc) 
-      {
-        log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc));
-        gcry_sexp_release (s_key);
-        free_public_key(pk);
-        free_secret_key(sk);
-        return rc;
-      }
-    rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
-    if (rc) 
-      {
-        log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
-        gcry_sexp_release (s_key);
-        free_public_key(pk);
-        free_secret_key(sk);
-        return rc;
-      }
-    gcry_sexp_release (s_key);
+/*
+ * Generate an ECC key
+ */
+static gpg_error_t
+gen_ecc (int algo, const char *curve, kbnode_t pub_root,
+         u32 timestamp, u32 expireval, int is_subkey,
+         int keygen_flags, char **cache_nonce_addr)
+{
+  gpg_error_t err;
+  char *keyparms;
+
+  assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
+
+  if (!curve || !*curve)
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+
+  keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))",
+                           strlen (curve), curve,
+                           (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                             && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                            " transient-key" : ""),
+                           (!strcmp (curve, "Ed25519")? " eddsa":""));
+  if (!keyparms)
+    err = gpg_error_from_syserror ();
+  else
+    {
+      err = common_gen (keyparms, algo, "",
+                        pub_root, timestamp, expireval, is_subkey,
+                        keygen_flags, cache_nonce_addr);
+      xfree (keyparms);
+    }
 
-    sk->is_protected = 0;
-    sk->protect.algo = 0;
+  return err;
+}
 
-    sk->csum  = checksum_mpi (sk->skey[2] );
-    sk->csum += checksum_mpi (sk->skey[3] );
-    sk->csum += checksum_mpi (sk->skey[4] );
-    sk->csum += checksum_mpi (sk->skey[5] );
-    if( ret_sk ) /* return an unprotected version of the sk */
-       *ret_sk = copy_secret_key( NULL, sk );
 
-    rc = genhelp_protect (dek, s2k, sk);
-    if (rc)
-      {
-        free_public_key (pk);
-        free_secret_key (sk);
-        return rc;
-      }
+/*
+ * Generate an RSA key.
+ */
+static int
+gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
+         u32 timestamp, u32 expireval, int is_subkey,
+         int keygen_flags, char **cache_nonce_addr)
+{
+  int err;
+  char *keyparms;
+  char nbitsstr[35];
 
-    pkt = xmalloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
-    pkt->pkt.public_key = pk;
-    add_kbnode(pub_root, new_kbnode( pkt ));
+  assert (is_RSA(algo));
 
-    pkt = xmalloc_clear(sizeof *pkt);
-    pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk;
-    add_kbnode(sec_root, new_kbnode( pkt ));
+  if (!nbits)
+    nbits = DEFAULT_STD_KEYSIZE;
 
-    return 0;
+  if (nbits < 1024)
+    {
+      nbits = 2048;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
+    }
+
+  if ((nbits % 32))
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      log_info (_("keysize rounded up to %u bits\n"), nbits );
+    }
+
+  snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits);
+  keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))",
+                           strlen (nbitsstr), nbitsstr,
+                           ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                            && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                           "(transient-key)" : "" );
+  if (!keyparms)
+    err = gpg_error_from_syserror ();
+  else
+    {
+      err = common_gen (keyparms, algo, "ne",
+                        pub_root, timestamp, expireval, is_subkey,
+                        keygen_flags, cache_nonce_addr);
+      xfree (keyparms);
+    }
+
+  return err;
 }
 
 
@@ -1506,13 +1632,27 @@ print_key_flags(int flags)
 static unsigned int
 ask_key_flags(int algo,int subkey)
 {
+  /* TRANSLATORS: Please use only plain ASCII characters for the
+     translation.  If this is not possible use single digits.  The
+     string needs to 8 bytes long. Here is a description of the
+     functions:
+
+       s = Toggle signing capability
+       e = Toggle encryption capability
+       a = Toggle authentication capability
+       q = Finish
+  */
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
   unsigned int current=0;
   unsigned int possible=openpgp_pk_algo_usage(algo);
 
-  if(strlen(togglers)!=8)
-    BUG();
+  if ( strlen(togglers) != 8 )
+    {
+      tty_printf ("NOTE: Bad translation at %s:%d. "
+                  "Please report.\n", __FILE__, __LINE__);
+      togglers = "11223300";
+    }
 
   /* Only primary keys may certify. */
   if(subkey)
@@ -1526,7 +1666,7 @@ ask_key_flags(int algo,int subkey)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                gcry_pk_algo_name (algo));
+                openpgp_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1588,101 +1728,255 @@ ask_key_flags(int algo,int subkey)
 }
 
 
-/****************
- * Returns: 0 to create both a DSA and a Elgamal key.
- *          and only if key flags are to be written the desired usage.
- */
+/* Check whether we have a key for the key with HEXGRIP.  Returns 0 if
+   there is no such key or the OpenPGP algo number for the key.  */
 static int
-ask_algo (int addmode, unsigned int *r_usage)
+check_keygrip (ctrl_t ctrl, const char *hexgrip)
 {
-    char *answer;
-    int algo;
-
-    *r_usage = 0;
-    tty_printf(_("Please select what kind of key you want:\n"));
-    if( !addmode )
-       tty_printf(_("   (%d) DSA and Elgamal (default)\n"), 1 );
-    tty_printf(    _("   (%d) DSA (sign only)\n"), 2 );
-    if (opt.expert)
-      tty_printf(  _("   (%d) DSA (set your own capabilities)\n"), 3 );
-    if( addmode )
-       tty_printf(_("   (%d) Elgamal (encrypt only)\n"), 4 );
-    tty_printf(    _("   (%d) RSA (sign only)\n"), 5 );
-    if (addmode)
-        tty_printf(_("   (%d) RSA (encrypt only)\n"), 6 );
-    if (opt.expert)
-      tty_printf(  _("   (%d) RSA (set your own capabilities)\n"), 7 );
+  gpg_error_t err;
+  unsigned char *public;
+  size_t publiclen;
+  int algo;
 
-    for(;;) {
-       answer = cpr_get("keygen.algo",_("Your selection? "));
-       cpr_kill_prompt();
-       algo = *answer? atoi(answer): 1;
-       xfree(answer);
-       if( algo == 1 && !addmode ) {
-           algo = 0;   /* create both keys */
-           break;
+  if (hexgrip[0] == '&')
+    hexgrip++;
+
+  err = agent_readkey (ctrl, 0, hexgrip, &public);
+  if (err)
+    return 0;
+  publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
+
+  get_pk_algo_from_canon_sexp (public, publiclen, &algo);
+  xfree (public);
+
+  switch (algo)
+    {
+    case GCRY_PK_RSA:   return PUBKEY_ALGO_RSA;
+    case GCRY_PK_DSA:   return PUBKEY_ALGO_DSA;
+    case GCRY_PK_ELG_E: return PUBKEY_ALGO_ELGAMAL_E;
+    case GCRY_PK_ECDH:  return PUBKEY_ALGO_ECDH;
+    case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
+    default: return 0;
+    }
+}
+
+
+
+/* Ask for an algorithm.  The function returns the algorithm id to
+ * create. If ADDMODE is false the function won't show an option to
+ * create the primary and subkey combined and won't set R_USAGE
+ * either.  If a combined algorithm has been selected, the subkey
+ * algorithm is stored at R_SUBKEY_ALGO.  If R_KEYGRIP is given, the
+ * user has the choice to enter the keygrip of an existing key.  That
+ * keygrip is then stored at this address.  The caller needs to free
+ * it. */
+static int
+ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
+          char **r_keygrip)
+{
+  char *keygrip = NULL;
+  char *answer;
+  int algo;
+  int dummy_algo;
+
+  if (!r_subkey_algo)
+    r_subkey_algo = &dummy_algo;
+
+  tty_printf (_("Please select what kind of key you want:\n"));
+
+  if (!addmode)
+    tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
+  if (!addmode)
+    tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
+
+  tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
+  tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
+
+  if (addmode)
+    {
+      tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
+      tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
+    }
+  if (opt.expert)
+    {
+      tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
+      tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
+    }
+
+  if (opt.expert && !addmode)
+    tty_printf (_("   (%d) ECDSA and ECDH\n"), 9 );
+  if (opt.expert)
+    tty_printf (_("  (%d) ECDSA (sign only)\n"), 10 );
+  if (opt.expert)
+    tty_printf (_("  (%d) ECDSA (set your own capabilities)\n"), 11 );
+  if (opt.expert && addmode)
+    tty_printf (_("  (%d) ECDH (encrypt only)\n"), 12 );
+
+  if (opt.expert && r_keygrip)
+    tty_printf (_("  (%d) Existing key\n"), 13 );
+
+  for (;;)
+    {
+      *r_usage = 0;
+      *r_subkey_algo = 0;
+      answer = cpr_get ("keygen.algo", _("Your selection? "));
+      cpr_kill_prompt ();
+      algo = *answer? atoi (answer) : 1;
+      xfree(answer);
+      answer = NULL;
+      if (algo == 1 && !addmode)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_subkey_algo = PUBKEY_ALGO_RSA;
+          break;
        }
-       else if( algo == 7 && opt.expert ) {
-           algo = PUBKEY_ALGO_RSA;
-           *r_usage=ask_key_flags(algo,addmode);
-           break;
+      else if (algo == 2 && !addmode)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E;
+          break;
        }
-       else if( algo == 6 && addmode ) {
-           algo = PUBKEY_ALGO_RSA;
-            *r_usage = PUBKEY_USAGE_ENC;
-           break;
+      else if (algo == 3)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
        }
-       else if( algo == 5 ) {
-           algo = PUBKEY_ALGO_RSA;
-            *r_usage = PUBKEY_USAGE_SIG;
-           break;
+      else if (algo == 4)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
        }
-       else if( algo == 4 && addmode ) {
-           algo = PUBKEY_ALGO_ELGAMAL_E;
-            *r_usage = PUBKEY_USAGE_ENC;
-           break;
+      else if (algo == 5 && addmode)
+        {
+          algo = PUBKEY_ALGO_ELGAMAL_E;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
        }
-       else if( algo == 3 && opt.expert ) {
-           algo = PUBKEY_ALGO_DSA;
-           *r_usage=ask_key_flags(algo,addmode);
-           break;
+      else if (algo == 6 && addmode)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
        }
-       else if( algo == 2 ) {
-           algo = PUBKEY_ALGO_DSA;
-            *r_usage = PUBKEY_USAGE_SIG;
-           break;
+      else if (algo == 7 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_DSA;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
        }
-       else
-           tty_printf(_("Invalid selection.\n"));
+      else if (algo == 8 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_RSA;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
+       }
+      else if (algo == 9 && opt.expert && !addmode)
+        {
+          algo = PUBKEY_ALGO_ECDSA;
+          *r_subkey_algo = PUBKEY_ALGO_ECDH;
+          break;
+       }
+      else if (algo == 10 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_ECDSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
+       }
+      else if (algo == 11 && opt.expert)
+        {
+          algo = PUBKEY_ALGO_ECDSA;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
+       }
+      else if (algo == 12 && opt.expert && addmode)
+        {
+          algo = PUBKEY_ALGO_ECDH;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
+       }
+      else if (algo == 13 && opt.expert && r_keygrip)
+        {
+          for (;;)
+            {
+              xfree (answer);
+              answer = tty_get (_("Enter the keygrip: "));
+              tty_kill_prompt ();
+              trim_spaces (answer);
+              if (!*answer)
+                {
+                  xfree (answer);
+                  answer = NULL;
+                  continue;
+                }
+
+              if (strlen (answer) != 40 &&
+                       !(answer[0] == '&' && strlen (answer+1) == 40))
+                tty_printf
+                  (_("Not a valid keygrip (expecting 40 hex digits)\n"));
+              else if (!(algo = check_keygrip (ctrl, answer)) )
+                tty_printf (_("No key with this keygrip\n"));
+              else
+                break; /* Okay.  */
+            }
+          xfree (keygrip);
+          keygrip = answer;
+          answer = NULL;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
+       }
+      else
+        tty_printf (_("Invalid selection.\n"));
     }
 
-    return algo;
+  if (r_keygrip)
+    *r_keygrip = keygrip;
+  return algo;
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
 static unsigned
-ask_keysize( int algo )
+ask_keysize (int algo, unsigned int primary_keysize)
 {
-  unsigned int nbits, min, def=2048, max=4096;
+  unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
 
   if(opt.expert)
     min=512;
   else
     min=1024;
 
+  if (primary_keysize && !opt.expert)
+    {
+      /* Deduce the subkey size from the primary key size.  */
+      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+        nbits = 3072; /* For performance reasons we don't support more
+                         than 3072 bit DSA.  However we won't see this
+                         case anyway because DSA can't be used as an
+                         encryption subkey ;-). */
+      else
+        nbits = primary_keysize;
+      autocomp = 1;
+      goto leave;
+    }
+
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      if(opt.flags.dsa2)
-       {
-         def=1024;
-         max=3072;
-       }
-      else
-       {
-         tty_printf(_("DSA keypair will have %u bits.\n"),1024);
-         return 1024;
-       }
+      def=2048;
+      max=3072;
+      break;
+
+    case PUBKEY_ALGO_ECDSA:
+    case PUBKEY_ALGO_ECDH:
+      min=256;
+      def=256;
+      max=521;
       break;
 
     case PUBKEY_ALGO_RSA:
@@ -1691,49 +1985,156 @@ ask_keysize( int algo )
     }
 
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            gcry_pk_algo_name (algo), min, max);
+            openpgp_pk_algo_name (algo), min, max);
 
-  for(;;)
+  for (;;)
     {
-      char *prompt,*answer;
-
-#define PROMPTSTRING _("What keysize do you want? (%u) ")
-
-      prompt=xmalloc(strlen(PROMPTSTRING)+20);
-      sprintf(prompt,PROMPTSTRING,def);
-
-#undef PROMPTSTRING
+      char *prompt, *answer;
 
-      answer = cpr_get("keygen.size",prompt);
-      cpr_kill_prompt();
-      nbits = *answer? atoi(answer): def;
+      if (for_subkey)
+        prompt = xasprintf (_("What keysize do you want "
+                              "for the subkey? (%u) "), def);
+      else
+        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+      answer = cpr_get ("keygen.size", prompt);
+      cpr_kill_prompt ();
+      nbits = *answer? atoi (answer): def;
       xfree(prompt);
       xfree(answer);
-      
+
       if(nbits<min || nbits>max)
        tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-                  gcry_pk_algo_name (algo), min, max);
+                  openpgp_pk_algo_name (algo), min, max);
       else
        break;
     }
 
-  tty_printf(_("Requested keysize is %u bits\n"), nbits );
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
-  if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
+ leave:
+  if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
-      tty_printf(_("rounded up to %u bits\n"), nbits );
+      if (!autocomp)
+        tty_printf (_("rounded up to %u bits\n"), nbits);
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+    {
+      if (nbits != 256 && nbits != 384 && nbits != 521)
+        {
+          if (nbits < 256)
+            nbits = 256;
+          else if (nbits < 384)
+            nbits = 384;
+          else
+            nbits = 521;
+          if (!autocomp)
+            tty_printf (_("rounded to %u bits\n"), nbits);
+        }
     }
-  else if( (nbits % 32) )
+  else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
-      tty_printf(_("rounded up to %u bits\n"), nbits );
+      if (!autocomp)
+        tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
   return nbits;
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
+static char *
+ask_curve (void)
+{
+  struct {
+    const char *name;
+    int available;
+    int expert_only;
+    const char *pretty_name;
+  } curves[] = {
+    { "Ed25519",         0, 0, "Curve 25519" },
+    { "NIST P-256",      0, 1, },
+    { "NIST P-384",      0, 0, },
+    { "NIST P-521",      0, 1, },
+    { "brainpoolP256r1", 0, 1, "Brainpool P-256" },
+    { "brainpoolP384r1", 0, 1, "Brainpool P-384" },
+    { "brainpoolP512r1", 0, 1, "Brainpool P-512" },
+  };
+  int idx;
+  char *answer;
+  char *result = NULL;
+  gcry_sexp_t keyparms;
+
+  tty_printf (_("Please select which elliptic curve you want:\n"));
+
+  keyparms = NULL;
+  for (idx=0; idx < DIM(curves); idx++)
+    {
+      int rc;
+
+      curves[idx].available = 0;
+      if (!opt.expert && curves[idx].expert_only)
+        continue;
+
+      gcry_sexp_release (keyparms);
+      rc = gcry_sexp_build (&keyparms, NULL,
+                            "(public-key(ecc(curve %s)))", curves[idx].name);
+      if (rc)
+        continue;
+      if (!gcry_pk_get_curve (keyparms, 0, NULL))
+        continue;
+
+      curves[idx].available = 1;
+      tty_printf (_("   (%d) %s\n"), idx + 1,
+                  curves[idx].pretty_name?
+                  curves[idx].pretty_name:curves[idx].name);
+    }
+  gcry_sexp_release (keyparms);
+
+
+  for (;;)
+    {
+      answer = cpr_get ("keygen.curve", _("Your selection? "));
+      cpr_kill_prompt ();
+      idx = *answer? atoi (answer) : 1;
+      if (*answer && !idx)
+        {
+          /* See whether the user entered the name of the curve.  */
+          for (idx=0; idx < DIM(curves); idx++)
+            {
+              if (!opt.expert && curves[idx].expert_only)
+                continue;
+              if (!stricmp (curves[idx].name, answer)
+                  || (curves[idx].pretty_name
+                      && !stricmp (curves[idx].pretty_name, answer)))
+                break;
+            }
+          if (idx == DIM(curves))
+            idx = -1;
+        }
+      else
+        idx--;
+      xfree(answer);
+      answer = NULL;
+      if (idx < 0 || idx >= DIM (curves) || !curves[idx].available)
+        tty_printf (_("Invalid selection.\n"));
+      else
+        {
+          result = xstrdup (curves[idx].name);
+          break;
+        }
+    }
+
+  if (!result)
+    result = xstrdup (curves[0].name);
+
+  return result;
+}
+
+
 /****************
  * Parse an expire string and return its value in seconds.
  * Returns (u32)-1 on error.
@@ -1747,23 +2148,49 @@ ask_keysize( int algo )
 u32
 parse_expire_string( const char *string )
 {
-    int mult;
-    u32 seconds,abs_date=0,curtime = make_timestamp();
-
-    if( !*string )
-      seconds = 0;
-    else if ( !strncmp (string, "seconds=", 8) )
-      seconds = atoi (string+8);
-    else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime )
-      seconds = abs_date - curtime;
-    else if( (mult=check_valid_days(string)) )
-      seconds = atoi(string) * 86400L * mult;
-    else
-      seconds=(u32)-1;
+  int mult;
+  u32 seconds;
+  u32 abs_date = 0;
+  u32 curtime = make_timestamp ();
+  time_t tt;
+
+  if (!*string)
+    seconds = 0;
+  else if (!strncmp (string, "seconds=", 8))
+    seconds = atoi (string+8);
+  else if ((abs_date = scan_isodatestr(string))
+           && (abs_date+86400/2) > curtime)
+    seconds = (abs_date+86400/2) - curtime;
+  else if ((tt = isotime2epoch (string)) != (time_t)(-1))
+    seconds = (u32)tt - curtime;
+  else if ((mult = check_valid_days (string)))
+    seconds = atoi (string) * 86400L * mult;
+  else
+    seconds = (u32)(-1);
 
-    return seconds;
+  return seconds;
 }
 
+/* Parsean Creation-Date string which is either "1986-04-26" or
+   "19860426T042640".  Returns 0 on error. */
+static u32
+parse_creation_string (const char *string)
+{
+  u32 seconds;
+
+  if (!*string)
+    seconds = 0;
+  else if ( !strncmp (string, "seconds=", 8) )
+    seconds = atoi (string+8);
+  else if ( !(seconds = scan_isodatestr (string)))
+    {
+      time_t tmp = isotime2epoch (string);
+      seconds = (tmp == (time_t)(-1))? 0 : tmp;
+    }
+  return seconds;
+}
+
+
 /* object == 0 for a key, and 1 for a sig */
 u32
 ask_expire_interval(int object,const char *def_expire)
@@ -1849,12 +2276,18 @@ ask_expire_interval(int object,const char *def_expire)
                       ? _("Key expires at %s\n")
                       : _("Signature expires at %s\n"),
                       asctimestamp((ulong)(curtime + interval) ) );
-#if SIZEOF_TIME_T <= 4
+#if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T)
            if ( (time_t)((ulong)(curtime+interval)) < 0 )
              tty_printf (_("Your system can't display dates beyond 2038.\n"
                             "However, it will be correctly handled up to"
                             " 2106.\n"));
+            else
 #endif /*SIZEOF_TIME_T*/
+              if ( (time_t)((unsigned long)(curtime+interval)) < curtime )
+                {
+                  tty_printf (_("invalid value\n"));
+                  continue;
+                }
          }
 
        if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
@@ -1874,18 +2307,66 @@ ask_expiredate()
 }
 
 
+
+static PKT_user_id *
+uid_from_string (const char *string)
+{
+  size_t n;
+  PKT_user_id *uid;
+
+  n = strlen (string);
+  uid = xmalloc_clear (sizeof *uid + n);
+  uid->len = n;
+  strcpy (uid->name, string);
+  uid->ref = 1;
+  return uid;
+}
+
+
+/* Ask for a user ID.  With a MODE of 1 an extra help prompt is
+   printed for use during a new key creation.  If KEYBLOCK is not NULL
+   the function prevents the creation of an already existing user
+   ID.  */
 static char *
-ask_user_id( int mode )
+ask_user_id (int mode, KBNODE keyblock)
 {
     char *answer;
     char *aname, *acomment, *amail, *uid;
 
-    if( !mode )
-       tty_printf( _("\n"
+    if ( !mode )
+      {
+        /* TRANSLATORS: This is the new string telling the user what
+           gpg is now going to do (i.e. ask for the parts of the user
+           ID).  Note that if you do not tyranslated this string, a
+           different string will be used used, which might still have
+           a correct transaltion.  */
+       const char *s1 =
+          N_("\n"
+             "GnuPG needs to construct a user ID to identify your key.\n"
+             "\n");
+        const char *s2 = _(s1);
+
+        if (!strcmp (s1, s2))
+          {
+            /* There is no translation for the string thus we to use
+               the old info text.  gettext has no way to tell whether
+               a translation is actually available, thus we need to
+               to compare again. */
+            /* TRANSLATORS: This string is in general not anymore used
+               but you should keep your existing translation.  In case
+               the new string is not translated this old string will
+               be used. */
+            const char *s3 = N_("\n"
 "You need a user ID to identify your key; "
                                         "the software constructs the user ID\n"
 "from the Real Name, Comment and Email Address in this form:\n"
-"    \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
+"    \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n");
+            const char *s4 = _(s3);
+            if (strcmp (s3, s4))
+              s2 = s3; /* A translation exists - use it. */
+          }
+        tty_printf ("%s", s2) ;
+      }
     uid = aname = acomment = amail = NULL;
     for(;;) {
        char *p;
@@ -1956,27 +2437,42 @@ ask_user_id( int mode )
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
            if( *p & 0x80 ) {
-               tty_printf(_("You are using the `%s' character set.\n"),
+               tty_printf(_("You are using the '%s' character set.\n"),
                           get_native_charset() );
                break;
            }
        }
 
        tty_printf(_("You selected this USER-ID:\n    \"%s\"\n\n"), uid);
-       /* fixme: add a warning if this user-id already exists */
+
        if( !*amail && !opt.allow_freeform_uid
            && (strchr( aname, '@' ) || strchr( acomment, '@'))) {
            fail = 1;
-           tty_printf(_("Please don't put the email address "
-                         "into the real name or the comment\n") );
+            tty_printf(_("Please don't put the email address "
+                         "into the real name or the comment\n") );
        }
 
+        if (!fail && keyblock)
+          {
+            PKT_user_id *uidpkt = uid_from_string (uid);
+            KBNODE node;
+
+            for (node=keyblock; node && !fail; node=node->next)
+              if (!is_deleted_kbnode (node)
+                  && node->pkt->pkttype == PKT_USER_ID
+                  && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id))
+               fail = 1;
+            if (fail)
+              tty_printf (_("Such a user ID already exists on this key!\n"));
+            free_user_id (uidpkt);
+          }
+
        for(;;) {
             /* TRANSLATORS: These are the allowed answers in
                lower and uppercase.  Below you will find the matching
                string which should be translated accordingly and the
                letter changed to match the one in the answer string.
-               
+
                  n = Change name
                  c = Change comment
                  e = Change email
@@ -1988,7 +2484,7 @@ ask_user_id( int mode )
            if( strlen(ansstr) != 10 )
                BUG();
            if( cpr_enabled() ) {
-               answer = xstrdup(ansstr+6);
+                answer = xstrdup (ansstr + (fail?8:6));
                answer[1] = 0;
            }
            else {
@@ -2045,21 +2541,28 @@ ask_user_id( int mode )
 }
 
 
+/*  MODE  0 - standard
+          1 - Ask for passphrase of the card backup key.  */
 static DEK *
-do_ask_passphrase ( STRING2KEY **ret_s2k, int *r_canceled )
+do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 {
     DEK *dek = NULL;
     STRING2KEY *s2k;
     const char *errtext = NULL;
+    const char *custdesc = NULL;
 
     tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
 
+    if (mode == 1)
+      custdesc = _("Please enter a passphrase to protect the off-card "
+                   "backup of the new encryption key.");
+
     s2k = xmalloc_secure( sizeof *s2k );
     for(;;) {
        s2k->mode = opt.s2k_mode;
        s2k->hash_algo = S2K_DIGEST_ALGO;
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,
-                                 errtext, r_canceled);
+       dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                                     errtext, custdesc, NULL, r_canceled);
         if (!dek && *r_canceled) {
            xfree(dek); dek = NULL;
            xfree(s2k); s2k = NULL;
@@ -2086,71 +2589,83 @@ do_ask_passphrase ( STRING2KEY **ret_s2k, int *r_canceled )
 }
 
 
+/* Basic key generation.  Here we divert to the actual generation
+   routines based on the requested algorithm.  */
 static int
-do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
-          DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate,
-          int is_subkey )
+do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
+           u32 timestamp, u32 expiredate, int is_subkey,
+           int keygen_flags, char **cache_nonce_addr)
 {
-  int rc=0;
+  gpg_error_t err;
 
-  if( !opt.batch )
-    tty_printf(_(
+  /* Fixme: The entropy collecting message should be moved to a
+     libgcrypt progress handler.  */
+  if (!opt.batch)
+    tty_printf (_(
 "We need to generate a lot of random bytes. It is a good idea to perform\n"
 "some other action (type on the keyboard, move the mouse, utilize the\n"
 "disks) during the prime generation; this gives the random number\n"
 "generator a better chance to gain enough entropy.\n") );
 
-  if( algo == PUBKEY_ALGO_ELGAMAL_E )
-    rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
-                is_subkey);
-  else if( algo == PUBKEY_ALGO_DSA )
-    rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
-                is_subkey);
-  else if( algo == PUBKEY_ALGO_RSA )
-    rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate,
-                is_subkey);
+  if (algo == PUBKEY_ALGO_ELGAMAL_E)
+    err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
+                   keygen_flags, cache_nonce_addr);
+  else if (algo == PUBKEY_ALGO_DSA)
+    err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
+                   keygen_flags, cache_nonce_addr);
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
+                   keygen_flags, cache_nonce_addr);
+  else if (algo == PUBKEY_ALGO_RSA)
+    err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
+                   keygen_flags, cache_nonce_addr);
   else
     BUG();
 
-  return rc;
+  return err;
 }
 
 
-/****************
- * Generate a new user id packet, or return NULL if canceled
- */
+/* Generate a new user id packet or return NULL if canceled.  If
+   KEYBLOCK is not NULL the function prevents the creation of an
  already existing user ID.  */
 PKT_user_id *
-generate_user_id()
+generate_user_id (KBNODE keyblock)
 {
-    PKT_user_id *uid;
-    char *p;
-    size_t n;
+  char *p;
 
-    p = ask_user_id( 1 );
-    if( !p )
-       return NULL;
-    n = strlen(p);
-    uid = xmalloc_clear( sizeof *uid + n - 1 );
-    uid->len = n;
-    strcpy(uid->name, p);
-    uid->ref = 1;
-    return uid;
+  p = ask_user_id (1, keyblock);
+  if (!p)
+    return NULL;  /* Canceled. */
+  return uid_from_string (p);
 }
 
 
+/* Append R to the linked list PARA.  */
+static void
+append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+{
+  assert (para);
+  while (para->next)
+    para = para->next;
+  para->next = r;
+}
+
+/* Release the parameter list R.  */
 static void
-release_parameter_list( struct para_data_s *r )
+release_parameter_list (struct para_data_s *r)
 {
-    struct para_data_s *r2;
+  struct para_data_s *r2;
 
-    for( ; r ; r = r2 ) {
-       r2 = r->next;
-       if( r->key == pPASSPHRASE_DEK )
-           xfree( r->u.dek );
-       else if( r->key == pPASSPHRASE_S2K )
-           xfree( r->u.s2k );
+  for (; r ; r = r2)
+    {
+      r2 = r->next;
+      if (r->key == pPASSPHRASE_DEK)
+        xfree (r->u.dek);
+      else if (r->key == pPASSPHRASE_S2K )
+        xfree (r->u.s2k);
 
-       xfree(r);
+      xfree (r);
     }
 }
 
@@ -2172,26 +2687,42 @@ get_parameter_value( struct para_data_s *para, enum para_name key )
 }
 
 static int
-get_parameter_algo( struct para_data_s *para, enum para_name key )
+get_parameter_algo( struct para_data_s *para, enum para_name key,
+                    int *r_default)
 {
-    int i;
-    struct para_data_s *r = get_parameter( para, key );
-    if( !r )
-       return -1;
-    if( digitp( r->u.value ) )
-       i = atoi( r->u.value );
-    else if ( !strcmp ( r->u.value, "ELG-E")
-              || !strcmp ( r->u.value, "ELG") )
-        i = GCRY_PK_ELG_E;
-    else
-        i = gcry_pk_map_name (r->u.value);
-    if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
-      i = 0; /* we don't want to allow generation of these algorithms */
-    return i;
+  int i;
+  struct para_data_s *r = get_parameter( para, key );
+
+  if (r_default)
+    *r_default = 0;
+
+  if (!r)
+    return -1;
+
+  if (!ascii_strcasecmp (r->u.value, "default"))
+    {
+      /* Note: If you change this default algo, remember to change it
+         also in gpg.c:gpgconf_list.  */
+      i = DEFAULT_STD_ALGO;
+      if (r_default)
+        *r_default = 1;
+    }
+  else if (digitp (r->u.value))
+    i = atoi( r->u.value );
+  else if (!strcmp (r->u.value, "ELG-E")
+           || !strcmp (r->u.value, "ELG"))
+    i = GCRY_PK_ELG_E;
+  else
+    i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
+
+  if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
+    i = 0; /* we don't want to allow generation of these algorithms */
+  return i;
 }
 
-/* 
- * parse the usage parameter and set the keyflags.  Return true on error.
+/*
+ * Parse the usage parameter and set the keyflags.  Returns -1 on
+ * error, 0 for no usage given or 1 for usage available.
  */
 static int
 parse_parameter_usage (const char *fname,
@@ -2203,7 +2734,7 @@ parse_parameter_usage (const char *fname,
 
     if( !r )
        return 0; /* none (this is an optional parameter)*/
-    
+
     use = 0;
     pn = r->u.value;
     while ( (p = strsep (&pn, " \t,")) ) {
@@ -2281,16 +2812,18 @@ parse_revocation_key (const char *fname,
 static u32
 get_parameter_u32( struct para_data_s *para, enum para_name key )
 {
-    struct para_data_s *r = get_parameter( para, key );
-
-    if( !r )
-       return 0;
-    if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
-       return r->u.expire;
-    if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
-       return r->u.usage;
+  struct para_data_s *r = get_parameter( para, key );
 
-    return (unsigned int)strtoul( r->u.value, NULL, 10 );
+  if( !r )
+    return 0;
+  if( r->key == pKEYCREATIONDATE )
+    return r->u.creation;
+  if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
+    return r->u.expire;
+  if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
+    return r->u.usage;
+
+  return (unsigned int)strtoul( r->u.value, NULL, 10 );
 }
 
 static unsigned int
@@ -2299,20 +2832,6 @@ get_parameter_uint( struct para_data_s *para, enum para_name key )
     return get_parameter_u32( para, key );
 }
 
-static DEK *
-get_parameter_dek( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r = get_parameter( para, key );
-    return r? r->u.dek : NULL;
-}
-
-static STRING2KEY *
-get_parameter_s2k( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r = get_parameter( para, key );
-    return r? r->u.s2k : NULL;
-}
-
 static struct revocation_key *
 get_parameter_revkey( struct para_data_s *para, enum para_name key )
 {
@@ -2328,63 +2847,90 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
   const char *s1, *s2, *s3;
   size_t n;
   char *p;
-  int have_user_id=0,err,algo;
+  int is_default = 0;
+  int have_user_id = 0;
+  int err, algo;
 
   /* Check that we have all required parameters. */
   r = get_parameter( para, pKEYTYPE );
   if(r)
     {
-      algo=get_parameter_algo(para,pKEYTYPE);
+      algo = get_parameter_algo (para, pKEYTYPE, &is_default);
       if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG))
        {
-         log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
+         log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
          return -1;
        }
     }
   else
     {
-      log_error("%s: no Key-Type specified\n",fname);
+      log_error ("%s: no Key-Type specified\n",fname);
       return -1;
     }
 
-  err=parse_parameter_usage (fname, para, pKEYUSAGE);
-  if(err==0)
+  err = parse_parameter_usage (fname, para, pKEYUSAGE);
+  if (!err)
     {
-      /* Default to algo capabilities if key-usage is not provided */
-      r=xmalloc_clear(sizeof(*r));
-      r->key=pKEYUSAGE;
-      r->u.usage=openpgp_pk_algo_usage(algo);
-      r->next=para;
-      para=r;
+      /* Default to algo capabilities if key-usage is not provided and
+         no default algorithm has been requested.  */
+      r = xmalloc_clear(sizeof(*r));
+      r->key = pKEYUSAGE;
+      r->u.usage = (is_default
+                    ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)
+                    : openpgp_pk_algo_usage(algo));
+      append_to_parameter (para, r);
     }
-  else if(err==-1)
+  else if (err == -1)
     return -1;
+  else
+    {
+      r = get_parameter (para, pKEYUSAGE);
+      if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo)))
+        {
+          log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n",
+                     fname, r->lnr, algo);
+          return -1;
+        }
+    }
 
+  is_default = 0;
   r = get_parameter( para, pSUBKEYTYPE );
   if(r)
     {
-      algo=get_parameter_algo( para, pSUBKEYTYPE);
+      algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default);
       if (openpgp_pk_test_algo (algo))
        {
-         log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
+         log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
          return -1;
        }
 
-      err=parse_parameter_usage (fname, para, pSUBKEYUSAGE);
-      if(err==0)
+      err = parse_parameter_usage (fname, para, pSUBKEYUSAGE);
+      if (!err)
        {
          /* Default to algo capabilities if subkey-usage is not
             provided */
-         r=xmalloc_clear(sizeof(*r));
-         r->key=pSUBKEYUSAGE;
-         r->u.usage=openpgp_pk_algo_usage(algo);
-         r->next=para;
-         para=r;
+         r = xmalloc_clear (sizeof(*r));
+         r->key = pSUBKEYUSAGE;
+         r->u.usage = (is_default
+                        ? PUBKEY_USAGE_ENC
+                        : openpgp_pk_algo_usage (algo));
+          append_to_parameter (para, r);
        }
-      else if(err==-1)
+      else if (err == -1)
        return -1;
+      else
+        {
+          r = get_parameter (para, pSUBKEYUSAGE);
+          if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo)))
+            {
+              log_error ("%s:%d: specified Subkey-Usage not allowed"
+                         " for algo %d\n", fname, r->lnr, algo);
+              return -1;
+            }
+        }
     }
 
+
   if( get_parameter_value( para, pUSERID ) )
     have_user_id=1;
   else
@@ -2405,8 +2951,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
            p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
-         r->next = para;
-         para = r;
+          append_to_parameter (para, r);
          have_user_id=1;
        }
     }
@@ -2434,47 +2979,99 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
        }
       else
        {
-         log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
+         log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
+         return -1;
+       }
+    }
+
+  /* Set revoker, if any. */
+  if (parse_revocation_key (fname, para, pREVOKER))
+    return -1;
+
+  /* Make DEK and S2K from the Passphrase. */
+  if (outctrl->ask_passphrase)
+    {
+      /* %ask-passphrase is active - ignore pPASSPRASE and ask.  This
+         feature is required so that GUIs are able to do a key
+         creation but have gpg-agent ask for the passphrase.  */
+      int canceled = 0;
+      STRING2KEY *s2k;
+      DEK *dek;
+
+      dek = do_ask_passphrase (&s2k, 0, &canceled);
+      if (dek)
+        {
+          r = xmalloc_clear( sizeof *r );
+          r->key = pPASSPHRASE_DEK;
+          r->u.dek = dek;
+          append_to_parameter (para, r);
+          r = xmalloc_clear( sizeof *r );
+          r->key = pPASSPHRASE_S2K;
+          r->u.s2k = s2k;
+          append_to_parameter (para, r);
+        }
+
+      if (canceled)
+        {
+         log_error ("%s:%d: key generation canceled\n", fname, r->lnr );
+          return -1;
+        }
+    }
+  else
+    {
+      r = get_parameter( para, pPASSPHRASE );
+      if ( r && *r->u.value )
+        {
+          /* We have a plain text passphrase - create a DEK from it.
+           * It is a little bit ridiculous to keep it in secure memory
+           * but because we do this always, why not here.  */
+          STRING2KEY *s2k;
+          DEK *dek;
+
+          s2k = xmalloc ( sizeof *s2k );
+          s2k->mode = opt.s2k_mode;
+          s2k->hash_algo = S2K_DIGEST_ALGO;
+          set_next_passphrase ( r->u.value );
+          dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
+                                   NULL, NULL);
+          if (!dek)
+            {
+              log_error ("%s:%d: error post processing the passphrase\n",
+                         fname, r->lnr );
+              xfree (s2k);
+              return -1;
+            }
+          set_next_passphrase (NULL);
+          memset (r->u.value, 0, strlen(r->u.value));
+
+          r = xmalloc_clear (sizeof *r);
+          r->key = pPASSPHRASE_S2K;
+          r->u.s2k = s2k;
+          append_to_parameter (para, r);
+          r = xmalloc_clear (sizeof *r);
+          r->key = pPASSPHRASE_DEK;
+          r->u.dek = dek;
+          append_to_parameter (para, r);
+        }
+    }
+
+  /* Make KEYCREATIONDATE from Creation-Date.  */
+  r = get_parameter (para, pCREATIONDATE);
+  if (r && *r->u.value)
+    {
+      u32 seconds;
+
+      seconds = parse_creation_string (r->u.value);
+      if (!seconds)
+       {
+         log_error ("%s:%d: invalid creation date\n", fname, r->lnr );
          return -1;
        }
+      r->u.creation = seconds;
+      r->key = pKEYCREATIONDATE;  /* Change that entry. */
     }
 
-  /* Set revoker, if any. */
-  if (parse_revocation_key (fname, para, pREVOKER))
-    return -1;
-
-  /* make DEK and S2K from the Passphrase */
-  r = get_parameter( para, pPASSPHRASE );
-  if( r && *r->u.value ) {
-    /* we have a plain text passphrase - create a DEK from it.
-     * It is a little bit ridiculous to keep it ih secure memory
-     * but becuase we do this alwasy, why not here */
-    STRING2KEY *s2k;
-    DEK *dek;
-
-    s2k = xmalloc_secure( sizeof *s2k );
-    s2k->mode = opt.s2k_mode;
-    s2k->hash_algo = S2K_DIGEST_ALGO;
-    set_next_passphrase( r->u.value );
-    dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                            NULL, NULL);
-    set_next_passphrase( NULL );
-    assert( dek );
-    memset( r->u.value, 0, strlen(r->u.value) );
-
-    r = xmalloc_clear( sizeof *r );
-    r->key = pPASSPHRASE_S2K;
-    r->u.s2k = s2k;
-    r->next = para;
-    para = r;
-    r = xmalloc_clear( sizeof *r );
-    r->key = pPASSPHRASE_DEK;
-    r->u.dek = dek;
-    r->next = para;
-    para = r;
-  }
-
-  /* make KEYEXPIRE from Expire-Date */
+  /* Make KEYEXPIRE from Expire-Date.  */
   r = get_parameter( para, pEXPIREDATE );
   if( r && *r->u.value )
     {
@@ -2492,15 +3089,9 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       r = xmalloc_clear( sizeof *r + 20 );
       r->key = pSUBKEYEXPIRE;
       r->u.expire = seconds;
-      r->next = para;
-      para = r;
+      append_to_parameter (para, r);
     }
 
-  if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
-    log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
-    return -1;
-  }
-
   do_generate_keypair( para, outctrl, card );
   return 0;
 }
@@ -2519,14 +3110,17 @@ read_parameter_file( const char *fname )
     } keywords[] = {
        { "Key-Type",       pKEYTYPE},
        { "Key-Length",     pKEYLENGTH },
+       { "Key-Curve",      pKEYCURVE },
        { "Key-Usage",      pKEYUSAGE },
        { "Subkey-Type",    pSUBKEYTYPE },
        { "Subkey-Length",  pSUBKEYLENGTH },
+       { "Subkey-Curve",   pSUBKEYCURVE },
        { "Subkey-Usage",   pSUBKEYUSAGE },
        { "Name-Real",      pNAMEREAL },
        { "Name-Email",     pNAMEEMAIL },
        { "Name-Comment",   pNAMECOMMENT },
        { "Expire-Date",    pEXPIREDATE },
+       { "Creation-Date",  pCREATIONDATE },
        { "Passphrase",     pPASSPHRASE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
@@ -2546,7 +3140,6 @@ read_parameter_file( const char *fname )
 
     memset( &outctrl, 0, sizeof( outctrl ) );
     outctrl.pub.afx = new_armor_context ();
-    outctrl.sec.afx = new_armor_context ();
 
     if( !fname || !*fname)
       fname = "-";
@@ -2556,13 +3149,13 @@ read_parameter_file( const char *fname )
       {
         iobuf_close (fp);
         fp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     if (!fp) {
-      log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
+      log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
       return;
     }
-    iobuf_ioctl (fp, 3, 1, NULL); /* No file caching. */
+    iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
 
     lnr = 0;
     err = NULL;
@@ -2595,10 +3188,18 @@ read_parameter_file( const char *fname )
                log_info("%s\n", value );
            else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
                outctrl.dryrun = 1;
+           else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) )
+               outctrl.ask_passphrase = 1;
+           else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) )
+               outctrl.ask_passphrase = 0;
+           else if( !ascii_strcasecmp( keyword, "%no-protection" ) )
+                outctrl.keygen_flags |= KEYGEN_FLAG_NO_PROTECTION;
+           else if( !ascii_strcasecmp( keyword, "%transient-key" ) )
+                outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY;
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
                if (proc_parameter_file( para, fname, &outctrl, 0 ))
-                  print_status_key_not_created 
+                  print_status_key_not_created
                     (get_parameter_value (para, pHANDLE));
                release_parameter_list( para );
                para = NULL;
@@ -2613,16 +3214,10 @@ read_parameter_file( const char *fname )
                }
            }
            else if( !ascii_strcasecmp( keyword, "%secring" ) ) {
-               if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
-                   ; /* still the same file - ignore it */
-               else {
-                  xfree( outctrl.sec.newfname );
-                  outctrl.sec.newfname = xstrdup( value );
-                  outctrl.use_files = 1;
-               }
+              /* Ignore this command.  */
            }
            else
-               log_info("skipping control `%s' (%s)\n", keyword, value );
+               log_info("skipping control '%s' (%s)\n", keyword, value );
 
 
            continue;
@@ -2695,43 +3290,35 @@ read_parameter_file( const char *fname )
 
     if( outctrl.use_files ) { /* close open streams */
        iobuf_close( outctrl.pub.stream );
-       iobuf_close( outctrl.sec.stream );
 
         /* Must invalidate that ugly cache to actually close it.  */
         if (outctrl.pub.fname)
-          iobuf_ioctl (NULL, 2, 0, (char*)outctrl.pub.fname);
-        if (outctrl.sec.fname)
-          iobuf_ioctl (NULL, 2, 0, (char*)outctrl.sec.fname);
+          iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
+                       0, (char*)outctrl.pub.fname);
 
        xfree( outctrl.pub.fname );
        xfree( outctrl.pub.newfname );
-       xfree( outctrl.sec.fname );
-       xfree( outctrl.sec.newfname );
     }
 
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
-    release_armor_context (outctrl.sec.afx);
 }
 
 
 /*
  * Generate a keypair (fname is only used in batch mode) If
  * CARD_SERIALNO is not NULL the function will create the keys on an
- * OpenPGP Card.  If BACKUP_ENCRYPTION_DIR has been set and
- * CARD_SERIALNO is NOT NULL, the encryption key for the card gets
- * generate in software, imported to the card and a backup file
- * written to directory given by this argument .
+ * OpenPGP Card.  If CARD_BACKUP_KEY has been set and CARD_SERIALNO is
+ * NOT NULL, the encryption key for the card is generated on the host,
+ * imported to the card and a backup file created by gpg-agent.
  */
 void
-generate_keypair (const char *fname, const char *card_serialno, 
-                  const char *backup_encryption_dir)
+generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
+                  int card_backup_key)
 {
   unsigned int nbits;
   char *uid = NULL;
-  DEK *dek;
-  STRING2KEY *s2k;
   int algo;
   unsigned int use;
   int both = 0;
@@ -2739,17 +3326,16 @@ generate_keypair (const char *fname, const char *card_serialno,
   struct para_data_s *para = NULL;
   struct para_data_s *r;
   struct output_control_s outctrl;
-  int canceled;
-  
+
   memset( &outctrl, 0, sizeof( outctrl ) );
-  
+
   if (opt.batch && card_serialno)
     {
       /* We don't yet support unattended key generation. */
       log_error (_("can't do this in batch mode\n"));
       return;
     }
-  
+
   if (opt.batch)
     {
       read_parameter_file( fname );
@@ -2764,9 +3350,9 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy( r->u.value, card_serialno);
       r->next = para;
       para = r;
-       
+
       algo = PUBKEY_ALGO_RSA;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pKEYTYPE;
       sprintf( r->u.value, "%d", algo );
@@ -2777,7 +3363,7 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy (r->u.value, "sign");
       r->next = para;
       para = r;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
       sprintf( r->u.value, "%d", algo );
@@ -2788,18 +3374,18 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pAUTHKEYTYPE;
       sprintf( r->u.value, "%d", algo );
       r->next = para;
       para = r;
 
-      if (backup_encryption_dir)
+      if (card_backup_key)
         {
-          r = xcalloc (1, sizeof *r + strlen (backup_encryption_dir) );
-          r->key = pBACKUPENCDIR;
-          strcpy (r->u.value, backup_encryption_dir);
+          r = xcalloc (1, sizeof *r + 1);
+          r->key = pCARDBACKUPKEY;
+          strcpy (r->u.value, "1");
           r->next = para;
           para = r;
         }
@@ -2807,31 +3393,50 @@ generate_keypair (const char *fname, const char *card_serialno,
     }
   else
     {
-      algo = ask_algo( 0, &use );
-      if( !algo )
-        { /* default: DSA with ElG subkey of the specified size */
+      int subkey_algo;
+      char *curve = NULL;
+
+      /* Fixme: To support creating a primary key by keygrip we better
+         also define the keyword for the parameter file.  Note that
+         the subkey case will never be asserted if a keygrip has been
+         given.  */
+      algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL);
+      if (subkey_algo)
+        {
+          /* Create primary and subkey at once.  */
           both = 1;
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+          sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
-         nbits = ask_keysize( PUBKEY_ALGO_DSA );
-         r = xmalloc_clear( sizeof *r + 20 );
-         r->key = pKEYLENGTH;
-         sprintf( r->u.value, "%u", nbits);
-         r->next = para;
-         para = r;
+          if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+            {
+              curve = ask_curve ();
+              r = xmalloc_clear (sizeof *r + strlen (curve));
+              r->key = pKEYCURVE;
+              strcpy (r->u.value, curve);
+              r->next = para;
+              para = r;
+            }
+          else
+            {
+              nbits = ask_keysize (algo, 0);
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYLENGTH;
+              sprintf( r->u.value, "%u", nbits);
+              r->next = para;
+              para = r;
+            }
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
           r->next = para;
           para = r;
-           
-          algo = PUBKEY_ALGO_ELGAMAL_E;
+
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pSUBKEYTYPE;
-          sprintf( r->u.value, "%d", algo );
+          sprintf( r->u.value, "%d", subkey_algo);
           r->next = para;
           para = r;
           r = xmalloc_clear( sizeof *r + 20 );
@@ -2840,14 +3445,14 @@ generate_keypair (const char *fname, const char *card_serialno,
           r->next = para;
           para = r;
         }
-      else 
+      else
         {
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYTYPE;
           sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
-           
+
           if (use)
             {
               r = xmalloc_clear( sizeof *r + 25 );
@@ -2859,17 +3464,32 @@ generate_keypair (const char *fname, const char *card_serialno,
               r->next = para;
               para = r;
             }
-           
+          nbits = 0;
         }
 
-      nbits = ask_keysize( algo );
-      r = xmalloc_clear( sizeof *r + 20 );
-      r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
-      sprintf( r->u.value, "%u", nbits);
-      r->next = para;
-      para = r;
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+        {
+          if (!both)
+            curve = ask_curve ();
+          r = xmalloc_clear (sizeof *r + strlen (curve));
+          r->key = both? pSUBKEYCURVE : pKEYCURVE;
+          strcpy (r->u.value, curve);
+          r->next = para;
+          para = r;
+        }
+      else
+        {
+          nbits = ask_keysize (both? subkey_algo : algo, nbits);
+          r = xmalloc_clear( sizeof *r + 20 );
+          r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+          sprintf( r->u.value, "%u", nbits);
+          r->next = para;
+          para = r;
+        }
+
+      xfree (curve);
     }
-   
+
   expire = ask_expire_interval(0,NULL);
   r = xmalloc_clear( sizeof *r + 20 );
   r->key = pKEYEXPIRE;
@@ -2882,8 +3502,8 @@ generate_keypair (const char *fname, const char *card_serialno,
   r->next = para;
   para = r;
 
-  uid = ask_user_id(0);
-  if( !uid ) 
+  uid = ask_user_id (0, NULL);
+  if( !uid )
     {
       log_error(_("Key generation canceled.\n"));
       release_parameter_list( para );
@@ -2894,32 +3514,13 @@ generate_keypair (const char *fname, const char *card_serialno,
   strcpy( r->u.value, uid );
   r->next = para;
   para = r;
-    
-  canceled = 0;
-  dek = card_serialno? NULL : do_ask_passphrase ( &s2k, &canceled );
-  if( dek )
-    {
-      r = xmalloc_clear( sizeof *r );
-      r->key = pPASSPHRASE_DEK;
-      r->u.dek = dek;
-      r->next = para;
-      para = r;
-      r = xmalloc_clear( sizeof *r );
-      r->key = pPASSPHRASE_S2K;
-      r->u.s2k = s2k;
-      r->next = para;
-      para = r;
-    }
 
-  if (canceled) 
-    log_error (_("Key generation canceled.\n"));
-  else
-    proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
+  proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
   release_parameter_list( para );
 }
 
 
-#ifdef ENABLE_CARD_SUPPORT
+#if 0 /* not required */
 /* Generate a raw key and return it as a secret key packet.  The
    function will ask for the passphrase and return a protected as well
    as an unprotected copy of a new secret key packet.  0 is returned
@@ -2948,13 +3549,13 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
-  if ((nbits % 32)) 
+  if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
       log_info(_("keysize rounded up to %u bits\n"), nbits );
     }
 
-  dek = do_ask_passphrase (&s2k, &canceled);
+  dek = do_ask_passphrase (&s2k, 1, &canceled);
   if (canceled)
     {
       rc = gpg_error (GPG_ERR_CANCELED);
@@ -2986,16 +3587,16 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
     }
   rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
   gcry_sexp_release (s_key);
-  if (rc) 
+  if (rc)
     {
       log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
       goto leave;
     }
-  
+
   for (i=npkey; i < nskey; i++)
     sk->csum += checksum_mpi (sk->skey[i]);
 
-  if (r_sk_unprotected) 
+  if (r_sk_unprotected)
     *r_sk_unprotected = copy_secret_key (NULL, sk);
 
   rc = genhelp_protect (dek, s2k, sk);
@@ -3029,518 +3630,450 @@ start_tree(KBNODE *tree)
   delete_kbnode(*tree);
 }
 
+
 static void
-do_generate_keypair( struct para_data_s *para,
-                    struct output_control_s *outctrl, int card )
-{
-    KBNODE pub_root = NULL;
-    KBNODE sec_root = NULL;
-    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
-    const char *s;
-    struct revocation_key *revkey;
-    int rc;
-    int did_sub = 0;
-
-    if( outctrl->dryrun )
-      {
-       log_info("dry-run mode - key generation skipped\n");
-       return;
-      }
+do_generate_keypair (struct para_data_s *para,
+                    struct output_control_s *outctrl, int card)
+{
+  gpg_error_t err;
+  KBNODE pub_root = NULL;
+  const char *s;
+  PKT_public_key *pri_psk = NULL;
+  PKT_public_key *sub_psk = NULL;
+  struct revocation_key *revkey;
+  int did_sub = 0;
+  u32 timestamp;
+  char *cache_nonce = NULL;
+
+  if (outctrl->dryrun)
+    {
+      log_info("dry-run mode - key generation skipped\n");
+      return;
+    }
 
-    if( outctrl->use_files ) {
-       if( outctrl->pub.newfname ) {
-           iobuf_close(outctrl->pub.stream);
-           outctrl->pub.stream = NULL;
-            if (outctrl->pub.fname)
-              iobuf_ioctl (NULL, 2, 0, (char*)outctrl->pub.fname);
-           xfree( outctrl->pub.fname );
-           outctrl->pub.fname =  outctrl->pub.newfname;
-           outctrl->pub.newfname = NULL;
-
-            if (is_secured_filename (outctrl->pub.fname) ) {
-                outctrl->pub.stream = NULL;
-                errno = EPERM;
+  if ( outctrl->use_files )
+    {
+      if ( outctrl->pub.newfname )
+        {
+          iobuf_close(outctrl->pub.stream);
+          outctrl->pub.stream = NULL;
+          if (outctrl->pub.fname)
+            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
+                         0, (char*)outctrl->pub.fname);
+          xfree( outctrl->pub.fname );
+          outctrl->pub.fname =  outctrl->pub.newfname;
+          outctrl->pub.newfname = NULL;
+
+          if (is_secured_filename (outctrl->pub.fname) )
+            {
+              outctrl->pub.stream = NULL;
+              gpg_err_set_errno (EPERM);
             }
-            else
-                outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
-           if( !outctrl->pub.stream ) {
-               log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
-                                                    strerror(errno) );
-               return;
-           }
-           if( opt.armor ) {
-               outctrl->pub.afx->what = 1;
-               push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
-           }
-       }
-       if( outctrl->sec.newfname ) {
-            mode_t oldmask;
-
-           iobuf_close(outctrl->sec.stream);
-           outctrl->sec.stream = NULL;
-            if (outctrl->sec.fname)
-              iobuf_ioctl (NULL, 2, 0, (char*)outctrl->sec.fname);
-           xfree( outctrl->sec.fname );
-           outctrl->sec.fname =  outctrl->sec.newfname;
-           outctrl->sec.newfname = NULL;
-
-           oldmask = umask (077);
-            if (is_secured_filename (outctrl->sec.fname) ) {
-                outctrl->sec.stream = NULL;
-                errno = EPERM;
+          else
+            outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
+          if (!outctrl->pub.stream)
+            {
+              log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname,
+                        strerror(errno) );
+              return;
+            }
+          if (opt.armor)
+            {
+              outctrl->pub.afx->what = 1;
+              push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
             }
-            else
-                outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
-            umask (oldmask);
-           if( !outctrl->sec.stream ) {
-               log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname,
-                                                    strerror(errno) );
-               return;
-           }
-           if( opt.armor ) {
-               outctrl->sec.afx->what = 5;
-               push_armor_filter (outctrl->sec.afx, outctrl->sec.stream);
-           }
-       }
-       assert( outctrl->pub.stream );
-       assert( outctrl->sec.stream );
-        if( opt.verbose ) {
-            log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
-            if (card)
-              log_info (_("writing secret key stub to `%s'\n"),
-                        outctrl->sec.fname);
-            else
-              log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
         }
+      assert( outctrl->pub.stream );
+      if (opt.verbose)
+        log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
 
 
-    /* we create the packets as a tree of kbnodes. Because the
-     * structure we create is known in advance we simply generate a
-     * linked list.  The first packet is a dummy packet which we flag
-     * as deleted.  The very first packet must always be a KEY packet.
-     */
-    
-    start_tree(&pub_root);
-    start_tree(&sec_root);
-
-    if (!card)
-      {
-        rc = do_create( get_parameter_algo( para, pKEYTYPE ),
-                        get_parameter_uint( para, pKEYLENGTH ),
-                        pub_root, sec_root,
-                        get_parameter_dek( para, pPASSPHRASE_DEK ),
-                        get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                        &pri_sk,
-                        get_parameter_u32( para, pKEYEXPIRE ), 0 );
-      }
-    else
-      {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
-                           get_parameter_u32 (para, pKEYEXPIRE), para);
-        if (!rc)
-          {
-            pri_sk = sec_root->next->pkt->pkt.secret_key;
-            assert (pri_sk);
-          }
-      }
+  /* We create the packets as a tree of kbnodes.  Because the
+     structure we create is known in advance we simply generate a
+     linked list.  The first packet is a dummy packet which we flag as
+     deleted.  The very first packet must always be a KEY packet.  */
+
+  start_tree (&pub_root);
+
+  timestamp = get_parameter_u32 (para, pKEYCREATIONDATE);
+  if (!timestamp)
+    timestamp = make_timestamp ();
+
+  /* Note that, depending on the backend (i.e. the used scdaemon
+     version), the card key generation may update TIMESTAMP for each
+     key.  Thus we need to pass TIMESTAMP to all signing function to
+     make sure that the binding signature is done using the timestamp
+     of the corresponding (sub)key and not that of the primary key.
+     An alternative implementation could tell the signing function the
+     node of the subkey but that is more work than just to pass the
+     current timestamp.  */
+
+  if (!card)
+    err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
+                     get_parameter_uint( para, pKEYLENGTH ),
+                     get_parameter_value (para, pKEYCURVE),
+                     pub_root,
+                     timestamp,
+                     get_parameter_u32( para, pKEYEXPIRE ), 0,
+                     outctrl->keygen_flags, &cache_nonce);
+  else
+    err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
+                        &timestamp,
+                        get_parameter_u32 (para, pKEYEXPIRE));
 
-    if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
-      {
-       rc=write_direct_sig(pub_root,pub_root,pri_sk,revkey);
-       if(!rc)
-         write_direct_sig(sec_root,pub_root,pri_sk,revkey);
-      }
+  /* Get the pointer to the generated public key packet.  */
+  if (!err)
+    {
+      pri_psk = pub_root->next->pkt->pkt.public_key;
+      assert (pri_psk);
+    }
 
-    if( !rc && (s=get_parameter_value(para, pUSERID)) )
-      {
-       write_uid(pub_root, s );
-       if( !rc )
-         write_uid(sec_root, s );
+  if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
+    err = write_direct_sig (pub_root, pri_psk, revkey, timestamp, cache_nonce);
 
-       if( !rc )
-         rc = write_selfsigs(sec_root, pub_root, pri_sk,
-                             get_parameter_uint (para, pKEYUSAGE));
-      }
+  if (!err && (s = get_parameter_value (para, pUSERID)))
+    {
+      write_uid (pub_root, s );
+      err = write_selfsigs (pub_root, pri_psk,
+                            get_parameter_uint (para, pKEYUSAGE), timestamp,
+                            cache_nonce);
+    }
 
-    /* Write the auth key to the card before the encryption key.  This
-       is a partial workaround for a PGP bug (as of this writing, all
-       versions including 8.1), that causes it to try and encrypt to
-       the most recent subkey regardless of whether that subkey is
-       actually an encryption type.  In this case, the auth key is an
-       RSA key so it succeeds. */
+  /* Write the auth key to the card before the encryption key.  This
+     is a partial workaround for a PGP bug (as of this writing, all
+     versions including 8.1), that causes it to try and encrypt to
+     the most recent subkey regardless of whether that subkey is
+     actually an encryption type.  In this case, the auth key is an
+     RSA key so it succeeds. */
 
-    if (!rc && card && get_parameter (para, pAUTHKEYTYPE))
-      {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL,
-                           get_parameter_u32 (para, pKEYEXPIRE), para);
-        
-        if (!rc)
-          rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
-        if (!rc)
-          rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
-      }
+  if (!err && card && get_parameter (para, pAUTHKEYTYPE))
+    {
+      err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root,
+                          &timestamp,
+                          get_parameter_u32 (para, pKEYEXPIRE));
+      if (!err)
+        err = write_keybinding (pub_root, pri_psk, NULL,
+                                PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
+    }
 
-    if( !rc && get_parameter( para, pSUBKEYTYPE ) )
-      {
-        if (!card)
-          {
-            rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
-                            get_parameter_uint( para, pSUBKEYLENGTH ),
-                            pub_root, sec_root,
-                            get_parameter_dek( para, pPASSPHRASE_DEK ),
-                            get_parameter_s2k( para, pPASSPHRASE_S2K ),
-                            &sub_sk,
-                            get_parameter_u32( para, pSUBKEYEXPIRE ), 1 );
-          }
-        else
-          {
-            if ((s = get_parameter_value (para, pBACKUPENCDIR)))
-              {
-                /* A backup of the encryption key has been requested.
-                   Generate the key i software and import it then to
-                   the card.  Write a backup file. */
-                rc = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0,
-                                               pub_root, sec_root,
-                                               get_parameter_u32 (para,
-                                                                  pKEYEXPIRE),
-                                               para, s);
-              }
-            else
-              rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
-                                NULL,
-                                 get_parameter_u32 (para, pKEYEXPIRE), para);
-          }
+  if (!err && get_parameter (para, pSUBKEYTYPE))
+    {
+      sub_psk = NULL;
+      if (!card)
+        {
+          err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
+                           get_parameter_uint (para, pSUBKEYLENGTH),
+                           get_parameter_value (para, pSUBKEYCURVE),
+                           pub_root,
+                           timestamp,
+                           get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
+                           outctrl->keygen_flags, &cache_nonce);
+          /* Get the pointer to the generated public subkey packet.  */
+          if (!err)
+            {
+              kbnode_t node;
 
-        if( !rc )
-          rc = write_keybinding(pub_root, pub_root, pri_sk, sub_sk,
-                                get_parameter_uint (para, pSUBKEYUSAGE));
-        if( !rc )
-          rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
-                                get_parameter_uint (para, pSUBKEYUSAGE));
-        did_sub = 1;
-      }
+              for (node = pub_root; node; node = node->next)
+                if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+                  sub_psk = node->pkt->pkt.public_key;
+              assert (sub_psk);
+            }
+        }
+      else
+        {
+          if ((s = get_parameter_value (para, pCARDBACKUPKEY)))
+            {
+              /* A backup of the encryption key has been requested.
+                 Generate the key in software and import it then to
+                 the card.  Write a backup file. */
+              err = gen_card_key_with_backup
+                (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp,
+                 get_parameter_u32 (para, pKEYEXPIRE), para);
+            }
+          else
+            {
+              err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root,
+                                  &timestamp,
+                                  get_parameter_u32 (para, pKEYEXPIRE));
+            }
+        }
 
-    if( !rc && outctrl->use_files ) { /* direct write to specified files */
-       rc = write_keyblock( outctrl->pub.stream, pub_root );
-       if( rc )
-           log_error("can't write public key: %s\n", g10_errstr(rc) );
-       if( !rc ) {
-           rc = write_keyblock( outctrl->sec.stream, sec_root );
-           if( rc )
-               log_error("can't write secret key: %s\n", g10_errstr(rc) );
-       }
+      if (!err)
+        err = write_keybinding (pub_root, pri_psk, sub_psk,
+                                get_parameter_uint (para, pSUBKEYUSAGE),
+                                timestamp, cache_nonce);
+      did_sub = 1;
+    }
 
+  if (!err && outctrl->use_files)  /* Direct write to specified files.  */
+    {
+      err = write_keyblock (outctrl->pub.stream, pub_root);
+      if (err)
+        log_error ("can't write public key: %s\n", g10_errstr (err));
     }
-    else if( !rc ) { /* write to the standard keyrings */
-       KEYDB_HANDLE pub_hd = keydb_new (0);
-       KEYDB_HANDLE sec_hd = keydb_new (1);
+  else if (!err) /* Write to the standard keyrings.  */
+    {
+      KEYDB_HANDLE pub_hd = keydb_new ();
 
-        /* FIXME: we may have to create the keyring first */
-        rc = keydb_locate_writable (pub_hd, NULL);
-        if (rc) 
-           log_error (_("no writable public keyring found: %s\n"),
-                       g10_errstr (rc));
+      err = keydb_locate_writable (pub_hd, NULL);
+      if (err)
+        log_error (_("no writable public keyring found: %s\n"),
+                   g10_errstr (err));
 
-        if (!rc) {  
-            rc = keydb_locate_writable (sec_hd, NULL);
-            if (rc) 
-                log_error (_("no writable secret keyring found: %s\n"),
-                           g10_errstr (rc));
+      if (!err && opt.verbose)
+        {
+          log_info (_("writing public key to '%s'\n"),
+                    keydb_get_resource_name (pub_hd));
         }
 
-        if (!rc && opt.verbose) {
-            log_info(_("writing public key to `%s'\n"),
-                     keydb_get_resource_name (pub_hd));
-            if (card)
-              log_info (_("writing secret key stub to `%s'\n"),
-                        keydb_get_resource_name (sec_hd));
-            else
-              log_info(_("writing secret key to `%s'\n"),
-                       keydb_get_resource_name (sec_hd));
+      if (!err)
+        {
+          err = keydb_insert_keyblock (pub_hd, pub_root);
+          if (err)
+            log_error (_("error writing public keyring '%s': %s\n"),
+                       keydb_get_resource_name (pub_hd), g10_errstr(err));
         }
 
-        if (!rc) {
-           rc = keydb_insert_keyblock (pub_hd, pub_root);
-            if (rc)
-                log_error (_("error writing public keyring `%s': %s\n"),
-                           keydb_get_resource_name (pub_hd), g10_errstr(rc));
-        }
+      keydb_release (pub_hd);
 
-        if (!rc) {
-           rc = keydb_insert_keyblock (sec_hd, sec_root);
-            if (rc)
-                log_error (_("error writing secret keyring `%s': %s\n"),
-                           keydb_get_resource_name (pub_hd), g10_errstr(rc));
-        }
+      if (!err)
+        {
+          int no_enc_rsa;
+          PKT_public_key *pk;
 
-        keydb_release (pub_hd);
-        keydb_release (sec_hd);
+          no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL)
+                         == PUBKEY_ALGO_RSA)
+                        && get_parameter_uint (para, pKEYUSAGE)
+                        && !((get_parameter_uint (para, pKEYUSAGE)
+                              & PUBKEY_USAGE_ENC)) );
 
-       if (!rc) {
-            int no_enc_rsa =
-                get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
-                && get_parameter_uint( para, pKEYUSAGE )
-                && !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
-            PKT_public_key *pk = find_kbnode (pub_root, 
-                                    PKT_PUBLIC_KEY)->pkt->pkt.public_key;
+          pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
 
-           keyid_from_pk(pk,pk->main_keyid);
-           register_trusted_keyid(pk->main_keyid);
+          keyid_from_pk (pk, pk->main_keyid);
+          register_trusted_keyid (pk->main_keyid);
 
-           update_ownertrust (pk,
-                              ((get_ownertrust (pk) & ~TRUST_MASK)
-                               | TRUST_ULTIMATE ));
+          update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
+                                  | TRUST_ULTIMATE ));
 
-           if (!opt.batch) {
-                tty_printf(_("public and secret key created and signed.\n") );
-               tty_printf("\n");
-               list_keyblock(pub_root,0,1,NULL);
+          if (!opt.batch)
+            {
+              tty_printf (_("public and secret key created and signed.\n") );
+              tty_printf ("\n");
+              list_keyblock (pub_root, 0, 1, NULL);
             }
-            
 
-           if( !opt.batch
-               && ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
-                     || no_enc_rsa )
-               && !get_parameter( para, pSUBKEYTYPE ) )
-           {
-               tty_printf(_("Note that this key cannot be used for "
-                            "encryption.  You may want to use\n"
-                            "the command \"--edit-key\" to generate a "
-                            "subkey for this purpose.\n") );
-           }
-       }
+
+          if (!opt.batch
+              && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
+                  || no_enc_rsa )
+              && !get_parameter (para, pSUBKEYTYPE) )
+            {
+              tty_printf(_("Note that this key cannot be used for "
+                           "encryption.  You may want to use\n"
+                           "the command \"--edit-key\" to generate a "
+                           "subkey for this purpose.\n") );
+            }
+        }
     }
 
-    if( rc ) {
-       if( opt.batch )
-           log_error("key generation failed: %s\n", g10_errstr(rc) );
-       else
-           tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
-        print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
+  if (err)
+    {
+      if (opt.batch)
+        log_error ("key generation failed: %s\n", g10_errstr(err) );
+      else
+        tty_printf (_("Key generation failed: %s\n"), g10_errstr(err) );
+      write_status_error (card? "card_key_generate":"key_generate", err);
+      print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
     }
-    else {
-        PKT_public_key *pk = find_kbnode (pub_root, 
-                                    PKT_PUBLIC_KEY)->pkt->pkt.public_key;
-        print_status_key_created (did_sub? 'B':'P', pk,
-                                  get_parameter_value (para, pHANDLE));
+  else
+    {
+      PKT_public_key *pk = find_kbnode (pub_root,
+                                        PKT_PUBLIC_KEY)->pkt->pkt.public_key;
+      print_status_key_created (did_sub? 'B':'P', pk,
+                                get_parameter_value (para, pHANDLE));
     }
-    release_kbnode( pub_root );
-    release_kbnode( sec_root );
 
-    if( pri_sk && !card) /* the unprotected  secret key unless we have a */
-      free_secret_key(pri_sk); /* shallow copy in card mode. */
-    if( sub_sk )
-       free_secret_key(sub_sk);
+  release_kbnode (pub_root);
+  xfree (cache_nonce);
 }
 
 
-/****************
- * add a new subkey to an existing key.
- * Returns true if a new key has been generated and put into the keyblocks.
- */
-int
-generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
+/* Add a new subkey to an existing key.  Returns 0 if a new key has
+   been generated and put into the keyblocks.  */
+gpg_error_t
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
 {
-    int okay=0, rc=0;
-    KBNODE node;
-    PKT_secret_key *pri_sk = NULL, *sub_sk = NULL;
-    int algo;
-    unsigned int use;
-    u32 expire;
-    unsigned nbits;
-    char *passphrase = NULL;
-    DEK *dek = NULL;
-    STRING2KEY *s2k = NULL;
-    u32 cur_time;
-    int ask_pass = 0;
-    int canceled;
-
-    /* break out the primary secret key */
-    node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
-    if( !node ) {
-       log_error("Oops; secret key not found anymore!\n");
-       goto leave;
-    }
-
-    /* make a copy of the sk to keep the protected one in the keyblock */
-    pri_sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
-
-    cur_time = make_timestamp();
-    if( pri_sk->timestamp > cur_time ) {
-       ulong d = pri_sk->timestamp - cur_time;
-       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 ) {
-           rc = G10ERR_TIME_CONFLICT;
-           goto leave;
-       }
+  gpg_error_t err = 0;
+  kbnode_t node;
+  PKT_public_key *pri_psk = NULL;
+  PKT_public_key *sub_psk = NULL;
+  int algo;
+  unsigned int use;
+  u32 expire;
+  unsigned int nbits = 0;
+  char *curve = NULL;
+  u32 cur_time;
+  char *hexgrip = NULL;
+  char *serialno = NULL;
+
+  /* Break out the primary key.  */
+  node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+  if (!node)
+    {
+      log_error ("Oops; primary key missing in keyblock!\n");
+      err = gpg_error (GPG_ERR_BUG);
+      goto leave;
     }
+  pri_psk = node->pkt->pkt.public_key;
 
-    if (pri_sk->version < 4) {
-        log_info (_("NOTE: creating subkeys for v3 keys "
-                    "is not OpenPGP compliant\n"));
-       goto leave;
+  cur_time = make_timestamp ();
+
+  if (pri_psk->timestamp > cur_time)
+    {
+      ulong d = pri_psk->timestamp - cur_time;
+      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)
+        {
+          err = gpg_error (GPG_ERR_TIME_CONFLICT);
+          goto leave;
+        }
     }
 
-    if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) {
-        tty_printf(_("Secret parts of primary key are not available.\n"));
-        rc = G10ERR_NO_SECKEY;
-        goto leave;
+  if (pri_psk->version < 4)
+    {
+      log_info (_("NOTE: creating subkeys for v3 keys "
+                  "is not OpenPGP compliant\n"));
+      err = gpg_error (GPG_ERR_CONFLICT);
+      goto leave;
     }
 
+  err = hexkeygrip_from_pk (pri_psk, &hexgrip);
+  if (err)
+    goto leave;
+  if (agent_get_keyinfo (NULL, hexgrip, &serialno))
+    {
+      tty_printf (_("Secret parts of primary key are not available.\n"));
+      goto leave;
+    }
+  if (serialno)
+    tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+
+  xfree (hexgrip);
+  hexgrip = NULL;
+  algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
+  assert (algo);
+
+  if (hexgrip)
+    nbits = 0;
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    curve = ask_curve ();
+  else
+    nbits = ask_keysize (algo, 0);
 
-    /* Unprotect to get the passphrase.  */
-    switch( is_secret_key_protected( pri_sk ) ) {
-      case -1:
-       rc = G10ERR_PUBKEY_ALGO;
-       break;
-      case 0:
-       tty_printf(_("This key is not protected.\n"));
-       break;
-      case -2:
-        tty_printf(_("Secret parts of primary key are stored on-card.\n"));
-        ask_pass = 1;
-        break;
-      default:
-        tty_printf(_("Key is protected.\n"));
-        rc = check_secret_key( pri_sk, 0 );
-        if( !rc )
-            passphrase = get_last_passphrase();
-        break;
-    }
-    if( rc )
-       goto leave;
-
-    algo = ask_algo( 1, &use );
-    assert(algo);
-    nbits = ask_keysize( algo );
-    expire = ask_expire_interval(0,NULL);
-    if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
-                                                 _("Really create? (y/N) ")))
-       goto leave;
-
-    canceled = 0;
-    if (ask_pass)
-        dek = do_ask_passphrase (&s2k, &canceled);
-    else if (passphrase) {
-       s2k = xmalloc_secure( sizeof *s2k );
-       s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = S2K_DIGEST_ALGO;
-       set_next_passphrase( passphrase );
-       dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                                 NULL, NULL );
-    }
-
-    if (canceled)
-      rc = GPG_ERR_CANCELED;
-    
-    if (!rc)
-      rc = do_create (algo, nbits, pub_keyblock, sec_keyblock,
-                      dek, s2k, &sub_sk, expire, 1 );
-    if( !rc )
-       rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-    if( !rc )
-       rc = write_keybinding(sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-    if( !rc ) {
-       okay = 1;
-        write_status_text (STATUS_KEY_CREATED, "S");
-    }
-
-  leave:
-    if( rc )
-       log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
-    xfree( passphrase );
-    xfree( dek );
-    xfree( s2k );
-    /* release the copy of the (now unprotected) secret keys */
-    if( pri_sk )
-       free_secret_key(pri_sk);
-    if( sub_sk )
-       free_secret_key(sub_sk);
-    set_next_passphrase( NULL );
-    return okay;
+  expire = ask_expire_interval (0, NULL);
+  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
+                                               _("Really create? (y/N) ")))
+    {
+      err = gpg_error (GPG_ERR_CANCELED);
+      goto leave;
+    }
+
+  if (hexgrip)
+    err = do_create_from_keygrip (ctrl, algo, hexgrip,
+                                  keyblock, cur_time, expire, 1);
+  else
+    err = do_create (algo, nbits, curve,
+                     keyblock, cur_time, expire, 1, 0, NULL);
+  if (err)
+    goto leave;
+
+  /* Get the pointer to the generated public subkey packet.  */
+  for (node = keyblock; node; node = node->next)
+    if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      sub_psk = node->pkt->pkt.public_key;
+
+  /* Write the binding signature.  */
+  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL);
+  if (err)
+    goto leave;
+
+  write_status_text (STATUS_KEY_CREATED, "S");
+
+ leave:
+  xfree (curve);
+  xfree (hexgrip);
+  xfree (serialno);
+  if (err)
+    log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
+  return err;
 }
 
 
 #ifdef ENABLE_CARD_SUPPORT
 /* Generate a subkey on a card. */
-int
-generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
+gpg_error_t
+generate_card_subkeypair (kbnode_t pub_keyblock,
                           int keyno, const char *serialno)
 {
-  int okay=0, rc=0;
-  KBNODE node;
-  PKT_secret_key *pri_sk = NULL, *sub_sk;
+  gpg_error_t err = 0;
+  kbnode_t node;
+  PKT_public_key *pri_pk = NULL;
   int algo;
   unsigned int use;
   u32 expire;
-  char *passphrase = NULL;
   u32 cur_time;
   struct para_data_s *para = NULL;
 
   assert (keyno >= 1 && keyno <= 3);
 
-  para = xcalloc (1, sizeof *para + strlen (serialno) );
+  para = xtrycalloc (1, sizeof *para + strlen (serialno) );
+  if (!para)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
   para->key = pSERIALNO;
   strcpy (para->u.value, serialno);
 
   /* Break out the primary secret key */
-  node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
-  if(!node)
+  node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY);
+  if (!node)
     {
-      log_error("Oops; secret key not found anymore!\n");
+      log_error ("Oops; publkic key lost!\n");
+      err = gpg_error (GPG_ERR_INTERNAL);
       goto leave;
     }
-
-  /* Make a copy of the sk to keep the protected one in the keyblock */
-  pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key);
+  pri_pk = node->pkt->pkt.public_key;
 
   cur_time = make_timestamp();
-  if (pri_sk->timestamp > cur_time)
+  if (pri_pk->timestamp > cur_time)
     {
-      ulong d = pri_sk->timestamp - cur_time;
+      ulong d = pri_pk->timestamp - cur_time;
       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)
           {
-           rc = G10ERR_TIME_CONFLICT;
+           err = gpg_error (GPG_ERR_TIME_CONFLICT);
            goto leave;
           }
     }
 
-  if (pri_sk->version < 4)
+  if (pri_pk->version < 4)
     {
       log_info (_("NOTE: creating subkeys for v3 keys "
                   "is not OpenPGP compliant\n"));
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
 
-  /* Unprotect to get the passphrase. */
-  switch( is_secret_key_protected (pri_sk) )
-    {
-    case -1:
-      rc = G10ERR_PUBKEY_ALGO;
-      break;
-    case 0:
-      tty_printf("This key is not protected.\n");
-      break;
-    default:
-      tty_printf("Key is protected.\n");
-      rc = check_secret_key( pri_sk, 0 );
-      if (!rc)
-        passphrase = get_last_passphrase();
-      break;
-    }
-  if (rc)
-    goto leave;
-
   algo = PUBKEY_ALGO_RSA;
-  expire = ask_expire_interval (0,NULL);
+  expire = ask_expire_interval (0, NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
   else if (keyno == 2)
@@ -3549,37 +4082,38 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
     use = PUBKEY_USAGE_AUTH;
   if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay",
                                                _("Really create? (y/N) ")))
-    goto leave;
+    {
+      err = gpg_error (GPG_ERR_CANCELED);
+      goto leave;
+    }
 
-  if (passphrase)
-    set_next_passphrase (passphrase);
-  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock,
-                    &sub_sk, expire, para);
-  if (!rc)
-    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-  if (!rc)
-    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
-  if (!rc)
+  /* Note, that depending on the backend, the card key generation may
+     update CUR_TIME.  */
+  err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire);
+  /* Get the pointer to the generated public subkey packet.  */
+  if (!err)
     {
-      okay = 1;
-      write_status_text (STATUS_KEY_CREATED, "S");
+      PKT_public_key *sub_pk = NULL;
+
+      for (node = pub_keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+          sub_pk = node->pkt->pkt.public_key;
+      assert (sub_pk);
+      err = write_keybinding (pub_keyblock, pri_pk, sub_pk,
+                              use, cur_time, NULL);
     }
 
  leave:
-  if (rc)
-    log_error (_("Key generation failed: %s\n"), g10_errstr(rc) );
-  xfree (passphrase);
-  /* Release the copy of the (now unprotected) secret keys. */
-  if (pri_sk)
-    free_secret_key (pri_sk);
-  set_next_passphrase( NULL );
+  if (err)
+    log_error (_("Key generation failed: %s\n"), g10_errstr(err) );
+  else
+    write_status_text (STATUS_KEY_CREATED, "S");
   release_parameter_list (para);
-  return okay;
+  return err;
 }
 #endif /* !ENABLE_CARD_SUPPORT */
 
-
-/****************
+/*
  * Write a keyblock to an output stream
  */
 static int
@@ -3603,85 +4137,78 @@ write_keyblock( IOBUF out, KBNODE node )
 }
 
 
-static int
-gen_card_key (int algo, int keyno, int is_primary,
-              KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
-              u32 expireval, struct para_data_s *para)
+/* Note that timestamp is an in/out arg. */
+static gpg_error_t
+gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+              u32 *timestamp, u32 expireval)
 {
 #ifdef ENABLE_CARD_SUPPORT
-  int rc;
-  const char *s;
+  gpg_error_t err;
   struct agent_card_genkey_s info;
   PACKET *pkt;
-  PKT_secret_key *sk;
   PKT_public_key *pk;
 
-  assert (algo == PUBKEY_ALGO_RSA);
-  
-  /* Fixme: We don't have the serialnumber available, thus passing NULL. */
-  rc = agent_scd_genkey (&info, keyno, 1, NULL);
-/*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
-/*      { */
-/*        tty_printf ("\n"); */
-/*        log_error ("WARNING: key does already exists!\n"); */
-/*        tty_printf ("\n"); */
-/*        if ( cpr_get_answer_is_yes( "keygen.card.replace_key", */
-/*                                    _("Replace existing key? "))) */
-/*          rc = agent_scd_genkey (&info, keyno, 1); */
-/*      } */
+  if (algo != PUBKEY_ALGO_RSA)
+    return gpg_error (GPG_ERR_PUBKEY_ALGO);
 
-  if (rc)
+  pk = xtrycalloc (1, sizeof *pk );
+  if (!pk)
+    return gpg_error_from_syserror ();
+  pkt = xtrycalloc (1, sizeof *pkt);
+  if (!pkt)
     {
-      log_error ("key generation failed: %s\n", gpg_strerror (rc));
-      return rc;
+      xfree (pk);
+      return gpg_error_from_syserror ();
     }
-  if ( !info.n || !info.e )
+
+  /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
+  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
+  /*  The code below is not used because we force creation of
+   *  the a card key (3rd arg).
+   * if (gpg_err_code (rc) == GPG_ERR_EEXIST)
+   *   {
+   *     tty_printf ("\n");
+   *     log_error ("WARNING: key does already exists!\n");
+   *     tty_printf ("\n");
+   *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
+   *                                 _("Replace existing key? ")))
+   *       rc = agent_scd_genkey (&info, keyno, 1);
+   *   }
+  */
+  if (!err && (!info.n || !info.e))
     {
       log_error ("communication error with SCD\n");
       gcry_mpi_release (info.n);
       gcry_mpi_release (info.e);
-      return gpg_error (GPG_ERR_GENERAL);
+      err =  gpg_error (GPG_ERR_GENERAL);
     }
-  
-
-  pk = xcalloc (1, sizeof *pk );
-  sk = xcalloc (1, sizeof *sk );
-  sk->timestamp = pk->timestamp = info.created_at;
-  sk->version = pk->version = 4;
-  if (expireval)
-      sk->expiredate = pk->expiredate = pk->timestamp + expireval;
-  sk->pubkey_algo = pk->pubkey_algo = algo;
-  pk->pkey[0] = info.n;
-  pk->pkey[1] = info.e; 
-  sk->skey[0] = gcry_mpi_copy (pk->pkey[0]);
-  sk->skey[1] = gcry_mpi_copy (pk->pkey[1]);
-  sk->skey[2] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
-  sk->is_protected = 1;
-  sk->protect.s2k.mode = 1002;
-  s = get_parameter_value (para, pSERIALNO);
-  if (s)
+  if (err)
     {
-      for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
-           sk->protect.ivlen++, s += 2)
-        sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+      log_error ("key generation failed: %s\n", gpg_strerror (err));
+      xfree (pkt);
+      xfree (pk);
+      return err;
     }
 
-  if( ret_sk )
-    *ret_sk = sk;
+  if (*timestamp != info.created_at)
+    log_info ("NOTE: the key does not use the suggested creation date\n");
+  *timestamp = info.created_at;
+
+  pk->timestamp = info.created_at;
+  pk->version = 4;
+  if (expireval)
+    pk->expiredate = pk->timestamp + expireval;
+  pk->pubkey_algo = algo;
+  pk->pkey[0] = info.n;
+  pk->pkey[1] = info.e;
 
-  pkt = xcalloc (1,sizeof *pkt);
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
-  add_kbnode(pub_root, new_kbnode( pkt ));
-
-  pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
-  pkt->pkt.secret_key = sk;
-  add_kbnode(sec_root, new_kbnode( pkt ));
+  add_kbnode (pub_root, new_kbnode (pkt));
 
   return 0;
 #else
-  return -1;
+  return gpg_error (GPG_ERR_NOT_SUPPORTED);
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
 
@@ -3689,11 +4216,10 @@ gen_card_key (int algo, int keyno, int is_primary,
 
 static int
 gen_card_key_with_backup (int algo, int keyno, int is_primary,
-                          KBNODE pub_root, KBNODE sec_root,
-                          u32 expireval, struct para_data_s *para,
-                          const char *backup_dir)
+                          KBNODE pub_root, u32 timestamp,
+                          u32 expireval, struct para_data_s *para)
 {
-#ifdef ENABLE_CARD_SUPPORT
+#if 0 /* FIXME: Move this to gpg-agent.  */
   int rc;
   const char *s;
   PACKET *pkt;
@@ -3701,19 +4227,35 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   PKT_public_key *pk;
   size_t n;
   int i;
+  unsigned int nbits;
+
+  /* Get the size of the key directly from the card.  */
+  {
+    struct agent_card_info_s info;
+
+    memset (&info, 0, sizeof info);
+    if (!agent_scd_getattr ("KEY-ATTR", &info)
+        && info.key_attr[1].algo)
+      nbits = info.key_attr[1].nbits;
+    else
+      nbits = 1024; /* All pre-v2.0 cards.  */
+    agent_release_card_info (&info);
+  }
 
-  rc = generate_raw_key (algo, 1024, make_timestamp (),
+  /* Create a key of this size in memory.  */
+  rc = generate_raw_key (algo, nbits, timestamp,
                          &sk_unprotected, &sk_protected);
   if (rc)
     return rc;
 
-  /* First, store the key to the card. */
+  /* Store the key to the card. */
   rc = save_unprotected_key_to_card (sk_unprotected, keyno);
   if (rc)
     {
       log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
       free_secret_key (sk_unprotected);
       free_secret_key (sk_protected);
+      write_status_errcode ("save_key_to_card", rc);
       return rc;
     }
 
@@ -3743,23 +4285,23 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
     mode_t oldmask;
 
     keyid_from_sk (sk, NULL);
-    sprintf (name_buffer,"sk_%08lX%08lX.gpg",
-             (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+    snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg",
+              (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
 
     fname = make_filename (backup_dir, name_buffer, NULL);
     oldmask = umask (077);
     if (is_secured_filename (fname))
       {
         fp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     else
       fp = iobuf_create (fname);
     umask (oldmask);
-    if (!fp) 
+    if (!fp)
       {
         rc = gpg_error_from_syserror ();
-       log_error (_("can't create backup file `%s': %s\n"),
+       log_error (_("can't create backup file '%s': %s\n"),
                    fname, strerror(errno) );
         xfree (fname);
         free_secret_key (sk_unprotected);
@@ -3782,10 +4324,10 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
       {
         unsigned char array[MAX_FINGERPRINT_LEN];
         char *fprbuf, *p;
-       
+
         iobuf_close (fp);
-        iobuf_ioctl (NULL, 2, 0, (char*)fname);
-        log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+        iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+        log_info (_("NOTE: backup of card key saved to '%s'\n"), fname);
 
         fingerprint_from_sk (sk, array, &n);
         p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);
@@ -3834,14 +4376,14 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
 
   return 0;
 #else
-  return -1;
+  return gpg_error (GPG_ERR_NOT_SUPPORTED);
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
 
 
-#ifdef ENABLE_CARD_SUPPORT
+#if 0
 int
-save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
+save_unprotected_key_to_card (PKT_public_key *sk, int keyno)
 {
   int rc;
   unsigned char *rsa_n = NULL;
@@ -3859,15 +4401,15 @@ save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
   /* Copy the parameters into straight buffers. */
   gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]);
   gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]);
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[2]);
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[3]);
-   if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
+  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]);
+  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]);
+  if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
     {
       rc = G10ERR_INV_ARG;
       goto leave;
     }
 
-  /* Put the key into an S-expression. */
+   /* Put the key into an S-expression. */
   sexp = p = xmalloc_secure (30
                              + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
                              + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
@@ -3899,7 +4441,7 @@ save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
   p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
 
   /* Fixme: Unfortunately we don't have the serialnumber available -
-     thus we can't pass it down to the agent. */ 
+     thus we can't pass it down to the agent. */
   rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
 
  leave: