gpg: When evaluating trust reg exps, treat tofu+pgp like pgp.
[gnupg.git] / g10 / keygen.c
index 03d53ce..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 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 "i18n.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
 #define KEYGEN_FLAG_TRANSIENT_KEY 2
 
-
-#define MAX_PREFS 30 
+/* Maximum number of supported algorithm preferences.  */
+#define MAX_PREFS 30
 
 enum para_name {
   pKEYTYPE,
   pKEYLENGTH,
+  pKEYCURVE,
   pKEYUSAGE,
   pSUBKEYTYPE,
   pSUBKEYLENGTH,
+  pSUBKEYCURVE,
   pSUBKEYUSAGE,
   pAUTHKEYTYPE,
   pNAMEREAL,
@@ -75,10 +86,8 @@ enum para_name {
   pKEYEXPIRE, /* in n seconds */
   pSUBKEYEXPIRE, /* in n seconds */
   pPASSPHRASE,
-  pPASSPHRASE_DEK,
-  pPASSPHRASE_S2K,
   pSERIALNO,
-  pBACKUPENCDIR,
+  pCARDBACKUPKEY,
   pHANDLE,
   pKEYSERVER
 };
@@ -88,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;
@@ -98,24 +105,18 @@ struct para_data_s {
     } u;
 };
 
-struct output_control_s {
-    int lnr;
-    int dryrun;
-    int ask_passphrase;
-    unsigned int keygen_flags;
-    int use_files;
-    struct {
-       char  *fname;
-       char  *newfname;
-       IOBUF stream;
-       armor_filter_context_t *afx;
-    } pub;
-    struct {
-       char  *fname;
-       char  *newfname;
-       IOBUF stream;
-       armor_filter_context_t *afx;
-    } sec;
+struct output_control_s
+{
+  int lnr;
+  int dryrun;
+  unsigned int keygen_flags;
+  int use_files;
+  struct {
+    char  *fname;
+    char  *newfname;
+    IOBUF stream;
+    armor_filter_context_t *afx;
+  } pub;
 };
 
 
@@ -134,16 +135,15 @@ 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 int gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
-                         u32 *timestamp, u32 expireval,
-                         struct para_data_s *para);
+static gpg_error_t gen_card_key (int algo, int keyno, int is_primary,
+                                 kbnode_t pub_root,
+                                 u32 *timestamp, u32 expireval);
 static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
                                      kbnode_t pub_root, u32 timestamp,
-                                     u32 expireval, struct para_data_s *para,
-                                     const char *backup_dir);
+                                     u32 expireval, struct para_data_s *para);
 
 
 static void
@@ -152,7 +152,7 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
   byte array[MAX_FINGERPRINT_LEN], *s;
   char *buf, *p;
   size_t i, n;
-  
+
   if (!handle)
     handle = "";
 
@@ -220,9 +220,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
 
-    if (!buf[0]) 
-        return;
-
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
@@ -233,14 +230,14 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
   PKT_public_key *pk = opaque;
   byte buf[8];
   u32  u;
-  
+
   if (pk->expiredate)
     {
       if (pk->expiredate > pk->timestamp)
         u = pk->expiredate - pk->timestamp;
       else
         u = 1;
-      
+
       buf[0] = (u >> 24) & 0xff;
       buf[1] = (u >> 16) & 0xff;
       buf[2] = (u >>   8) & 0xff;
@@ -262,7 +259,7 @@ static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
   struct opaque_data_usage_and_pk *oduap = opaque;
-  
+
   do_add_key_flags (sig, oduap->usage);
   return keygen_add_key_expire (sig, oduap->pk);
 }
@@ -276,7 +273,7 @@ set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
     for (i=0; i < *nbuf; i++ )
       if (buf[i] == val)
        {
-         log_info (_("preference `%s' duplicated\n"), item);
+         log_info (_("preference '%s' duplicated\n"), item);
          return -1;
         }
 
@@ -329,7 +326,7 @@ keygen_set_std_prefs (const char *string,int personal)
 
                  gpg -r pgpkey -r gpgkey  ---gives--> AES256
                  gpg -r gpgkey -r pgpkey  ---gives--> AES
-                 
+
                Note that by using --personal-cipher-preferences it is
                possible to prefer AES128.
             */
@@ -343,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 ( !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 ");
 
@@ -379,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 ");
@@ -396,7 +376,7 @@ keygen_set_std_prefs (const char *string,int personal)
                 strcat(dummy_string,"Z1 ");
                 any_compress = 1;
               }
-            
+
             /* In case we have no compress algo at all, declare that
                we prefer no compresssion.  */
             if (!any_compress)
@@ -445,13 +425,7 @@ keygen_set_std_prefs (const char *string,int personal)
              modify=0;
            else
              {
-               log_info (_("invalid item `%s' in preference string\n"),tok);
-
-               /* Complain if IDEA is not available. */
-               if(ascii_strcasecmp(tok,"s1")==0
-                  || ascii_strcasecmp(tok,"idea")==0)
-                 idea_cipher_warn(1);
-
+               log_info (_("invalid item '%s' in preference string\n"),tok);
                rc=-1;
              }
          }
@@ -680,18 +654,18 @@ int
 keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
 {
   (void)opaque;
-  
+
   if (!prefs_initialized)
     keygen_set_std_prefs (NULL, 0);
-  
-  if (nsym_prefs) 
+
+  if (nsym_prefs)
     build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
   else
     {
       delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
     }
-  
+
   if (nhash_prefs)
     build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
   else
@@ -707,7 +681,7 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque)
       delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
       delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
     }
-  
+
   /* Make sure that the MDC feature flag is set if needed.  */
   add_feature_mdc (sig,mdc_available);
   add_keyserver_modify (sig,ks_modify);
@@ -725,12 +699,12 @@ int
 keygen_add_std_prefs (PKT_signature *sig, void *opaque)
 {
   PKT_public_key *pk = opaque;
-  
+
   do_add_key_flags (sig, pk->pubkey_usage);
   keygen_add_key_expire (sig, opaque );
   keygen_upd_std_prefs (sig, opaque);
   keygen_add_keyserver_url (sig,NULL);
-  
+
   return 0;
 }
 
@@ -836,35 +810,36 @@ 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. */
       IOBUF backsig_out = iobuf_temp();
       PACKET backsig_pkt;
+
       init_packet (&backsig_pkt);
       backsig_pkt.pkttype = PKT_SIGNATURE;
       backsig_pkt.pkt.signature = backsig;
       err = build_packet (backsig_out, &backsig_pkt);
       free_packet (&backsig_pkt);
       if (err)
-       log_error ("build_packet failed for backsig: %s\n", g10_errstr(err));
+       log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err));
       else
        {
          size_t pktlen = 0;
          byte *buf = iobuf_get_temp_buffer (backsig_out);
+
          /* Remove the packet header. */
          if(buf[0]&0x40)
            {
              if (buf[1] < 192)
                {
                  pktlen = buf[1];
-                 buf += 2; 
-               } 
+                 buf += 2;
+               }
              else if(buf[1] < 224)
                {
                  pktlen = (buf[1]-192)*256;
@@ -873,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
@@ -885,34 +857,34 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
          else
            {
              int mark = 1;
+
              switch (buf[0]&3)
                {
                case 3:
                  BUG ();
                  break;
+
                case 2:
-                 pktlen  = buf[mark++] << 24;
+                 pktlen  = (size_t)buf[mark++] << 24;
                  pktlen |= buf[mark++] << 16;
+
                case 1:
                  pktlen |= buf[mark++] << 8;
+
                case 0:
                  pktlen |= buf[mark++];
                }
+
              buf += mark;
            }
+
          /* Now make the binary blob into a subpacket.  */
          build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen);
 
          iobuf_close (backsig_out);
        }
     }
