dirmngr: Fix error handling.
[gnupg.git] / g10 / keygen.c
index b6b50f6..44f139a 100644 (file)
@@ -1,7 +1,6 @@
-/* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- *               2007, 2009, 2010, 2011  Free Software Foundation, Inc.
- * Copyright (C) 2014  Werner Koch
+/* keygen.c - Generate a key pair
+ * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
+ * Copyright (C) 2014, 2015, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -16,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "gpg.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
 #include "packet.h"
-#include "ttyio.h"
+#include "../common/ttyio.h"
 #include "options.h"
 #include "keydb.h"
 #include "trustdb.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "pkglue.h"
+#include "../common/shareddefs.h"
+#include "../common/host2net.h"
+#include "../common/mbox-util.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
+   is inside the bounds enforced by ask_keysize and gen_xxx.  See also
+   get_keysize_range which encodes the allowed ranges.  */
+#define DEFAULT_STD_KEY_PARAM  "rsa2048/cert,sign+rsa2048/encr"
+#define FUTURE_STD_KEY_PARAM   "ed25519/cert,sign+cv25519/encr"
+
+/* When generating keys using the streamlined key generation dialog,
+   use this as a default expiration interval.  */
+const char *default_expiration_interval = "2y";
 
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
@@ -79,12 +86,11 @@ enum para_name {
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
   pPASSPHRASE,
-  pPASSPHRASE_DEK,
-  pPASSPHRASE_S2K,
   pSERIALNO,
   pCARDBACKUPKEY,
   pHANDLE,
-  pKEYSERVER
+  pKEYSERVER,
+  pKEYGRIP
 };
 
 struct para_data_s {
@@ -92,8 +98,6 @@ struct para_data_s {
     int lnr;
     enum para_name key;
     union {
-        DEK *dek;
-        STRING2KEY *s2k;
         u32 expire;
         u32 creation;
         unsigned int usage;
@@ -106,7 +110,6 @@ struct output_control_s
 {
   int lnr;
   int dryrun;
-  int ask_passphrase;
   unsigned int keygen_flags;
   int use_files;
   struct {
@@ -133,15 +136,39 @@ static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
 static int mdc_available,ks_modify;
 
-static void do_generate_keypair( struct para_data_s *para,
-                                struct output_control_s *outctrl, int card );
+static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                                     const char *algostr, const char *usagestr,
+                                     const char *expirestr,
+                                     int *r_algo, unsigned int *r_usage,
+                                     u32 *r_expire,
+                                     unsigned int *r_nbits, char **r_curve);
+static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
+                                 struct output_control_s *outctrl, int card );
 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_t pub_root, u32 timestamp,
-                                     u32 expireval, struct para_data_s *para);
+static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
+                                 kbnode_t pub_root, u32 *timestamp,
+                                 u32 expireval);
+static unsigned int get_keysize_range (int algo,
+                                       unsigned int *min, unsigned int *max);
+
+
+\f
+/* Return the algo string for a default new key.  */
+const char *
+get_default_pubkey_algo (void)
+{
+  if (opt.def_new_key_algo)
+    {
+      if (*opt.def_new_key_algo && !strchr (opt.def_new_key_algo, ':'))
+        return opt.def_new_key_algo;
+      /* To avoid checking that option every time we delay that until
+       * here.  The only thing we really need to make sure is that
+       * there is no colon in the string so that the --gpgconf-list
+       * command won't mess up its output.  */
+      log_info (_("invalid value for option '%s'\n"), "--default-new-key-algo");
+    }
+  return DEFAULT_STD_KEY_PARAM;
+}
 
 
 static void
@@ -160,11 +187,15 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
   if (letter || pk)
     {
       *p++ = letter;
-      *p++ = ' ';
-      fingerprint_from_pk (pk, array, &n);
-      s = array;
-      for (i=0; i < n ; i++, s++, p += 2)
-        sprintf (p, "%02X", *s);
+      if (pk)
+        {
+          *p++ = ' ';
+          fingerprint_from_pk (pk, array, &n);
+          s = array;
+          /* Fixme: Use bin2hex */
+          for (i=0; i < n ; i++, s++, p += 2)
+            snprintf (p, 3, "%02X", *s);
+        }
     }
   if (*handle)
     {
@@ -193,7 +224,7 @@ write_uid( KBNODE root, const char *s )
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
-    pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
@@ -238,7 +269,7 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
 
       buf[0] = (u >> 24) & 0xff;
       buf[1] = (u >> 16) & 0xff;
-      buf[2] = (u >>   8) & 0xff;
+      buf[2] = (u >>  8) & 0xff;
       buf[3] = u & 0xff;
       build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
     }
@@ -253,6 +284,18 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
 }
 
 
+/* Add the key usage (i.e. key flags) in SIG from the public keys
+ * pubkey_usage field.  OPAQUE has the public key.  */
+int
+keygen_add_key_flags (PKT_signature *sig, void *opaque)
+{
+  PKT_public_key *pk = opaque;
+
+  do_add_key_flags (sig, pk->pubkey_usage);
+  return 0;
+}
+
+
 static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
@@ -392,9 +435,11 @@ keygen_set_std_prefs (const char *string,int personal)
 
     if(strlen(string))
       {
-       char *tok,*prefstring;
+       char *prefstringbuf;
+        char *tok, *prefstring;
 
-       prefstring=xstrdup(string); /* need a writable string! */
+        /* We need a writable string. */
+       prefstring = prefstringbuf = xstrdup (string);
 
        while((tok=strsep(&prefstring," ,")))
          {
@@ -428,7 +473,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
-       xfree(prefstring);
+       xfree (prefstringbuf);
       }
 
     if(!rc)
@@ -808,9 +853,10 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
   cache_public_key (sub_pk);
 
   err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19,
-                            0, 0, timestamp, 0, NULL, NULL, cache_nonce);
+                            0, timestamp, 0, NULL, NULL, cache_nonce);
   if (err)
-    log_error ("make_keysig_packet failed for backsig: %s\n", g10_errstr(err));
+    log_error ("make_keysig_packet failed for backsig: %s\n",
+               gpg_strerror (err));
   else
     {
       /* Get it into a binary packed form. */
@@ -823,7 +869,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
       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));
+       log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err));
       else
        {
          size_t pktlen = 0;
@@ -845,10 +891,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
                }
              else if (buf[1] == 255)
                {
-                 pktlen  = buf[2] << 24;
-                 pktlen |= buf[3] << 16;
-                 pktlen |= buf[4] << 8;
-                 pktlen |= buf[5];
+                  pktlen = buf32_to_size_t (buf+2);
                  buf += 6;
                }
              else
@@ -865,7 +908,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
                  break;
 
                case 2:
-                 pktlen  = buf[mark++] << 24;
+                 pktlen  = (size_t)buf[mark++] << 24;
                  pktlen |= buf[mark++] << 16;
 
                case 1:
@@ -918,11 +961,11 @@ write_direct_sig (KBNODE root, PKT_public_key *psk,
 
   /* Make the signature.  */
   err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F,
-                            0, 0, timestamp, 0,
+                            0, timestamp, 0,
                             keygen_add_revkey, revkey, cache_nonce);
   if (err)
     {
-      log_error ("make_keysig_packet failed: %s\n", g10_errstr (err) );
+      log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err) );
       return err;
     }
 
@@ -973,11 +1016,11 @@ write_selfsigs (KBNODE root, PKT_public_key *psk,
 
   /* Make the signature.  */
   err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13,
-                            0, 0, timestamp, 0,
+                            0, timestamp, 0,
                             keygen_add_std_prefs, pk, cache_nonce);
   if (err)
     {
-      log_error ("make_keysig_packet failed: %s\n", g10_errstr (err));
+      log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err));
       return err;
     }
 
@@ -1032,12 +1075,12 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   oduap.usage = use;
   oduap.pk = sub_pk;
   err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
-                            0, 0, timestamp, 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));
+      log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err));
       return err;
     }
 
@@ -1062,7 +1105,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
 {
   gpg_error_t err;
   gcry_sexp_t list, l2;
-  char *curve;
+  char *curve = NULL;
   int i;
   const char *oidstr;
   unsigned int nbits;
@@ -1131,6 +1174,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
     }
 
  leave:
+  xfree (curve);
   if (err)
     {
       for (i=0; i < 3; i++)
@@ -1284,19 +1328,22 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 }
 
 
-/* Common code for the key generation fucntion gen_xxx.  */
+/* Common code for the key generation function 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 keygen_flags, const char *passphrase,
+            char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   PACKET *pkt;
   PKT_public_key *pk;
   gcry_sexp_t s_key;
 
-  err = agent_genkey (NULL, cache_nonce_addr, keyparms,
-                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
+  err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
+                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
+                      passphrase,
+                      &s_key);
   if (err)
     {
       log_error ("agent_genkey failed: %s\n", gpg_strerror (err) );
@@ -1354,13 +1401,14 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
 static int
 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 keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
 
-  assert (is_ELGAMAL (algo));
+  log_assert (is_ELGAMAL (algo));
 
   if (nbits < 1024)
     {
@@ -1395,7 +1443,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "pgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1409,7 +1458,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 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 keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   unsigned int qbits;
@@ -1482,7 +1532,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1497,14 +1548,15 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 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)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
   char *keyparms;
 
-  assert (algo == PUBKEY_ALGO_ECDSA
-          || algo == PUBKEY_ALGO_EDDSA
-          || algo == PUBKEY_ALGO_ECDH);
+  log_assert (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH);
 
   if (!curve || !*curve)
     return gpg_error (GPG_ERR_UNKNOWN_CURVE);
@@ -1518,6 +1570,13 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
        (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
          && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
         " transient-key" : ""));
+  else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519"))
+    keyparms = xtryasprintf
+      ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
+       strlen (curve), curve,
+       (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+         && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+        " transient-key" : ""));
   else
     keyparms = xtryasprintf
       ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
@@ -1532,7 +1591,8 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1546,25 +1606,27 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
 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 keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
+  const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096);
 
-  assert (is_RSA(algo));
+  log_assert (is_RSA(algo));
 
   if (!nbits)
-    nbits = DEFAULT_STD_KEYSIZE;
+    nbits = get_keysize_range (algo, NULL, NULL);
 
   if (nbits < 1024)
     {
       nbits = 2048;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
-  else if (nbits > 4096)
+  else if (nbits > maxsize)
     {
-      nbits = 4096;
+      nbits = maxsize;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
@@ -1586,7 +1648,8 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "ne",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1639,9 +1702,10 @@ print_key_flags(int flags)
 }
 
 
-/* Returns the key flags */
-static unsigned int
-ask_key_flags(int algo,int subkey)
+/* Ask for the key flags and return them.  CURRENT gives the current
+ * usage which should normally be given as 0. */
+unsigned int
+ask_key_flags (int algo, int subkey, unsigned int current)
 {
   /* TRANSLATORS: Please use only plain ASCII characters for the
      translation.  If this is not possible use single digits.  The
@@ -1653,10 +1717,10 @@ ask_key_flags(int algo,int subkey)
        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);
+  const char *togglers = _("SsEeAaQq");
+  char *answer = NULL;
+  const char *s;
+  unsigned int possible = openpgp_pk_algo_usage(algo);
 
   if ( strlen(togglers) != 8 )
     {
@@ -1670,14 +1734,20 @@ ask_key_flags(int algo,int subkey)
     possible&=~PUBKEY_USAGE_CERT;
 
   /* Preload the current set with the possible set, minus
-     authentication, since nobody really uses auth yet. */
-  current=possible&~PUBKEY_USAGE_AUTH;
+     authentication if CURRENT has been given as 0.  If CURRENT has
+     been has non-zero we mask with all possible usages. */
+  if (current)
+    current &= possible;
+  else
+    current = (possible&~PUBKEY_USAGE_AUTH);
 
   for(;;)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                openpgp_pk_algo_name (algo));
+                 (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA)
+                 ? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1701,7 +1771,29 @@ ask_key_flags(int algo,int subkey)
       answer = cpr_get("keygen.flags",_("Your selection? "));
       cpr_kill_prompt();
 
