gpg: When evaluating trust reg exps, treat tofu+pgp like pgp.
[gnupg.git] / g10 / keygen.c
index 2017662..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.
  *
@@ -33,7 +33,6 @@
 #include "util.h"
 #include "main.h"
 #include "packet.h"
-#include "cipher.h"
 #include "ttyio.h"
 #include "options.h"
 #include "keydb.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    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
 enum para_name {
   pKEYTYPE,
   pKEYLENGTH,
+  pKEYCURVE,
   pKEYUSAGE,
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
+  pSUBKEYCURVE,
   pSUBKEYUSAGE,
   pAUTHKEYTYPE,
   pNAMEREAL,
@@ -77,8 +86,6 @@ enum para_name {
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
   pPASSPHRASE,
-  pPASSPHRASE_DEK,
-  pPASSPHRASE_S2K,
   pSERIALNO,
   pCARDBACKUPKEY,
   pHANDLE,
@@ -90,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;
@@ -104,7 +109,6 @@ struct output_control_s
 {
   int lnr;
   int dryrun;
-  int ask_passphrase;
   unsigned int keygen_flags;
   int use_files;
   struct {
@@ -131,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,
@@ -336,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 ");
 
@@ -372,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 ");
@@ -823,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. */
@@ -838,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;
@@ -860,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
@@ -880,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:
@@ -933,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;
     }
 
@@ -988,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;
     }
 
@@ -1047,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;
     }
 
@@ -1071,40 +1056,6 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   return err;
 }
 
-/* Map the Libgcrypt ECC curve NAME to an OID.  If R_NBITS is not NULL
-   store the bit size of the curve there.  Returns NULL for unknown
-   curve names.  */
-const char *
-gpg_curve_to_oid (const char *name, unsigned int *r_nbits)
-{
-  unsigned int nbits = 0;
-  const char *oidstr;
-
-  if (!name)
-    oidstr = NULL;
-  else if (!strcmp (name, "NIST P-256"))
-    {
-      oidstr = "1.2.840.10045.3.1.7";
-      nbits = 256;
-    }
-  else if (!strcmp (name, "NIST P-384"))
-    {
-      oidstr = "1.3.132.0.34";
-      nbits = 384;
-    }
-  else if (!strcmp (name, "NIST P-521"))
-    {
-      oidstr = "1.3.132.0.35";
-      nbits = 521;
-    }
-  else
-    oidstr = NULL;
-
-  if (r_nbits)
-    *r_nbits = nbits;
-  return oidstr;
-}
-
 
 static gpg_error_t
 ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
@@ -1142,7 +1093,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
       goto leave;
     }
   gcry_sexp_release (l2);
