gpg: New option --with-tofu-info.
[gnupg.git] / g10 / keygen.c
index 2610af5..2b3d328 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.
  *
@@ -25,7 +24,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "pkglue.h"
+#include "../common/shareddefs.h"
+#include "host2net.h"
+#include "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       PUBKEY_ALGO_RSA
 #define DEFAULT_STD_KEYSIZE    2048
+#define DEFAULT_STD_KEYUSE     (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)
 #define DEFAULT_STD_CURVE      NULL
 #define DEFAULT_STD_SUBALGO    PUBKEY_ALGO_RSA
 #define DEFAULT_STD_SUBKEYSIZE 2048
+#define DEFAULT_STD_SUBKEYUSE  PUBKEY_USAGE_ENC
 #define DEFAULT_STD_SUBCURVE   NULL
 
 /* Flag bits used during key generation.  */
@@ -132,15 +136,18 @@ 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,
+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 void
@@ -159,11 +166,14 @@ 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;
+          for (i=0; i < n ; i++, s++, p += 2)
+            sprintf (p, "%02X", *s);
+        }
     }
   if (*handle)
     {
@@ -192,7 +202,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);
@@ -252,6 +262,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)
 {
@@ -391,9 +413,9 @@ keygen_set_std_prefs (const char *string,int personal)
 
     if(strlen(string))
       {
-       char *tok,*prefstring;
+       char *dup, *tok, *prefstring;
 
-       prefstring=xstrdup(string); /* need a writable string! */
+       dup = prefstring = xstrdup (string); /* need a writable string! */
 
        while((tok=strsep(&prefstring," ,")))
          {
@@ -427,7 +449,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
-       xfree(prefstring);
+       xfree (dup);
       }
 
     if(!rc)
@@ -809,7 +831,8 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
   err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19,
                             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. */
@@ -822,7 +845,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;
@@ -844,10 +867,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
@@ -864,7 +884,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:
@@ -921,7 +941,7 @@ write_direct_sig (KBNODE root, PKT_public_key *psk,
                             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;
     }
 
@@ -976,7 +996,7 @@ write_selfsigs (KBNODE root, PKT_public_key *psk,
                             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;
     }
 
@@ -1036,7 +1056,7 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
                             cache_nonce);
   if (err)
     {
-      log_error ("make_keysig_packeto failed: %s\n", g10_errstr (err));
+      log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err));
       return err;
     }
 
@@ -1283,19 +1303,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) );
@@ -1353,13 +1376,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)
     {
@@ -1394,7 +1418,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);
     }
 
@@ -1408,7 +1433,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;
@@ -1481,7 +1507,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);
     }
 
@@ -1496,14 +1523,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);
@@ -1517,6 +1545,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)))",
@@ -1531,7 +1566,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);
     }
 
@@ -1545,14 +1581,15 @@ 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;
@@ -1586,7 +1623,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 +1677,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,11 +1692,10 @@ ask_key_flags(int algo,int subkey)
        a = Toggle authentication capability
        q = Finish
   */
-  const char *togglers=_("SsEeAaQq");
-  char *answer=NULL;
+  const char *togglers = _("SsEeAaQq");
+  char *answer = NULL;
   const char *s;
