gpg: When evaluating trust reg exps, treat tofu+pgp like pgp.
[gnupg.git] / g10 / keygen.c
index 0c95435..85bbe13 100644 (file)
@@ -1,6 +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.
+/* keygen.c - Generate a key pair
+ * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
+ * Copyright (C) 2014, 2015  Werner Koch
  *
  * This file is part of GnuPG.
  *
 #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    GCRY_PK_RSA
-#define DEFAULT_STD_KEYSIZE 2048
+#define DEFAULT_STD_ALGO       PUBKEY_ALGO_RSA
+#define DEFAULT_STD_KEYSIZE    2048
+#define DEFAULT_STD_CURVE      NULL
+#define DEFAULT_STD_SUBALGO    PUBKEY_ALGO_RSA
+#define DEFAULT_STD_SUBKEYSIZE 2048
+#define DEFAULT_STD_SUBCURVE   NULL
 
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
@@ -78,8 +86,6 @@ enum para_name {
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
   pPASSPHRASE,
-  pPASSPHRASE_DEK,
-  pPASSPHRASE_S2K,
   pSERIALNO,
   pCARDBACKUPKEY,
   pHANDLE,
@@ -91,8 +97,6 @@ struct para_data_s {
     int lnr;
     enum para_name key;
     union {
-        DEK *dek;
-        STRING2KEY *s2k;
         u32 expire;
         u32 creation;
         unsigned int usage;
@@ -105,7 +109,6 @@ struct output_control_s
 {
   int lnr;
   int dryrun;
-  int ask_passphrase;
   unsigned int keygen_flags;
   int use_files;
   struct {
@@ -132,7 +135,7 @@ 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 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,
@@ -337,33 +340,14 @@ keygen_set_std_prefs (const char *string,int personal)
              strcat(dummy_string,"S8 ");
            if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) )
              strcat(dummy_string,"S7 ");
-           if ( !openpgp_cipher_test_algo (CIPHER_ALGO_CAST5) )
-             strcat(dummy_string,"S3 ");
            strcat(dummy_string,"S2 "); /* 3DES */
-           /* If we have it, IDEA goes *after* 3DES so it won't be
-              used unless we're encrypting along with a V3 key.
-              Ideally, we would only put the S1 preference in if the
-              key was RSA and <=2048 bits, as that is what won't
-              break PGP2, but that is difficult with the current
-              code, and not really worth checking as a non-RSA <=2048
-              bit key wouldn't be usable by PGP2 anyway. -dms */
-           if (PGP2 && !openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) )
-             strcat(dummy_string,"S1 ");
-
 
             /* The default hash algo order is:
-                 SHA-256, SHA-1, SHA-384, SHA-512, SHA-224.
-               Ordering SHA-1 before SHA-384 might be viewed as a bit
-               strange; it is done because we expect that soon enough
-               SHA-3 will be available and at that point there should
-               be no more need for SHA-384 etc.  Anyway this order is
-               just a default and can easily be changed by a config
-               option.  */
+                 SHA-256, SHA-384, SHA-512, SHA-224, SHA-1.
+             */
            if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
              strcat (dummy_string, "H8 ");
 
-           strcat (dummy_string, "H2 "); /* SHA-1 */
-
            if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
              strcat (dummy_string, "H9 ");
 
@@ -373,6 +357,8 @@ keygen_set_std_prefs (const char *string,int personal)
            if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224))
              strcat (dummy_string, "H11 ");
 
+           strcat (dummy_string, "H2 "); /* SHA-1 */
+
            if(!check_compress_algo(COMPRESS_ALGO_ZLIB))
               {
                 strcat(dummy_string,"Z2 ");
@@ -824,9 +810,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. */
@@ -839,7 +826,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;
@@ -861,10 +848,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
@@ -881,7 +865,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:
@@ -934,11 +918,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;
     }
 
@@ -989,11 +973,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;
     }
 
@@ -1048,12 +1032,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;
     }
 