-      if(strlen(answer)>1)
+      if (*answer == '=')
+        {
+          /* Hack to allow direct entry of the capabilities.  */
+          current = 0;
+          for (s=answer+1; *s; s++)
+            {
+              if ((*s == 's' || *s == 'S') && (possible&PUBKEY_USAGE_SIG))
+                current |= PUBKEY_USAGE_SIG;
+              else if ((*s == 'e' || *s == 'E') && (possible&PUBKEY_USAGE_ENC))
+                current |= PUBKEY_USAGE_ENC;
+              else if ((*s == 'a' || *s == 'A') && (possible&PUBKEY_USAGE_AUTH))
+                current |= PUBKEY_USAGE_AUTH;
+              else if (!subkey && *s == 'c')
+                {
+                  /* Accept 'c' for the primary key because USAGE_CERT
+                     will be set anyway.  This is for folks who
+                     want to experiment with a cert-only primary key.  */
+                  current |= PUBKEY_USAGE_CERT;
+                }
+            }
+          break;
+        }
+      else if (strlen(answer)>1)
        tty_printf(_("Invalid selection.\n"));
       else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7])
        break;
@@ -1747,7 +1839,7 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
   gpg_error_t err;
   unsigned char *public;
   size_t publiclen;
-  const char *algostr;
+  int algo;
 
   if (hexgrip[0] == '&')
     hexgrip++;
@@ -1757,26 +1849,10 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
     return 0;
   publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
 
-  get_pk_algo_from_canon_sexp (public, publiclen, &algostr);
+  algo = get_pk_algo_from_canon_sexp (public, publiclen);
   xfree (public);
 
-  /* FIXME: Mapping of ECC algorithms is probably not correct. */
-  if (!algostr)
-    return 0;
-  else if (!strcmp (algostr, "rsa"))
-    return PUBKEY_ALGO_RSA;
-  else if (!strcmp (algostr, "dsa"))
-    return PUBKEY_ALGO_DSA;
-  else if (!strcmp (algostr, "elg"))
-    return PUBKEY_ALGO_ELGAMAL_E;
-  else if (!strcmp (algostr, "ecc"))
-    return PUBKEY_ALGO_ECDH;
-  else if (!strcmp (algostr, "ecdsa"))
-    return PUBKEY_ALGO_ECDSA;
-  else if (!strcmp (algostr, "eddsa"))
-    return PUBKEY_ALGO_EDDSA;
-  else
-    return 0;
+  return map_pk_gcry_to_openpgp (algo);
 }
 
 
@@ -1794,7 +1870,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           char **r_keygrip)
 {
   char *keygrip = NULL;
-  char *answer;
+  char *answer = NULL;
   int algo;
   int dummy_algo;
 
@@ -1808,24 +1884,27 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
     tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
 #endif
 
-  if (!addmode)
+  if (!addmode && opt.compliance != CO_DE_VS)
     tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
 
-  tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
+  if (opt.compliance != CO_DE_VS)
+    tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
 #if GPG_USE_RSA
   tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
 #endif
 
   if (addmode)
     {
-      tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
+      if (opt.compliance != CO_DE_VS)
+        tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
 #endif
     }
   if (opt.expert)
     {
-      tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
+      if (opt.compliance != CO_DE_VS)
+        tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
 #endif
@@ -1849,84 +1928,92 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
     {
       *r_usage = 0;
       *r_subkey_algo = 0;
+      xfree (answer);
       answer = cpr_get ("keygen.algo", _("Your selection? "));
       cpr_kill_prompt ();
       algo = *answer? atoi (answer) : 1;
-      xfree(answer);
-      answer = NULL;
-      if (algo == 1 && !addmode)
+
+      if (opt.compliance == CO_DE_VS
+          && (algo == 2 || algo == 3 || algo == 5 || algo == 7))
+        {
+          tty_printf (_("Invalid selection.\n"));
+        }
+      else if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_subkey_algo = PUBKEY_ALGO_RSA;
           break;
        }
-      else if (algo == 2 && !addmode)
+      else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode)
         {
           algo = PUBKEY_ALGO_DSA;
           *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E;
           break;
        }
-      else if (algo == 3)
+      else if (algo == 3 || !strcmp (answer, "dsa"))
         {
           algo = PUBKEY_ALGO_DSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 4)
+      else if (algo == 4 || !strcmp (answer, "rsa/s"))
         {
           algo = PUBKEY_ALGO_RSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 5 && addmode)
+      else if ((algo == 5 || !strcmp (answer, "elg")) && addmode)
         {
           algo = PUBKEY_ALGO_ELGAMAL_E;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 6 && addmode)
+      else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 7 && opt.expert)
+      else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_DSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
-      else if (algo == 8 && opt.expert)
+      else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_RSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
-      else if (algo == 9 && opt.expert && !addmode)
+      else if ((algo == 9 || !strcmp (answer, "ecc+ecc"))
+               && opt.expert && !addmode)
         {
           algo = PUBKEY_ALGO_ECDSA;
           *r_subkey_algo = PUBKEY_ALGO_ECDH;
           break;
        }
-      else if (algo == 10 && opt.expert)
+      else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 11 && opt.expert)
+      else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
-      else if (algo == 12 && opt.expert && addmode)
+      else if ((algo == 12 || !strcmp (answer, "ecc/e"))
+               && opt.expert && addmode)
         {
           algo = PUBKEY_ALGO_ECDH;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 13 && opt.expert && r_keygrip)
+      else if ((algo == 13 || !strcmp (answer, "keygrip"))
+               && opt.expert && r_keygrip)
         {
           for (;;)
             {
@@ -1953,105 +2040,72 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           xfree (keygrip);
           keygrip = answer;
           answer = NULL;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else
         tty_printf (_("Invalid selection.\n"));
+
     }
 
+  xfree(answer);
   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, unsigned int primary_keysize)
+static unsigned int
+get_keysize_range (int algo, unsigned int *min, unsigned int *max)
 {
-  unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096;
-  int for_subkey = !!primary_keysize;
-  int autocomp = 0;
+  unsigned int def;
+  unsigned int dummy1, dummy2;
 
-  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;
-    }
+  if (!min)
+    min = &dummy1;
+  if (!max)
+    max = &dummy2;
 
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
+      *min = opt.expert? 768 : 1024;
+      *max=3072;
       def=2048;
-      max=3072;
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
-      min=256;
+      *min=256;
+      *max=521;
       def=256;
-      max=521;
       break;
 
     case PUBKEY_ALGO_EDDSA:
-      min=255;
+      *min=255;
+      *max=441;
       def=255;
-      max=441;
       break;
 
-    case PUBKEY_ALGO_RSA:
-      min=1024;
+    default:
+      *min = opt.compliance == CO_DE_VS ? 2048: 1024;
+      *max = 4096;
+      def = 2048;
       break;
     }
 
-  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            openpgp_pk_algo_name (algo), min, max);
-
-  for (;;)
-    {
-      char *prompt, *answer;
-
-      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"),
-                  openpgp_pk_algo_name (algo), min, max);
-      else
-       break;
-    }
+  return def;
+}
 
-  tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
- leave:
+/* Return a fixed up keysize depending on ALGO.  */
+static unsigned int
+fixup_keysize (unsigned int nbits, int algo, int silent)
+{
   if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits);
     }
   else if (algo == PUBKEY_ALGO_EDDSA)
@@ -2062,7 +2116,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 255;
           else
             nbits = 441;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
@@ -2076,14 +2130,14 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 384;
           else
             nbits = 521;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
   else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
@@ -2091,32 +2145,99 @@ ask_keysize (int algo, unsigned int primary_keysize)
 }
 
 
+/* 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, unsigned int primary_keysize)
+{
+  unsigned int nbits;
+  unsigned int min, def, max;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
+
+  def = get_keysize_range (algo, &min, &max);
+
+  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;
+    }
+
+  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+            openpgp_pk_algo_name (algo), min, max);
+
+  for (;;)
+    {
+      char *prompt, *answer;
+
+      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"),
+                  openpgp_pk_algo_name (algo), min, max);
+      else
+       break;
+    }
+
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
+
+ leave:
+  nbits = fixup_keysize (nbits, algo, autocomp);
+  return nbits;
+}
+
+
 /* Ask for the curve.  ALGO is the selected algorithm which this
    function may adjust.  Returns a malloced string with the name of
    the curve.  BOTH tells that gpg creates a primary and subkey. */
 static char *