-  
+
   return err;
 }
 
@@ -946,14 +918,14 @@ 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;
     }
-  
+
   pkt = xmalloc_clear (sizeof *pkt);
   pkt->pkttype = PKT_SIGNATURE;
   pkt->pkt.signature = sig;
@@ -994,18 +966,18 @@ write_selfsigs (KBNODE root, PKT_public_key *psk,
 
   /* The usage has not yet been set - do it now. */
   pk->pubkey_usage = use;
+
   /* We have to cache the key, so that the verification of the
      signature creation is able to retrieve the public key.  */
   cache_public_key (pk);
 
   /* Make the signature.  */
   err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13,
-                            0, 0, timestamp, 0,
+                            0, timestamp, 0,
                             keygen_add_std_prefs, pk, cache_nonce);
-  if (err) 
+  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;
     }
 
@@ -1045,10 +1017,10 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   /* We have to cache the key, so that the verification of the
    * signature creation is able to retrieve the public key.  */
   cache_public_key (pri_pk);
+
   /* Find the last subkey. */
   sub_pk = NULL;
-  for (node = root; node; node = node->next ) 
+  for (node = root; node; node = node->next )
     {
       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
         sub_pk = node->pkt->pkt.public_key;
@@ -1059,13 +1031,13 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   /* Make the signature.  */
   oduap.usage = use;
   oduap.pk = sub_pk;
-  err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, 
-                            0, 0, timestamp, 0,
+  err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
+                            0, timestamp, 0,
                             keygen_add_key_flags_and_expire, &oduap,
                             cache_nonce);
-  if (err) 
+  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;
     }
 
@@ -1076,7 +1048,7 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
       if (err)
         return err;
     }
-  
+
   pkt = xmalloc_clear ( sizeof *pkt );
   pkt->pkttype = PKT_SIGNATURE;
   pkt->pkt.signature = sig;
@@ -1085,7 +1057,95 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
 }
 
 
+static gpg_error_t
+ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
+{
+  gpg_error_t err;
+  gcry_sexp_t list, l2;
+  char *curve;
+  int i;
+  const char *oidstr;
+  unsigned int nbits;
+
+  array[0] = NULL;
+  array[1] = NULL;
+  array[2] = NULL;
+
+  list = gcry_sexp_find_token (sexp, "public-key", 0);
+  if (!list)
+    return gpg_error (GPG_ERR_INV_OBJ);
+  l2 = gcry_sexp_cadr (list);
+  gcry_sexp_release (list);
+  list = l2;
+  if (!list)
+    return gpg_error (GPG_ERR_NO_OBJ);
+
+  l2 = gcry_sexp_find_token (list, "curve", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  curve = gcry_sexp_nth_string (l2, 1);
+  if (!curve)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (l2);
+  oidstr = openpgp_curve_to_oid (curve, &nbits);
+  if (!oidstr)
+    {
+      /* That can't happen because we used one of the curves
+         gpg_curve_to_oid knows about.  */
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  err = openpgp_oid_from_str (oidstr, &array[0]);
+  if (err)
+    goto leave;
+
+  l2 = gcry_sexp_find_token (list, "q", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l2);
+  if (!array[1])
+    {
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (list);
+
+  if (algo == PUBKEY_ALGO_ECDH)
+    {
+      array[2] = pk_ecdh_default_params (nbits);
+      if (!array[2])
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
+ leave:
+  if (err)
+    {
+      for (i=0; i < 3; i++)
+        {
+          gcry_mpi_release (array[i]);
+          array[i] = NULL;
+        }
+    }
+  return err;
+}
+
 
+/* Extract key parameters from SEXP and store them in ARRAY.  ELEMS is
+   a string where each character denotes a parameter name.  TOPNAME is
+   the name of the top element above the elements.  */
 static int
 key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
                const char *topname, const char *elems)
@@ -1114,7 +1174,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
         }
       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
       gcry_sexp_release (l2);
-      if (!array[idx]) 
+      if (!array[idx])
         {
           rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
           goto leave;
@@ -1136,26 +1196,115 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
 }
 
 
+/* Create a keyblock using the given KEYGRIP.  ALGO is the OpenPGP
+   algorithm of that keygrip.  */
+static int
+do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
+                        kbnode_t pub_root, u32 timestamp, u32 expireval,
+                        int is_subkey)
+{
+  int err;
+  PACKET *pkt;
+  PKT_public_key *pk;
+  gcry_sexp_t s_key;
+  const char *algoelem;
+
+  if (hexkeygrip[0] == '&')
+    hexkeygrip++;
+
+  switch (algo)
+    {
+    case PUBKEY_ALGO_RSA:       algoelem = "ne"; break;
+    case PUBKEY_ALGO_DSA:       algoelem = "pqgy"; break;
+    case PUBKEY_ALGO_ELGAMAL_E: algoelem = "pgy"; break;
+    case PUBKEY_ALGO_ECDH:
+    case PUBKEY_ALGO_ECDSA:     algoelem = ""; break;
+    case PUBKEY_ALGO_EDDSA:     algoelem = ""; break;
+    default: return gpg_error (GPG_ERR_INTERNAL);
+    }
+
+
+  /* Ask the agent for the public key matching HEXKEYGRIP.  */
+  {
+    unsigned char *public;
+
+    err = agent_readkey (ctrl, 0, hexkeygrip, &public);
+    if (err)
+      return err;
+    err = gcry_sexp_sscan (&s_key, NULL,
+                           public, gcry_sexp_canon_len (public, 0, NULL, NULL));
+    xfree (public);
+    if (err)
+      return err;
+  }
+
+  /* Build a public key packet.  */
+  pk = xtrycalloc (1, sizeof *pk);
+  if (!pk)
+    {
+      err = gpg_error_from_syserror ();
+      gcry_sexp_release (s_key);
+      return err;
+    }
+
+  pk->timestamp = timestamp;
+  pk->version = 4;
+  if (expireval)
+    pk->expiredate = pk->timestamp + expireval;
+  pk->pubkey_algo = algo;
+
+  if (algo == PUBKEY_ALGO_ECDSA
+      || algo == PUBKEY_ALGO_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);
+  if (err)
+    {
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      gcry_sexp_release (s_key);
+      free_public_key (pk);
+      return err;
+    }
+  gcry_sexp_release (s_key);
+
+  pkt = xtrycalloc (1, sizeof *pkt);
+  if (!pkt)
+    {
+      err = gpg_error_from_syserror ();
+      free_public_key (pk);
+      return err;
+    }
+
+  pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY;
+  pkt->pkt.public_key = pk;
+  add_kbnode (pub_root, new_kbnode (pkt));
+
+  return 0;
+}
+
 
 /* Common code for the key generation fucntion gen_xxx.  */
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
-            int keygen_flags, char **cache_nonce_addr)
+            int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   int err;
   PACKET *pkt;
   PKT_public_key *pk;
   gcry_sexp_t s_key;