@@ -1304,7 +1288,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 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)
 {
   int err;
   PACKET *pkt;
@@ -1312,7 +1296,9 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
   gcry_sexp_t s_key;
 
   err = agent_genkey (NULL, cache_nonce_addr, keyparms,
-                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
+                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
+                      passphrase,
+                      &s_key);
   if (err)
     {
       log_error ("agent_genkey failed: %s\n", gpg_strerror (err) );
@@ -1370,7 +1356,7 @@ 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)
 {
   int err;
   char *keyparms;
@@ -1378,11 +1364,16 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 
   assert (is_ELGAMAL (algo));
 
-  if (nbits < 512)
+  if (nbits < 1024)
     {
       nbits = 2048;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
+  else if (nbits > 4096)
+    {
+      nbits = 4096;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
+    }
 
   if ((nbits % 32))
     {
@@ -1406,7 +1397,7 @@ 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);
       xfree (keyparms);
     }
 
@@ -1420,7 +1411,7 @@ 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)
 {
   int err;
   unsigned int qbits;
@@ -1428,7 +1419,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
   char nbitsstr[35];
   char qbitsstr[35];
 
-  if ( nbits < 512)
+  if (nbits < 768)
     {
       nbits = 2048;
       log_info(_("keysize invalid; using %u bits\n"), nbits );
@@ -1493,7 +1484,7 @@ 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);
       xfree (keyparms);
     }
 
@@ -1508,7 +1499,7 @@ 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)
 {
   gpg_error_t err;
   char *keyparms;
@@ -1520,19 +1511,37 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
   if (!curve || !*curve)
     return gpg_error (GPG_ERR_UNKNOWN_CURVE);
 
-  keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s%s)))",
-                           strlen (curve), curve,
-                           (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
-                             && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
-                            " transient-key" : ""),
-                           (!strcmp (curve, "Ed25519")? " eddsa":""));
+  /* Note that we use the "comp" flag with EdDSA to request the use of
+     a 0x40 compression prefix octet.  */
+  if (algo == PUBKEY_ALGO_EDDSA)
+    keyparms = xtryasprintf
+      ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))",
+       strlen (curve), curve,
+       (((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)))",
+       strlen (curve), curve,
+       (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+         && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+        " transient-key" : ""));
+
   if (!keyparms)
     err = gpg_error_from_syserror ();
   else
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase, cache_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1546,11 +1555,12 @@ 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)
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
+  const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096);
 
   assert (is_RSA(algo));
 
@@ -1562,6 +1572,11 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
       nbits = 2048;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
+  else if (nbits > maxsize)
+    {
+      nbits = maxsize;
+      log_info (_("keysize invalid; using %u bits\n"), nbits );
+    }
 
   if ((nbits % 32))
     {
@@ -1581,7 +1596,7 @@ 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);
       xfree (keyparms);
     }
 
@@ -1650,6 +1665,7 @@ ask_key_flags(int algo,int subkey)
   */
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
+  const char *s;
   unsigned int current=0;
   unsigned int possible=openpgp_pk_algo_usage(algo);
 
@@ -1696,7 +1712,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 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;
@@ -1789,7 +1827,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;
 
@@ -1828,7 +1866,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 
 #if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA
   if (opt.expert && !addmode)
-    tty_printf (_("   (%d) ECC\n"), 9 );
+    tty_printf (_("   (%d) ECC and ECC\n"), 9 );
   if (opt.expert)
     tty_printf (_("  (%d) ECC (sign only)\n"), 10 );
   if (opt.expert)
@@ -1844,84 +1882,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);
           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);
           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);
           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,8 +1993,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
        }
       else
         tty_printf (_("Invalid selection.\n"));
+
     }
 
+  xfree(answer);
   if (r_keygrip)
     *r_keygrip = keygrip;
   return algo;
@@ -2088,9 +2130,9 @@ ask_keysize (int algo, unsigned int primary_keysize)
 
 /* Ask for the curve.  ALGO is the selected algorithm which this
    function may adjust.  Returns a malloced string with the name of
-   the curve.  */
+   the curve.  BOTH tells that gpg creates a primary and subkey. */
 static char *