-ask_curve (int *algo, int both)
+ask_curve (int *algo, int *subkey_algo)
 {
+  /* NB: We always use a complete algo list so that we have stable
+     numbers in the menu regardless on how Gpg was configured.  */
   struct {
     const char *name;
-    int available;
-    int expert_only;
-    int fix_curve;
+    const char* eddsa_curve; /* Corresponding EdDSA curve.  */
     const char *pretty_name;
+    unsigned int supported : 1;   /* Supported by gpg.     */
+    unsigned int de_vs : 1;       /* Allowed in CO_DE_VS.  */
+    unsigned int expert_only : 1; /* Only with --expert    */
+    unsigned int available : 1;   /* Available in Libycrypt (runtime checked) */
   } curves[] = {
-#if GPG_USE_EDDSA
-    { "Curve25519",      0, 0, 1, "Curve 25519" },
-#endif
 #if GPG_USE_ECDSA || GPG_USE_ECDH
-    { "NIST P-256",      0, 1, 0, },
-    { "NIST P-384",      0, 0, 0, },
-    { "NIST P-521",      0, 1, 0, },
-    { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
-    { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
-    { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
-    { "secp256k1",       0, 1, 0  },
+# define MY_USE_ECDSADH 1
+#else
+# define MY_USE_ECDSADH 0
 #endif
+    { "Curve25519",      "Ed25519", "Curve 25519", !!GPG_USE_EDDSA, 0, 0, 0 },
+    { "Curve448",        "Ed448",   "Curve 448",   0/*reserved*/  , 0, 1, 0 },
+    { "NIST P-256",      NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
+    { "NIST P-384",      NULL, NULL,               MY_USE_ECDSADH,  0, 0, 0 },
+    { "NIST P-521",      NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
+    { "brainpoolP256r1", NULL, "Brainpool P-256",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "brainpoolP384r1", NULL, "Brainpool P-384",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "brainpoolP512r1", NULL, "Brainpool P-512",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "secp256k1",       NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
   };
+#undef MY_USE_ECDSADH
   int idx;
   char *answer;
   char *result = NULL;
@@ -2124,32 +2245,38 @@ ask_curve (int *algo, int both)
 
   tty_printf (_("Please select which elliptic curve you want:\n"));
 
- again:
   keyparms = NULL;
   for (idx=0; idx < DIM(curves); idx++)
     {
       int rc;
 
       curves[idx].available = 0;
-      if (!opt.expert && curves[idx].expert_only)
+      if (!curves[idx].supported)
+        continue;
+
+      if (opt.compliance==CO_DE_VS)
+        {
+          if (!curves[idx].de_vs)
+            continue; /* Not allowed.  */
+        }
+      else if (!opt.expert && curves[idx].expert_only)
         continue;
 
-      /* FIXME: The strcmp below is a temporary hack during
-         development.  It shall be removed as soon as we have proper
-         Curve25519 support in Libgcrypt.  */
+      /* We need to switch from the ECDH name of the curve to the
+         EDDSA name of the curve if we want a signing key.  */
       gcry_sexp_release (keyparms);
       rc = gcry_sexp_build (&keyparms, NULL,
                             "(public-key(ecc(curve %s)))",
-                            (!strcmp (curves[idx].name, "Curve25519")
-                             ? "Ed25519" : curves[idx].name));
+                            curves[idx].eddsa_curve? curves[idx].eddsa_curve
+                            /**/                   : curves[idx].name);
       if (rc)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
-      if (both && curves[idx].fix_curve)
+      if (subkey_algo && curves[idx].eddsa_curve)
         {
-          /* Both Curve 25519 keys are to be created.  Check that
-             Libgcrypt also supports the real Curve25519.  */
+          /* Both Curve 25519 (or 448) keys are to be created.  Check that
+             Libgcrypt also supports the real Curve25519 (or 448).  */
           gcry_sexp_release (keyparms);
           rc = gcry_sexp_build (&keyparms, NULL,
                                 "(public-key(ecc(curve %s)))",
@@ -2196,23 +2323,15 @@ ask_curve (int *algo, int both)
         tty_printf (_("Invalid selection.\n"));
       else
         {
-          if (curves[idx].fix_curve)
-            {
-              log_info ("WARNING: Curve25519 is not yet part of the"
-                        " OpenPGP standard.\n");
-
-              if (!cpr_get_answer_is_yes("experimental_curve.override",
-                                         "Use this curve anyway? (y/N) ")  )
-                goto again;
-            }
-
           /* If the user selected a signing algorithm and Curve25519
-             we need to update the algo and and the curve name.  */
+             we need to set the algo to EdDSA and update the curve name. */
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
-              && curves[idx].fix_curve)
+              && curves[idx].eddsa_curve)
             {
+              if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
+                *subkey_algo = PUBKEY_ALGO_EDDSA;
               *algo = PUBKEY_ALGO_EDDSA;
-              result = xstrdup ("Ed25519");
+              result = xstrdup (curves[idx].eddsa_curve);
             }
           else
             result = xstrdup (curves[idx].name);
@@ -2246,7 +2365,8 @@ parse_expire_string( const char *string )
   u32 curtime = make_timestamp ();
   time_t tt;
 
-  if (!*string)
+  if (!string || !*string || !strcmp (string, "none")
+      || !strcmp (string, "never") || !strcmp (string, "-"))
     seconds = 0;
   else if (!strncmp (string, "seconds=", 8))
     seconds = atoi (string+8);
@@ -2263,7 +2383,7 @@ parse_expire_string( const char *string )
   return seconds;
 }
 
-/* Parsean Creation-Date string which is either "1986-04-26" or
+/* Parse a Creation-Date string which is either "1986-04-26" or
    "19860426T042640".  Returns 0 on error. */
 static u32
 parse_creation_string (const char *string)
@@ -2334,13 +2454,7 @@ ask_expire_interval(int object,const char *def_expire)
          {
            char *prompt;
 
-#define PROMPTSTRING _("Signature is valid for? (%s) ")
-           /* This will actually end up larger than necessary because
-              of the 2 bytes for '%s' */
-           prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1);
-           sprintf(prompt,PROMPTSTRING,def_expire);
-#undef PROMPTSTRING
-
+           prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire);
            answer = cpr_get("siggen.valid",prompt);
            xfree(prompt);
 
@@ -2416,12 +2530,30 @@ uid_from_string (const char *string)
 }
 
 
+/* Return true if the user id UID already exists in the keyblock.  */
+static int
+uid_already_in_keyblock (kbnode_t keyblock, const char *uid)
+{
+  PKT_user_id *uidpkt = uid_from_string (uid);
+  kbnode_t node;
+  int result = 0;
+
+  for (node=keyblock; node && !result; node=node->next)
+    if (!is_deleted_kbnode (node)
+        && node->pkt->pkttype == PKT_USER_ID
+        && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id))
+      result = 1;
+  free_user_id (uidpkt);
+  return result;
+}
+
+
 /* 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.  */
+   ID.  IF FULL is not set some prompts are not shown.  */
 static char *
-ask_user_id (int mode, KBNODE keyblock)
+ask_user_id (int mode, int full, KBNODE keyblock)
 {
     char *answer;
     char *aname, *acomment, *amail, *uid;
@@ -2431,7 +2563,7 @@ ask_user_id (int mode, KBNODE keyblock)
         /* 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 translate this string, a
-           different string will be used used, which might still have
+           different string will be used, which might still have
            a correct translation.  */
        const char *s1 =
           N_("\n"
@@ -2476,11 +2608,18 @@ ask_user_id (int mode, KBNODE keyblock)
                    break;
 
                if( strpbrk( aname, "<>" ) )
+                  {
                    tty_printf(_("Invalid character in name\n"));
+                   tty_printf(_("The characters '%s' and '%s' may not "
+                                 "appear in name\n"), "<", ">");
+                  }
                else if( digitp(aname) )
                    tty_printf(_("Name may not start with a digit\n"));
-               else if( strlen(aname) < 5 )
+               else if (*aname && strlen (aname) < 5)
+                  {
                    tty_printf(_("Name must be at least 5 characters long\n"));
+                    /* However, we allow an empty name.  */
+                  }
                else
                    break;
            }
@@ -2499,7 +2638,8 @@ ask_user_id (int mode, KBNODE keyblock)
                    break;
            }
        }
-       if( !acomment ) {
+       if (!acomment) {
+          if (full) {
            for(;;) {
                xfree(acomment);
                acomment = cpr_get("keygen.comment",_("Comment: "));
@@ -2512,16 +2652,30 @@ ask_user_id (int mode, KBNODE keyblock)
                else
                    break;
            }
+          }
+          else {
+            xfree (acomment);
+            acomment = xstrdup ("");
+          }
        }
 
 
        xfree(uid);
        uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
-       p = stpcpy(p, aname );
-       if( *acomment )
-           p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
-       if( *amail )
-           p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
+        if (!*aname && *amail && !*acomment && !random_is_faked ())
+          { /* Empty name and comment but with mail address.  Use
+               simplified form with only the non-angle-bracketed mail
+               address.  */
+            p = stpcpy (p, amail);
+          }
+        else
+          {
+            p = stpcpy (p, aname );
+            if (*acomment)
+              p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
+            if (*amail)
+              p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
+          }
 
        /* Append a warning if the RNG is switched into fake mode.  */
         if ( random_is_faked ()  )
@@ -2547,17 +2701,11 @@ ask_user_id (int mode, KBNODE keyblock)
 
         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);
+            if (uid_already_in_keyblock (keyblock, uid))
+              {
+                tty_printf (_("Such a user ID already exists on this key!\n"));
+                fail = 1;
+              }
           }
 
        for(;;) {
@@ -2580,11 +2728,17 @@ ask_user_id (int mode, KBNODE keyblock)
                 answer = xstrdup (ansstr + (fail?8:6));
                answer[1] = 0;
            }
-           else {
+            else if (full) {
                answer = cpr_get("keygen.userid.cmd", fail?
                  _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") :
                  _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "));
                cpr_kill_prompt();
+            }
+            else {
+               answer = cpr_get("keygen.userid.cmd", fail?
+                 _("Change (N)ame, (E)mail, or (Q)uit? ") :
+                 _("Change (N)ame, (E)mail, or (O)kay/(Q)uit? "));
+               cpr_kill_prompt();
            }
            if( strlen(answer) > 1 )
                ;
@@ -2621,7 +2775,7 @@ ask_user_id (int mode, KBNODE keyblock)
            xfree(answer);
        }
        xfree(answer);
-       if( !amail && !acomment && !amail )
+       if (!amail && !acomment)
            break;
        xfree(uid); uid = NULL;
     }
@@ -2634,60 +2788,13 @@ ask_user_id (int mode, KBNODE keyblock)
 }
 
 
-/*  MODE  0 - standard
-          1 - Ask for passphrase of the card backup key.  */
-static DEK *
-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_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;
-            break;
-        }
-       else if( !dek ) {
-           errtext = N_("passphrase not correctly repeated; try again");
-           tty_printf(_("%s.\n"), _(errtext));
-       }
-       else if( !dek->keylen ) {
-           xfree(dek); dek = NULL;
-           xfree(s2k); s2k = NULL;
-           tty_printf(_(
-           "You don't want a passphrase - this is probably a *bad* idea!\n"
-           "I will do it anyway.  You can change your passphrase at any time,\n"
-           "using this program with the option \"--edit-key\".\n\n"));
-           break;
-       }
-       else
-           break; /* okay */
-    }
-    *ret_s2k = s2k;
-    return dek;
-}
-
-
 /* 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, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
-           int keygen_flags, char **cache_nonce_addr)
+           int keygen_flags, const char *passphrase,
+           char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
 
@@ -2702,18 +2809,22 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
   if (algo == PUBKEY_ALGO_ELGAMAL_E)
     err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_DSA)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
     err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else
     BUG();
 
@@ -2723,64 +2834,384 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
 /* 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.  */
+   already existing user ID.  If UIDSTR is not NULL the user is not
+   asked but UIDSTR is used to create the user id packet; if the user
+   id already exists NULL is returned.  UIDSTR is expected to be utf-8
+   encoded and should have already been checked for a valid length
+   etc.  */
 PKT_user_id *
-generate_user_id (KBNODE keyblock)
+generate_user_id (KBNODE keyblock, const char *uidstr)
 {
+  PKT_user_id *uid;
   char *p;
 
-  p = ask_user_id (1, keyblock);
-  if (!p)
-    return NULL;  /* Canceled. */
-  return uid_from_string (p);
+  if (uidstr)
+    {
+      if (uid_already_in_keyblock (keyblock, uidstr))
+        return NULL;  /* Already exists.  */
+      uid = uid_from_string (uidstr);
+    }
+  else
+    {
+      p = ask_user_id (1, 1, keyblock);
+      if (!p)
+        return NULL;  /* Canceled. */
+      uid = uid_from_string (p);
+      xfree (p);
+    }
+  return uid;
 }
 
 
-/* Append R to the linked list PARA.  */
-static void
-append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+/* Helper for parse_key_parameter_string for one part of the
+ * specification string; i.e.  ALGO/FLAGS.  If STRING is NULL or empty
+ * success is returned.  On error an error code is returned.  Note
+ * that STRING may be modified by this function.  NULL may be passed
+ * for any parameter.  FOR_SUBKEY shall be true if this is used as a
+ * subkey.  */
+static gpg_error_t
+parse_key_parameter_part (char *string, int for_subkey,
+                          int *r_algo, unsigned int *r_size,
+                          unsigned int *r_keyuse,
+                          char const **r_curve)
 {
-  assert (para);
-  while (para->next)
-    para = para->next;
-  para->next = r;
-}
+  char *flags;
+  int algo;
+  char *endp;
+  const char *curve = NULL;
+  int ecdh_or_ecdsa = 0;
+  unsigned int size;
+  int keyuse;
+  int i;
+  const char *s;
 
-/* Release the parameter list R.  */
-static void
-release_parameter_list (struct para_data_s *r)
-{
-  struct para_data_s *r2;
+  if (!string || !*string)
+    return 0; /* Success.  */
 
-  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);
+  flags = strchr (string, '/');
+  if (flags)
+    *flags++ = 0;
 
-      xfree (r);
+  algo = 0;
+  if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
+    {
+      if (!ascii_memcasecmp (string, "rsa", 3))
+        algo = PUBKEY_ALGO_RSA;
+      else if (!ascii_memcasecmp (string, "dsa", 3))
+        algo = PUBKEY_ALGO_DSA;
+      else if (!ascii_memcasecmp (string, "elg", 3))
+        algo = PUBKEY_ALGO_ELGAMAL_E;
+    }
+  if (algo)
+    {
+      if (!string[3])
+        size = get_keysize_range (algo, NULL, NULL);
+      else
+        {
+          size = strtoul (string+3, &endp, 10);
+          if (size < 512 || size > 16384 || *endp)
+            return gpg_error (GPG_ERR_INV_VALUE);
+        }
     }
-}
+  else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
+    {
+      if (!algo)
+        {
+          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
+          ecdh_or_ecdsa = 1;       /* We may need to switch the algo.  */
+        }
+    }
+  else
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
 