-  unsigned int current=0;
-  unsigned int possible=openpgp_pk_algo_usage(algo);
+  unsigned int possible = openpgp_pk_algo_usage(algo);
 
   if ( strlen(togglers) != 8 )
     {
@@ -1671,14 +1709,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: "));
@@ -1817,7 +1861,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;
 
@@ -1872,84 +1916,86 @@ 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 ((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 (;;)
             {
@@ -1976,33 +2022,113 @@ 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;
 }
 
 
+static void
+get_keysize_range (int algo,
+                   unsigned int *min, unsigned int *def, unsigned int *max)
+{
+  *min = 1024;
+  *def = DEFAULT_STD_KEYSIZE;
+  *max = 4096;
+
+  /* Deviations from the standard values.  */
+  switch(algo)
+    {
+    case PUBKEY_ALGO_DSA:
+      *min = opt.expert? 768 : 1024;
+      *def=2048;
+      *max=3072;
+      break;
+
+    case PUBKEY_ALGO_ECDSA:
+    case PUBKEY_ALGO_ECDH:
+      *min=256;
+      *def=256;
+      *max=521;
+      break;
+
+    case PUBKEY_ALGO_EDDSA:
+      *min=255;
+      *def=255;
+      *max=441;
+      break;
+    }
+}
+
+
+/* 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 (!silent)
+        tty_printf (_("rounded up to %u bits\n"), nbits);
+    }
+  else if (algo == PUBKEY_ALGO_EDDSA)
+    {
+      if (nbits != 255 && nbits != 441)
+        {
+          if (nbits < 256)
+            nbits = 255;
+          else
+            nbits = 441;
+          if (!silent)
+            tty_printf (_("rounded to %u bits\n"), nbits);
+        }
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+    {
+      if (nbits != 256 && nbits != 384 && nbits != 521)
+        {
+          if (nbits < 256)
+            nbits = 256;
+          else if (nbits < 384)
+            nbits = 384;
+          else
+            nbits = 521;
+          if (!silent)
+            tty_printf (_("rounded to %u bits\n"), nbits);
+        }
+    }
+  else if ((nbits % 32))
+    {
+      nbits = ((nbits + 31) / 32) * 32;
+      if (!silent)
+        tty_printf (_("rounded up to %u bits\n"), nbits );
+    }
+
+  return nbits;
+}
+
+
 /* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
    is not 0, the function asks for the size of the encryption
    subkey. */
 static unsigned
 ask_keysize (int algo, unsigned int primary_keysize)
 {
-  unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096;
+  unsigned int nbits;
+  unsigned int min, def, max;
   int for_subkey = !!primary_keysize;
   int autocomp = 0;
 
-  if(opt.expert)
-    min=512;
-  else
-    min=1024;
+  get_keysize_range (algo, &min, &def, &max);
 
   if (primary_keysize && !opt.expert)
     {
@@ -2018,31 +2144,6 @@ ask_keysize (int algo, unsigned int primary_keysize)
       goto leave;
     }
 
-  switch(algo)
-    {
-    case PUBKEY_ALGO_DSA:
-      def=2048;
-      max=3072;
-      break;
-
-    case PUBKEY_ALGO_ECDSA:
-    case PUBKEY_ALGO_ECDH:
-      min=256;
-      def=256;
-      max=521;
-      break;
-
-    case PUBKEY_ALGO_EDDSA:
-      min=255;
-      def=255;
-      max=441;
-      break;
-
-    case PUBKEY_ALGO_RSA:
-      min=1024;
-      break;
-    }
-
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
             openpgp_pk_algo_name (algo), min, max);
 
@@ -2071,45 +2172,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
   tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
  leave:
-  if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
-    {
-      nbits = ((nbits + 63) / 64) * 64;
-      if (!autocomp)
-        tty_printf (_("rounded up to %u bits\n"), nbits);
-    }
-  else if (algo == PUBKEY_ALGO_EDDSA)
-    {
-      if (nbits != 255 && nbits != 441)
-        {
-          if (nbits < 256)
-            nbits = 255;
-          else
-            nbits = 441;
-          if (!autocomp)
-            tty_printf (_("rounded to %u bits\n"), nbits);
-        }
-    }
-  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
-    {
-      if (nbits != 256 && nbits != 384 && nbits != 521)
-        {
-          if (nbits < 256)
-            nbits = 256;
-          else if (nbits < 384)
-            nbits = 384;
-          else
-            nbits = 521;
-          if (!autocomp)
-            tty_printf (_("rounded to %u bits\n"), nbits);
-        }
-    }
-  else if ((nbits % 32))
-    {
-      nbits = ((nbits + 31) / 32) * 32;
-      if (!autocomp)
-        tty_printf (_("rounded up to %u bits\n"), nbits );
-    }
-
+  nbits = fixup_keysize (nbits, algo, autocomp);
   return nbits;
 }
 
@@ -2118,28 +2181,34 @@ ask_keysize (int algo, unsigned int primary_keysize)
    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 available;   /* Available in Libycrypt (runtime checked) */
     int expert_only;
-    int fix_curve;
+    const char* eddsa_curve; /* Corresponding EdDSA curve.  */
     const char *pretty_name;
+    int supported;   /* Supported by gpg.  */
   } 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",      0, 0, "Ed25519", "Curve 25519", GPG_USE_EDDSA  },
+    { "Curve448",        0, 1, "Ed448",   "Curve 448",   0/*reserved*/  },
+    { "NIST P-256",      0, 1, NULL, NULL,               MY_USE_ECDSADH },
+    { "NIST P-384",      0, 0, NULL, NULL,               MY_USE_ECDSADH },
+    { "NIST P-521",      0, 1, NULL, NULL,               MY_USE_ECDSADH },
+    { "brainpoolP256r1", 0, 1, NULL, "Brainpool P-256",  MY_USE_ECDSADH },
+    { "brainpoolP384r1", 0, 1, NULL, "Brainpool P-384",  MY_USE_ECDSADH },
+    { "brainpoolP512r1", 0, 1, NULL, "Brainpool P-512",  MY_USE_ECDSADH },
+    { "secp256k1",       0, 1, NULL, NULL,               MY_USE_ECDSADH },
   };