-ask_curve (int *algo)
+ask_curve (int *algo, int *subkey_algo)
 {
   struct {
     const char *name;
@@ -2119,6 +2161,7 @@ ask_curve (int *algo)
 
   tty_printf (_("Please select which elliptic curve you want:\n"));
 
+ again:
   keyparms = NULL;
   for (idx=0; idx < DIM(curves); idx++)
     {
@@ -2140,6 +2183,19 @@ ask_curve (int *algo)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
+      if (subkey_algo && curves[idx].fix_curve)
+        {
+          /* Both Curve 25519 keys are to be created.  Check that
+             Libgcrypt also supports the real Curve25519.  */
+          gcry_sexp_release (keyparms);
+          rc = gcry_sexp_build (&keyparms, NULL,
+                                "(public-key(ecc(curve %s)))",
+                                 curves[idx].name);
+          if (rc)
+            continue;
+          if (!gcry_pk_get_curve (keyparms, 0, NULL))
+            continue;
+        }
 
       curves[idx].available = 1;
       tty_printf ("   (%d) %s\n", idx + 1,
@@ -2178,16 +2234,25 @@ ask_curve (int *algo)
       else
         {
           if (curves[idx].fix_curve)
-            log_info ("WARNING: Curve25519 is an experimental algorithm and"
-                      " not yet specified by OpenPGP.  The current"
-                      " implementation may change with the next GnuPG release"
-                      " and thus rendering the key unusable!\n");
+            {
+              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.  */
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
               && curves[idx].fix_curve)
             {
+              if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
+                {
+                  *subkey_algo = PUBKEY_ALGO_EDDSA;
+                  result = xstrdup ("Ed25519");
+                }
               *algo = PUBKEY_ALGO_EDDSA;
               result = xstrdup ("Ed25519");
             }
@@ -2393,12 +2458,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;
@@ -2408,7 +2491,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,7 +2559,8 @@ ask_user_id (int mode, KBNODE keyblock)
                    break;
            }
        }
-       if( !acomment ) {
+       if (!acomment) {
+          if (full) {
            for(;;) {
                xfree(acomment);
                acomment = cpr_get("keygen.comment",_("Comment: "));
@@ -2489,6 +2573,11 @@ ask_user_id (int mode, KBNODE keyblock)
                else
                    break;
            }
+          }
+          else {
+            xfree (acomment);
+            acomment = xstrdup ("");
+          }
        }
 
 
@@ -2524,17 +2613,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(;;) {
@@ -2557,11 +2640,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 )
                ;
@@ -2598,7 +2687,7 @@ ask_user_id (int mode, KBNODE keyblock)
            xfree(answer);
        }
        xfree(answer);
-       if( !amail && !acomment && !amail )
+       if (!amail && !acomment)
            break;
        xfree(uid); uid = NULL;
     }
@@ -2613,6 +2702,7 @@ ask_user_id (int mode, 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)
 {
@@ -2657,6 +2747,7 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
     *ret_s2k = s2k;
     return dek;
 }
+#endif /* 0 */
 
 
 /* Basic key generation.  Here we divert to the actual generation
@@ -2664,7 +2755,7 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 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)
 {
   gpg_error_t err;
 
@@ -2679,18 +2770,18 @@ 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);
   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);
   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);
   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);
   else
     BUG();
 
@@ -2700,16 +2791,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, 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;
 }
 
 
@@ -2732,11 +2839,8 @@ release_parameter_list (struct para_data_s *r)
   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);
-
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
       xfree (r);
     }
 }
@@ -2758,6 +2862,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)
@@ -2771,6 +2887,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
@@ -2783,7 +2901,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));
 
@@ -2912,7 +3036,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;
@@ -3043,7 +3167,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);
@@ -3060,72 +3184,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);
@@ -3164,7 +3222,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;
 }
 
@@ -3175,7 +3233,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;
@@ -3261,16 +3319,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 );
@@ -3326,7 +3384,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 );
@@ -3356,7 +3414,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));
     }
 
@@ -3378,16 +3436,157 @@ 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)
+{
+  struct para_data_s *r;
+
+  r = xmalloc_clear (sizeof *r + 20);
+  r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
+  strcpy (r->u.value, for_subkey ? "encrypt" : "sign");
+  r->next = para;
+  para = r;
+  r = xmalloc_clear (sizeof *r + 20);
+  r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE;
+  sprintf (r->u.value, "%d", algo);
+  r->next = para;
+  para = r;
+
+  if (curve)
+    {
+      r = xmalloc_clear (sizeof *r + strlen (curve));
+      r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE;
+      strcpy (r->u.value, curve);
+      r->next = para;
+      para = r;
+    }
+  else
+    {
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH;
+      sprintf (r->u.value, "%u", nbits);
+      r->next = para;
+      para = r;
+    }
+
+  return para;
+}
+
+
+/*
+ * Unattended generation of a standard key.
+ */
+void
+quick_generate_keypair (ctrl_t ctrl, const char *uid)
+{
+  gpg_error_t err;
+  struct para_data_s *para = NULL;
+  struct para_data_s *r;
+  struct output_control_s outctrl;
+  int use_tty;
+
+  memset (&outctrl, 0, sizeof outctrl);
+
+  use_tty = (!opt.batch && !opt.answer_yes
+             && !cpr_enabled ()
+             && gnupg_isatty (fileno (stdin))
+             && gnupg_isatty (fileno (stdout))
+             && gnupg_isatty (fileno (stderr)));
+
+  r = xmalloc_clear (sizeof *r + strlen (uid));
+  r->key = pUSERID;
+  strcpy (r->u.value, uid);
+  r->next = para;
+  para = r;
+
+  uid = trim_spaces (r->u.value);
+  if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid)))
+    {
+      log_error (_("Key generation failed: %s\n"),
+                 gpg_strerror (GPG_ERR_INV_USER_ID));
+      goto leave;
+    }
+
+  /* If gpg is directly used on the console ask whether a key with the
+     given user id shall really be created.  */
+  if (use_tty)
+    {
+      tty_printf (_("About to create a key for:\n    \"%s\"\n\n"), uid);
+      if (!cpr_get_answer_is_yes_def ("quick_keygen.okay",
+                                      _("Continue? (Y/n) "), 1))
+        goto leave;
+    }
+
+  /* Check whether such a user ID already exists.  */
+  {
+    KEYDB_HANDLE kdbhd;
+    KEYDB_SEARCH_DESC desc;
+
+    memset (&desc, 0, sizeof desc);
+    desc.mode = KEYDB_SEARCH_MODE_EXACT;
+    desc.u.name = uid;
+
+    kdbhd = keydb_new ();
+    err = keydb_search (kdbhd, &desc, 1, NULL);
+    keydb_release (kdbhd);
+    if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
+      {
+        log_info (_("A key for \"%s\" already exists\n"), uid);
+        if (opt.answer_yes)
+          ;
+        else if (!use_tty
+                 || !cpr_get_answer_is_yes_def ("quick_keygen.force",
+                                                _("Create anyway? (y/N) "), 0))
+          {
+            log_inc_errorcount ();  /* we used log_info */
+            goto leave;
+          }
+        log_info (_("creating anyway\n"));
+      }
+  }
+
+  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);
+
+  /* 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);
+}
+
+
 /*
  * Generate a keypair (fname is only used in batch mode) If
  * CARD_SERIALNO is not NULL the function will create the keys on an
  * OpenPGP Card.  If 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)
 {
   unsigned int nbits;
   char *uid = NULL;
@@ -3414,7 +3613,7 @@ 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;
     }
 
@@ -3467,7 +3666,7 @@ 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;
@@ -3485,7 +3684,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo);
+              curve = ask_curve (&algo, &subkey_algo);
               r = xmalloc_clear( sizeof *r + 20 );
               r->key = pKEYTYPE;
               sprintf( r->u.value, "%d", algo);
@@ -3551,12 +3750,12 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
       else /* Create only a single key.  */
         {
           /* For ECC we need to ask for the curve before storing the
-             algo becuase ask_curve may change the algo.  */
+             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);
+              curve = ask_curve (&algo, NULL);
               nbits = 0;
               r = xmalloc_clear (sizeof *r + strlen (curve));
               r->key = pKEYCURVE;