-static struct para_data_s *
-get_parameter( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r;
+  /* Parse the flags.  */
+  keyuse = 0;
+  if (flags)
+    {
+      char **tokens = NULL;
 
-    for( r = para; r && r->key != key; r = r->next )
-       ;
-    return r;
-}
+      tokens = strtokenize (flags, ",");
+      if (!tokens)
+        return gpg_error_from_syserror ();
 
-static const char *
-get_parameter_value( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r = get_parameter( para, key );
+      for (i=0; (s = tokens[i]); i++)
+        {
+          if (!*s)
+            ;
+          else if (!ascii_strcasecmp (s, "sign"))
+            keyuse |= PUBKEY_USAGE_SIG;
+          else if (!ascii_strcasecmp (s, "encrypt")
+                   || !ascii_strcasecmp (s, "encr"))
+            keyuse |= PUBKEY_USAGE_ENC;
+          else if (!ascii_strcasecmp (s, "auth"))
+            keyuse |= PUBKEY_USAGE_AUTH;
+          else if (!ascii_strcasecmp (s, "cert"))
+            keyuse |= PUBKEY_USAGE_CERT;
+          else if (!ascii_strcasecmp (s, "ecdsa"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDSA;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "ecdh"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDH;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "eddsa"))
+            {
+              /* Not required but we allow it for consistency.  */
+              if (algo == PUBKEY_ALGO_EDDSA)
+                ;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+            }
+          else
+            {
+              xfree (tokens);
+              return gpg_error (GPG_ERR_UNKNOWN_FLAG);
+            }
+        }
+
+      xfree (tokens);
+    }
+
+  /* If not yet decided switch between ecdh and ecdsa.  */
+  if (ecdh_or_ecdsa && keyuse)
+    algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+  else if (ecdh_or_ecdsa)
+    algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+
+  /* Set or fix key usage.  */
+  if (!keyuse)
+    {
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_DSA)
+        keyuse = PUBKEY_USAGE_SIG;
+      else if (algo == PUBKEY_ALGO_RSA)
+        keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG;
+      else
+        keyuse = PUBKEY_USAGE_ENC;
+    }
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+           || algo == PUBKEY_ALGO_DSA)
+    {
+      keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption.  */
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E)
+    {
+      keyuse = PUBKEY_USAGE_ENC;   /* Allow only encryption.  */
+    }
+
+  /* Make sure a primary key can certify.  */
+  if (!for_subkey)
+    keyuse |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is actually possible.  */
+  if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((keyuse & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (keyuse & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Return values.  */
+  if (r_algo)
+    *r_algo = algo;
+  if (r_size)
+    {
+      unsigned int min, def, max;
+
+      /* Make sure the keysize is in the allowed range.  */
+      def = get_keysize_range (algo, &min, &max);
+      if (!size)
+        size = def;
+      else if (size < min)
+        size = min;
+      else if (size > max)
+        size = max;
+
+      *r_size = fixup_keysize (size, algo, 1);
+    }
+  if (r_keyuse)
+    *r_keyuse = keyuse;
+  if (r_curve)
+    *r_curve = curve;
+
+  return 0;
+}
+
+/* Parse and return the standard key generation parameter.
+ * The string is expected to be in this format:
+ *
+ *   ALGO[/FLAGS][+SUBALGO[/FLAGS]]
+ *
+ * Here ALGO is a string in the same format as printed by the
+ * keylisting.  For example:
+ *
+ *   rsa3072 := RSA with 3072 bit.
+ *   dsa2048 := DSA with 2048 bit.
+ *   elg2048 := Elgamal with 2048 bit.
+ *   ed25519 := EDDSA using curve Ed25519.
+ *   cv25519 := ECDH using curve Curve25519.
+ *   nistp256:= ECDSA or ECDH using curve NIST P-256
+ *
+ * All strings with an unknown prefix are considered an elliptic
+ * curve.  Curves which have no implicit algorithm require that FLAGS
+ * is given to select whether ECDSA or ECDH is used; this can eoither
+ * be done using an algorithm keyword or usage keywords.
+ *
+ * FLAGS is a comma delimited string of keywords:
+ *
+ *   cert := Allow usage Certify
+ *   sign := Allow usage Sign
+ *   encr := Allow usage Encrypt
+ *   auth := Allow usage Authentication
+ *   encrypt := Alias for "encr"
+ *   ecdsa := Use algorithm ECDSA.
+ *   eddsa := Use algorithm EdDSA.
+ *   ecdh  := Use algorithm ECDH.
+ *
+ * There are several defaults and fallbacks depending on the
+ * algorithm.  PART can be used to select which part of STRING is
+ * used:
+ *   -1 := Both parts
+ *    0 := Only the part of the primary key
+ *    1 := If there is one part parse that one, if there are
+ *         two parts parse the second part.  Always return
+ *         in the args for the primary key (R_ALGO,....).
+ *
+ */
+gpg_error_t
+parse_key_parameter_string (const char *string, int part,
+                            int *r_algo, unsigned int *r_size,
+                            unsigned *r_keyuse,
+                            char const **r_curve,
+                            int *r_subalgo, unsigned int *r_subsize,
+                            unsigned *r_subkeyuse,
+                            char const **r_subcurve)
+{
+  gpg_error_t err = 0;
+  char *primary, *secondary;
+
+  if (r_algo)
+    *r_algo = 0;
+  if (r_size)
+    *r_size = 0;
+  if (r_keyuse)
+    *r_keyuse = 0;
+  if (r_curve)
+    *r_curve = NULL;
+  if (r_subalgo)
+    *r_subalgo = 0;
+  if (r_subsize)
+    *r_subsize = 0;
+  if (r_subkeyuse)
+    *r_subkeyuse = 0;
+  if (r_subcurve)
+    *r_subcurve = NULL;
+
+  if (!string || !*string
+      || !strcmp (string, "default") || !strcmp (string, "-"))
+    string = get_default_pubkey_algo ();
+  else if (!strcmp (string, "future-default"))
+    string = FUTURE_STD_KEY_PARAM;
+
+  primary = xstrdup (string);
+  secondary = strchr (primary, '+');
+  if (secondary)
+    *secondary++ = 0;
+  if (part == -1 || part == 0)
+    {
+      err = parse_key_parameter_part (primary, 0, r_algo, r_size,
+                                      r_keyuse, r_curve);
+      if (!err && part == -1)
+        err = parse_key_parameter_part (secondary, 1, r_subalgo, r_subsize,
+                                        r_subkeyuse, r_subcurve);
+    }
+  else if (part == 1)
+    {
+      /* If we have SECONDARY, use that part.  If there is only one
+       * part consider this to be the subkey algo.  */
+      err = parse_key_parameter_part (secondary? secondary : primary, 1,
+                                      r_algo, r_size, r_keyuse, r_curve);
+    }
+
+  xfree (primary);
+
+  return err;
+}
+
+
+
+/* Append R to the linked list PARA.  */
+static void
+append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+{
+  log_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)
+{
+  struct para_data_s *r2;
+
+  for (; r ; r = r2)
+    {
+      r2 = r->next;
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
+      xfree (r);
+    }
+}
+
+static struct para_data_s *
+get_parameter( struct para_data_s *para, enum para_name key )
+{
+    struct para_data_s *r;
+
+    for( r = para; r && r->key != key; r = r->next )
+       ;
+    return r;
+}
+
+static const char *
+get_parameter_value( struct para_data_s *para, enum para_name key )
+{
+    struct para_data_s *r = get_parameter( para, key );
     return (r && *r->u.value)? r->u.value : NULL;
 }
 
+
+/* This is similar to get_parameter_value but also returns the empty
+   string.  This is required so that quick_generate_keypair can use an
+   empty Passphrase to specify no-protection.  */
+static const char *
+get_parameter_passphrase (struct para_data_s *para)
+{
+  struct para_data_s *r = get_parameter (para, pPASSPHRASE);
+  return r ? r->u.value : NULL;
+}
+
+
 static int
 get_parameter_algo( struct para_data_s *para, enum para_name key,
                     int *r_default)
@@ -2794,11 +3225,20 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   if (!r)
     return -1;
 
+  /* Note that we need to handle the ECC algorithms specified as
+     strings directly because Libgcrypt folds them all to ECC.  */
   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;
+       * also in gpg.c:gpgconf_list.  */
+      /* FIXME: We only allow the algo here and have a separate thing
+       * for the curve etc.  That is a ugly but demanded for backward
+       * compatibility with the batch key generation.  It would be
+       * better to make full use of parse_key_parameter_string.  */
+      parse_key_parameter_string (NULL, 0,
+                                  &i, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL);
+
       if (r_default)
         *r_default = 1;
     }
@@ -2806,7 +3246,13 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
     i = atoi( r->u.value );
   else if (!strcmp (r->u.value, "ELG-E")
            || !strcmp (r->u.value, "ELG"))
-    i = GCRY_PK_ELG_E;
+    i = PUBKEY_ALGO_ELGAMAL_E;
+  else if (!ascii_strcasecmp (r->u.value, "EdDSA"))
+    i = PUBKEY_ALGO_EDDSA;
+  else if (!ascii_strcasecmp (r->u.value, "ECDSA"))
+    i = PUBKEY_ALGO_ECDSA;
+  else if (!ascii_strcasecmp (r->u.value, "ECDH"))
+    i = PUBKEY_ALGO_ECDH;
   else
     i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
 
@@ -2815,6 +3261,52 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   return i;
 }
 
+
+/* Parse a usage string.  The usage keywords "auth", "sign", "encr"
+ * may be delimited by space, tab, or comma.  On error -1 is returned
+ * instead of the usage flags.  */
+static int
+parse_usagestr (const char *usagestr)
+{
+  gpg_error_t err;
+  char **tokens = NULL;
+  const char *s;
+  int i;
+  unsigned int use = 0;
+
+  tokens = strtokenize (usagestr, " \t,");
+  if (!tokens)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+      return -1;
+    }
+
+  for (i=0; (s = tokens[i]); i++)
+    {
+      if (!*s)
+        ;
+      else if (!ascii_strcasecmp (s, "sign"))
+        use |= PUBKEY_USAGE_SIG;
+      else if (!ascii_strcasecmp (s, "encrypt")
+                || !ascii_strcasecmp (s, "encr"))
+        use |= PUBKEY_USAGE_ENC;
+      else if (!ascii_strcasecmp (s, "auth"))
+        use |= PUBKEY_USAGE_AUTH;
+      else if (!ascii_strcasecmp (s, "cert"))
+        use |= PUBKEY_USAGE_CERT;
+      else
+        {
+          xfree (tokens);
+          return -1; /* error */
+        }
+    }
+
+  xfree (tokens);
+  return use;
+}
+
+
 /*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
@@ -2823,33 +3315,24 @@ static int
 parse_parameter_usage (const char *fname,
                        struct para_data_s *para, enum para_name key)
 {
-    struct para_data_s *r = get_parameter( para, key );
-    char *p, *pn;
-    unsigned int use;
+  struct para_data_s *r = get_parameter( para, key );
+  int i;
 
-    if( !r )
-       return 0; /* none (this is an optional parameter)*/
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
 
-    use = 0;
-    pn = r->u.value;
-    while ( (p = strsep (&pn, " \t,")) ) {
-        if ( !*p)
-            ;
-        else if ( !ascii_strcasecmp (p, "sign") )
-            use |= PUBKEY_USAGE_SIG;
-        else if ( !ascii_strcasecmp (p, "encrypt") )
-            use |= PUBKEY_USAGE_ENC;
-        else if ( !ascii_strcasecmp (p, "auth") )
-            use |= PUBKEY_USAGE_AUTH;
-        else {
-            log_error("%s:%d: invalid usage list\n", fname, r->lnr );
-            return -1; /* error */
-        }
+  i = parse_usagestr (r->u.value);
+  if (i == -1)
+    {
+      log_error ("%s:%d: invalid usage list\n", fname, r->lnr );
+      return -1; /* error */
     }
-    r->u.usage = use;
-    return 1;
+
+  r->u.usage = i;
+  return 1;
 }
 
+
 static int
 parse_revocation_key (const char *fname,
                      struct para_data_s *para, enum para_name key)
@@ -2935,7 +3418,7 @@ get_parameter_revkey( struct para_data_s *para, enum para_name key )
 }
 
 static int