-  
+
   err = agent_genkey (NULL, cache_nonce_addr, keyparms,
-                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
+                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
+                      passphrase,
+                      &s_key);
   if (err)
     {
       log_error ("agent_genkey failed: %s\n", gpg_strerror (err) );
       return err;
     }
-  
+
   pk = xtrycalloc (1, sizeof *pk);
   if (!pk)
     {
@@ -1166,12 +1315,17 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
 
   pk->timestamp = timestamp;
   pk->version = 4;
-  if (expireval) 
+  if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
 
-  err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
-  if (err) 
+  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);
+  if (err)
     {
       log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
       gcry_sexp_release (s_key);
@@ -1179,7 +1333,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
       return err;
     }
   gcry_sexp_release (s_key);
-  
+
   pkt = xtrycalloc (1, sizeof *pkt);
   if (!pkt)
     {
@@ -1202,17 +1356,22 @@ 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;
   char nbitsstr[35];
-  
+
   assert (is_ELGAMAL (algo));
 
-  if (nbits < 512)
+  if (nbits < 1024)
     {
-      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 );
     }
 
@@ -1236,9 +1395,9 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
     err = gpg_error_from_syserror ();
   else
     {
-      err = common_gen (keyparms, algo, "pgy", 
+      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);
     }
 
@@ -1250,9 +1409,9 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
  * Generate an DSA key
  */
 static gpg_error_t
-gen_dsa (unsigned int nbits, KBNODE pub_root, 
+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;
@@ -1260,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 )
@@ -1287,26 +1446,26 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 
   /*
     Figure out a q size based on the key size.  FIPS 180-3 says:
+
     L = 1024, N = 160
     L = 2048, N = 224
     L = 2048, N = 256
     L = 3072, N = 256
+
     2048/256 is an odd pair since there is also a 2048/224 and
     3072/256.  Matching sizes is not a very exact science.
-      
+
     We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024
     but less than 2048, and 160 for 1024 (DSA1).
   */
+
   if (nbits > 2047)
     qbits = 256;
   else if ( nbits > 1024)
     qbits = 224;
   else
     qbits = 160;
+
   if (qbits != 160 )
     log_info (_("WARNING: some OpenPGP programs can't"
                 " handle a DSA key with this digest size\n"));
@@ -1323,9 +1482,66 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
     err = gpg_error_from_syserror ();
   else
     {
-      err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", 
+      err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
+                        pub_root, timestamp, expireval, is_subkey,
+                        keygen_flags, passphrase, cache_nonce_addr);
+      xfree (keyparms);
+    }
+
+  return err;
+}
+
+
+
+/*
+ * Generate an ECC key
+ */
+static gpg_error_t
+gen_ecc (int algo, const char *curve, kbnode_t pub_root,
+         u32 timestamp, u32 expireval, int is_subkey,
+         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+{
+  gpg_error_t err;
+  char *keyparms;
+
+  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
+    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);
     }
 
@@ -1333,29 +1549,35 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 }
 
 
-/* 
+/*
  * Generate an RSA key.
  */
 static int
 gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, char **cache_nonce_addr)
+         int 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));
 
   if (!nbits)
     nbits = DEFAULT_STD_KEYSIZE;
 
-  if (nbits < 1024) 
+  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 );
+    }
+
   if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
@@ -1363,7 +1585,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     }
 
   snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits);
-  keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))", 
+  keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))",
                            strlen (nbitsstr), nbitsstr,
                            ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
                             && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
@@ -1372,9 +1594,9 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     err = gpg_error_from_syserror ();
   else
     {
-      err = common_gen (keyparms, algo, "ne", 
+      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);
     }
 
@@ -1443,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);
 
@@ -1465,7 +1688,7 @@ ask_key_flags(int algo,int subkey)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                gcry_pk_algo_name (algo));
+                openpgp_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1489,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;
@@ -1527,102 +1772,233 @@ ask_key_flags(int algo,int subkey)
 }
 
 
+/* Check whether we have a key for the key with HEXGRIP.  Returns 0 if
+   there is no such key or the OpenPGP algo number for the key.  */
+static int
+check_keygrip (ctrl_t ctrl, const char *hexgrip)
+{
+  gpg_error_t err;
+  unsigned char *public;
+  size_t publiclen;
+  const char *algostr;
+
+  if (hexgrip[0] == '&')
+    hexgrip++;
+
+  err = agent_readkey (ctrl, 0, hexgrip, &public);
+  if (err)
+    return 0;
+  publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
+
+  get_pk_algo_from_canon_sexp (public, publiclen, &algostr);
+  xfree (public);
+
+  /* FIXME: Mapping of ECC algorithms is probably not correct. */
+  if (!algostr)
+    return 0;
+  else if (!strcmp (algostr, "rsa"))
+    return PUBKEY_ALGO_RSA;
+  else if (!strcmp (algostr, "dsa"))
+    return PUBKEY_ALGO_DSA;
+  else if (!strcmp (algostr, "elg"))
+    return PUBKEY_ALGO_ELGAMAL_E;
+  else if (!strcmp (algostr, "ecc"))
+    return PUBKEY_ALGO_ECDH;
+  else if (!strcmp (algostr, "ecdsa"))
+    return PUBKEY_ALGO_ECDSA;
+  else if (!strcmp (algostr, "eddsa"))
+    return PUBKEY_ALGO_EDDSA;
+  else
+    return 0;
+}
+
+
+
 /* Ask for an algorithm.  The function returns the algorithm id to
  * create. If ADDMODE is false the function won't show an option to
  * create the primary and subkey combined and won't set R_USAGE
  * either.  If a combined algorithm has been selected, the subkey
- * algorithm is stored at R_SUBKEY_ALGO.  */
+ * algorithm is stored at R_SUBKEY_ALGO.  If R_KEYGRIP is given, the
+ * user has the choice to enter the keygrip of an existing key.  That
+ * keygrip is then stored at this address.  The caller needs to free
+ * it. */
 static int
-ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage)
+ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
+          char **r_keygrip)
 {
-  char *answer;
+  char *keygrip = NULL;
+  char *answer = NULL;
   int algo;
   int dummy_algo;
 
   if (!r_subkey_algo)
     r_subkey_algo = &dummy_algo;
-  
+
   tty_printf (_("Please select what kind of key you want:\n"));
 
+#if 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
     }
-  
-  for(;;)
+
+#if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA
+  if (opt.expert && !addmode)
+    tty_printf (_("   (%d) ECC and ECC\n"), 9 );
+  if (opt.expert)
+    tty_printf (_("  (%d) ECC (sign only)\n"), 10 );
+  if (opt.expert)
+    tty_printf (_("  (%d) ECC (set your own capabilities)\n"), 11 );
+  if (opt.expert && addmode)
+    tty_printf (_("  (%d) ECC (encrypt only)\n"), 12 );
+#endif
+
+  if (opt.expert && r_keygrip)
+    tty_printf (_("  (%d) Existing key\n"), 13 );
+
+  for (;;)
     {
       *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);