-  oidstr = gpg_curve_to_oid (curve, &nbits);
+  oidstr = openpgp_curve_to_oid (curve, &nbits);
   if (!oidstr)
     {
       /* That can't happen because we used one of the curves
@@ -1188,7 +1139,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
           array[i] = NULL;
         }
     }
-  return 0;
+  return err;
 }
 
 
@@ -1268,6 +1219,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
     case PUBKEY_ALGO_ELGAMAL_E: algoelem = "pgy"; break;
     case PUBKEY_ALGO_ECDH:
     case PUBKEY_ALGO_ECDSA:     algoelem = ""; break;
+    case PUBKEY_ALGO_EDDSA:     algoelem = ""; break;
     default: return gpg_error (GPG_ERR_INTERNAL);
     }
 
@@ -1301,7 +1253,9 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
 
-  if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+  if (algo == PUBKEY_ALGO_ECDSA
+      || algo == PUBKEY_ALGO_EDDSA
+      || algo == PUBKEY_ALGO_ECDH )
     err = ecckey_from_sexp (pk->pkey, s_key, algo);
   else
     err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
@@ -1334,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;
@@ -1342,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) );
@@ -1363,7 +1319,9 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
 
-  if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+  if (algo == PUBKEY_ALGO_ECDSA
+      || algo == PUBKEY_ALGO_EDDSA
+      || algo == PUBKEY_ALGO_ECDH )
     err = ecckey_from_sexp (pk->pkey, s_key, algo);
   else
     err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
@@ -1398,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;
@@ -1406,9 +1364,14 @@ 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 = 1024;
+      nbits = 4096;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
@@ -1434,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);
     }
 
@@ -1448,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;
@@ -1456,9 +1419,9 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
   char nbitsstr[35];
   char qbitsstr[35];
 
-  if ( nbits < 512)
+  if (nbits < 768)
     {
-      nbits = 1024;
+      nbits = 2048;
       log_info(_("keysize invalid; using %u bits\n"), nbits );
     }
   else if ( nbits > 3072 )
@@ -1521,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);
     }
 
@@ -1534,38 +1497,51 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
  * Generate an ECC key
  */
 static gpg_error_t
-gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
+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;
-  const char *curve;
   char *keyparms;
 
-  assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
-
-  /* For now we may only use one of the 3 NIST curves.  See also
-     gpg_curve_to_oid.  */
-  if (nbits <= 256)
-    curve = "NIST P-256";
-  else if (nbits <= 384)
-    curve = "NIST P-384";
+  assert (algo == PUBKEY_ALGO_ECDSA
+          || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_ECDH);
+
+  if (!curve || !*curve)
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+
+  /* 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
-    curve = "NIST P-521";
+    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" : ""));
 
-  keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))",
-                           algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
-                           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);
     }
 
@@ -1579,11 +1555,12 @@ gen_ecc (int algo, unsigned int nbits, 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));
 
@@ -1592,7 +1569,12 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
 
   if (nbits < 1024)
     {
-      nbits = 1024;
+      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 );
     }
 
@@ -1614,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);
     }
 
@@ -1683,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);
 
@@ -1729,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;
@@ -1775,7 +1780,7 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
   gpg_error_t err;
   unsigned char *public;
   size_t publiclen;
-  int algo;
+  const char *algostr;
 
   if (hexgrip[0] == '&')
     hexgrip++;
@@ -1785,18 +1790,26 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
     return 0;
   publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
 
-  get_pk_algo_from_canon_sexp (public, publiclen, &algo);
+  get_pk_algo_from_canon_sexp (public, publiclen, &algostr);
   xfree (public);
 
-  switch (algo)
-    {
-    case GCRY_PK_RSA:   return PUBKEY_ALGO_RSA;
-    case GCRY_PK_DSA:   return PUBKEY_ALGO_DSA;
-    case GCRY_PK_ELG_E: return PUBKEY_ALGO_ELGAMAL_E;
-    case GCRY_PK_ECDH:  return PUBKEY_ALGO_ECDH;
-    case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
-    default: return 0;
-    }
+  /* FIXME: Mapping of ECC algorithms is probably not correct. */
+  if (!algostr)
+    return 0;
+  else if (!strcmp (algostr, "rsa"))
+    return PUBKEY_ALGO_RSA;
+  else if (!strcmp (algostr, "dsa"))
+    return PUBKEY_ALGO_DSA;
+  else if (!strcmp (algostr, "elg"))
+    return PUBKEY_ALGO_ELGAMAL_E;
+  else if (!strcmp (algostr, "ecc"))
+    return PUBKEY_ALGO_ECDH;
+  else if (!strcmp (algostr, "ecdsa"))
+    return PUBKEY_ALGO_ECDSA;
+  else if (!strcmp (algostr, "eddsa"))
+    return PUBKEY_ALGO_EDDSA;
+  else
+    return 0;
 }
 
 
@@ -1814,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;
 
@@ -1823,33 +1836,44 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 
   tty_printf (_("Please select what kind of key you want:\n"));
 
+#if GPG_USE_RSA
   if (!addmode)
     tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
+#endif
+
   if (!addmode)
     tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
 
   tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
+#if GPG_USE_RSA
   tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
+#endif
 
   if (addmode)
     {
       tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
+#if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
+#endif
     }
   if (opt.expert)
     {
       tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
+#if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
+#endif
     }
 
+#if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA
   if (opt.expert && !addmode)
-    tty_printf (_("   (%d) ECDSA and ECDH\n"), 9 );
+    tty_printf (_("   (%d) ECC and ECC\n"), 9 );
   if (opt.expert)
-    tty_printf (_("  (%d) ECDSA (sign only)\n"), 10 );
+    tty_printf (_("  (%d) ECC (sign only)\n"), 10 );
   if (opt.expert)
-    tty_printf (_("  (%d) ECDSA (set your own capabilities)\n"), 11 );
+    tty_printf (_("  (%d) ECC (set your own capabilities)\n"), 11 );
   if (opt.expert && addmode)