-proc_parameter_file( struct para_data_s *para, const char *fname,
+proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
                      struct output_control_s *outctrl, int card )
 {
   struct para_data_s *r;
@@ -3066,7 +3549,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
     {
       struct keyserver_spec *spec;
 
-      spec=parse_keyserver_uri(s1,1,NULL,0);
+      spec = parse_keyserver_uri (s1, 1);
       if(spec)
        {
          free_keyserver_spec(spec);
@@ -3074,6 +3557,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
        }
       else
        {
+          r = get_parameter (para, pKEYSERVER);
          log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
          return -1;
        }
@@ -3083,72 +3567,6 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
   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);
@@ -3187,7 +3605,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       append_to_parameter (para, r);
     }
 
-  do_generate_keypair( para, outctrl, card );
+  do_generate_keypair (ctrl, para, outctrl, card );
   return 0;
 }
 
@@ -3198,7 +3616,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
  * Note, that string parameters are expected to be in UTF-8
  */
 static void
-read_parameter_file( const char *fname )
+read_parameter_file (ctrl_t ctrl, const char *fname )
 {
     static struct { const char *name;
                    enum para_name key;
@@ -3220,8 +3638,9 @@ read_parameter_file( const char *fname )
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
         { "Handle",         pHANDLE },
-       { "Keyserver",      pKEYSERVER },
-       { NULL, 0 }
+        { "Keyserver",      pKEYSERVER },
+        { "Keygrip",        pKEYGRIP },
+        { NULL, 0 }
     };
     IOBUF fp;
     byte *line;
@@ -3284,16 +3703,16 @@ read_parameter_file( const char *fname )
            else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
                outctrl.dryrun = 1;
            else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) )
-               outctrl.ask_passphrase = 1;
+              ; /* Dummy for backward compatibility. */
            else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) )
-               outctrl.ask_passphrase = 0;
+             ; /* Dummy for backward compatibility. */
            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 ))
+               if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
                   print_status_key_not_created
                     (get_parameter_value (para, pHANDLE));
                release_parameter_list( para );
@@ -3349,7 +3768,7 @@ read_parameter_file( const char *fname )
 
        if( keywords[i].key == pKEYTYPE && para ) {
            outctrl.lnr = lnr;
-           if (proc_parameter_file( para, fname, &outctrl, 0 ))
+           if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
               print_status_key_not_created
                 (get_parameter_value (para, pHANDLE));
            release_parameter_list( para );
@@ -3379,7 +3798,7 @@ read_parameter_file( const char *fname )
     }
     else if( para ) {
        outctrl.lnr = lnr;
-       if (proc_parameter_file( para, fname, &outctrl, 0 ))
+       if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
           print_status_key_not_created (get_parameter_value (para, pHANDLE));
     }
 
@@ -3395,6 +3814,7 @@ read_parameter_file( const char *fname )
        xfree( outctrl.pub.newfname );
     }
 
+    xfree (line);
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
@@ -3404,18 +3824,25 @@ read_parameter_file( const char *fname )
 /* Helper for quick_generate_keypair.  */
 static struct para_data_s *
 quickgen_set_para (struct para_data_s *para, int for_subkey,
-                   int algo, int nbits, const char *curve)
+                   int algo, int nbits, const char *curve, unsigned int use)
 {
   struct para_data_s *r;
 
-  r = xmalloc_clear (sizeof *r + 20);
+  r = xmalloc_clear (sizeof *r + 30);
   r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
-  strcpy (r->u.value, for_subkey ? "encrypt" : "sign");
+  if (use)
+    snprintf (r->u.value, 30, "%s%s%s%s",
+              (use & PUBKEY_USAGE_ENC)?  "encr " : "",
+              (use & PUBKEY_USAGE_SIG)?  "sign " : "",
+              (use & PUBKEY_USAGE_AUTH)? "auth " : "",
+              (use & PUBKEY_USAGE_CERT)? "cert " : "");
+  else
+    strcpy (r->u.value, for_subkey ? "encr" : "sign");
   r->next = para;
   para = r;
   r = xmalloc_clear (sizeof *r + 20);
   r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE;
-  sprintf (r->u.value, "%d", algo);
+  snprintf (r->u.value, 20, "%d", algo);
   r->next = para;
   para = r;
 
@@ -3444,7 +3871,8 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
  * Unattended generation of a standard key.
  */
 void
-quick_generate_keypair (const char *uid)
+quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
+                        const char *usagestr, const char *expirestr)
 {
   gpg_error_t err;
   struct para_data_s *para = NULL;
@@ -3455,6 +3883,7 @@ quick_generate_keypair (const char *uid)
   memset (&outctrl, 0, sizeof outctrl);
 
   use_tty = (!opt.batch && !opt.answer_yes
+             && !*algostr && !*usagestr && !*expirestr
              && !cpr_enabled ()
              && gnupg_isatty (fileno (stdin))
              && gnupg_isatty (fileno (stdout))
@@ -3494,6 +3923,9 @@ quick_generate_keypair (const char *uid)
     desc.u.name = uid;
 
     kdbhd = keydb_new ();
+    if (!kdbhd)
+      goto leave;
+
     err = keydb_search (kdbhd, &desc, 1, NULL);
     keydb_release (kdbhd);
     if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
@@ -3505,6 +3937,7 @@ quick_generate_keypair (const char *uid)
                  || !cpr_get_answer_is_yes_def ("quick_keygen.force",
                                                 _("Create anyway? (y/N) "), 0))
           {
+            write_status_error ("genkey", gpg_error (304));
             log_inc_errorcount ();  /* we used log_info */
             goto leave;
           }
@@ -3512,12 +3945,95 @@ quick_generate_keypair (const char *uid)
       }
   }
 
-  para = quickgen_set_para (para, 0, PUBKEY_ALGO_RSA, 2048, NULL);
-  para = quickgen_set_para (para, 1, PUBKEY_ALGO_RSA, 2048, NULL);
-  /* para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519"); */
-  /* para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH,  0, "Curve25519"); */
+  if (!*expirestr || strcmp (expirestr, "-") == 0)
+    expirestr = default_expiration_interval;
+
+  if ((!*algostr || !strcmp (algostr, "default")
+       || !strcmp (algostr, "future-default"))
+      && (!*usagestr || !strcmp (usagestr, "default")
+          || !strcmp (usagestr, "-")))
+    {
+      /* Use default key parameters.  */
+      int algo, subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
+      err = parse_key_parameter_string (algostr, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize, &subkeyuse,
+                                        &subcurve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
+      if (*expirestr)
+        {
+          u32 expire;
+
+          expire = parse_expire_string (expirestr);
+          if (expire == (u32)-1 )
+            {
+              err = gpg_error (GPG_ERR_INV_VALUE);
+              log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+              goto leave;
+            }
+          r = xmalloc_clear (sizeof *r + 20);
+          r->key = pKEYEXPIRE;
+          r->u.expire = expire;
+          r->next = para;
+          para = r;
+        }
+    }
+  else
+    {
+      /* Extended unattended mode.  Creates only the primary key. */
+      int algo;
+      unsigned int use;
+      u32 expire;
+      unsigned int nbits;
+      char *curve;
+
+      err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
+          goto leave;
+        }
+
+      para = quickgen_set_para (para, 0, algo, nbits, curve, use);
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = pKEYEXPIRE;
+      r->u.expire = expire;
+      r->next = para;
+      para = r;
+    }
+
+  /* If the pinentry loopback mode is not and we have a static
+     passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
+     mode), we use that passphrase for the new key.  */
+  if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK
+      && have_static_passphrase ())
+    {
+      const char *s = get_static_passphrase ();
+
+      r = xmalloc_clear (sizeof *r + strlen (s));
+      r->key = pPASSPHRASE;
+      strcpy (r->u.value, s);
+      r->next = para;
+      para = r;
+    }
+
+  proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
 
-  proc_parameter_file (para, "[internal]", &outctrl, 0);
  leave:
   release_parameter_list (para);
 }
@@ -3528,12 +4044,15 @@ quick_generate_keypair (const char *uid)
  * CARD_SERIALNO is not NULL the function will create the keys on an
  * 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.
+ * imported to the card and a backup file created by gpg-agent.  If
+ * FULL is not set only the basic prompts are used (except for batch
+ * mode).
  */
 void
-generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
-                  int card_backup_key)
+generate_keypair (ctrl_t ctrl, int full, const char *fname,
+                  const char *card_serialno, int card_backup_key)
 {
+  gpg_error_t err;
   unsigned int nbits;
   char *uid = NULL;
   int algo;
@@ -3559,24 +4078,33 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
 
   if (opt.batch)
     {
-      read_parameter_file( fname );
+      read_parameter_file (ctrl, fname);
       return;
     }
 
   if (card_serialno)
     {
 #ifdef ENABLE_CARD_SUPPORT
+      struct agent_card_info_s info;
+
+      memset (&info, 0, sizeof (info));
+      err = agent_scd_getattr ("KEY-ATTR", &info);
+      if (err)
+        {
+          log_error (_("error getting current key info: %s\n"),
+                     gpg_strerror (err));
+          return;
+        }
+
       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
       r->key = pSERIALNO;
       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 );
+      sprintf( r->u.value, "%d", info.key_attr[0].algo );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
@@ -3587,7 +4115,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      sprintf( r->u.value, "%d", info.key_attr[1].algo );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
@@ -3595,10 +4123,28 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
       strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
+      if (info.key_attr[1].algo == PUBKEY_ALGO_RSA)
+        {
+          r = xcalloc (1, sizeof *r + 20 );
+          r->key = pSUBKEYLENGTH;
+          sprintf( r->u.value, "%u", info.key_attr[1].nbits);
+          r->next = para;
+          para = r;
+        }
+      else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA
+               || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA
+               || info.key_attr[1].algo == PUBKEY_ALGO_ECDH)
+        {
+          r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve));
+          r->key = pSUBKEYCURVE;
+          strcpy (r->u.value, info.key_attr[1].curve);
+          r->next = para;
+          para = r;
+        }
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pAUTHKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      sprintf( r->u.value, "%d", info.key_attr[2].algo );
       r->next = para;
       para = r;
 
@@ -3612,286 +4158,399 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
         }
 #endif /*ENABLE_CARD_SUPPORT*/
     }
-  else
+  else if (full)  /* Full featured key generation.  */
     {
       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)