-      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 || !strcmp (answer, "ecc+ecc"))
+               && opt.expert && !addmode)
+        {
+          algo = PUBKEY_ALGO_ECDSA;
+          *r_subkey_algo = PUBKEY_ALGO_ECDH;
+          break;
+       }
+      else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert)
+        {
+          algo = PUBKEY_ALGO_ECDSA;
+          *r_usage = PUBKEY_USAGE_SIG;
+          break;
+       }
+      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 || !strcmp (answer, "ecc/e"))
+               && opt.expert && addmode)
+        {
+          algo = PUBKEY_ALGO_ECDH;
+          *r_usage = PUBKEY_USAGE_ENC;
+          break;
+       }
+      else if ((algo == 13 || !strcmp (answer, "keygrip"))
+               && opt.expert && r_keygrip)
+        {
+          for (;;)
+            {
+              xfree (answer);
+              answer = tty_get (_("Enter the keygrip: "));
+              tty_kill_prompt ();
+              trim_spaces (answer);
+              if (!*answer)
+                {
+                  xfree (answer);
+                  answer = NULL;
+                  continue;
+                }
+
+              if (strlen (answer) != 40 &&
+                       !(answer[0] == '&' && strlen (answer+1) == 40))
+                tty_printf
+                  (_("Not a valid keygrip (expecting 40 hex digits)\n"));
+              else if (!(algo = check_keygrip (ctrl, answer)) )
+                tty_printf (_("No key with this keygrip\n"));
+              else
+                break; /* Okay.  */
+            }
+          xfree (keygrip);
+          keygrip = answer;
+          answer = NULL;
+          *r_usage = ask_key_flags (algo, addmode);
+          break;
+       }
       else
         tty_printf (_("Invalid selection.\n"));
+
     }
-  
+
+  xfree(answer);
+  if (r_keygrip)
+    *r_keygrip = keygrip;
   return algo;
 }
 
@@ -1663,15 +2039,28 @@ ask_keysize (int algo, unsigned int primary_keysize)
       max=3072;
       break;
 
+    case PUBKEY_ALGO_ECDSA:
+    case PUBKEY_ALGO_ECDH:
+      min=256;
+      def=256;
+      max=521;
+      break;
+
+    case PUBKEY_ALGO_EDDSA:
+      min=255;
+      def=255;
+      max=441;
+      break;
+
     case PUBKEY_ALGO_RSA:
       min=1024;
       break;
     }
 
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            gcry_pk_algo_name (algo), min, max);
+            openpgp_pk_algo_name (algo), min, max);
 
-  for(;;)
+  for (;;)
     {
       char *prompt, *answer;
 
@@ -1685,34 +2074,201 @@ ask_keysize (int algo, unsigned int primary_keysize)
       nbits = *answer? atoi (answer): def;
       xfree(prompt);
       xfree(answer);
-      
+
       if(nbits<min || nbits>max)
        tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-                  gcry_pk_algo_name (algo), min, max);
+                  openpgp_pk_algo_name (algo), min, max);
       else
        break;
     }
 
-  tty_printf(_("Requested keysize is %u bits\n"), nbits );
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
 
  leave:
-  if( algo == PUBKEY_ALGO_DSA && (nbits % 64) )
+  if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
       if (!autocomp)
-        tty_printf(_("rounded up to %u bits\n"), nbits );
+        tty_printf (_("rounded up to %u bits\n"), nbits);
     }
-  else if( (nbits % 32) )
+  else if (algo == PUBKEY_ALGO_EDDSA)
+    {
+      if (nbits != 255 && nbits != 441)
+        {
+          if (nbits < 256)
+            nbits = 255;
+          else
+            nbits = 441;
+          if (!autocomp)
+            tty_printf (_("rounded to %u bits\n"), nbits);
+        }
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+    {
+      if (nbits != 256 && nbits != 384 && nbits != 521)
+        {
+          if (nbits < 256)
+            nbits = 256;
+          else if (nbits < 384)
+            nbits = 384;
+          else
+            nbits = 521;
+          if (!autocomp)
+            tty_printf (_("rounded to %u bits\n"), nbits);
+        }
+    }
+  else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
       if (!autocomp)
-        tty_printf(_("rounded up to %u bits\n"), nbits );
+        tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
   return nbits;
 }
 
 
+/* Ask for the curve.  ALGO is the selected algorithm which this
+   function may adjust.  Returns a malloced string with the name of
+   the curve.  BOTH tells that gpg creates a primary and subkey. */
+static char *
+ask_curve (int *algo, int *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.
@@ -1731,7 +2287,7 @@ parse_expire_string( const char *string )
   u32 abs_date = 0;
   u32 curtime = make_timestamp ();
   time_t tt;
-  
+
   if (!*string)
     seconds = 0;
   else if (!strncmp (string, "seconds=", 8))
@@ -1745,7 +2301,7 @@ parse_expire_string( const char *string )
     seconds = atoi (string) * 86400L * mult;
   else
     seconds = (u32)(-1);
-  
+
   return seconds;
 }
 
@@ -1755,7 +2311,7 @@ static u32
 parse_creation_string (const char *string)
 {
   u32 seconds;
-  
+
   if (!*string)
     seconds = 0;
   else if ( !strncmp (string, "seconds=", 8) )
@@ -1811,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)
@@ -1835,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 )
          {
@@ -1854,7 +2411,7 @@ ask_expire_interval(int object,const char *def_expire)
                       ? _("Key expires at %s\n")
                       : _("Signature expires at %s\n"),
                       asctimestamp((ulong)(curtime + interval) ) );
-#if SIZEOF_TIME_T <= 4
+#if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T)
            if ( (time_t)((ulong)(curtime+interval)) < 0 )
              tty_printf (_("Your system can't display dates beyond 2038.\n"
                             "However, it will be correctly handled up to"
@@ -1901,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;
@@ -1915,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"
@@ -1984,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: "));
@@ -1997,6 +2573,11 @@ ask_user_id (int mode, KBNODE keyblock)
                else
                    break;
            }
+          }
+          else {
+            xfree (acomment);
+            acomment = xstrdup ("");
+          }
        }
 
 
@@ -2015,7 +2596,7 @@ ask_user_id (int mode, KBNODE keyblock)
        /* print a note in case that UTF8 mapping has to be done */
        for(p=uid; *p; p++ ) {
            if( *p & 0x80 ) {
-               tty_printf(_("You are using the `%s' character set.\n"),
+               tty_printf(_("You are using the '%s' character set.\n"),
                           get_native_charset() );
                break;
            }
@@ -2032,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(;;) {
@@ -2050,7 +2625,7 @@ ask_user_id (int mode, KBNODE keyblock)
                lower and uppercase.  Below you will find the matching
                string which should be translated accordingly and the
                letter changed to match the one in the answer string.
-               
+
                  n = Change name
                  c = Change comment
                  e = Change email
@@ -2065,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 )
                ;
@@ -2106,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;
     }
@@ -2121,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)
 {
@@ -2165,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;
 
@@ -2187,13 +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);
+                   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();
 
@@ -2203,32 +2791,57 @@ 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;
 }
 
 
+/* Append R to the linked list PARA.  */
 static void
-release_parameter_list( struct para_data_s *r )
+append_to_parameter (struct para_data_s *para, struct para_data_s *r)
 {
-    struct para_data_s *r2;
+  assert (para);
+  while (para->next)
+    para = para->next;
+  para->next = 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 );
+/* Release the parameter list R.  */
+static void
+release_parameter_list (struct para_data_s *r)
+{
+  struct para_data_s *r2;
 
-       xfree(r);
+  for (; r ; r = r2)
+    {
+      r2 = r->next;
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
+      xfree (r);
     }
 }
 