-    tty_printf (_("  (%d) ECDH (encrypt only)\n"), 12 );
+    tty_printf (_("  (%d) ECC (encrypt only)\n"), 12 );
+#endif
 
   if (opt.expert && r_keygrip)
     tty_printf (_("  (%d) Existing key\n"), 13 );
@@ -1858,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 (;;)
             {
@@ -1967,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;
@@ -2018,6 +2046,12 @@ ask_keysize (int algo, unsigned int primary_keysize)
       max=521;
       break;
 
+    case PUBKEY_ALGO_EDDSA:
+      min=255;
+      def=255;
+      max=441;
+      break;
+
     case PUBKEY_ALGO_RSA:
       min=1024;
       break;
@@ -2057,6 +2091,18 @@ ask_keysize (int algo, unsigned int primary_keysize)
       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)
@@ -2082,6 +2128,147 @@ 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.  BOTH tells that gpg creates a primary and subkey. */
+static char *
+ask_curve (int *algo, int *subkey_algo)
+{
+  struct {
+    const char *name;
+    int available;
+    int expert_only;
+    int fix_curve;
+    const char *pretty_name;
+  } 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  },
+#endif
+  };
+  int idx;
+  char *answer;
+  char *result = NULL;
+  gcry_sexp_t keyparms;
+
+  tty_printf (_("Please select which elliptic curve you want:\n"));
+
+ again:
+  keyparms = NULL;
+  for (idx=0; idx < DIM(curves); idx++)
+    {
+      int rc;
+
+      curves[idx].available = 0;
+      if (!opt.expert && curves[idx].expert_only)
+        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.  */
+      gcry_sexp_release (keyparms);
+      rc = gcry_sexp_build (&keyparms, NULL,
+                            "(public-key(ecc(curve %s)))",
+                            (!strcmp (curves[idx].name, "Curve25519")
+                             ? "Ed25519" : curves[idx].name));
+      if (rc)
+        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,
+                  curves[idx].pretty_name?
+                  curves[idx].pretty_name:curves[idx].name);
+    }
+  gcry_sexp_release (keyparms);
+
+
+  for (;;)
+    {
+      answer = cpr_get ("keygen.curve", _("Your selection? "));
+      cpr_kill_prompt ();
+      idx = *answer? atoi (answer) : 1;
+      if (*answer && !idx)
+        {
+          /* See whether the user entered the name of the curve.  */
+          for (idx=0; idx < DIM(curves); idx++)
+            {
+              if (!opt.expert && curves[idx].expert_only)
+                continue;
+              if (!stricmp (curves[idx].name, answer)
+                  || (curves[idx].pretty_name
+                      && !stricmp (curves[idx].pretty_name, answer)))
+                break;
+            }
+          if (idx == DIM(curves))
+            idx = -1;
+        }
+      else
+        idx--;
+      xfree(answer);
+      answer = NULL;
+      if (idx < 0 || idx >= DIM (curves) || !curves[idx].available)
+        tty_printf (_("Invalid selection.\n"));
+      else
+        {
+          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.  */
+          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");
+            }
+          else
+            result = xstrdup (curves[idx].name);
+          break;
+        }
+    }
+
+  if (!result)
+    result = xstrdup (curves[0].name);
+
+  return result;
+}
+
+
 /****************
  * Parse an expire string and return its value in seconds.
  * Returns (u32)-1 on error.
@@ -2180,7 +2367,7 @@ ask_expire_interval(int object,const char *def_expire)
     answer = NULL;
     for(;;)
       {
-       u32 curtime=make_timestamp();
+       u32 curtime;
 
        xfree(answer);
        if(object==0)
@@ -2204,6 +2391,7 @@ ask_expire_interval(int object,const char *def_expire)
          }
        cpr_kill_prompt();
        trim_spaces(answer);
+        curtime = make_timestamp ();
        interval = parse_expire_string( answer );
        if( interval == (u32)-1 )
          {
@@ -2270,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;
@@ -2284,9 +2490,9 @@ 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 tyranslated this string, a
-           different string will be used used, which might still have
-           a correct transaltion.  */
+           ID).  Note that if you do not translate this string, a
+           different string will be used, which might still have
+           a correct translation.  */
        const char *s1 =
           N_("\n"
              "GnuPG needs to construct a user ID to identify your key.\n"
@@ -2353,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: "));
@@ -2366,6 +2573,11 @@ ask_user_id (int mode, KBNODE keyblock)
                else
                    break;
            }