@@ -3603,34 +3802,47 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
 
       xfree (curve);
     }
+  else /* Default key generation.  */
+    {
+      tty_printf ( _("Note: Use \"%s %s\""
+                     " for a full featured key generation dialog.\n"),
+                   NAME_OF_INSTALLED_GPG, "--full-gen-key" );
+      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);
+    }
 
-  expire = ask_expire_interval(0,NULL);
-  r = xmalloc_clear( sizeof *r + 20 );
+
+  expire = full? ask_expire_interval (0, NULL) : 0;
+  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);
 }
 
 
@@ -3746,7 +3958,7 @@ start_tree(KBNODE *tree)
 
 
 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;
@@ -3784,7 +3996,7 @@ do_generate_keypair (struct para_data_s *para,
               gpg_err_set_errno (EPERM);
             }
           else
-            outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
+            outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0);
           if (!outctrl->pub.stream)
             {
               log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname,
@@ -3830,7 +4042,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);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
@@ -3882,7 +4096,9 @@ do_generate_keypair (struct para_data_s *para,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           outctrl->keygen_flags, &cache_nonce);
+                           outctrl->keygen_flags,
+                           get_parameter_passphrase (para),
+                           &cache_nonce);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -3924,16 +4140,16 @@ 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 ();
 
-      err = keydb_locate_writable (pub_hd, NULL);
+      err = keydb_locate_writable (pub_hd);
       if (err)
         log_error (_("no writable public keyring found: %s\n"),
-                   g10_errstr (err));
+                   gpg_strerror (err));
 
       if (!err && opt.verbose)
         {
@@ -3946,7 +4162,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);
@@ -3970,11 +4186,13 @@ do_generate_keypair (struct para_data_s *para,
           update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
                                   | TRUST_ULTIMATE ));
 