@@ -2249,8 +2862,20 @@ 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, 
+get_parameter_algo( struct para_data_s *para, enum para_name key,
                     int *r_default)
 {
   int i;
@@ -2262,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
@@ -2274,16 +2901,22 @@ 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 = gcry_pk_map_name (r->u.value);
+    i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
 
   if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
     i = 0; /* we don't want to allow generation of these algorithms */
   return i;
 }
 
-/* 
+/*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
  */
@@ -2297,7 +2930,7 @@ parse_parameter_usage (const char *fname,
 
     if( !r )
        return 0; /* none (this is an optional parameter)*/
-    
+
     use = 0;
     pn = r->u.value;
     while ( (p = strsep (&pn, " \t,")) ) {
@@ -2385,7 +3018,7 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
     return r->u.expire;
   if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
     return r->u.usage;
-  
+
   return (unsigned int)strtoul( r->u.value, NULL, 10 );
 }
 
@@ -2403,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;
@@ -2441,8 +3074,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       r->u.usage = (is_default
                     ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)
                     : openpgp_pk_algo_usage(algo));
-      r->next = para;
-      para = r;
+      append_to_parameter (para, r);
     }
   else if (err == -1)
     return -1;
@@ -2478,8 +3110,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
          r->u.usage = (is_default
                         ? PUBKEY_USAGE_ENC
                         : openpgp_pk_algo_usage (algo));
-         r->next = para;
-         para = r;
+          append_to_parameter (para, r);
        }
       else if (err == -1)
        return -1;
@@ -2516,8 +3147,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
            p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
-         r->next = para;
-         para = r;
+          append_to_parameter (para, r);
          have_user_id=1;
        }
     }
@@ -2537,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);
@@ -2554,70 +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;
-          r->next = para;
-          para = r;
-          r = xmalloc_clear( sizeof *r );
-          r->key = pPASSPHRASE_S2K;
-          r->u.s2k = s2k;
-          r->next = para;
-          para = r;
-        }
-
-      if (canceled) 
-        {
-         log_error ("%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_secure ( sizeof *s2k );
-          s2k->mode = opt.s2k_mode;
-          s2k->hash_algo = S2K_DIGEST_ALGO;
-          set_next_passphrase ( r->u.value );
-          dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                                   NULL, NULL);
-          set_next_passphrase (NULL );
-          assert (dek);
-          memset (r->u.value, 0, strlen(r->u.value));
-          
-          r = xmalloc_clear (sizeof *r);
-          r->key = pPASSPHRASE_S2K;
-          r->u.s2k = s2k;
-          r->next = para;
-          para = r;
-          r = xmalloc_clear (sizeof *r);
-          r->key = pPASSPHRASE_DEK;
-          r->u.dek = dek;
-          r->next = para;
-          para = r;
-        }
-    }
 
   /* Make KEYCREATIONDATE from Creation-Date.  */
   r = get_parameter (para, pCREATIONDATE);
@@ -2653,16 +3219,10 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       r = xmalloc_clear( sizeof *r + 20 );
       r->key = pSUBKEYEXPIRE;
       r->u.expire = seconds;
-      r->next = para;
-      para = r;
+      append_to_parameter (para, r);
     }
 
-  if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
-    log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
-    return -1;
-  }
-
-  do_generate_keypair( para, outctrl, card );
+  do_generate_keypair (ctrl, para, outctrl, card );
   return 0;
 }
 
@@ -2673,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 },
@@ -2708,7 +3270,6 @@ read_parameter_file( const char *fname )
 
     memset( &outctrl, 0, sizeof( outctrl ) );
     outctrl.pub.afx = new_armor_context ();
-    outctrl.sec.afx = new_armor_context ();
 
     if( !fname || !*fname)
       fname = "-";
@@ -2721,7 +3282,7 @@ read_parameter_file( const char *fname )
         gpg_err_set_errno (EPERM);
       }
     if (!fp) {
-      log_error (_("can't open `%s': %s\n"), fname, strerror(errno) );
+      log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
       return;
     }
     iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
@@ -2758,17 +3319,17 @@ 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 ))
-                  print_status_key_not_created 
+               if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
+                  print_status_key_not_created
                     (get_parameter_value (para, pHANDLE));
                release_parameter_list( para );
                para = NULL;
@@ -2783,16 +3344,10 @@ read_parameter_file( const char *fname )
                }
            }
            else if( !ascii_strcasecmp( keyword, "%secring" ) ) {
-               if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
-                   ; /* still the same file - ignore it */
-               else {
-                  xfree( outctrl.sec.newfname );
-                  outctrl.sec.newfname = xstrdup( value );
-                  outctrl.use_files = 1;
-               }
+              /* Ignore this command.  */
            }
            else
-               log_info("skipping control `%s' (%s)\n", keyword, value );
+               log_info("skipping control '%s' (%s)\n", keyword, value );
 
 
            continue;
@@ -2829,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 );
@@ -2859,46 +3414,179 @@ 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));
     }
 
     if( outctrl.use_files ) { /* close open streams */
        iobuf_close( outctrl.pub.stream );
-       iobuf_close( outctrl.sec.stream );
 
         /* Must invalidate that ugly cache to actually close it.  */
         if (outctrl.pub.fname)
-          iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 
-                       0, (char*)outctrl.pub.fname);
-        if (outctrl.sec.fname)
           iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
-                       0, (char*)outctrl.sec.fname);
+                       0, (char*)outctrl.pub.fname);
 
        xfree( outctrl.pub.fname );
        xfree( outctrl.pub.newfname );
-       xfree( outctrl.sec.fname );
-       xfree( outctrl.sec.newfname );
     }
 
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
-    release_armor_context (outctrl.sec.afx);
+}
+
+
+/* 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 BACKUP_ENCRYPTION_DIR has been set and
- * CARD_SERIALNO is NOT NULL, the encryption key for the card gets
- * generate in software, imported to the card and a backup file
- * written to directory given by this argument .
+ * OpenPGP Card.  If CARD_BACKUP_KEY has been set and CARD_SERIALNO is
+ * NOT NULL, the encryption key for the card is generated on the host,
+ * imported to the card and a backup file created by gpg-agent.  If
+ * FULL is not set only the basic prompts are used (except for batch
+ * mode).
  */
 void