+      char *key_from_hexgrip = NULL;
+
+      algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip);
+      if (key_from_hexgrip)
         {
-          /* Create primary and subkey at once.  */
-          both = 1;
-          if (algo == PUBKEY_ALGO_ECDSA
-              || algo == PUBKEY_ALGO_EDDSA
-              || algo == PUBKEY_ALGO_ECDH)
+          r = xmalloc_clear( sizeof *r + 20 );
+          r->key = pKEYTYPE;
+          sprintf( r->u.value, "%d", algo);
+          r->next = para;
+          para = r;
+
+          if (use)
             {
-              curve = ask_curve (&algo, both);
-              r = xmalloc_clear( sizeof *r + 20 );
-              r->key = pKEYTYPE;
-              sprintf( r->u.value, "%d", algo);
-              r->next = para;
-              para = r;
-              nbits = 0;
-              r = xmalloc_clear (sizeof *r + strlen (curve));
-              r->key = pKEYCURVE;
-              strcpy (r->u.value, curve);
+              r = xmalloc_clear( sizeof *r + 25 );
+              r->key = pKEYUSAGE;
+              sprintf( r->u.value, "%s%s%s",
+                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
               r->next = para;
               para = r;
             }
-          else
+
+          r = xmalloc_clear( sizeof *r + 40 );
+          r->key = pKEYGRIP;
+          strcpy (r->u.value, key_from_hexgrip);
+          r->next = para;
+          para = r;
+
+          xfree (key_from_hexgrip);
+        }
+      else
+        {
+          char *curve = NULL;
+
+          if (subkey_algo)
             {
+              /* Create primary and subkey at once.  */
+              both = 1;
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
+                {
+                  curve = ask_curve (&algo, &subkey_algo);
+                  r = xmalloc_clear( sizeof *r + 20 );
+                  r->key = pKEYTYPE;
+                  sprintf( r->u.value, "%d", algo);
+                  r->next = para;
+                  para = r;
+                  nbits = 0;
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
+                }
+              else
+                {
+                  r = xmalloc_clear( sizeof *r + 20 );
+                  r->key = pKEYTYPE;
+                  sprintf( r->u.value, "%d", algo);
+                  r->next = para;
+                  para = r;
+                  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 = pKEYTYPE;
-              sprintf( r->u.value, "%d", algo);
+              r->key = pKEYUSAGE;
+              strcpy( r->u.value, "sign" );
               r->next = para;
               para = r;
-              nbits = ask_keysize (algo, 0);
+
               r = xmalloc_clear( sizeof *r + 20 );
-              r->key = pKEYLENGTH;
-              sprintf( r->u.value, "%u", nbits);
+              r->key = pSUBKEYTYPE;
+              sprintf( r->u.value, "%d", subkey_algo);
+              r->next = para;
+              para = r;
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pSUBKEYUSAGE;
+              strcpy( r->u.value, "encrypt" );
               r->next = para;
               para = r;
-            }
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYUSAGE;
-          strcpy( r->u.value, "sign" );
-          r->next = para;
-          para = r;
-
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pSUBKEYTYPE;
-          sprintf( r->u.value, "%d", subkey_algo);
-          r->next = para;
-          para = r;
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pSUBKEYUSAGE;
-          strcpy( r->u.value, "encrypt" );
-          r->next = para;
-          para = r;
 
-          if (algo == PUBKEY_ALGO_ECDSA
-              || algo == PUBKEY_ALGO_EDDSA
-              || algo == PUBKEY_ALGO_ECDH)
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
+                {
+                  if (algo == PUBKEY_ALGO_EDDSA
+                      && subkey_algo == PUBKEY_ALGO_ECDH)
+                    {
+                      /* Need to switch to a different curve for the
+                         encryption key.  */
+                      xfree (curve);
+                      curve = xstrdup ("Curve25519");
+                    }
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pSUBKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
+                }
+            }
+          else /* Create only a single key.  */
             {
-              if (algo == PUBKEY_ALGO_EDDSA
-                  && subkey_algo == PUBKEY_ALGO_ECDH)
+              /* For ECC we need to ask for the curve before storing the
+                 algo because ask_curve may change the algo.  */
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
                 {
-                  /* Need to switch to a different curve for the
-                     encryption key.  */
-                  xfree (curve);
-                  curve = xstrdup ("Curve25519");
+                  curve = ask_curve (&algo, NULL);
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
                 }
-              r = xmalloc_clear (sizeof *r + strlen (curve));
-              r->key = pSUBKEYCURVE;
-              strcpy (r->u.value, curve);
+
+              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 );
+                  r->key = pKEYUSAGE;
+                  sprintf( r->u.value, "%s%s%s",
+                           (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                           (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                           (use & PUBKEY_USAGE_AUTH)? "auth":"" );
+                  r->next = para;
+                  para = r;
+                }
+              nbits = 0;
             }
-        }
-      else /* Create only a single key.  */
-        {
-          /* For ECC we need to ask for the curve before storing the
-             algo because ask_curve may change the algo.  */
+
           if (algo == PUBKEY_ALGO_ECDSA
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo, 0);
-              nbits = 0;
-              r = xmalloc_clear (sizeof *r + strlen (curve));
-              r->key = pKEYCURVE;
-              strcpy (r->u.value, curve);
-              r->next = para;
-              para = r;
+              /* The curve has already been set.  */
             }
-
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", algo );
-          r->next = para;
-          para = r;
-
-          if (use)
+          else
             {
-              r = xmalloc_clear( sizeof *r + 25 );
-              r->key = pKEYUSAGE;
-              sprintf( r->u.value, "%s%s%s",
-                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
-                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
+              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;
             }
-          nbits = 0;
-        }
 
-      if (algo == PUBKEY_ALGO_ECDSA
-          || algo == PUBKEY_ALGO_EDDSA
-          || algo == PUBKEY_ALGO_ECDH)
-        {
-          /* The curve has already been set.  */
+          xfree (curve);
         }
-      else
+    }
+  else /* Default key generation.  */
+    {
+      int subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
+      tty_printf ( _("Note: Use \"%s %s\""
+                     " for a full featured key generation dialog.\n"),
+#if USE_GPG2_HACK
+                   GPG_NAME "2"
+#else
+                   GPG_NAME
+#endif
+                   , "--full-generate-key" );
+
+      err = parse_key_parameter_string (NULL, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize,
+                                        &subkeyuse, &subcurve);
+      if (err)
         {
-          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;
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          return;
         }
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
 
-      xfree (curve);
     }
 
-  expire = ask_expire_interval(0,NULL);
-  r = xmalloc_clear( sizeof *r + 20 );
+
+  expire = full? ask_expire_interval (0, NULL)
+               : parse_expire_string (default_expiration_interval);
+  r = xcalloc (1, sizeof *r + 20);
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
-  r = xmalloc_clear( sizeof *r + 20 );
+  r = xcalloc (1, sizeof *r + 20);
   r->key = pSUBKEYEXPIRE;
   r->u.expire = expire;
   r->next = para;
   para = r;
 
-  uid = ask_user_id (0, NULL);
-  if( !uid )
+  uid = ask_user_id (0, full, NULL);
+  if (!uid)
     {
       log_error(_("Key generation canceled.\n"));
       release_parameter_list( para );
       return;
     }
-  r = xmalloc_clear( sizeof *r + strlen(uid) );
+  r = xcalloc (1, sizeof *r + strlen (uid));
   r->key = pUSERID;
-  strcpy( r->u.value, uid );
+  strcpy (r->u.value, uid);
   r->next = para;
   para = r;
 
-  proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
-  release_parameter_list( para );
+  proc_parameter_file (ctrl, para, "[internal]", &outctrl, !!card_serialno);
+  release_parameter_list (para);
 }
 
 
-#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
-   on success and the caller must then free the returned values.  */
-static int
-generate_raw_key (int algo, unsigned int nbits, u32 created_at,
-                  PKT_secret_key **r_sk_unprotected,
-                  PKT_secret_key **r_sk_protected)
+/* Create and delete a dummy packet to start off a list of kbnodes. */
+static void
+start_tree(KBNODE *tree)
 {
-  int rc;
-  DEK *dek = NULL;
-  STRING2KEY *s2k = NULL;
-  PKT_secret_key *sk = NULL;
-  int i;
-  size_t nskey, npkey;
-  gcry_sexp_t s_parms, s_key;
-  int canceled;
+  PACKET *pkt;
 
-  npkey = pubkey_get_npkey (algo);
-  nskey = pubkey_get_nskey (algo);
-  assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);
+  pkt=xmalloc_clear(sizeof(*pkt));
+  pkt->pkttype=PKT_NONE;
+  *tree=new_kbnode(pkt);
+  delete_kbnode(*tree);
+}
 
-  if (nbits < 512)
-    {
-      nbits = 512;
-      log_info (_("keysize invalid; using %u bits\n"), nbits );
-    }
 
-  if ((nbits % 32))
+/* Write the *protected* secret key to the file.  */
+static gpg_error_t
+card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
+{
+  gpg_error_t err = 0;
+  int rc;
+  char keyid_buffer[2 * 8 + 1];
+  char name_buffer[50];
+  char *fname;
+  IOBUF fp;
+  mode_t oldmask;
+  PACKET *pkt = NULL;
+
+  format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer));
+  snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer);
+
+  fname = make_filename (backup_dir, name_buffer, NULL);
+  /* Note that the umask call is not anymore needed because
+     iobuf_create now takes care of it.  However, it does not harm
+     and thus we keep it.  */
+  oldmask = umask (077);
+  if (is_secured_filename (fname))
     {
-      nbits = ((nbits + 31) / 32) * 32;
-      log_info(_("keysize rounded up to %u bits\n"), nbits );
+      fp = NULL;
+      gpg_err_set_errno (EPERM);
     }
-
-  dek = do_ask_passphrase (&s2k, 1, &canceled);
-  if (canceled)
+  else
+    fp = iobuf_create (fname, 1);
+  umask (oldmask);
+  if (!fp)
     {
-      rc = gpg_error (GPG_ERR_CANCELED);
+      err = gpg_error_from_syserror ();
+      log_error (_("can't create backup file '%s': %s\n"), fname, strerror (errno) );
       goto leave;
     }
 
-  sk = xmalloc_clear (sizeof *sk);
-  sk->timestamp = created_at;
-  sk->version = 4;
-  sk->pubkey_algo = algo;
+  pkt = xcalloc (1, sizeof *pkt);
+  pkt->pkttype = PKT_SECRET_KEY;
+  pkt->pkt.secret_key = sk;
 
-  if ( !is_RSA (algo) )
+  rc = build_packet (fp, pkt);
+  if (rc)
     {
-      log_error ("only RSA is supported for offline generated keys\n");
-      rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-      goto leave;
+      log_error ("build packet failed: %s\n", gpg_strerror (rc));
+      iobuf_cancel (fp);
     }
-  rc = gcry_sexp_build (&s_parms, NULL,
-                        "(genkey(rsa(nbits %d)))",
-                        (int)nbits);
+  else
+    {
+      char *fprbuf;
+
+      iobuf_close (fp);
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+      log_info (_("Note: backup of card key saved to '%s'\n"), fname);
+
+      fprbuf = hexfingerprint (sk, NULL, 0);
+      write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf,
+                                    fname, strlen (fname), 0);
+      xfree (fprbuf);
+    }
+
+ leave:
+  xfree (pkt);
+  xfree (fname);
+  return err;
+}
+
+
+/* Store key to card and make a backup file in OpenPGP format.  */
+static gpg_error_t
+card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
+                            const char *backup_dir)
+{
+  PKT_public_key *sk;
+  gnupg_isotime_t timestamp;
+  gpg_error_t err;
+  char *hexgrip;
+  int rc;
+  struct agent_card_info_s info;
+  gcry_cipher_hd_t cipherhd = NULL;
+  char *cache_nonce = NULL;
+  void *kek = NULL;
+  size_t keklen;
+
+  sk = copy_public_key (NULL, sub_psk);
+  if (!sk)
+    return gpg_error_from_syserror ();
+
+  epoch2isotime (timestamp, (time_t)sk->timestamp);
+  err = hexkeygrip_from_pk (sk, &hexgrip);
+  if (err)
+    return err;
+
+  memset(&info, 0, sizeof (info));
+  rc = agent_scd_getattr ("SERIALNO", &info);
   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);
+    return (gpg_error_t)rc;
+
+  rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp);
+  xfree (info.serialno);
   if (rc)
     {
-      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
+      err = (gpg_error_t)rc;
       goto leave;
     }
-  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
-  gcry_sexp_release (s_key);
-  if (rc)
+
+  err = agent_keywrap_key (ctrl, 1, &kek, &keklen);
+  if (err)
     {
-      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      log_error ("error getting the KEK: %s\n", gpg_strerror (err));
       goto leave;
     }
 
-  for (i=npkey; i < nskey; i++)
-    sk->csum += checksum_mpi (sk->skey[i]);
-
-  if (r_sk_unprotected)
-    *r_sk_unprotected = copy_secret_key (NULL, sk);
-
-  rc = genhelp_protect (dek, s2k, sk);
-  if (rc)
-    goto leave;
-
-  if (r_sk_protected)
+  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
+                          GCRY_CIPHER_MODE_AESWRAP, 0);
+  if (!err)
+    err = gcry_cipher_setkey (cipherhd, kek, keklen);
+  if (err)
     {
-      *r_sk_protected = sk;
-      sk = NULL;
+      log_error ("error setting up an encryption context: %s\n",
+                 gpg_strerror (err));
+      goto leave;
     }
 
- leave:
-  if (sk)
-    free_secret_key (sk);
-  xfree (dek);
-  xfree (s2k);
-  return rc;
-}
-#endif /* ENABLE_CARD_SUPPORT */
+  err = receive_seckey_from_agent (ctrl, cipherhd, 0,
+                                   &cache_nonce, hexgrip, sk);
+  if (err)
+    {
+      log_error ("error getting secret key from agent: %s\n",
+                 gpg_strerror (err));
+      goto leave;
+    }
 