+          }
+          else {
+            xfree (acomment);
+            acomment = xstrdup ("");
+          }
        }
 
 
@@ -2401,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(;;) {
@@ -2434,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 )
                ;
@@ -2475,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;
     }
@@ -2490,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)
 {
@@ -2534,14 +2747,15 @@ 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
    routines based on the requested algorithm.  */
 static int
-do_create (int algo, unsigned int nbits, KBNODE pub_root,
+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;
 
@@ -2556,16 +2770,18 @@ do_create (int algo, unsigned int nbits, 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);
-  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
-    err = gen_ecc (algo, 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, 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();
 
@@ -2575,16 +2791,32 @@ do_create (int algo, unsigned int nbits, 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;
 }
 
 
@@ -2607,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);
     }
 }
@@ -2633,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)
@@ -2646,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
@@ -2658,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));
 
@@ -2787,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;
@@ -2918,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);
@@ -2935,73 +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;
-          static int count;
-
-          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);
@@ -3040,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;
 }
 
@@ -3051,16 +3233,18 @@ 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;
     } keywords[] = {
        { "Key-Type",       pKEYTYPE},
        { "Key-Length",     pKEYLENGTH },
+       { "Key-Curve",      pKEYCURVE },
        { "Key-Usage",      pKEYUSAGE },
        { "Subkey-Type",    pSUBKEYTYPE },
        { "Subkey-Length",  pSUBKEYLENGTH },
+       { "Subkey-Curve",   pSUBKEYCURVE },
        { "Subkey-Usage",   pSUBKEYUSAGE },
        { "Name-Real",      pNAMEREAL },
        { "Name-Email",     pNAMEEMAIL },
@@ -3135,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 );
@@ -3200,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 );
@@ -3230,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));
     }
 
@@ -3252,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;
@@ -3273,6 +3598,10 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
   struct para_data_s *r;
   struct output_control_s outctrl;
 
+#ifndef ENABLE_CARD_SUPPORT
+  (void)card_backup_key;
+#endif
+
   memset( &outctrl, 0, sizeof( outctrl ) );
 
   if (opt.batch && card_serialno)
@@ -3284,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;
     }
 
@@ -3337,9 +3666,10 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
         }
 #endif /*ENABLE_CARD_SUPPORT*/
     }
-  else
+  else if (full)  /* Full featured key generation.  */
     {
       int subkey_algo;
+      char *curve = NULL;
 
       /* Fixme: To support creating a primary key by keygrip we better
          also define the keyword for the parameter file.  Note that
@@ -3350,17 +3680,37 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
         {
           /* Create primary and subkey at once.  */
           both = 1;
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", algo );
-          r->next = para;
-          para = r;
-         nbits = ask_keysize (algo, 0);
-         r = xmalloc_clear( sizeof *r + 20 );
-         r->key = pKEYLENGTH;
-         sprintf( r->u.value, "%u", nbits);
-         r->next = para;
-         para = r;
+          if (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH)
+            {
+              curve = ask_curve (&algo, &subkey_algo);
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYTYPE;
+              sprintf( r->u.value, "%d", algo);
+              r->next = para;
+              para = r;
+              nbits = 0;
+              r = xmalloc_clear (sizeof *r + strlen (curve));
+              r->key = pKEYCURVE;
+              strcpy (r->u.value, curve);
+              r->next = para;
+              para = r;
+            }
+          else
+            {
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYTYPE;
+              sprintf( r->u.value, "%d", algo);
+              r->next = para;
+              para = r;
+              nbits = ask_keysize (algo, 0);
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYLENGTH;
+              sprintf( r->u.value, "%u", nbits);
+              r->next = para;
+              para = r;
+            }
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
@@ -3377,9 +3727,43 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
           strcpy( r->u.value, "encrypt" );
           r->next = para;
           para = r;
+
+          if (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH)
+            {
+              if (algo == PUBKEY_ALGO_EDDSA
+                  && subkey_algo == PUBKEY_ALGO_ECDH)
+                {
+                  /* Need to switch to a different curve for the
+                     encryption key.  */
+                  xfree (curve);
+                  curve = xstrdup ("Curve25519");
+                }
+              r = xmalloc_clear (sizeof *r + strlen (curve));
+              r->key = pSUBKEYCURVE;
+              strcpy (r->u.value, curve);
+              r->next = para;
+              para = r;
+            }
         }