-generate_keypair (const char *fname, const char *card_serialno, 
-                  const char *backup_encryption_dir)
+generate_keypair (ctrl_t ctrl, int full, const char *fname,
+                  const char *card_serialno, int card_backup_key)
 {
   unsigned int nbits;
   char *uid = NULL;
@@ -2909,19 +3597,23 @@ generate_keypair (const char *fname, const char *card_serialno,
   struct para_data_s *para = NULL;
   struct para_data_s *r;
   struct output_control_s outctrl;
-  
+
+#ifndef ENABLE_CARD_SUPPORT
+  (void)card_backup_key;
+#endif
+
   memset( &outctrl, 0, sizeof( outctrl ) );
-  
+
   if (opt.batch && card_serialno)
     {
       /* We don't yet support unattended key generation. */
       log_error (_("can't do this in batch mode\n"));
       return;
     }
-  
+
   if (opt.batch)
     {
-      read_parameter_file( fname );
+      read_parameter_file (ctrl, fname);
       return;
     }
 
@@ -2933,9 +3625,9 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy( r->u.value, card_serialno);
       r->next = para;
       para = r;
-       
+
       algo = PUBKEY_ALGO_RSA;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pKEYTYPE;
       sprintf( r->u.value, "%d", algo );
@@ -2946,7 +3638,7 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy (r->u.value, "sign");
       r->next = para;
       para = r;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
       sprintf( r->u.value, "%d", algo );
@@ -2957,49 +3649,74 @@ generate_keypair (const char *fname, const char *card_serialno,
       strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
-       
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pAUTHKEYTYPE;
       sprintf( r->u.value, "%d", algo );
       r->next = para;
       para = r;
 
-      if (backup_encryption_dir)
+      if (card_backup_key)
         {
-          r = xcalloc (1, sizeof *r + strlen (backup_encryption_dir) );
-          r->key = pBACKUPENCDIR;
-          strcpy (r->u.value, backup_encryption_dir);
+          r = xcalloc (1, sizeof *r + 1);
+          r->key = pCARDBACKUPKEY;
+          strcpy (r->u.value, "1");
           r->next = para;
           para = r;
         }
 #endif /*ENABLE_CARD_SUPPORT*/
     }
-  else
+  else if (full)  /* Full featured key generation.  */
     {
-      int subkey_algo; 
-
-      algo = ask_algo (0, &subkey_algo, &use);
+      int subkey_algo;
+      char *curve = NULL;
+
+      /* Fixme: To support creating a primary key by keygrip we better
+         also define the keyword for the parameter file.  Note that
+         the subkey case will never be asserted if a keygrip has been
+         given.  */
+      algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL);
       if (subkey_algo)
-        { 
+        {
           /* Create primary and subkey at once.  */
           both = 1;
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", 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" );
           r->next = para;
           para = r;
-           
+
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pSUBKEYTYPE;
           sprintf( r->u.value, "%d", subkey_algo);
@@ -3010,15 +3727,49 @@ generate_keypair (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 );
           r->next = para;
           para = r;
-           
+
           if (use)
             {
               r = xmalloc_clear( sizeof *r + 25 );
@@ -3033,45 +3784,69 @@ generate_keypair (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);
 }
 
 
-#ifdef ENABLE_CARD_SUPPORT
+#if 0 /* not required */
 /* Generate a raw key and return it as a secret key packet.  The
    function will ask for the passphrase and return a protected as well
    as an unprotected copy of a new secret key packet.  0 is returned
@@ -3100,7 +3875,7 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
 
-  if ((nbits % 32)) 
+  if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
       log_info(_("keysize rounded up to %u bits\n"), nbits );
@@ -3138,16 +3913,16 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at,
     }
   rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
   gcry_sexp_release (s_key);
-  if (rc) 
+  if (rc)
     {
       log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
       goto leave;
     }
-  
+
   for (i=npkey; i < nskey; i++)
     sk->csum += checksum_mpi (sk->skey[i]);
 
-  if (r_sk_unprotected) 
+  if (r_sk_unprotected)
     *r_sk_unprotected = copy_secret_key (NULL, sk);
 
   rc = genhelp_protect (dek, s2k, sk);
@@ -3183,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;
@@ -3201,10 +3976,10 @@ do_generate_keypair (struct para_data_s *para,
       log_info("dry-run mode - key generation skipped\n");
       return;
     }
-  
-  if ( outctrl->use_files ) 
+
+  if ( outctrl->use_files )
     {
-      if ( outctrl->pub.newfname ) 
+      if ( outctrl->pub.newfname )
         {
           iobuf_close(outctrl->pub.stream);
           outctrl->pub.stream = NULL;
@@ -3214,17 +3989,17 @@ do_generate_keypair (struct para_data_s *para,
           xfree( outctrl->pub.fname );
           outctrl->pub.fname =  outctrl->pub.newfname;
           outctrl->pub.newfname = NULL;
-          
-          if (is_secured_filename (outctrl->pub.fname) ) 
+
+          if (is_secured_filename (outctrl->pub.fname) )
             {
               outctrl->pub.stream = NULL;
               gpg_err_set_errno (EPERM);
             }
           else
-            outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
+            outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0);
           if (!outctrl->pub.stream)
             {
-              log_error(_("can't create `%s': %s\n"), outctrl->pub.newfname,
+              log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname,
                         strerror(errno) );
               return;
             }
@@ -3236,7 +4011,7 @@ do_generate_keypair (struct para_data_s *para,
         }
       assert( outctrl->pub.stream );
       if (opt.verbose)
-        log_info (_("writing public key to `%s'\n"), outctrl->pub.fname );
+        log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
 
 
@@ -3244,7 +4019,7 @@ do_generate_keypair (struct para_data_s *para,
      structure we create is known in advance we simply generate a
      linked list.  The first packet is a dummy packet which we flag as
      deleted.  The very first packet must always be a KEY packet.  */
-    
+
   start_tree (&pub_root);
 
   timestamp = get_parameter_u32 (para, pKEYCREATIONDATE);
@@ -3263,14 +4038,17 @@ 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);
+                     get_parameter_u32( para, pKEYEXPIRE ), 0,
+                     outctrl->keygen_flags,
+                     get_parameter_passphrase (para),
+                     &cache_nonce);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
-                        get_parameter_u32 (para, pKEYEXPIRE), para);
+                        get_parameter_u32 (para, pKEYEXPIRE));
 
   /* Get the pointer to the generated public key packet.  */
   if (!err)
@@ -3301,7 +4079,7 @@ do_generate_keypair (struct para_data_s *para,
     {
       err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root,
                           &timestamp,
-                          get_parameter_u32 (para, pKEYEXPIRE), para);
+                          get_parameter_u32 (para, pKEYEXPIRE));
       if (!err)
         err = write_keybinding (pub_root, pri_psk, NULL,
                                 PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
@@ -3314,15 +4092,18 @@ do_generate_keypair (struct para_data_s *para,
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
-                           pub_root, 
+                           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)
             {
               kbnode_t node;
-              
+
               for (node = pub_root; node; node = node->next)
                 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
                   sub_psk = node->pkt->pkt.public_key;
@@ -3331,23 +4112,20 @@ do_generate_keypair (struct para_data_s *para,
         }
       else
         {
-          if ((s = get_parameter_value (para, pBACKUPENCDIR)))
+          if ((s = get_parameter_value (para, pCARDBACKUPKEY)))
             {
               /* A backup of the encryption key has been requested.
                  Generate the key in software and import it then to
                  the card.  Write a backup file. */
-              err = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0,
-                                              pub_root,
-                                              timestamp,
-                                              get_parameter_u32 (para,
-                                                                 pKEYEXPIRE),
-                                              para, s);
+              err = gen_card_key_with_backup
+                (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp,
+                 get_parameter_u32 (para, pKEYEXPIRE), para);
             }
           else
             {
               err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root,
                                   &timestamp,
-                                  get_parameter_u32 (para, pKEYEXPIRE), para);
+                                  get_parameter_u32 (para, pKEYEXPIRE));
             }
         }
 