+#undef MY_USE_ECDSADH
   int idx;
   char *answer;
   char *result = NULL;
@@ -2147,32 +2216,32 @@ 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 (!curves[idx].supported)
+        continue;
       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)))",
@@ -2219,23 +2288,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);
@@ -2439,6 +2500,24 @@ 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
@@ -2499,11 +2578,18 @@ ask_user_id (int mode, int full, 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;
            }
@@ -2546,11 +2632,20 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 
        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 ()  )
@@ -2576,17 +2671,11 @@ ask_user_id (int mode, int full, 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(;;) {
@@ -2656,7 +2745,7 @@ ask_user_id (int mode, int full, KBNODE keyblock)
            xfree(answer);
        }
        xfree(answer);
-       if( !amail && !acomment && !amail )
+       if (!amail && !acomment)
            break;
        xfree(uid); uid = NULL;
     }
@@ -2669,62 +2758,13 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 }
 
 
-/*  MODE  0 - standard
-          1 - Ask for passphrase of the card backup key.  */
-#if 0
-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;
-}
-#endif /* 0 */
-
-
 /* 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;
 
@@ -2739,18 +2779,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();
 
@@ -2760,16 +2804,32 @@ 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, 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;
 }
 
 
@@ -2777,7 +2837,7 @@ generate_user_id (KBNODE keyblock)
 static void
 append_to_parameter (struct para_data_s *para, struct para_data_s *r)
 {
-  assert (para);
+  log_assert (para);
   while (para->next)
     para = para->next;
   para->next = r;
@@ -2792,6 +2852,8 @@ release_parameter_list (struct para_data_s *r)
   for (; r ; r = r2)
     {
       r2 = r->next;
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
       xfree (r);
     }
 }
@@ -2813,6 +2875,18 @@ get_parameter_value( struct para_data_s *para, enum para_name 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)
@@ -2826,6 +2900,8 @@ 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
@@ -2839,6 +2915,12 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   else if (!strcmp (r->u.value, "ELG-E")
            || !strcmp (r->u.value, "ELG"))
     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));
 
@@ -2847,6 +2929,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 elimited 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.
@@ -2855,33 +2983,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;
-
-    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 */
-        }
+  struct para_data_s *r = get_parameter( para, key );
+  int i;
+
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
+
+  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)
@@ -2967,7 +3086,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;
@@ -3098,7 +3217,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);
@@ -3106,6 +3225,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;
        }
@@ -3153,7 +3273,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;
 }
 
@@ -3164,7 +3284,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;
@@ -3259,7 +3379,7 @@ read_parameter_file( const char *fname )
                 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 );
@@ -3315,7 +3435,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 );
@@ -3345,7 +3465,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));
     }
 