-      else
+      else /* Create only a single key.  */
         {
+          /* For ECC we need to ask for the curve before storing the
+             algo because ask_curve may change the algo.  */
+          if (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH)
+            {
+              curve = ask_curve (&algo, NULL);
+              nbits = 0;
+              r = xmalloc_clear (sizeof *r + strlen (curve));
+              r->key = pKEYCURVE;
+              strcpy (r->u.value, curve);
+              r->next = para;
+              para = r;
+            }
+
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYTYPE;
           sprintf( r->u.value, "%d", algo );
@@ -3400,41 +3784,65 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
           nbits = 0;
         }
 
-      nbits = ask_keysize (both? subkey_algo : algo, nbits);
-      r = xmalloc_clear( sizeof *r + 20 );
-      r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
-      sprintf( r->u.value, "%u", nbits);
-      r->next = para;
-      para = r;
+      if (algo == PUBKEY_ALGO_ECDSA
+          || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_ECDH)
+        {
+          /* The curve has already been set.  */
+        }
+      else
+        {
+          nbits = ask_keysize (both? subkey_algo : algo, nbits);
+          r = xmalloc_clear( sizeof *r + 20 );
+          r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+          sprintf( r->u.value, "%u", nbits);
+          r->next = para;
+          para = r;
+        }
+
+      xfree (curve);
     }
+  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);
 }
 
 
@@ -3550,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;
@@ -3588,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,
@@ -3630,10 +4038,13 @@ do_generate_keypair (struct para_data_s *para,
   if (!card)
     err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
                      get_parameter_uint( para, pKEYLENGTH ),
+                     get_parameter_value (para, pKEYCURVE),
                      pub_root,
                      timestamp,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
-                     outctrl->keygen_flags, &cache_nonce);
+                     outctrl->keygen_flags,
+                     get_parameter_passphrase (para),
+                     &cache_nonce);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
@@ -3681,10 +4092,13 @@ do_generate_keypair (struct para_data_s *para,
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
+                           get_parameter_value (para, pSUBKEYCURVE),
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           outctrl->keygen_flags, &cache_nonce);
+                           outctrl->keygen_flags,
+                           get_parameter_passphrase (para),
+                           &cache_nonce);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -3726,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)
         {
@@ -3748,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);
@@ -3772,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);
             }
 
 
@@ -3796,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) );
     }
@@ -3827,7 +4243,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   int algo;
   unsigned int use;
   u32 expire;
-  unsigned int nbits;
+  unsigned int nbits = 0;
+  char *curve = NULL;
   u32 cur_time;
   char *hexgrip = NULL;
   char *serialno = NULL;
@@ -3860,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;
@@ -3881,7 +4298,16 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   hexgrip = NULL;
   algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
   assert (algo);
-  nbits = hexgrip? 0 : ask_keysize (algo, 0);
+
+  if (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) ")))
@@ -3894,7 +4320,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
     err = do_create_from_keygrip (ctrl, algo, hexgrip,
                                   keyblock, cur_time, expire, 1);
   else
-    err = do_create (algo, nbits, keyblock, cur_time, expire, 1, 0, NULL);
+    err = do_create (algo, nbits, curve,
+                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
   if (err)
     goto leave;
 
@@ -3911,10 +4338,11 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   write_status_text (STATUS_KEY_CREATED, "S");
 
  leave:
+  xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
   if (err)
-    log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
+    log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
 }
 
@@ -3972,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;
@@ -4011,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);
@@ -4033,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;
            }
        }
@@ -4096,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;
@@ -4114,6 +4555,12 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
 
   return 0;
 #else
+  (void)algo;
+  (void)keyno;
+  (void)is_primary;
+  (void)pub_root;
+  (void)timestamp;
+  (void)expireval;
   return gpg_error (GPG_ERR_NOT_SUPPORTED);
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
@@ -4125,7 +4572,8 @@ 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 0 /* FIXME: Move this to gpg-agent.  */
+#if ENABLE_CARD_SUPPORT && 0
+  /* FIXME: Move this to gpg-agent.  */
   int rc;
   const char *s;
   PACKET *pkt;
@@ -4158,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);
@@ -4195,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))
       {
@@ -4202,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)
       {
@@ -4223,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
@@ -4233,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);
@@ -4282,6 +4733,16 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
 
   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*/
 }
@@ -4311,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;
     }