+          gen_standard_revoke (pk, cache_nonce);
+
           if (!opt.batch)
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
-              list_keyblock (pub_root, 0, 1, NULL);
+              list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
             }
 
 
@@ -3994,9 +4212,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) );
     }
@@ -4059,7 +4277,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;
@@ -4086,7 +4304,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo);
+    curve = ask_curve (&algo, NULL);
   else
     nbits = ask_keysize (algo, 0);
 
@@ -4103,7 +4321,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
                                   keyblock, cur_time, expire, 1);
   else
     err = do_create (algo, nbits, curve,
-                     keyblock, cur_time, expire, 1, 0, NULL);
+                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
   if (err)
     goto leave;
 
@@ -4124,7 +4342,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   xfree (hexgrip);
   xfree (serialno);
   if (err)
-    log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
+    log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
 }
 
@@ -4182,7 +4400,7 @@ 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;
@@ -4221,7 +4439,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
 
  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");
   release_parameter_list (para);
@@ -4243,7 +4461,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;
            }
        }
@@ -4306,6 +4524,19 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
       return err;
     }
 
+  /* 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_scd_learn (NULL, 0);
+  if (err)
+    {
+      /* Oops: Card removed during generation.  */
+      log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
+      xfree (pkt);
+      xfree (pk);
+      return err;
+    }
+
   if (*timestamp != info.created_at)
     log_info ("NOTE: the key does not use the suggested creation date\n");
   *timestamp = info.created_at;
@@ -4375,7 +4606,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   rc = save_unprotected_key_to_card (sk_unprotected, keyno);
   if (rc)
     {
-      log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
+      log_error (_("storing key onto card failed: %s\n"), gpg_strerror (rc));
       free_secret_key (sk_unprotected);
       free_secret_key (sk_protected);
       write_status_errcode ("save_key_to_card", rc);
@@ -4412,6 +4643,9 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
               (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))
       {
@@ -4419,7 +4653,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
         gpg_err_set_errno (EPERM);
       }
     else
-      fp = iobuf_create (fname);
+      fp = iobuf_create (fname, 1);
     umask (oldmask);
     if (!fp)
       {
@@ -4440,7 +4674,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
     rc = build_packet (fp, pkt);
     if (rc)
       {
-        log_error("build packet failed: %s\n", g10_errstr(rc) );
+        log_error("build packet failed: %s\n", gpg_strerror (rc));
         iobuf_cancel (fp);
       }
     else
@@ -4450,7 +4684,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
 
         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);
+        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);
@@ -4538,7 +4772,7 @@ save_unprotected_key_to_card (PKT_public_key *sk, int keyno)
   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;
+      rc = GPG_ERR_INV_ARG;
       goto leave;
     }