@@ -3362,33 +4140,33 @@ 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);
-      if (err) 
+      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)
         {
-          log_info (_("writing public key to `%s'\n"),
+          log_info (_("writing public key to '%s'\n"),
                     keydb_get_resource_name (pub_hd));
         }
-      
-      if (!err) 
+
+      if (!err)
         {
           err = keydb_insert_keyblock (pub_hd, pub_root);
           if (err)
-            log_error (_("error writing public keyring `%s': %s\n"),
-                       keydb_get_resource_name (pub_hd), g10_errstr(err));
+            log_error (_("error writing public keyring '%s': %s\n"),
+                       keydb_get_resource_name (pub_hd), gpg_strerror (err));
         }
-      
+
       keydb_release (pub_hd);
-      
+
       if (!err)
         {
           int no_enc_rsa;
@@ -3408,14 +4186,16 @@ do_generate_keypair (struct para_data_s *para,
           update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
                                   | TRUST_ULTIMATE ));
 
-          if (!opt.batch) 
+          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);
             }
-            
-          
+
+
           if (!opt.batch
               && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
                   || no_enc_rsa )
@@ -3432,20 +4212,20 @@ 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) );
     }
   else
     {
-      PKT_public_key *pk = find_kbnode (pub_root, 
+      PKT_public_key *pk = find_kbnode (pub_root,
                                         PKT_PUBLIC_KEY)->pkt->pkt.public_key;
       print_status_key_created (did_sub? 'B':'P', pk,
                                 get_parameter_value (para, pHANDLE));
     }
-  
+
   release_kbnode (pub_root);
   xfree (cache_nonce);
 }
@@ -3454,7 +4234,7 @@ do_generate_keypair (struct para_data_s *para,
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
    been generated and put into the keyblocks.  */
 gpg_error_t
-generate_subkeypair (KBNODE keyblock)
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
 {
   gpg_error_t err = 0;
   kbnode_t node;
@@ -3463,14 +4243,15 @@ generate_subkeypair (KBNODE 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;
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
-  if (!node) 
+  if (!node)
     {
       log_error ("Oops; primary key missing in keyblock!\n");
       err = gpg_error (GPG_ERR_BUG);
@@ -3494,9 +4275,9 @@ generate_subkeypair (KBNODE keyblock)
         }
     }
 
-  if (pri_psk->version < 4) 
+  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;
@@ -3513,18 +4294,34 @@ generate_subkeypair (KBNODE keyblock)
   if (serialno)
     tty_printf (_("Secret parts of primary key are stored on-card.\n"));
 
-  algo = ask_algo (1, NULL, &use);
+  xfree (hexgrip);
+  hexgrip = NULL;
+  algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
   assert (algo);
-  nbits = 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) ")))
     {
       err = gpg_error (GPG_ERR_CANCELED);
       goto leave;
-    }  
+    }
 
-  err = do_create (algo, nbits, keyblock, cur_time, expire, 1, 0, NULL);
+  if (hexgrip)
+    err = do_create_from_keygrip (ctrl, algo, hexgrip,
+                                  keyblock, cur_time, expire, 1);
+  else
+    err = do_create (algo, nbits, curve,
+                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
   if (err)
     goto leave;
 
@@ -3541,91 +4338,76 @@ generate_subkeypair (KBNODE 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;
 }
 
 
 #ifdef ENABLE_CARD_SUPPORT
 /* Generate a subkey on a card. */
-int
-generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
+gpg_error_t
+generate_card_subkeypair (kbnode_t pub_keyblock,
                           int keyno, const char *serialno)
 {
   gpg_error_t err = 0;
-  int okay = 0;
   kbnode_t node;
-  PKT_secret_key *pri_sk = NULL, *sub_sk;
+  PKT_public_key *pri_pk = NULL;
   int algo;
   unsigned int use;
   u32 expire;
-  char *passphrase = NULL;
   u32 cur_time;
   struct para_data_s *para = NULL;
 
   assert (keyno >= 1 && keyno <= 3);
 
-  para = xcalloc (1, sizeof *para + strlen (serialno) );
+  para = xtrycalloc (1, sizeof *para + strlen (serialno) );
+  if (!para)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
   para->key = pSERIALNO;
   strcpy (para->u.value, serialno);
 
   /* Break out the primary secret key */
-  node = find_kbnode (sec_keyblock, PKT_SECRET_KEY);
+  node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
-      log_error("Oops; secret key not found anymore!\n");
+      log_error ("Oops; publkic key lost!\n");
+      err = gpg_error (GPG_ERR_INTERNAL);
       goto leave;
     }
-
-  /* Make a copy of the sk to keep the protected one in the keyblock */
-  pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key);
+  pri_pk = node->pkt->pkt.public_key;
 
   cur_time = make_timestamp();
-  if (pri_sk->timestamp > cur_time)
+  if (pri_pk->timestamp > cur_time)
     {
-      ulong d = pri_sk->timestamp - cur_time;
+      ulong d = pri_pk->timestamp - cur_time;
       log_info (d==1 ? _("key has been created %lu second "
                          "in future (time warp or clock problem)\n")
                      : _("key has been created %lu seconds "
                          "in future (time warp or clock problem)\n"), d );
        if (!opt.ignore_time_conflict)
           {
-           err = G10ERR_TIME_CONFLICT;
+           err = gpg_error (GPG_ERR_TIME_CONFLICT);
            goto leave;
           }
     }
 
-  if (pri_sk->version < 4)
+  if (pri_pk->version < 4)
     {
-      log_info (_("NOTE: creating subkeys for v3 keys "
+      log_info (_("Note: creating subkeys for v3 keys "
                   "is not OpenPGP compliant\n"));
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
 
-  /* Unprotect to get the passphrase. */
-  switch( is_secret_key_protected (pri_sk) )
-    {
-    case -1:
-      err = G10ERR_PUBKEY_ALGO;
-      break;
-    case 0:
-      tty_printf("This key is not protected.\n");
-      break;
-    default:
-      tty_printf("Key is protected.\n");
-      err = check_secret_key( pri_sk, 0 );
-      if (!err)
-        passphrase = get_last_passphrase();
-      break;
-    }
-  if (err)
-    goto leave;
-
   algo = PUBKEY_ALGO_RSA;
-  expire = ask_expire_interval (0,NULL);
+  expire = ask_expire_interval (0, NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
   else if (keyno == 2)
@@ -3634,40 +4416,37 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
     use = PUBKEY_USAGE_AUTH;
   if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay",
                                                _("Really create? (y/N) ")))
-    goto leave;
-
-  if (passphrase)
-    set_next_passphrase (passphrase);
+    {
+      err = gpg_error (GPG_ERR_CANCELED);
+      goto leave;
+    }
 
   /* Note, that depending on the backend, the card key generation may
      update CUR_TIME.  */
-  err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire, para);
-  if (!err)
-    err = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, 
-                            use, cur_time);
-  if (!err)
-    err = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, 
-                           use, cur_time);
+  err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire);
+  /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
-      okay = 1;
-      write_status_text (STATUS_KEY_CREATED, "S");
+      PKT_public_key *sub_pk = NULL;
+
+      for (node = pub_keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+          sub_pk = node->pkt->pkt.public_key;
+      assert (sub_pk);
+      err = write_keybinding (pub_keyblock, pri_pk, sub_pk,
+                              use, cur_time, NULL);
     }
 
  leave:
   if (err)