-/* Create and delete a dummy packet to start off a list of kbnodes. */
-static void
-start_tree(KBNODE *tree)
-{
-  PACKET *pkt;
+  err = card_write_key_to_backup_file (sk, backup_dir);
+  if (err)
+    log_error ("writing card key to backup file: %s\n", gpg_strerror (err));
+  else
+    /* Remove secret key data in agent side.  */
+    agent_scd_learn (NULL, 1);
 
-  pkt=xmalloc_clear(sizeof(*pkt));
-  pkt->pkttype=PKT_NONE;
-  *tree=new_kbnode(pkt);
-  delete_kbnode(*tree);
+ leave:
+  xfree (cache_nonce);
+  gcry_cipher_close (cipherhd);
+  xfree (kek);
+  xfree (hexgrip);
+  free_public_key (sk);
+  return err;
 }
 
 
 static void
-do_generate_keypair (struct para_data_s *para,
+do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                     struct output_control_s *outctrl, int card)
 {
   gpg_error_t err;
@@ -3903,6 +4562,9 @@ do_generate_keypair (struct para_data_s *para,
   int did_sub = 0;
   u32 timestamp;
   char *cache_nonce = NULL;
+  int algo;
+  u32 expire;
+  const char *key_from_hexgrip = NULL;
 
   if (outctrl->dryrun)
     {
@@ -3942,7 +4604,7 @@ do_generate_keypair (struct para_data_s *para,
               push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
             }
         }
-      assert( outctrl->pub.stream );
+      log_assert( outctrl->pub.stream );
       if (opt.verbose)
         log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
@@ -3968,24 +4630,40 @@ do_generate_keypair (struct para_data_s *para,
      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 ),
+  algo = get_parameter_algo( para, pKEYTYPE, NULL );
+  expire = get_parameter_u32( para, pKEYEXPIRE );
+  key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
+  if (key_from_hexgrip)
+    err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
+                                  pub_root, timestamp, expire, 0);
+  else if (!card)
+    err = do_create (algo,
                      get_parameter_uint( para, pKEYLENGTH ),
                      get_parameter_value (para, pKEYCURVE),
                      pub_root,
                      timestamp,
-                     get_parameter_u32( para, pKEYEXPIRE ), 0,
-                     outctrl->keygen_flags, &cache_nonce);
+                     expire, 0,
+                     outctrl->keygen_flags,
+                     get_parameter_passphrase (para),
+                     &cache_nonce, NULL);
   else
-    err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
-                        &timestamp,
-                        get_parameter_u32 (para, pKEYEXPIRE));
+    err = gen_card_key (1, algo,
+                        1, pub_root, &timestamp,
+                        expire);
 
   /* Get the pointer to the generated public key packet.  */
   if (!err)
     {
       pri_psk = pub_root->next->pkt->pkt.public_key;
-      assert (pri_psk);
+      log_assert (pri_psk);
+
+      /* Make sure a few fields are correctly set up before going
+         further.  */
+      pri_psk->flags.primary = 1;
+      keyid_from_pk (pri_psk, NULL);
+      /* We don't use pk_keyid to get keyid, because it also asserts
+         that main_keyid is set!  */
+      keyid_copy (pri_psk->main_keyid, pri_psk->keyid);
     }
 
   if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
@@ -4008,8 +4686,8 @@ do_generate_keypair (struct para_data_s *para,
 
   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
     {
-      err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root,
-                          &timestamp,
+      err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
+                          0, pub_root, &timestamp,
                           get_parameter_u32 (para, pKEYEXPIRE));
       if (!err)
         err = write_keybinding (pub_root, pri_psk, NULL,
@@ -4019,7 +4697,8 @@ do_generate_keypair (struct para_data_s *para,
   if (!err && get_parameter (para, pSUBKEYTYPE))
     {
       sub_psk = NULL;
-      if (!card)
+      s = NULL;
+      if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
@@ -4027,7 +4706,9 @@ do_generate_keypair (struct para_data_s *para,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           outctrl->keygen_flags, &cache_nonce);
+                           s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
+                           get_parameter_passphrase (para),
+                           &cache_nonce, NULL);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -4036,26 +4717,18 @@ do_generate_keypair (struct para_data_s *para,
               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);
+              log_assert (sub_psk);
+
+              if (s)
+                err = card_store_key_with_backup (ctrl,
+                                                  sub_psk, gnupg_homedir ());
             }
         }
       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));
-            }
+          err = gen_card_key (2, get_parameter_algo (para, pSUBKEYTYPE, NULL),
+                              0, pub_root, &timestamp,
+                              get_parameter_u32 (para, pKEYEXPIRE));
         }
 
       if (!err)
@@ -4069,16 +4742,22 @@ do_generate_keypair (struct para_data_s *para,
     {
       err = write_keyblock (outctrl->pub.stream, pub_root);
       if (err)
-        log_error ("can't write public key: %s\n", g10_errstr (err));
+        log_error ("can't write public key: %s\n", gpg_strerror (err));
     }
   else if (!err) /* Write to the standard keyrings.  */
     {
-      KEYDB_HANDLE pub_hd = keydb_new ();
+      KEYDB_HANDLE pub_hd;
 
-      err = keydb_locate_writable (pub_hd, NULL);
-      if (err)
-        log_error (_("no writable public keyring found: %s\n"),
-                   g10_errstr (err));
+      pub_hd = keydb_new ();
+      if (!pub_hd)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          err = keydb_locate_writable (pub_hd);
+          if (err)
+            log_error (_("no writable public keyring found: %s\n"),
+                       gpg_strerror (err));
+        }
 
       if (!err && opt.verbose)
         {
@@ -4091,7 +4770,7 @@ do_generate_keypair (struct para_data_s *para,
           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));
+                       keydb_get_resource_name (pub_hd), gpg_strerror (err));
         }
 
       keydb_release (pub_hd);
@@ -4112,16 +4791,20 @@ do_generate_keypair (struct para_data_s *para,
           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 ));
 
           gen_standard_revoke (pk, cache_nonce);
 
+          /* Get rid of the first empty packet.  */
+          commit_kbnode (&pub_root);
+
           if (!opt.batch)
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
-              list_keyblock (pub_root, 0, 1, 1, NULL);
+              merge_keys_and_selfsig (pub_root);
+              list_keyblock_direct (ctrl, pub_root, 0, 1, 1, 1);
             }
 
 
@@ -4141,9 +4824,9 @@ do_generate_keypair (struct para_data_s *para,
   if (err)
     {
       if (opt.batch)
-        log_error ("key generation failed: %s\n", g10_errstr(err) );
+        log_error ("key generation failed: %s\n", gpg_strerror (err) );
       else
-        tty_printf (_("Key generation failed: %s\n"), g10_errstr(err) );
+        tty_printf (_("Key generation failed: %s\n"), gpg_strerror (err) );
       write_status_error (card? "card_key_generate":"key_generate", err);
       print_status_key_not_created ( get_parameter_value (para, pHANDLE) );
     }
@@ -4160,12 +4843,90 @@ do_generate_keypair (struct para_data_s *para,
 }
 
 
+static gpg_error_t
+parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                         const char *algostr, const char *usagestr,
+                         const char *expirestr,
+                         int *r_algo, unsigned int *r_usage, u32 *r_expire,
+                         unsigned int *r_nbits, char **r_curve)
+{
+  gpg_error_t err;
+  int algo;
+  unsigned int use, nbits;
+  u32 expire;
+  int wantuse;
+  const char *curve = NULL;
+
+  *r_curve = NULL;
+
+  nbits = 0;
+
+  /* Parse the algo string.  */
+  if (algostr && *algostr == '&' && strlen (algostr) == 41)
+    {
+      /* Take algo from existing key.  */
+      algo = check_keygrip (ctrl, algostr+1);
+      /* FIXME: We need the curve name as well.  */
+      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+    }
+
+  err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
+                                    &algo, &nbits, &use, &curve,
+                                    NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
+
+  /* Parse the usage string.  */
+  if (!usagestr || !*usagestr
+      || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
+    ; /* Keep usage from parse_key_parameter_string.  */
+  else if ((wantuse = parse_usagestr (usagestr)) != -1)
+    use = wantuse;
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Make sure a primary key has the CERT usage.  */
+  if (!for_subkey)
+    use |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is possible.  NB: We have the same check in
+   * parse_key_parameter_string but need it here again in case the
+   * separate usage value has been given. */
+  if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((use & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (use & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Parse the expire string.  */
+  expire = parse_expire_string (expirestr);
+  if (expire == (u32)-1 )
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (curve)
+    {
+      *r_curve = xtrystrdup (curve);
+      if (!*r_curve)
+        return gpg_error_from_syserror ();
+    }
+  *r_algo = algo;
+  *r_usage = use;
+  *r_expire = expire;
+  *r_nbits = nbits;
+  return 0;
+}
+
+
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
-   been generated and put into the keyblocks.  */
+   been generated and put into the keyblocks.  If any of ALGOSTR,
+   USAGESTR, or EXPIRESTR is NULL interactive mode is used. */
 gpg_error_t
-generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
+                     const char *usagestr, const char *expirestr)
 {
   gpg_error_t err = 0;
+  int interactive;
   kbnode_t node;
   PKT_public_key *pri_psk = NULL;
   PKT_public_key *sub_psk = NULL;
@@ -4175,8 +4936,13 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   unsigned int nbits = 0;
   char *curve = NULL;
   u32 cur_time;
+  char *key_from_hexgrip = NULL;
   char *hexgrip = NULL;
   char *serialno = NULL;
+  char *cache_nonce = NULL;
+  char *passwd_nonce = NULL;
+
+  interactive = (!algostr || !usagestr || !expirestr);
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -4206,7 +4972,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
 
   if (pri_psk->version < 4)
     {
-      log_info (_("NOTE: creating subkeys for v3 keys "
+      log_info (_("Note: creating subkeys for v3 keys "
                   "is not OpenPGP compliant\n"));
       err = gpg_error (GPG_ERR_CONFLICT);
       goto leave;
@@ -4215,42 +4981,87 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   err = hexkeygrip_from_pk (pri_psk, &hexgrip);
   if (err)
     goto leave;
-  if (agent_get_keyinfo (NULL, hexgrip, &serialno))
+  if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
     {
-      tty_printf (_("Secret parts of primary key are not available.\n"));
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are not available.\n"));
+      else
+        log_info (  _("Secret parts of primary key are not available.\n"));
+      err = gpg_error (GPG_ERR_NO_SECKEY);
       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 (interactive)
+        tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+      else
+        log_info (  _("Secret parts of primary key are stored on-card.\n"));
+    }
 
-  if (hexgrip)
-    nbits = 0;
-  else if (algo == PUBKEY_ALGO_ECDSA
-           || algo == PUBKEY_ALGO_EDDSA
-           || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo, 0);
-  else
-    nbits = ask_keysize (algo, 0);
+  if (interactive)
+    {
+      algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip);
+      log_assert (algo);
+
+      if (key_from_hexgrip)
+        nbits = 0;
+      else if (algo == PUBKEY_ALGO_ECDSA
+               || algo == PUBKEY_ALGO_EDDSA
+               || algo == PUBKEY_ALGO_ECDH)
+        curve = ask_curve (&algo, NULL);
+      else
+        nbits = ask_keysize (algo, 0);
 
-  expire = ask_expire_interval (0, NULL);
-  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
-                                               _("Really create? (y/N) ")))
+      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;
+        }
+    }
+  else /* Unattended mode.  */
     {
-      err = gpg_error (GPG_ERR_CANCELED);
-      goto leave;
+      err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        goto leave;
     }
 
-  if (hexgrip)
-    err = do_create_from_keygrip (ctrl, algo, hexgrip,
-                                  keyblock, cur_time, expire, 1);
+  /* Verify the passphrase now so that we get a cache item for the
+   * primary key passphrase.  The agent also returns a passphrase
+   * nonce, which we can use to set the passphrase for the subkey to
+   * that of the primary key.  */
+  {
+    char *desc = gpg_format_keydesc (pri_psk, FORMAT_KEYDESC_NORMAL, 1);
+    err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/,
+                        &cache_nonce, &passwd_nonce);
+    xfree (desc);
+  }
+
+  /* Start creation.  */
+  if (key_from_hexgrip)
+    {
+      err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
+                                    keyblock, cur_time, expire, 1);
+    }
   else
-    err = do_create (algo, nbits, curve,
-                     keyblock, cur_time, expire, 1, 0, NULL);
+    {
+      const char *passwd;
+
+      /* If the pinentry loopback mode is not and we have a static
+         passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
+         mode), we use that passphrase for the new subkey.  */
+      if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK
+          && have_static_passphrase ())
+        passwd = get_static_passphrase ();
+      else
+        passwd = NULL;
+
+      err = do_create (algo, nbits, curve,
+                       keyblock, cur_time, expire, 1, 0,
+                       passwd, &cache_nonce, &passwd_nonce);
+    }
   if (err)
     goto leave;
 
@@ -4260,18 +5071,23 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
       sub_psk = node->pkt->pkt.public_key;
 
   /* Write the binding signature.  */
-  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL);
+  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time,
+                          cache_nonce);
   if (err)
     goto leave;
 
-  write_status_text (STATUS_KEY_CREATED, "S");
+  print_status_key_created ('S', sub_psk, NULL);
+
 
  leave:
+  xfree (key_from_hexgrip);
   xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
+  xfree (cache_nonce);
+  xfree (passwd_nonce);
   if (err)
-    log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
+    log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
 }
 
@@ -4285,13 +5101,24 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   gpg_error_t err = 0;
   kbnode_t node;
   PKT_public_key *pri_pk = NULL;
-  int algo;
   unsigned int use;
   u32 expire;
   u32 cur_time;
   struct para_data_s *para = NULL;
+  PKT_public_key *sub_pk = NULL;
+  int algo;
+  struct agent_card_info_s info;
+
+  log_assert (keyno >= 1 && keyno <= 3);
 
-  assert (keyno >= 1 && keyno <= 3);
+  memset (&info, 0, sizeof (info));
+  err = agent_scd_getattr ("KEY-ATTR", &info);
+  if (err)
+    {
+      log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
+      return err;
+    }
+  algo = info.key_attr[keyno-1].algo;
 
   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
   if (!para)
@@ -4306,7 +5133,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
-      log_error ("Oops; publkic key lost!\n");
+      log_error ("Oops; public key lost!\n");
       err = gpg_error (GPG_ERR_INTERNAL);
       goto leave;
     }
@@ -4329,13 +5156,12 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
 
   if (pri_pk->version < 4)
     {
-      log_info (_("NOTE: creating subkeys for v3 keys "
+      log_info (_("Note: creating subkeys for v3 keys "
                   "is not OpenPGP compliant\n"));
       err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
 
-  algo = PUBKEY_ALGO_RSA;
   expire = ask_expire_interval (0, NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
@@ -4352,25 +5178,23 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
 
   /* 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);
+  err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire);
   /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
-      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);
+      log_assert (sub_pk);
       err = write_keybinding (pub_keyblock, pri_pk, sub_pk,
                               use, cur_time, NULL);
     }
 
  leave:
   if (err)
-    log_error (_("Key generation failed: %s\n"), g10_errstr(err) );
+    log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   else
-    write_status_text (STATUS_KEY_CREATED, "S");
+    print_status_key_created ('S', sub_pk, NULL);
   release_parameter_list (para);
   return err;
 }
@@ -4390,7 +5214,7 @@ write_keyblock( IOBUF out, KBNODE node )
          if( rc )
            {
              log_error("build_packet(%d) failed: %s\n",
-                       node->pkt->pkttype, g10_errstr(rc) );
+                       node->pkt->pkttype, gpg_strerror (rc) );
              return rc;
            }
        }
@@ -4402,17 +5226,18 @@ write_keyblock( IOBUF out, KBNODE node )
 
 /* 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,
+gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
               u32 *timestamp, u32 expireval)
 {
 #ifdef ENABLE_CARD_SUPPORT
   gpg_error_t err;
-  struct agent_card_genkey_s info;
   PACKET *pkt;
   PKT_public_key *pk;
+  char keyid[10];
+  unsigned char *public;
+  gcry_sexp_t s_key;
 
-  if (algo != PUBKEY_ALGO_RSA)
-    return gpg_error (GPG_ERR_PUBKEY_ALGO);
+  snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
 
   pk = xtrycalloc (1, sizeof *pk );
   if (!pk)
@@ -4425,7 +5250,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
     }
 
   /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
-  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
+  err = agent_scd_genkey (keyno, 1, 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)
@@ -4435,16 +5260,9 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
    *     tty_printf ("\n");
    *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
    *                                 _("Replace existing key? ")))
-   *       rc = agent_scd_genkey (&info, keyno, 1);
+   *       rc = agent_scd_genkey (keyno, 1, timestamp);
    *   }
   */
-  if (!err && (!info.n || !info.e))
-    {
-      log_error ("communication error with SCD\n");
-      gcry_mpi_release (info.n);
-      gcry_mpi_release (info.e);
-      err =  gpg_error (GPG_ERR_GENERAL);
-    }
   if (err)
     {
       log_error ("key generation failed: %s\n", gpg_strerror (err));
@@ -4453,17 +5271,40 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
       return err;
     }
 
-  if (*timestamp != info.created_at)
-    log_info ("NOTE: the key does not use the suggested creation date\n");
-  *timestamp = info.created_at;
+  /* Send the READKEY command so that the agent creates a shadow key for
+     card key.  We need to do that now so that we are able to create
+     the self-signatures. */
+  err = agent_readkey (NULL, 1, keyid, &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;
+
+  if (algo == PUBKEY_ALGO_RSA)
+    err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
+  else if (algo == PUBKEY_ALGO_ECDSA
+           || algo == PUBKEY_ALGO_EDDSA
+           || algo == PUBKEY_ALGO_ECDH )
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+  gcry_sexp_release (s_key);
+
+  if (err)
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      free_public_key (pk);
+      return err;
+    }
 
-  pk->timestamp = info.created_at;
+  pk->timestamp = *timestamp;
   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->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
@@ -4471,7 +5312,6 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
 
   return 0;
 #else
-  (void)algo;
   (void)keyno;
   (void)is_primary;
   (void)pub_root;
@@ -4480,259 +5320,3 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
   return gpg_error (GPG_ERR_NOT_SUPPORTED);
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
-
-
-
-static int
-gen_card_key_with_backup (int algo, int keyno, int is_primary,
-                          KBNODE pub_root, u32 timestamp,
-                          u32 expireval, struct para_data_s *para)
-{
-#if ENABLE_CARD_SUPPORT && 0
-  /* FIXME: Move this to gpg-agent.  */
-  int rc;
-  const char *s;
-  PACKET *pkt;
-  PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL;
-  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);
-  }
-
-  /* Create a key of this size in memory.  */
-  rc = generate_raw_key (algo, nbits, timestamp,
-                         &sk_unprotected, &sk_protected);
-  if (rc)
-    return rc;
-
-  /* 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;
-    }
-
-  /* Get rid of the secret key parameters and store the serial numer. */
-  sk = sk_unprotected;
-  n = pubkey_get_nskey (sk->pubkey_algo);
-  for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
-    {
-      gcry_mpi_release (sk->skey[i]);
-      sk->skey[i] = NULL;
-    }
-  i = pubkey_get_npkey (sk->pubkey_algo);
-  sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
-  sk->is_protected = 1;
-  sk->protect.s2k.mode = 1002;
-  s = get_parameter_value (para, pSERIALNO);
-  assert (s);
-  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);
-
-  /* Now write the *protected* secret key to the file.  */
-  {
-    char name_buffer[50];
-    char *fname;
-    IOBUF fp;
-    mode_t oldmask;
-
-    keyid_from_sk (sk, NULL);
-    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);
-    /* Note that the umask call is not anymore needed because
-       iobuf_create now takes care of it.  However, it does not harm
-       and thus we keep it.  */
-    oldmask = umask (077);
-    if (is_secured_filename (fname))
-      {
-        fp = NULL;
-        gpg_err_set_errno (EPERM);
-      }
-    else
-      fp = iobuf_create (fname, 1);
-    umask (oldmask);
-    if (!fp)
-      {
-        rc = gpg_error_from_syserror ();
-       log_error (_("can't create backup file '%s': %s\n"),
-                   fname, strerror(errno) );
-        xfree (fname);
-        free_secret_key (sk_unprotected);
-        free_secret_key (sk_protected);
-        return rc;
-      }
-
-    pkt = xcalloc (1, sizeof *pkt);
-    pkt->pkttype = PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk_protected;
-    sk_protected = NULL;
-
-    rc = build_packet (fp, pkt);
-    if (rc)
-      {
-        log_error("build packet failed: %s\n", g10_errstr(rc) );
-        iobuf_cancel (fp);
-      }
-    else
-      {
-        unsigned char array[MAX_FINGERPRINT_LEN];
-        char *fprbuf, *p;
-
-        iobuf_close (fp);
-        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);
-        for (i=0; i < n ; i++, p += 2)
-          sprintf (p, "%02X", array[i]);
-        *p++ = ' ';
-        *p = 0;
-
-        write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED,
-                                      fprbuf,
-                                      fname, strlen (fname),
-                                      0);
-        xfree (fprbuf);
-      }
-    free_packet (pkt);
-    xfree (pkt);
-    xfree (fname);
-    if (rc)
-      {
-        free_secret_key (sk_unprotected);
-        return rc;
-      }
-  }
-
-  /* Create the public key from the secret key. */
-  pk = xcalloc (1, sizeof *pk );
-  pk->timestamp = sk->timestamp;
-  pk->version = sk->version;
-  if (expireval)
-      pk->expiredate = sk->expiredate = sk->timestamp + expireval;
-  pk->pubkey_algo = sk->pubkey_algo;
-  n = pubkey_get_npkey (sk->pubkey_algo);
-  for (i=0; i < n; i++)
-    pk->pkey[i] = mpi_copy (sk->skey[i]);
-
-  /* Build packets and add them to the node lists.  */
-  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 ));
-
-  return 0;
-#else
-# if __GCC__ && ENABLE_CARD_SUPPORT
-#  warning Card support still missing
-# endif
-  (void)algo;
-  (void)keyno;
-  (void)is_primary;
-  (void)pub_root;
-  (void)timestamp;
-  (void)expireval;
-  (void)para;
-  return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif /*!ENABLE_CARD_SUPPORT*/
-}
-
-
-#if 0
-int
-save_unprotected_key_to_card (PKT_public_key *sk, int keyno)
-{
-  int rc;
-  unsigned char *rsa_n = NULL;
-  unsigned char *rsa_e = NULL;
-  unsigned char *rsa_p = NULL;
-  unsigned char *rsa_q = NULL;
-  size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
-  unsigned char *sexp = NULL;
-  unsigned char *p;
-  char numbuf[55], numbuf2[50];
-
-  assert (is_RSA (sk->pubkey_algo));
-  assert (!sk->is_protected);
-
-  /* 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[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. */
-  sexp = p = xmalloc_secure (30
-                             + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
-                             + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
-
-  p = stpcpy (p,"(11:private-key(3:rsa(1:n");
-  sprintf (numbuf, "%u:", (unsigned int)rsa_n_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_n, rsa_n_len);
-  p += rsa_n_len;
-
-  sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_e, rsa_e_len);
-  p += rsa_e_len;
-
-  sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_p, rsa_p_len);
-  p += rsa_p_len;
-
-  sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_q, rsa_q_len);
-  p += rsa_q_len;
-
-  p = stpcpy (p,"))(10:created-at");
-  sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp);
-  sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2));
-  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. */
-  rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
-
- leave:
-  xfree (sexp);
-  xfree (rsa_n);
-  xfree (rsa_e);
-  xfree (rsa_p);
-  xfree (rsa_q);
-  return rc;
-}
-#endif /*ENABLE_CARD_SUPPORT*/