@@ -3361,6 +3481,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);
@@ -3370,18 +3491,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;
 
@@ -3410,7 +3538,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;
@@ -3421,6 +3550,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))
@@ -3460,6 +3590,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)
@@ -3478,14 +3611,63 @@ quick_generate_keypair (const char *uid)
       }
   }
 
-  para = quickgen_set_para (para, 0,
-                            DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                            DEFAULT_STD_CURVE);
-  para = quickgen_set_para (para, 1,
-                            DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                            DEFAULT_STD_SUBCURVE);
 
-  proc_parameter_file (para, "[internal]", &outctrl, 0);
+  if (!strcmp (algostr, "test-default"))
+    {
+      para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519", 0);
+      para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH,  0, "Curve25519", 0);
+    }
+  else if (*algostr || *usagestr || *expirestr)
+    {
+      /* 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;
+    }
+  else
+    {
+      para = quickgen_set_para (para, 0,
+                                DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
+                                DEFAULT_STD_CURVE, 0);
+      para = quickgen_set_para (para, 1,
+                                DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
+                                DEFAULT_STD_SUBCURVE, 0);
+    }
+
+  /* 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);
+
  leave:
   release_parameter_list (para);
 }
@@ -3529,7 +3711,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
 
   if (opt.batch)
     {
-      read_parameter_file( fname );
+      read_parameter_file (ctrl, fname);
       return;
     }
 
@@ -3600,7 +3782,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo, both);
+              curve = ask_curve (&algo, &subkey_algo);
               r = xmalloc_clear( sizeof *r + 20 );
               r->key = pKEYTYPE;
               sprintf( r->u.value, "%d", algo);
@@ -3671,8 +3853,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo, 0);
-              nbits = 0;
+              curve = ask_curve (&algo, NULL);
               r = xmalloc_clear (sizeof *r + strlen (curve));
               r->key = pKEYCURVE;
               strcpy (r->u.value, curve);
@@ -3722,13 +3903,18 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
     {
       tty_printf ( _("Note: Use \"%s %s\""
                      " for a full featured key generation dialog.\n"),
-                   NAME_OF_INSTALLED_GPG, "--full-gen-key" );
+#if USE_GPG2_HACK
+                   GPG_NAME "2"
+#else
+                   GPG_NAME
+#endif
+                   , "--full-gen-key" );
       para = quickgen_set_para (para, 0,
                                 DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                                DEFAULT_STD_CURVE);
+                                DEFAULT_STD_CURVE, 0);
       para = quickgen_set_para (para, 1,
                                 DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                                DEFAULT_STD_SUBCURVE);
+                                DEFAULT_STD_SUBCURVE, 0);
     }
 
 
@@ -3757,124 +3943,175 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
   r->next = para;
   para = r;
 
-  proc_parameter_file (para, "[internal]", &outctrl, !!card_serialno);
+  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);
+    }
+  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);
     }
-  rc = gcry_sexp_build (&s_parms, NULL,
-                        "(genkey(rsa(nbits %d)))",
-                        (int)nbits);
+
+ 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;
@@ -3925,7 +4162,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 );
     }
@@ -3958,7 +4195,9 @@ do_generate_keypair (struct para_data_s *para,
                      pub_root,
                      timestamp,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
-                     outctrl->keygen_flags, &cache_nonce);
+                     outctrl->keygen_flags,
+                     get_parameter_passphrase (para),
+                     &cache_nonce, NULL);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
@@ -3968,7 +4207,15 @@ do_generate_keypair (struct para_data_s *para,
   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)))
@@ -4002,7 +4249,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),
@@ -4010,7 +4258,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)
             {
@@ -4019,26 +4269,17 @@ 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 (PUBKEY_ALGO_RSA, 2, 0, pub_root, &timestamp,
+                              get_parameter_u32 (para, pKEYEXPIRE));
         }
 
       if (!err)
@@ -4052,16 +4293,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)
         {
@@ -4074,7 +4321,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);
@@ -4100,11 +4347,15 @@ do_generate_keypair (struct para_data_s *para,
 
           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);
             }
 
 
@@ -4124,9 +4375,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) );
     }
@@ -4143,12 +4394,144 @@ 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)
+{
+  int algo;
+  unsigned int use, nbits;
+  u32 expire;
+  int wantuse;
+  unsigned int min, def, max;
+  const char *curve = NULL;
+  int eccalgo = 0;
+
+  *r_curve = NULL;
+
+  nbits = 0;
+  /* Parse the algo string.  */
+  if (!algostr || !*algostr
+      || !strcmp (algostr, "default") || !strcmp (algostr, "-"))
+    {
+      algo = for_subkey? DEFAULT_STD_SUBALGO : DEFAULT_STD_ALGO;
+      use = for_subkey?  DEFAULT_STD_SUBKEYUSE : DEFAULT_STD_KEYUSE;
+      nbits = for_subkey?DEFAULT_STD_SUBKEYSIZE : DEFAULT_STD_KEYSIZE;
+    }
+  else if (*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);
+    }
+  else if (!strncmp (algostr, "rsa", 3))
+    {
+      algo = PUBKEY_ALGO_RSA;
+      use = for_subkey? DEFAULT_STD_SUBKEYUSE : DEFAULT_STD_KEYUSE;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if (!strncmp (algostr, "elg", 3))
+    {
+      algo = PUBKEY_ALGO_ELGAMAL_E;
+      use = PUBKEY_USAGE_ENC;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if (!strncmp (algostr, "dsa", 3))
+    {
+      algo = PUBKEY_ALGO_DSA;
+      use = PUBKEY_USAGE_SIG;
+      if (algostr[3])
+        nbits = atoi (algostr + 3);
+    }
+  else if ((curve = openpgp_is_curve_supported (algostr, &algo)))
+    {
+      if (!algo)
+        {
+          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
+          eccalgo = 1;  /* Remember - we may need to fix it up.  */
+        }
+
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA)
+        use = PUBKEY_USAGE_SIG;
+      else
+        use = PUBKEY_USAGE_ENC;
+    }
+  else
+    return gpg_error (GPG_ERR_INV_CURVE);
+
+  /* Parse the usage string.  */
+  if (!usagestr || !*usagestr
+      || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
+    ; /* Keep default usage */
+  else if ((wantuse = parse_usagestr (usagestr)) != -1)
+    {
+      use = wantuse;
+      if (eccalgo && !(use & PUBKEY_USAGE_ENC))
+        algo = PUBKEY_ALGO_ECDSA; /* Switch from ECDH to ECDSA.  */
+    }
+  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.  */
+  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.  */
+  if (!expirestr || !*expirestr || !strcmp (expirestr, "none")
+      || !strcmp (expirestr, "never") || !strcmp (expirestr, "-"))
+    expire = 0;
+  else
+    expire = parse_expire_string (expirestr);
+  if (expire == (u32)-1 )
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Make sure the keysize is in the allowed range.  */
+  get_keysize_range (algo, &min, &def, &max);
+  if (!nbits)
+    nbits = def;
+  else if (nbits < min)
+    nbits = min;
+  else if (nbits > max)
+    nbits = max;
+
+  nbits = fixup_keysize (nbits, algo, 1);
+
+  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;
@@ -4158,8 +4541,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);
@@ -4198,42 +4586,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;
 
@@ -4243,18 +4676,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;
 }
 
@@ -4273,8 +4711,9 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   u32 expire;
   u32 cur_time;
   struct para_data_s *para = NULL;
+  PKT_public_key *sub_pk = NULL;
 
-  assert (keyno >= 1 && keyno <= 3);
+  log_assert (keyno >= 1 && keyno <= 3);
 
   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
   if (!para)
@@ -4339,21 +4778,19 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   /* 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;
 }
@@ -4373,7 +4810,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;
            }
        }
@@ -4439,7 +4876,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
   /* Send the learn 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_learn ();
+  err = agent_scd_learn (NULL, 0);
   if (err)
     {
       /* Oops: Card removed during generation.  */
@@ -4476,259 +4913,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*/