-    log_error (_("Key generation failed: %s\n"), g10_errstr(err) );
-  xfree (passphrase);
-  /* Release the copy of the (now unprotected) secret keys. */
-  if (pri_sk)
-    free_secret_key (pri_sk);
-  set_next_passphrase( NULL );
+    log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
+  else
+    write_status_text (STATUS_KEY_CREATED, "S");
   release_parameter_list (para);
-  return okay;
+  return err;
 }
 #endif /* !ENABLE_CARD_SUPPORT */
 
-
 /*
  * Write a keyblock to an output stream
  */
@@ -3682,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;
            }
        }
@@ -3693,86 +4472,95 @@ write_keyblock( IOBUF out, KBNODE node )
 
 
 /* Note that timestamp is an in/out arg. */
-static int
-gen_card_key (int algo, int keyno, int is_primary, KBNODE pub_root, 
-              u32 *timestamp, u32 expireval, struct para_data_s *para)
+static gpg_error_t
+gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+              u32 *timestamp, u32 expireval)
 {
 #ifdef ENABLE_CARD_SUPPORT
-  int rc;
-  const char *s;
+  gpg_error_t err;
   struct agent_card_genkey_s info;
   PACKET *pkt;
-  PKT_secret_key *sk;
   PKT_public_key *pk;
 
-  assert (algo == PUBKEY_ALGO_RSA);
-  
-  /* Fixme: We don't have the serialnumber available, thus passing NULL. */
-  rc = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
-/*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
-/*      { */
-/*        tty_printf ("\n"); */
-/*        log_error ("WARNING: key does already exists!\n"); */
-/*        tty_printf ("\n"); */
-/*        if ( cpr_get_answer_is_yes( "keygen.card.replace_key", */
-/*                                    _("Replace existing key? "))) */
-/*          rc = agent_scd_genkey (&info, keyno, 1); */
-/*      } */
+  if (algo != PUBKEY_ALGO_RSA)
+    return gpg_error (GPG_ERR_PUBKEY_ALGO);
 
-  if (rc)
+  pk = xtrycalloc (1, sizeof *pk );
+  if (!pk)
+    return gpg_error_from_syserror ();
+  pkt = xtrycalloc (1, sizeof *pkt);
+  if (!pkt)
     {
-      log_error ("key generation failed: %s\n", gpg_strerror (rc));
-      return rc;
+      xfree (pk);
+      return gpg_error_from_syserror ();
     }
-  if ( !info.n || !info.e )
+
+  /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
+  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
+  /*  The code below is not used because we force creation of
+   *  the a card key (3rd arg).
+   * if (gpg_err_code (rc) == GPG_ERR_EEXIST)
+   *   {
+   *     tty_printf ("\n");
+   *     log_error ("WARNING: key does already exists!\n");
+   *     tty_printf ("\n");
+   *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
+   *                                 _("Replace existing key? ")))
+   *       rc = agent_scd_genkey (&info, keyno, 1);
+   *   }
+  */
+  if (!err && (!info.n || !info.e))
     {
       log_error ("communication error with SCD\n");
       gcry_mpi_release (info.n);
       gcry_mpi_release (info.e);
-      return gpg_error (GPG_ERR_GENERAL);
+      err =  gpg_error (GPG_ERR_GENERAL);
     }
-  
+  if (err)
+    {
+      log_error ("key generation failed: %s\n", gpg_strerror (err));
+      xfree (pkt);
+      xfree (pk);
+      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 that the key does not use the suggested creation date\n");
+    log_info ("NOTE: the key does not use the suggested creation date\n");
   *timestamp = info.created_at;
 
-  pk = xcalloc (1, sizeof *pk );
-  sk = xcalloc (1, sizeof *sk );
-  sk->timestamp = pk->timestamp = info.created_at;
-  sk->version = pk->version = 4;
+  pk->timestamp = info.created_at;
+  pk->version = 4;
   if (expireval)
-      sk->expiredate = pk->expiredate = pk->timestamp + expireval;
-  sk->pubkey_algo = pk->pubkey_algo = algo;
+    pk->expiredate = pk->timestamp + expireval;
+  pk->pubkey_algo = algo;
   pk->pkey[0] = info.n;
-  pk->pkey[1] = info.e; 
-  sk->skey[0] = gcry_mpi_copy (pk->pkey[0]);
-  sk->skey[1] = gcry_mpi_copy (pk->pkey[1]);
-  sk->skey[2] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
-  sk->is_protected = 1;
-  sk->protect.s2k.mode = 1002;
-  s = get_parameter_value (para, pSERIALNO);
-  if (s)
-    {
-      for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
-           sk->protect.ivlen++, s += 2)
-        sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
-    }
-
-  if( ret_sk )
-    *ret_sk = sk;
+  pk->pkey[1] = info.e;
 
-  pkt = xcalloc (1,sizeof *pkt);
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
-  add_kbnode(pub_root, new_kbnode( pkt ));
-
-  pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
-  pkt->pkt.secret_key = sk;
-  add_kbnode(sec_root, new_kbnode( pkt ));
+  add_kbnode (pub_root, new_kbnode (pkt));
 
   return 0;
 #else
+  (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*/
 }
@@ -3782,10 +4570,10 @@ gen_card_key (int algo, int keyno, int is_primary, KBNODE pub_root,
 static int
 gen_card_key_with_backup (int algo, int keyno, int is_primary,
                           KBNODE pub_root, u32 timestamp,
-                          u32 expireval, struct para_data_s *para,
-                          const char *backup_dir)
+                          u32 expireval, struct para_data_s *para)
 {
-#ifdef ENABLE_CARD_SUPPORT
+#if ENABLE_CARD_SUPPORT && 0
+  /* FIXME: Move this to gpg-agent.  */
   int rc;
   const char *s;
   PACKET *pkt;
@@ -3794,11 +4582,11 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
   size_t n;
   int i;
   unsigned int nbits;
-    
+
   /* Get the size of the key directly from the card.  */
   {
     struct agent_card_info_s info;
-    
+
     memset (&info, 0, sizeof info);
     if (!agent_scd_getattr ("KEY-ATTR", &info)
         && info.key_attr[1].algo)
@@ -3818,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);
@@ -3855,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))
       {
@@ -3862,12 +4653,12 @@ 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) 
+    if (!fp)
       {
         rc = gpg_error_from_syserror ();
-       log_error (_("can't create backup file `%s': %s\n"),
+       log_error (_("can't create backup file '%s': %s\n"),
                    fname, strerror(errno) );
         xfree (fname);
         free_secret_key (sk_unprotected);
@@ -3883,17 +4674,17 @@ 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
       {
         unsigned char array[MAX_FINGERPRINT_LEN];
         char *fprbuf, *p;
-       
+
         iobuf_close (fp);
         iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
-        log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+        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);
@@ -3942,14 +4733,24 @@ 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*/
 }
 
 
-#ifdef ENABLE_CARD_SUPPORT
+#if 0
 int
-save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
+save_unprotected_key_to_card (PKT_public_key *sk, int keyno)
 {
   int rc;
   unsigned char *rsa_n = NULL;
@@ -3971,7 +4772,7 @@ save_unprotected_key_to_card (PKT_secret_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;
     }
 
@@ -4007,7 +4808,7 @@ save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
   p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
 
   /* Fixme: Unfortunately we don't have the serialnumber available -
-     thus we can't pass it down to the agent. */ 
+     thus we can't pass it down to the agent. */
   rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
 
  leave: