Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / g10 / keygen.c
index 921e938..912fa39 100644 (file)
@@ -1,6 +1,6 @@
 /* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
 /* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
- * Copyright (C) 2014, 2015  Werner Koch
+ * Copyright (C) 2014, 2015, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "gpg.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "gpg.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
 #include "packet.h"
 #include "main.h"
 #include "packet.h"
-#include "ttyio.h"
+#include "../common/ttyio.h"
 #include "options.h"
 #include "keydb.h"
 #include "trustdb.h"
 #include "options.h"
 #include "keydb.h"
 #include "trustdb.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "pkglue.h"
 #include "../common/shareddefs.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "pkglue.h"
 #include "../common/shareddefs.h"
-#include "host2net.h"
-#include "mbox-util.h"
+#include "../common/host2net.h"
+#include "../common/mbox-util.h"
 
 
 
 
-/* The default algorithms.  If you change them remember to change them
-   also in gpg.c:gpgconf_list.  You should also check that the value
-   is inside the bounds enforced by ask_keysize and gen_xxx.  */
-#define DEFAULT_STD_ALGO       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
+/* The default algorithms.  If you change them, you should ensure the value
+   is inside the bounds enforced by ask_keysize and gen_xxx.  See also
+   get_keysize_range which encodes the allowed ranges.  */
+#define DEFAULT_STD_KEY_PARAM  "rsa3072/cert,sign+rsa3072/encr"
+#define FUTURE_STD_KEY_PARAM   "ed25519/cert,sign+cv25519/encr"
+
+/* When generating keys using the streamlined key generation dialog,
+   use this as a default expiration interval.  */
+const char *default_expiration_interval = "2y";
 
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
 
 /* Flag bits used during key generation.  */
 #define KEYGEN_FLAG_NO_PROTECTION 1
@@ -89,7 +88,9 @@ enum para_name {
   pSERIALNO,
   pCARDBACKUPKEY,
   pHANDLE,
   pSERIALNO,
   pCARDBACKUPKEY,
   pHANDLE,
-  pKEYSERVER
+  pKEYSERVER,
+  pKEYGRIP,
+  pSUBKEYGRIP
 };
 
 struct para_data_s {
 };
 
 struct para_data_s {
@@ -135,12 +136,39 @@ static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
 static int mdc_available,ks_modify;
 
 static int nzip_prefs;
 static int mdc_available,ks_modify;
 
+static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                                     const char *algostr, const char *usagestr,
+                                     const char *expirestr,
+                                     int *r_algo, unsigned int *r_usage,
+                                     u32 *r_expire,
+                                     unsigned int *r_nbits, char **r_curve);
 static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
-                                struct output_control_s *outctrl, int card );
+                                 struct output_control_s *outctrl, int card );
 static int write_keyblock (iobuf_t out, kbnode_t node);
 static int write_keyblock (iobuf_t out, kbnode_t node);
-static gpg_error_t gen_card_key (int algo, int keyno, int is_primary,
-                                 kbnode_t pub_root,
-                                 u32 *timestamp, u32 expireval);
+static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
+                                 kbnode_t pub_root, u32 *timestamp,
+                                 u32 expireval);
+static unsigned int get_keysize_range (int algo,
+                                       unsigned int *min, unsigned int *max);
+
+
+\f
+/* Return the algo string for a default new key.  */
+const char *
+get_default_pubkey_algo (void)
+{
+  if (opt.def_new_key_algo)
+    {
+      if (*opt.def_new_key_algo && !strchr (opt.def_new_key_algo, ':'))
+        return opt.def_new_key_algo;
+      /* To avoid checking that option every time we delay that until
+       * here.  The only thing we really need to make sure is that
+       * there is no colon in the string so that the --gpgconf-list
+       * command won't mess up its output.  */
+      log_info (_("invalid value for option '%s'\n"), "--default-new-key-algo");
+    }
+  return DEFAULT_STD_KEY_PARAM;
+}
 
 
 static void
 
 
 static void
@@ -159,11 +187,15 @@ print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
   if (letter || pk)
     {
       *p++ = letter;
   if (letter || pk)
     {
       *p++ = letter;
-      *p++ = ' ';
-      fingerprint_from_pk (pk, array, &n);
-      s = array;
-      for (i=0; i < n ; i++, s++, p += 2)
-        sprintf (p, "%02X", *s);
+      if (pk)
+        {
+          *p++ = ' ';
+          fingerprint_from_pk (pk, array, &n);
+          s = array;
+          /* Fixme: Use bin2hex */
+          for (i=0; i < n ; i++, s++, p += 2)
+            snprintf (p, 3, "%02X", *s);
+        }
     }
   if (*handle)
     {
     }
   if (*handle)
     {
@@ -192,7 +224,7 @@ write_uid( KBNODE root, const char *s )
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
     size_t n = strlen(s);
 
     pkt->pkttype = PKT_USER_ID;
-    pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
     pkt->pkt.user_id->len = n;
     pkt->pkt.user_id->ref = 1;
     strcpy(pkt->pkt.user_id->name, s);
@@ -237,7 +269,7 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
 
       buf[0] = (u >> 24) & 0xff;
       buf[1] = (u >> 16) & 0xff;
 
       buf[0] = (u >> 24) & 0xff;
       buf[1] = (u >> 16) & 0xff;
-      buf[2] = (u >>   8) & 0xff;
+      buf[2] = (u >>  8) & 0xff;
       buf[3] = u & 0xff;
       build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
     }
       buf[3] = u & 0xff;
       build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
     }
@@ -252,6 +284,18 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
 }
 
 
 }
 
 
+/* Add the key usage (i.e. key flags) in SIG from the public keys
+ * pubkey_usage field.  OPAQUE has the public key.  */
+int
+keygen_add_key_flags (PKT_signature *sig, void *opaque)
+{
+  PKT_public_key *pk = opaque;
+
+  do_add_key_flags (sig, pk->pubkey_usage);
+  return 0;
+}
+
+
 static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
 static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
@@ -339,19 +383,36 @@ keygen_set_std_prefs (const char *string,int personal)
              strcat(dummy_string,"S7 ");
            strcat(dummy_string,"S2 "); /* 3DES */
 
              strcat(dummy_string,"S7 ");
            strcat(dummy_string,"S2 "); /* 3DES */
 
-            /* The default hash algo order is:
-                 SHA-256, SHA-384, SHA-512, SHA-224, SHA-1.
-             */
-           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
-             strcat (dummy_string, "H8 ");
+            if (personal)
+              {
+                /* The default internal hash algo order is:
+                 *  SHA-256, SHA-384, SHA-512, SHA-224, SHA-1.
+                 */
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
+                  strcat (dummy_string, "H8 ");
+
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
+                  strcat (dummy_string, "H9 ");
+
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512))
+                  strcat (dummy_string, "H10 ");
+              }
+            else
+              {
+                /* The default advertised hash algo order is:
+                 *  SHA-512, SHA-384, SHA-256, SHA-224, SHA-1.
+                 */
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512))
+                  strcat (dummy_string, "H10 ");
 
 
-           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
-             strcat (dummy_string, "H9 ");
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384))
+                  strcat (dummy_string, "H9 ");
 
 
-           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512))
-             strcat (dummy_string, "H10 ");
+                if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256))
+                  strcat (dummy_string, "H8 ");
+              }
 
 
-           if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224))
+            if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224))
              strcat (dummy_string, "H11 ");
 
            strcat (dummy_string, "H2 "); /* SHA-1 */
              strcat (dummy_string, "H11 ");
 
            strcat (dummy_string, "H2 "); /* SHA-1 */
@@ -391,9 +452,11 @@ keygen_set_std_prefs (const char *string,int personal)
 
     if(strlen(string))
       {
 
     if(strlen(string))
       {
-       char *tok,*prefstring;
+       char *prefstringbuf;
+        char *tok, *prefstring;
 
 
-       prefstring=xstrdup(string); /* need a writable string! */
+        /* We need a writable string. */
+       prefstring = prefstringbuf = xstrdup (string);
 
        while((tok=strsep(&prefstring," ,")))
          {
 
        while((tok=strsep(&prefstring," ,")))
          {
@@ -427,7 +490,7 @@ keygen_set_std_prefs (const char *string,int personal)
              }
          }
 
              }
          }
 
-       xfree(prefstring);
+       xfree (prefstringbuf);
       }
 
     if(!rc)
       }
 
     if(!rc)
@@ -797,7 +860,7 @@ keygen_add_revkey (PKT_signature *sig, void *opaque)
 /* Create a back-signature.  If TIMESTAMP is not NULL, use it for the
    signature creation time.  */
 gpg_error_t
 /* Create a back-signature.  If TIMESTAMP is not NULL, use it for the
    signature creation time.  */
 gpg_error_t
-make_backsig (PKT_signature *sig, PKT_public_key *pk,
+make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk,
               PKT_public_key *sub_pk, PKT_public_key *sub_psk,
               u32 timestamp, const char *cache_nonce)
 {
               PKT_public_key *sub_pk, PKT_public_key *sub_psk,
               u32 timestamp, const char *cache_nonce)
 {
@@ -806,7 +869,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
 
   cache_public_key (sub_pk);
 
 
   cache_public_key (sub_pk);
 
-  err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19,
+  err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19,
                             0, timestamp, 0, NULL, NULL, cache_nonce);
   if (err)
     log_error ("make_keysig_packet failed for backsig: %s\n",
                             0, timestamp, 0, NULL, NULL, cache_nonce);
   if (err)
     log_error ("make_keysig_packet failed for backsig: %s\n",
@@ -821,7 +884,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
       backsig_pkt.pkttype = PKT_SIGNATURE;
       backsig_pkt.pkt.signature = backsig;
       err = build_packet (backsig_out, &backsig_pkt);
       backsig_pkt.pkttype = PKT_SIGNATURE;
       backsig_pkt.pkt.signature = backsig;
       err = build_packet (backsig_out, &backsig_pkt);
-      free_packet (&backsig_pkt);
+      free_packet (&backsig_pkt, NULL);
       if (err)
        log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err));
       else
       if (err)
        log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err));
       else
@@ -864,10 +927,10 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
                case 2:
                  pktlen  = (size_t)buf[mark++] << 24;
                  pktlen |= buf[mark++] << 16;
                case 2:
                  pktlen  = (size_t)buf[mark++] << 24;
                  pktlen |= buf[mark++] << 16;
-
+                 /* fall through */
                case 1:
                  pktlen |= buf[mark++] << 8;
                case 1:
                  pktlen |= buf[mark++] << 8;
-
+                 /* fall through */
                case 0:
                  pktlen |= buf[mark++];
                }
                case 0:
                  pktlen |= buf[mark++];
                }
@@ -890,7 +953,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
    PSK.  REVKEY is describes the direct key signature and TIMESTAMP is
    the timestamp to set on the signature.  */
 static gpg_error_t
    PSK.  REVKEY is describes the direct key signature and TIMESTAMP is
    the timestamp to set on the signature.  */
 static gpg_error_t
-write_direct_sig (KBNODE root, PKT_public_key *psk,
+write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
                   struct revocation_key *revkey, u32 timestamp,
                   const char *cache_nonce)
 {
                   struct revocation_key *revkey, u32 timestamp,
                   const char *cache_nonce)
 {
@@ -914,7 +977,7 @@ write_direct_sig (KBNODE root, PKT_public_key *psk,
   cache_public_key (pk);
 
   /* Make the signature.  */
   cache_public_key (pk);
 
   /* Make the signature.  */
-  err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F,
+  err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F,
                             0, timestamp, 0,
                             keygen_add_revkey, revkey, cache_nonce);
   if (err)
                             0, timestamp, 0,
                             keygen_add_revkey, revkey, cache_nonce);
   if (err)
@@ -936,7 +999,7 @@ write_direct_sig (KBNODE root, PKT_public_key *psk,
    PSK.  USE and TIMESTAMP give the extra data we need for the
    signature.  */
 static gpg_error_t
    PSK.  USE and TIMESTAMP give the extra data we need for the
    signature.  */
 static gpg_error_t
-write_selfsigs (KBNODE root, PKT_public_key *psk,
+write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
                unsigned int use, u32 timestamp, const char *cache_nonce)
 {
   gpg_error_t err;
                unsigned int use, u32 timestamp, const char *cache_nonce)
 {
   gpg_error_t err;
@@ -969,7 +1032,7 @@ write_selfsigs (KBNODE root, PKT_public_key *psk,
   cache_public_key (pk);
 
   /* Make the signature.  */
   cache_public_key (pk);
 
   /* Make the signature.  */
-  err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13,
+  err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13,
                             0, timestamp, 0,
                             keygen_add_std_prefs, pk, cache_nonce);
   if (err)
                             0, timestamp, 0,
                             keygen_add_std_prefs, pk, cache_nonce);
   if (err)
@@ -992,7 +1055,8 @@ write_selfsigs (KBNODE root, PKT_public_key *psk,
    SUB_PSK is a key used to create a back-signature; that one is only
    used if USE has the PUBKEY_USAGE_SIG capability.  */
 static int
    SUB_PSK is a key used to create a back-signature; that one is only
    used if USE has the PUBKEY_USAGE_SIG capability.  */
 static int
-write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
+write_keybinding (ctrl_t ctrl, kbnode_t root,
+                  PKT_public_key *pri_psk, PKT_public_key *sub_psk,
                   unsigned int use, u32 timestamp, const char *cache_nonce)
 {
   gpg_error_t err;
                   unsigned int use, u32 timestamp, const char *cache_nonce)
 {
   gpg_error_t err;
@@ -1028,7 +1092,7 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   /* Make the signature.  */
   oduap.usage = use;
   oduap.pk = sub_pk;
   /* Make the signature.  */
   oduap.usage = use;
   oduap.pk = sub_pk;
-  err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
+  err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
                             0, timestamp, 0,
                             keygen_add_key_flags_and_expire, &oduap,
                             cache_nonce);
                             0, timestamp, 0,
                             keygen_add_key_flags_and_expire, &oduap,
                             cache_nonce);
@@ -1041,7 +1105,8 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
   /* Make a backsig.  */
   if (use & PUBKEY_USAGE_SIG)
     {
   /* Make a backsig.  */
   if (use & PUBKEY_USAGE_SIG)
     {
-      err = make_backsig (sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce);
+      err = make_backsig (ctrl,
+                          sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce);
       if (err)
         return err;
     }
       if (err)
         return err;
     }
@@ -1059,7 +1124,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
 {
   gpg_error_t err;
   gcry_sexp_t list, l2;
 {
   gpg_error_t err;
   gcry_sexp_t list, l2;
-  char *curve;
+  char *curve = NULL;
   int i;
   const char *oidstr;
   unsigned int nbits;
   int i;
   const char *oidstr;
   unsigned int nbits;
@@ -1128,6 +1193,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
     }
 
  leave:
     }
 
  leave:
+  xfree (curve);
   if (err)
     {
       for (i=0; i < 3; i++)
   if (err)
     {
       for (i=0; i < 3; i++)
@@ -1285,14 +1351,15 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
 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, const char *passphrase, char **cache_nonce_addr)
+            int keygen_flags, const char *passphrase,
+            char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   PACKET *pkt;
   PKT_public_key *pk;
   gcry_sexp_t s_key;
 
 {
   int err;
   PACKET *pkt;
   PKT_public_key *pk;
   gcry_sexp_t s_key;
 
-  err = agent_genkey (NULL, cache_nonce_addr, keyparms,
+  err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
                       !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
                       passphrase,
                       &s_key);
                       !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
                       passphrase,
                       &s_key);
@@ -1353,13 +1420,14 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
 static int
 gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
 static int
 gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
 
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
 
-  assert (is_ELGAMAL (algo));
+  log_assert (is_ELGAMAL (algo));
 
   if (nbits < 1024)
     {
 
   if (nbits < 1024)
     {
@@ -1394,7 +1462,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "pgy",
                         pub_root, timestamp, expireval, is_subkey,
     {
       err = common_gen (keyparms, algo, "pgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
       xfree (keyparms);
     }
 
@@ -1408,7 +1477,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_dsa (unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
 static gpg_error_t
 gen_dsa (unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   unsigned int qbits;
 {
   int err;
   unsigned int qbits;
@@ -1481,7 +1551,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
                         pub_root, timestamp, expireval, is_subkey,
     {
       err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
       xfree (keyparms);
     }
 
@@ -1496,14 +1567,15 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_ecc (int algo, const char *curve, kbnode_t pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
 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)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
   char *keyparms;
 
 {
   gpg_error_t err;
   char *keyparms;
 
-  assert (algo == PUBKEY_ALGO_ECDSA
-          || algo == PUBKEY_ALGO_EDDSA
-          || algo == PUBKEY_ALGO_ECDH);
+  log_assert (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH);
 
   if (!curve || !*curve)
     return gpg_error (GPG_ERR_UNKNOWN_CURVE);
 
   if (!curve || !*curve)
     return gpg_error (GPG_ERR_UNKNOWN_CURVE);
@@ -1538,7 +1610,8 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
       xfree (keyparms);
     }
 
@@ -1552,21 +1625,22 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
 static int
 gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
 static int
 gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase,
+         char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
   const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096);
 
 {
   int err;
   char *keyparms;
   char nbitsstr[35];
   const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096);
 
-  assert (is_RSA(algo));
+  log_assert (is_RSA(algo));
 
   if (!nbits)
 
   if (!nbits)
-    nbits = DEFAULT_STD_KEYSIZE;
+    nbits = get_keysize_range (algo, NULL, NULL);
 
   if (nbits < 1024)
     {
 
   if (nbits < 1024)
     {
-      nbits = 2048;
+      nbits = 3072;
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
   else if (nbits > maxsize)
       log_info (_("keysize invalid; using %u bits\n"), nbits );
     }
   else if (nbits > maxsize)
@@ -1593,7 +1667,8 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "ne",
                         pub_root, timestamp, expireval, is_subkey,
     {
       err = common_gen (keyparms, algo, "ne",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, passphrase, cache_nonce_addr);
+                        keygen_flags, passphrase,
+                        cache_nonce_addr, passwd_nonce_addr);
       xfree (keyparms);
     }
 
       xfree (keyparms);
     }
 
@@ -1646,9 +1721,10 @@ print_key_flags(int flags)
 }
 
 
 }
 
 
-/* Returns the key flags */
-static unsigned int
-ask_key_flags(int algo,int subkey)
+/* Ask for the key flags and return them.  CURRENT gives the current
+ * usage which should normally be given as 0. */
+unsigned int
+ask_key_flags (int algo, int subkey, unsigned int current)
 {
   /* TRANSLATORS: Please use only plain ASCII characters for the
      translation.  If this is not possible use single digits.  The
 {
   /* TRANSLATORS: Please use only plain ASCII characters for the
      translation.  If this is not possible use single digits.  The
@@ -1660,11 +1736,10 @@ ask_key_flags(int algo,int subkey)
        a = Toggle authentication capability
        q = Finish
   */
        a = Toggle authentication capability
        q = Finish
   */
-  const char *togglers=_("SsEeAaQq");
-  char *answer=NULL;
+  const char *togglers = _("SsEeAaQq");
+  char *answer = NULL;
   const char *s;
   const char *s;
-  unsigned int current=0;
-  unsigned int possible=openpgp_pk_algo_usage(algo);
+  unsigned int possible = openpgp_pk_algo_usage(algo);
 
   if ( strlen(togglers) != 8 )
     {
 
   if ( strlen(togglers) != 8 )
     {
@@ -1678,14 +1753,20 @@ ask_key_flags(int algo,int subkey)
     possible&=~PUBKEY_USAGE_CERT;
 
   /* Preload the current set with the possible set, minus
     possible&=~PUBKEY_USAGE_CERT;
 
   /* Preload the current set with the possible set, minus
-     authentication, since nobody really uses auth yet. */
-  current=possible&~PUBKEY_USAGE_AUTH;
+     authentication if CURRENT has been given as 0.  If CURRENT has
+     been has non-zero we mask with all possible usages. */
+  if (current)
+    current &= possible;
+  else
+    current = (possible&~PUBKEY_USAGE_AUTH);
 
   for(;;)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
 
   for(;;)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                openpgp_pk_algo_name (algo));
+                 (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA)
+                 ? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1724,7 +1805,7 @@ ask_key_flags(int algo,int subkey)
               else if (!subkey && *s == 'c')
                 {
                   /* Accept 'c' for the primary key because USAGE_CERT
               else if (!subkey && *s == 'c')
                 {
                   /* Accept 'c' for the primary key because USAGE_CERT
-                     will will be set anyway.  This is for folks who
+                     will be set anyway.  This is for folks who
                      want to experiment with a cert-only primary key.  */
                   current |= PUBKEY_USAGE_CERT;
                 }
                      want to experiment with a cert-only primary key.  */
                   current |= PUBKEY_USAGE_CERT;
                 }
@@ -1777,7 +1858,7 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
   gpg_error_t err;
   unsigned char *public;
   size_t publiclen;
   gpg_error_t err;
   unsigned char *public;
   size_t publiclen;
-  const char *algostr;
+  int algo;
 
   if (hexgrip[0] == '&')
     hexgrip++;
 
   if (hexgrip[0] == '&')
     hexgrip++;
@@ -1787,26 +1868,10 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip)
     return 0;
   publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
 
     return 0;
   publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL);
 
-  get_pk_algo_from_canon_sexp (public, publiclen, &algostr);
+  algo = get_pk_algo_from_canon_sexp (public, publiclen);
   xfree (public);
 
   xfree (public);
 
-  /* FIXME: Mapping of ECC algorithms is probably not correct. */
-  if (!algostr)
-    return 0;
-  else if (!strcmp (algostr, "rsa"))
-    return PUBKEY_ALGO_RSA;
-  else if (!strcmp (algostr, "dsa"))
-    return PUBKEY_ALGO_DSA;
-  else if (!strcmp (algostr, "elg"))
-    return PUBKEY_ALGO_ELGAMAL_E;
-  else if (!strcmp (algostr, "ecc"))
-    return PUBKEY_ALGO_ECDH;
-  else if (!strcmp (algostr, "ecdsa"))
-    return PUBKEY_ALGO_ECDSA;
-  else if (!strcmp (algostr, "eddsa"))
-    return PUBKEY_ALGO_EDDSA;
-  else
-    return 0;
+  return map_pk_gcry_to_openpgp (algo);
 }
 
 
 }
 
 
@@ -1838,24 +1903,27 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
     tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
 #endif
 
     tty_printf (_("   (%d) RSA and RSA (default)\n"), 1 );
 #endif
 
-  if (!addmode)
+  if (!addmode && opt.compliance != CO_DE_VS)
     tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
 
     tty_printf (_("   (%d) DSA and Elgamal\n"), 2 );
 
-  tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
+  if (opt.compliance != CO_DE_VS)
+    tty_printf (_("   (%d) DSA (sign only)\n"), 3 );
 #if GPG_USE_RSA
   tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
 #endif
 
   if (addmode)
     {
 #if GPG_USE_RSA
   tty_printf (_("   (%d) RSA (sign only)\n"), 4 );
 #endif
 
   if (addmode)
     {
-      tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
+      if (opt.compliance != CO_DE_VS)
+        tty_printf (_("   (%d) Elgamal (encrypt only)\n"), 5 );
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
 #endif
     }
   if (opt.expert)
     {
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (encrypt only)\n"), 6 );
 #endif
     }
   if (opt.expert)
     {
-      tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
+      if (opt.compliance != CO_DE_VS)
+        tty_printf (_("   (%d) DSA (set your own capabilities)\n"), 7 );
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
 #endif
 #if GPG_USE_RSA
       tty_printf (_("   (%d) RSA (set your own capabilities)\n"), 8 );
 #endif
@@ -1883,7 +1951,13 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
       answer = cpr_get ("keygen.algo", _("Your selection? "));
       cpr_kill_prompt ();
       algo = *answer? atoi (answer) : 1;
       answer = cpr_get ("keygen.algo", _("Your selection? "));
       cpr_kill_prompt ();
       algo = *answer? atoi (answer) : 1;
-      if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode)
+
+      if (opt.compliance == CO_DE_VS
+          && (algo == 2 || algo == 3 || algo == 5 || algo == 7))
+        {
+          tty_printf (_("Invalid selection.\n"));
+        }
+      else if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_subkey_algo = PUBKEY_ALGO_RSA;
         {
           algo = PUBKEY_ALGO_RSA;
           *r_subkey_algo = PUBKEY_ALGO_RSA;
@@ -1922,13 +1996,13 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
       else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_DSA;
       else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_DSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_RSA;
           break;
        }
       else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_RSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 9 || !strcmp (answer, "ecc+ecc"))
           break;
        }
       else if ((algo == 9 || !strcmp (answer, "ecc+ecc"))
@@ -1947,7 +2021,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
       else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
       else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 12 || !strcmp (answer, "ecc/e"))
           break;
        }
       else if ((algo == 12 || !strcmp (answer, "ecc/e"))
@@ -1985,7 +2059,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           xfree (keygrip);
           keygrip = answer;
           answer = NULL;
           xfree (keygrip);
           keygrip = answer;
           answer = NULL;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else
           break;
        }
       else
@@ -2000,88 +2074,57 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 }
 
 
 }
 
 
-/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
-   is not 0, the function asks for the size of the encryption
-   subkey. */
-static unsigned
-ask_keysize (int algo, unsigned int primary_keysize)
+static unsigned int
+get_keysize_range (int algo, unsigned int *min, unsigned int *max)
 {
 {
-  unsigned int nbits;
-  unsigned int min = 1024;
-  unsigned int def = DEFAULT_STD_KEYSIZE;
-  unsigned int max = 4096;
-  int for_subkey = !!primary_keysize;
-  int autocomp = 0;
+  unsigned int def;
+  unsigned int dummy1, dummy2;
 
 
-  if (primary_keysize && !opt.expert)
-    {
-      /* Deduce the subkey size from the primary key size.  */
-      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
-        nbits = 3072; /* For performance reasons we don't support more
-                         than 3072 bit DSA.  However we won't see this
-                         case anyway because DSA can't be used as an
-                         encryption subkey ;-). */
-      else
-        nbits = primary_keysize;
-      autocomp = 1;
-      goto leave;
-    }
+  if (!min)
+    min = &dummy1;
+  if (!max)
+    max = &dummy2;
 
 
-  /* Deviations from the standard values.  */
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      min = opt.expert? 768 : 1024;
+      *min = opt.expert? 768 : 1024;
+      *max=3072;
       def=2048;
       def=2048;
-      max=3072;
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
       break;
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
-      min=256;
+      *min=256;
+      *max=521;
       def=256;
       def=256;
-      max=521;
       break;
 
     case PUBKEY_ALGO_EDDSA:
       break;
 
     case PUBKEY_ALGO_EDDSA:
-      min=255;
+      *min=255;
+      *max=441;
       def=255;
       def=255;
-      max=441;
       break;
       break;
-    }
-
-  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
-            openpgp_pk_algo_name (algo), min, max);
-
-  for (;;)
-    {
-      char *prompt, *answer;
-
-      if (for_subkey)
-        prompt = xasprintf (_("What keysize do you want "
-                              "for the subkey? (%u) "), def);
-      else
-        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
-      answer = cpr_get ("keygen.size", prompt);
-      cpr_kill_prompt ();
-      nbits = *answer? atoi (answer): def;
-      xfree(prompt);
-      xfree(answer);
 
 
-      if(nbits<min || nbits>max)
-       tty_printf(_("%s keysizes must be in the range %u-%u\n"),
-                  openpgp_pk_algo_name (algo), min, max);
-      else
-       break;
+    default:
+      *min = opt.compliance == CO_DE_VS ? 2048: 1024;
+      *max = 4096;
+      def = 3072;
+      break;
     }
 
     }
 
-  tty_printf (_("Requested keysize is %u bits\n"), nbits);
+  return def;
+}
 
 
- leave:
+
+/* Return a fixed up keysize depending on ALGO.  */
+static unsigned int
+fixup_keysize (unsigned int nbits, int algo, int silent)
+{
   if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
   if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
     {
       nbits = ((nbits + 63) / 64) * 64;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits);
     }
   else if (algo == PUBKEY_ALGO_EDDSA)
         tty_printf (_("rounded up to %u bits\n"), nbits);
     }
   else if (algo == PUBKEY_ALGO_EDDSA)
@@ -2092,7 +2135,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 255;
           else
             nbits = 441;
             nbits = 255;
           else
             nbits = 441;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
@@ -2106,14 +2149,14 @@ ask_keysize (int algo, unsigned int primary_keysize)
             nbits = 384;
           else
             nbits = 521;
             nbits = 384;
           else
             nbits = 521;
-          if (!autocomp)
+          if (!silent)
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
   else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
             tty_printf (_("rounded to %u bits\n"), nbits);
         }
     }
   else if ((nbits % 32))
     {
       nbits = ((nbits + 31) / 32) * 32;
-      if (!autocomp)
+      if (!silent)
         tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
         tty_printf (_("rounded up to %u bits\n"), nbits );
     }
 
@@ -2121,32 +2164,99 @@ ask_keysize (int algo, unsigned int primary_keysize)
 }
 
 
 }
 
 
+/* Ask for the key size.  ALGO is the algorithm.  If PRIMARY_KEYSIZE
+   is not 0, the function asks for the size of the encryption
+   subkey. */
+static unsigned
+ask_keysize (int algo, unsigned int primary_keysize)
+{
+  unsigned int nbits;
+  unsigned int min, def, max;
+  int for_subkey = !!primary_keysize;
+  int autocomp = 0;
+
+  def = get_keysize_range (algo, &min, &max);
+
+  if (primary_keysize && !opt.expert)
+    {
+      /* Deduce the subkey size from the primary key size.  */
+      if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072)
+        nbits = 3072; /* For performance reasons we don't support more
+                         than 3072 bit DSA.  However we won't see this
+                         case anyway because DSA can't be used as an
+                         encryption subkey ;-). */
+      else
+        nbits = primary_keysize;
+      autocomp = 1;
+      goto leave;
+    }
+
+  tty_printf(_("%s keys may be between %u and %u bits long.\n"),
+            openpgp_pk_algo_name (algo), min, max);
+
+  for (;;)
+    {
+      char *prompt, *answer;
+
+      if (for_subkey)
+        prompt = xasprintf (_("What keysize do you want "
+                              "for the subkey? (%u) "), def);
+      else
+        prompt = xasprintf (_("What keysize do you want? (%u) "), def);
+      answer = cpr_get ("keygen.size", prompt);
+      cpr_kill_prompt ();
+      nbits = *answer? atoi (answer): def;
+      xfree(prompt);
+      xfree(answer);
+
+      if(nbits<min || nbits>max)
+       tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+                  openpgp_pk_algo_name (algo), min, max);
+      else
+       break;
+    }
+
+  tty_printf (_("Requested keysize is %u bits\n"), nbits);
+
+ leave:
+  nbits = fixup_keysize (nbits, algo, autocomp);
+  return nbits;
+}
+
+
 /* Ask for the curve.  ALGO is the selected algorithm which this
    function may adjust.  Returns a malloced string with the name of
    the curve.  BOTH tells that gpg creates a primary and subkey. */
 static char *
 ask_curve (int *algo, int *subkey_algo)
 {
 /* 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)
 {
+  /* NB: We always use a complete algo list so that we have stable
+     numbers in the menu regardless on how Gpg was configured.  */
   struct {
     const char *name;
   struct {
     const char *name;
-    int available;
-    int expert_only;
-    int fix_curve;
+    const char* eddsa_curve; /* Corresponding EdDSA curve.  */
     const char *pretty_name;
     const char *pretty_name;
+    unsigned int supported : 1;   /* Supported by gpg.     */
+    unsigned int de_vs : 1;       /* Allowed in CO_DE_VS.  */
+    unsigned int expert_only : 1; /* Only with --expert    */
+    unsigned int available : 1;   /* Available in Libycrypt (runtime checked) */
   } curves[] = {
   } curves[] = {
-#if GPG_USE_EDDSA
-    { "Curve25519",      0, 0, 1, "Curve 25519" },
-#endif
 #if GPG_USE_ECDSA || GPG_USE_ECDH
 #if GPG_USE_ECDSA || GPG_USE_ECDH
-    { "NIST P-256",      0, 1, 0, },
-    { "NIST P-384",      0, 0, 0, },
-    { "NIST P-521",      0, 1, 0, },
-    { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
-    { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
-    { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
-    { "secp256k1",       0, 1, 0  },
+# define MY_USE_ECDSADH 1
+#else
+# define MY_USE_ECDSADH 0
 #endif
 #endif
+    { "Curve25519",      "Ed25519", "Curve 25519", !!GPG_USE_EDDSA, 0, 0, 0 },
+    { "Curve448",        "Ed448",   "Curve 448",   0/*reserved*/  , 0, 1, 0 },
+    { "NIST P-256",      NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
+    { "NIST P-384",      NULL, NULL,               MY_USE_ECDSADH,  0, 0, 0 },
+    { "NIST P-521",      NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
+    { "brainpoolP256r1", NULL, "Brainpool P-256",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "brainpoolP384r1", NULL, "Brainpool P-384",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "brainpoolP512r1", NULL, "Brainpool P-512",  MY_USE_ECDSADH,  1, 1, 0 },
+    { "secp256k1",       NULL, NULL,               MY_USE_ECDSADH,  0, 1, 0 },
   };
   };
+#undef MY_USE_ECDSADH
   int idx;
   char *answer;
   char *result = NULL;
   int idx;
   char *answer;
   char *result = NULL;
@@ -2154,32 +2264,38 @@ ask_curve (int *algo, int *subkey_algo)
 
   tty_printf (_("Please select which elliptic curve you want:\n"));
 
 
   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;
   keyparms = NULL;
   for (idx=0; idx < DIM(curves); idx++)
     {
       int rc;
 
       curves[idx].available = 0;
-      if (!opt.expert && curves[idx].expert_only)
+      if (!curves[idx].supported)
+        continue;
+
+      if (opt.compliance==CO_DE_VS)
+        {
+          if (!curves[idx].de_vs)
+            continue; /* Not allowed.  */
+        }
+      else if (!opt.expert && curves[idx].expert_only)
         continue;
 
         continue;
 
-      /* FIXME: The strcmp below is a temporary hack during
-         development.  It shall be removed as soon as we have proper
-         Curve25519 support in Libgcrypt.  */
+      /* We need to switch from the ECDH name of the curve to the
+         EDDSA name of the curve if we want a signing key.  */
       gcry_sexp_release (keyparms);
       rc = gcry_sexp_build (&keyparms, NULL,
                             "(public-key(ecc(curve %s)))",
       gcry_sexp_release (keyparms);
       rc = gcry_sexp_build (&keyparms, NULL,
                             "(public-key(ecc(curve %s)))",
-                            (!strcmp (curves[idx].name, "Curve25519")
-                             ? "Ed25519" : curves[idx].name));
+                            curves[idx].eddsa_curve? curves[idx].eddsa_curve
+                            /**/                   : curves[idx].name);
       if (rc)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
       if (rc)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
-      if (subkey_algo && curves[idx].fix_curve)
+      if (subkey_algo && curves[idx].eddsa_curve)
         {
         {
-          /* Both Curve 25519 keys are to be created.  Check that
-             Libgcrypt also supports the real Curve25519.  */
+          /* Both Curve 25519 (or 448) keys are to be created.  Check that
+             Libgcrypt also supports the real Curve25519 (or 448).  */
           gcry_sexp_release (keyparms);
           rc = gcry_sexp_build (&keyparms, NULL,
                                 "(public-key(ecc(curve %s)))",
           gcry_sexp_release (keyparms);
           rc = gcry_sexp_build (&keyparms, NULL,
                                 "(public-key(ecc(curve %s)))",
@@ -2226,28 +2342,15 @@ ask_curve (int *algo, int *subkey_algo)
         tty_printf (_("Invalid selection.\n"));
       else
         {
         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
           /* If the user selected a signing algorithm and Curve25519
-             we need to update the algo and and the curve name.  */
+             we need to set the algo to EdDSA and update the curve name. */
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
-              && curves[idx].fix_curve)
+              && curves[idx].eddsa_curve)
             {
               if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
             {
               if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
-                {
-                  *subkey_algo = PUBKEY_ALGO_EDDSA;
-                  result = xstrdup ("Ed25519");
-                }
+                *subkey_algo = PUBKEY_ALGO_EDDSA;
               *algo = PUBKEY_ALGO_EDDSA;
               *algo = PUBKEY_ALGO_EDDSA;
-              result = xstrdup ("Ed25519");
+              result = xstrdup (curves[idx].eddsa_curve);
             }
           else
             result = xstrdup (curves[idx].name);
             }
           else
             result = xstrdup (curves[idx].name);
@@ -2281,7 +2384,8 @@ parse_expire_string( const char *string )
   u32 curtime = make_timestamp ();
   time_t tt;
 
   u32 curtime = make_timestamp ();
   time_t tt;
 
-  if (!*string)
+  if (!string || !*string || !strcmp (string, "none")
+      || !strcmp (string, "never") || !strcmp (string, "-"))
     seconds = 0;
   else if (!strncmp (string, "seconds=", 8))
     seconds = atoi (string+8);
     seconds = 0;
   else if (!strncmp (string, "seconds=", 8))
     seconds = atoi (string+8);
@@ -2298,7 +2402,7 @@ parse_expire_string( const char *string )
   return seconds;
 }
 
   return seconds;
 }
 
-/* Parsean Creation-Date string which is either "1986-04-26" or
+/* Parse a Creation-Date string which is either "1986-04-26" or
    "19860426T042640".  Returns 0 on error. */
 static u32
 parse_creation_string (const char *string)
    "19860426T042640".  Returns 0 on error. */
 static u32
 parse_creation_string (const char *string)
@@ -2369,13 +2473,7 @@ ask_expire_interval(int object,const char *def_expire)
          {
            char *prompt;
 
          {
            char *prompt;
 
-#define PROMPTSTRING _("Signature is valid for? (%s) ")
-           /* This will actually end up larger than necessary because
-              of the 2 bytes for '%s' */
-           prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1);
-           sprintf(prompt,PROMPTSTRING,def_expire);
-#undef PROMPTSTRING
-
+           prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire);
            answer = cpr_get("siggen.valid",prompt);
            xfree(prompt);
 
            answer = cpr_get("siggen.valid",prompt);
            xfree(prompt);
 
@@ -2536,8 +2634,11 @@ ask_user_id (int mode, int full, KBNODE keyblock)
                   }
                else if( digitp(aname) )
                    tty_printf(_("Name may not start with a digit\n"));
                   }
                else if( digitp(aname) )
                    tty_printf(_("Name may not start with a digit\n"));
-               else if( strlen(aname) < 5 )
+               else if (*aname && strlen (aname) < 5)
+                  {
                    tty_printf(_("Name must be at least 5 characters long\n"));
                    tty_printf(_("Name must be at least 5 characters long\n"));
+                    /* However, we allow an empty name.  */
+                  }
                else
                    break;
            }
                else
                    break;
            }
@@ -2580,11 +2681,20 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 
        xfree(uid);
        uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
 
        xfree(uid);
        uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
-       p = stpcpy(p, aname );
-       if( *acomment )
-           p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
-       if( *amail )
-           p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
+        if (!*aname && *amail && !*acomment && !random_is_faked ())
+          { /* Empty name and comment but with mail address.  Use
+               simplified form with only the non-angle-bracketed mail
+               address.  */
+            p = stpcpy (p, amail);
+          }
+        else
+          {
+            p = stpcpy (p, aname );
+            if (*acomment)
+              p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
+            if (*amail)
+              p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
+          }
 
        /* Append a warning if the RNG is switched into fake mode.  */
         if ( random_is_faked ()  )
 
        /* Append a warning if the RNG is switched into fake mode.  */
         if ( random_is_faked ()  )
@@ -2702,7 +2812,8 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 static int
 do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
 static int
 do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
-           int keygen_flags, const char *passphrase, char **cache_nonce_addr)
+           int keygen_flags, const char *passphrase,
+           char **cache_nonce_addr, char **passwd_nonce_addr)
 {
   gpg_error_t err;
 
 {
   gpg_error_t err;
 
@@ -2717,18 +2828,22 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
   if (algo == PUBKEY_ALGO_ELGAMAL_E)
     err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
 
   if (algo == PUBKEY_ALGO_ELGAMAL_E)
     err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_DSA)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
   else if (algo == PUBKEY_ALGO_DSA)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
     err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
   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);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, passphrase, cache_nonce_addr);
+                   keygen_flags, passphrase,
+                   cache_nonce_addr, passwd_nonce_addr);
   else
     BUG();
 
   else
     BUG();
 
@@ -2767,63 +2882,358 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
 }
 
 
 }
 
 
-/* Append R to the linked list PARA.  */
-static void
-append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+/* Helper for parse_key_parameter_string for one part of the
+ * specification string; i.e.  ALGO/FLAGS.  If STRING is NULL or empty
+ * success is returned.  On error an error code is returned.  Note
+ * that STRING may be modified by this function.  NULL may be passed
+ * for any parameter.  FOR_SUBKEY shall be true if this is used as a
+ * subkey.  */
+static gpg_error_t
+parse_key_parameter_part (char *string, int for_subkey,
+                          int *r_algo, unsigned int *r_size,
+                          unsigned int *r_keyuse,
+                          char const **r_curve)
 {
 {
-  assert (para);
-  while (para->next)
-    para = para->next;
-  para->next = r;
-}
+  char *flags;
+  int algo;
+  char *endp;
+  const char *curve = NULL;
+  int ecdh_or_ecdsa = 0;
+  unsigned int size;
+  int keyuse;
+  int i;
+  const char *s;
 
 
-/* Release the parameter list R.  */
-static void
-release_parameter_list (struct para_data_s *r)
-{
-  struct para_data_s *r2;
+  if (!string || !*string)
+    return 0; /* Success.  */
 
 
-  for (; r ; r = r2)
+  flags = strchr (string, '/');
+  if (flags)
+    *flags++ = 0;
+
+  algo = 0;
+  if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
     {
     {
-      r2 = r->next;
-      if (r->key == pPASSPHRASE && *r->u.value)
-        wipememory (r->u.value, strlen (r->u.value));
-      xfree (r);
+      if (!ascii_memcasecmp (string, "rsa", 3))
+        algo = PUBKEY_ALGO_RSA;
+      else if (!ascii_memcasecmp (string, "dsa", 3))
+        algo = PUBKEY_ALGO_DSA;
+      else if (!ascii_memcasecmp (string, "elg", 3))
+        algo = PUBKEY_ALGO_ELGAMAL_E;
+    }
+  if (algo)
+    {
+      if (!string[3])
+        size = get_keysize_range (algo, NULL, NULL);
+      else
+        {
+          size = strtoul (string+3, &endp, 10);
+          if (size < 512 || size > 16384 || *endp)
+            return gpg_error (GPG_ERR_INV_VALUE);
+        }
     }
     }
-}
-
-static struct para_data_s *
-get_parameter( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r;
+  else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
+    {
+      if (!algo)
+        {
+          algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm.  */
+          ecdh_or_ecdsa = 1;       /* We may need to switch the algo.  */
+        }
+    }
+  else
+    return gpg_error (GPG_ERR_UNKNOWN_CURVE);
 
 
-    for( r = para; r && r->key != key; r = r->next )
-       ;
-    return r;
-}
+  /* Parse the flags.  */
+  keyuse = 0;
+  if (flags)
+    {
+      char **tokens = NULL;
 
 
-static const char *
-get_parameter_value( struct para_data_s *para, enum para_name key )
-{
-    struct para_data_s *r = get_parameter( para, key );
-    return (r && *r->u.value)? r->u.value : NULL;
-}
+      tokens = strtokenize (flags, ",");
+      if (!tokens)
+        return gpg_error_from_syserror ();
 
 
+      for (i=0; (s = tokens[i]); i++)
+        {
+          if (!*s)
+            ;
+          else if (!ascii_strcasecmp (s, "sign"))
+            keyuse |= PUBKEY_USAGE_SIG;
+          else if (!ascii_strcasecmp (s, "encrypt")
+                   || !ascii_strcasecmp (s, "encr"))
+            keyuse |= PUBKEY_USAGE_ENC;
+          else if (!ascii_strcasecmp (s, "auth"))
+            keyuse |= PUBKEY_USAGE_AUTH;
+          else if (!ascii_strcasecmp (s, "cert"))
+            keyuse |= PUBKEY_USAGE_CERT;
+          else if (!ascii_strcasecmp (s, "ecdsa"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDSA;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "ecdh"))
+            {
+              if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
+                algo = PUBKEY_ALGO_ECDH;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+              ecdh_or_ecdsa = 0;
+            }
+          else if (!ascii_strcasecmp (s, "eddsa"))
+            {
+              /* Not required but we allow it for consistency.  */
+              if (algo == PUBKEY_ALGO_EDDSA)
+                ;
+              else
+                {
+                  xfree (tokens);
+                  return gpg_error (GPG_ERR_INV_FLAG);
+                }
+            }
+          else
+            {
+              xfree (tokens);
+              return gpg_error (GPG_ERR_UNKNOWN_FLAG);
+            }
+        }
 
 
-/* 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;
-}
+      xfree (tokens);
+    }
 
 
+  /* If not yet decided switch between ecdh and ecdsa.  */
+  if (ecdh_or_ecdsa && keyuse)
+    algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
+  else if (ecdh_or_ecdsa)
+    algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
 
 
-static int
-get_parameter_algo( struct para_data_s *para, enum para_name key,
-                    int *r_default)
+  /* Set or fix key usage.  */
+  if (!keyuse)
+    {
+      if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_DSA)
+        keyuse = PUBKEY_USAGE_SIG;
+      else if (algo == PUBKEY_ALGO_RSA)
+        keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG;
+      else
+        keyuse = PUBKEY_USAGE_ENC;
+    }
+  else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA
+           || algo == PUBKEY_ALGO_DSA)
+    {
+      keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption.  */
+    }
+  else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E)
+    {
+      keyuse = PUBKEY_USAGE_ENC;   /* Allow only encryption.  */
+    }
+
+  /* Make sure a primary key can certify.  */
+  if (!for_subkey)
+    keyuse |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is actually possible.  */
+  if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((keyuse & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (keyuse & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Return values.  */
+  if (r_algo)
+    *r_algo = algo;
+  if (r_size)
+    {
+      unsigned int min, def, max;
+
+      /* Make sure the keysize is in the allowed range.  */
+      def = get_keysize_range (algo, &min, &max);
+      if (!size)
+        size = def;
+      else if (size < min)
+        size = min;
+      else if (size > max)
+        size = max;
+
+      *r_size = fixup_keysize (size, algo, 1);
+    }
+  if (r_keyuse)
+    *r_keyuse = keyuse;
+  if (r_curve)
+    *r_curve = curve;
+
+  return 0;
+}
+
+/* Parse and return the standard key generation parameter.
+ * The string is expected to be in this format:
+ *
+ *   ALGO[/FLAGS][+SUBALGO[/FLAGS]]
+ *
+ * Here ALGO is a string in the same format as printed by the
+ * keylisting.  For example:
+ *
+ *   rsa3072 := RSA with 3072 bit.
+ *   dsa2048 := DSA with 2048 bit.
+ *   elg2048 := Elgamal with 2048 bit.
+ *   ed25519 := EDDSA using curve Ed25519.
+ *   cv25519 := ECDH using curve Curve25519.
+ *   nistp256:= ECDSA or ECDH using curve NIST P-256
+ *
+ * All strings with an unknown prefix are considered an elliptic
+ * curve.  Curves which have no implicit algorithm require that FLAGS
+ * is given to select whether ECDSA or ECDH is used; this can eoither
+ * be done using an algorithm keyword or usage keywords.
+ *
+ * FLAGS is a comma delimited string of keywords:
+ *
+ *   cert := Allow usage Certify
+ *   sign := Allow usage Sign
+ *   encr := Allow usage Encrypt
+ *   auth := Allow usage Authentication
+ *   encrypt := Alias for "encr"
+ *   ecdsa := Use algorithm ECDSA.
+ *   eddsa := Use algorithm EdDSA.
+ *   ecdh  := Use algorithm ECDH.
+ *
+ * There are several defaults and fallbacks depending on the
+ * algorithm.  PART can be used to select which part of STRING is
+ * used:
+ *   -1 := Both parts
+ *    0 := Only the part of the primary key
+ *    1 := If there is one part parse that one, if there are
+ *         two parts parse the second part.  Always return
+ *         in the args for the primary key (R_ALGO,....).
+ *
+ */
+gpg_error_t
+parse_key_parameter_string (const char *string, int part,
+                            int *r_algo, unsigned int *r_size,
+                            unsigned *r_keyuse,
+                            char const **r_curve,
+                            int *r_subalgo, unsigned int *r_subsize,
+                            unsigned *r_subkeyuse,
+                            char const **r_subcurve)
+{
+  gpg_error_t err = 0;
+  char *primary, *secondary;
+
+  if (r_algo)
+    *r_algo = 0;
+  if (r_size)
+    *r_size = 0;
+  if (r_keyuse)
+    *r_keyuse = 0;
+  if (r_curve)
+    *r_curve = NULL;
+  if (r_subalgo)
+    *r_subalgo = 0;
+  if (r_subsize)
+    *r_subsize = 0;
+  if (r_subkeyuse)
+    *r_subkeyuse = 0;
+  if (r_subcurve)
+    *r_subcurve = NULL;
+
+  if (!string || !*string
+      || !strcmp (string, "default") || !strcmp (string, "-"))
+    string = get_default_pubkey_algo ();
+  else if (!strcmp (string, "future-default"))
+    string = FUTURE_STD_KEY_PARAM;
+
+  primary = xstrdup (string);
+  secondary = strchr (primary, '+');
+  if (secondary)
+    *secondary++ = 0;
+  if (part == -1 || part == 0)
+    {
+      err = parse_key_parameter_part (primary, 0, r_algo, r_size,
+                                      r_keyuse, r_curve);
+      if (!err && part == -1)
+        err = parse_key_parameter_part (secondary, 1, r_subalgo, r_subsize,
+                                        r_subkeyuse, r_subcurve);
+    }
+  else if (part == 1)
+    {
+      /* If we have SECONDARY, use that part.  If there is only one
+       * part consider this to be the subkey algo.  */
+      err = parse_key_parameter_part (secondary? secondary : primary, 1,
+                                      r_algo, r_size, r_keyuse, r_curve);
+    }
+
+  xfree (primary);
+
+  return err;
+}
+
+
+
+/* Append R to the linked list PARA.  */
+static void
+append_to_parameter (struct para_data_s *para, struct para_data_s *r)
+{
+  log_assert (para);
+  while (para->next)
+    para = para->next;
+  para->next = r;
+}
+
+/* Release the parameter list R.  */
+static void
+release_parameter_list (struct para_data_s *r)
+{
+  struct para_data_s *r2;
+
+  for (; r ; r = r2)
+    {
+      r2 = r->next;
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
+      xfree (r);
+    }
+}
+
+static struct para_data_s *
+get_parameter( struct para_data_s *para, enum para_name key )
+{
+    struct para_data_s *r;
+
+    for( r = para; r && r->key != key; r = r->next )
+       ;
+    return r;
+}
+
+static const char *
+get_parameter_value( struct para_data_s *para, enum para_name key )
+{
+    struct para_data_s *r = get_parameter( para, key );
+    return (r && *r->u.value)? r->u.value : NULL;
+}
+
+
+/* This is similar to get_parameter_value but also returns the empty
+   string.  This is required so that quick_generate_keypair can use an
+   empty Passphrase to specify no-protection.  */
+static const char *
+get_parameter_passphrase (struct para_data_s *para)
+{
+  struct para_data_s *r = get_parameter (para, pPASSPHRASE);
+  return r ? r->u.value : NULL;
+}
+
+
+static int
+get_parameter_algo( struct para_data_s *para, enum para_name key,
+                    int *r_default)
 {
   int i;
   struct para_data_s *r = get_parameter( para, key );
 {
   int i;
   struct para_data_s *r = get_parameter( para, key );
@@ -2839,8 +3249,15 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   if (!ascii_strcasecmp (r->u.value, "default"))
     {
       /* Note: If you change this default algo, remember to change it
   if (!ascii_strcasecmp (r->u.value, "default"))
     {
       /* Note: If you change this default algo, remember to change it
-         also in gpg.c:gpgconf_list.  */
-      i = DEFAULT_STD_ALGO;
+       * also in gpg.c:gpgconf_list.  */
+      /* FIXME: We only allow the algo here and have a separate thing
+       * for the curve etc.  That is a ugly but demanded for backward
+       * compatibility with the batch key generation.  It would be
+       * better to make full use of parse_key_parameter_string.  */
+      parse_key_parameter_string (NULL, 0,
+                                  &i, NULL, NULL, NULL,
+                                  NULL, NULL, NULL, NULL);
+
       if (r_default)
         *r_default = 1;
     }
       if (r_default)
         *r_default = 1;
     }
@@ -2863,6 +3280,52 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
   return i;
 }
 
   return i;
 }
 
+
+/* Parse a usage string.  The usage keywords "auth", "sign", "encr"
+ * may be delimited by space, tab, or comma.  On error -1 is returned
+ * instead of the usage flags.  */
+static int
+parse_usagestr (const char *usagestr)
+{
+  gpg_error_t err;
+  char **tokens = NULL;
+  const char *s;
+  int i;
+  unsigned int use = 0;
+
+  tokens = strtokenize (usagestr, " \t,");
+  if (!tokens)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+      return -1;
+    }
+
+  for (i=0; (s = tokens[i]); i++)
+    {
+      if (!*s)
+        ;
+      else if (!ascii_strcasecmp (s, "sign"))
+        use |= PUBKEY_USAGE_SIG;
+      else if (!ascii_strcasecmp (s, "encrypt")
+                || !ascii_strcasecmp (s, "encr"))
+        use |= PUBKEY_USAGE_ENC;
+      else if (!ascii_strcasecmp (s, "auth"))
+        use |= PUBKEY_USAGE_AUTH;
+      else if (!ascii_strcasecmp (s, "cert"))
+        use |= PUBKEY_USAGE_CERT;
+      else
+        {
+          xfree (tokens);
+          return -1; /* error */
+        }
+    }
+
+  xfree (tokens);
+  return use;
+}
+
+
 /*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
 /*
  * Parse the usage parameter and set the keyflags.  Returns -1 on
  * error, 0 for no usage given or 1 for usage available.
@@ -2871,33 +3334,24 @@ static int
 parse_parameter_usage (const char *fname,
                        struct para_data_s *para, enum para_name key)
 {
 parse_parameter_usage (const char *fname,
                        struct para_data_s *para, enum para_name key)
 {
-    struct para_data_s *r = get_parameter( para, key );
-    char *p, *pn;
-    unsigned int use;
+  struct para_data_s *r = get_parameter( para, key );
+  int i;
 
 
-    if( !r )
-       return 0; /* none (this is an optional parameter)*/
+  if (!r)
+    return 0; /* none (this is an optional parameter)*/
 
 
-    use = 0;
-    pn = r->u.value;
-    while ( (p = strsep (&pn, " \t,")) ) {
-        if ( !*p)
-            ;
-        else if ( !ascii_strcasecmp (p, "sign") )
-            use |= PUBKEY_USAGE_SIG;
-        else if ( !ascii_strcasecmp (p, "encrypt") )
-            use |= PUBKEY_USAGE_ENC;
-        else if ( !ascii_strcasecmp (p, "auth") )
-            use |= PUBKEY_USAGE_AUTH;
-        else {
-            log_error("%s:%d: invalid usage list\n", fname, r->lnr );
-            return -1; /* error */
-        }
+  i = parse_usagestr (r->u.value);
+  if (i == -1)
+    {
+      log_error ("%s:%d: invalid usage list\n", fname, r->lnr );
+      return -1; /* error */
     }
     }
-    r->u.usage = use;
-    return 1;
+
+  r->u.usage = i;
+  return 1;
 }
 
 }
 
+
 static int
 parse_revocation_key (const char *fname,
                      struct para_data_s *para, enum para_name key)
 static int
 parse_revocation_key (const char *fname,
                      struct para_data_s *para, enum para_name key)
@@ -3093,7 +3547,14 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
          if( s2 )
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
          if( s2 )
            p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
          if( s3 )
-           p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
+            {
+              /* If we have only the email part, do not add the space
+               * and the angle brackets.  */
+              if (*r->u.value)
+                p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
+              else
+                p = stpcpy (p, s3);
+            }
           append_to_parameter (para, r);
          have_user_id=1;
        }
           append_to_parameter (para, r);
          have_user_id=1;
        }
@@ -3122,6 +3583,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
        }
       else
        {
        }
       else
        {
+          r = get_parameter (para, pKEYSERVER);
          log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
          return -1;
        }
          log_error("%s:%d: invalid keyserver url\n", fname, r->lnr );
          return -1;
        }
@@ -3202,8 +3664,11 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
         { "Handle",         pHANDLE },
        { "Preferences",    pPREFERENCES },
        { "Revoker",        pREVOKER },
         { "Handle",         pHANDLE },
-       { "Keyserver",      pKEYSERVER },
-       { NULL, 0 }
+        { "Keyserver",      pKEYSERVER },
+        { "Keygrip",        pKEYGRIP },
+        { "Key-Grip",       pKEYGRIP },
+        { "Subkey-grip",    pSUBKEYGRIP },
+        { NULL, 0 }
     };
     IOBUF fp;
     byte *line;
     };
     IOBUF fp;
     byte *line;
@@ -3377,6 +3842,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
        xfree( outctrl.pub.newfname );
     }
 
        xfree( outctrl.pub.newfname );
     }
 
+    xfree (line);
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
     release_parameter_list( para );
     iobuf_close (fp);
     release_armor_context (outctrl.pub.afx);
@@ -3386,18 +3852,25 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
 /* Helper for quick_generate_keypair.  */
 static struct para_data_s *
 quickgen_set_para (struct para_data_s *para, int for_subkey,
 /* Helper for quick_generate_keypair.  */
 static struct para_data_s *
 quickgen_set_para (struct para_data_s *para, int for_subkey,
-                   int algo, int nbits, const char *curve)
+                   int algo, int nbits, const char *curve, unsigned int use)
 {
   struct para_data_s *r;
 
 {
   struct para_data_s *r;
 
-  r = xmalloc_clear (sizeof *r + 20);
+  r = xmalloc_clear (sizeof *r + 30);
   r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
   r->key = for_subkey? pSUBKEYUSAGE :  pKEYUSAGE;
-  strcpy (r->u.value, for_subkey ? "encrypt" : "sign");
+  if (use)
+    snprintf (r->u.value, 30, "%s%s%s%s",
+              (use & PUBKEY_USAGE_ENC)?  "encr " : "",
+              (use & PUBKEY_USAGE_SIG)?  "sign " : "",
+              (use & PUBKEY_USAGE_AUTH)? "auth " : "",
+              (use & PUBKEY_USAGE_CERT)? "cert " : "");
+  else
+    strcpy (r->u.value, for_subkey ? "encr" : "sign");
   r->next = para;
   para = r;
   r = xmalloc_clear (sizeof *r + 20);
   r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE;
   r->next = para;
   para = r;
   r = xmalloc_clear (sizeof *r + 20);
   r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE;
-  sprintf (r->u.value, "%d", algo);
+  snprintf (r->u.value, 20, "%d", algo);
   r->next = para;
   para = r;
 
   r->next = para;
   para = r;
 
@@ -3426,7 +3899,8 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
  * Unattended generation of a standard key.
  */
 void
  * Unattended generation of a standard key.
  */
 void
-quick_generate_keypair (ctrl_t ctrl, const char *uid)
+quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
+                        const char *usagestr, const char *expirestr)
 {
   gpg_error_t err;
   struct para_data_s *para = NULL;
 {
   gpg_error_t err;
   struct para_data_s *para = NULL;
@@ -3437,6 +3911,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
   memset (&outctrl, 0, sizeof outctrl);
 
   use_tty = (!opt.batch && !opt.answer_yes
   memset (&outctrl, 0, sizeof outctrl);
 
   use_tty = (!opt.batch && !opt.answer_yes
+             && !*algostr && !*usagestr && !*expirestr
              && !cpr_enabled ()
              && gnupg_isatty (fileno (stdin))
              && gnupg_isatty (fileno (stdout))
              && !cpr_enabled ()
              && gnupg_isatty (fileno (stdin))
              && gnupg_isatty (fileno (stdout))
@@ -3490,6 +3965,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
                  || !cpr_get_answer_is_yes_def ("quick_keygen.force",
                                                 _("Create anyway? (y/N) "), 0))
           {
                  || !cpr_get_answer_is_yes_def ("quick_keygen.force",
                                                 _("Create anyway? (y/N) "), 0))
           {
+            write_status_error ("genkey", gpg_error (304));
             log_inc_errorcount ();  /* we used log_info */
             goto leave;
           }
             log_inc_errorcount ();  /* we used log_info */
             goto leave;
           }
@@ -3497,12 +3973,77 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
       }
   }
 
       }
   }
 
-  para = quickgen_set_para (para, 0,
-                            DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
-                            DEFAULT_STD_CURVE);
-  para = quickgen_set_para (para, 1,
-                            DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE,
-                            DEFAULT_STD_SUBCURVE);
+  if (!*expirestr || strcmp (expirestr, "-") == 0)
+    expirestr = default_expiration_interval;
+
+  if ((!*algostr || !strcmp (algostr, "default")
+       || !strcmp (algostr, "future-default"))
+      && (!*usagestr || !strcmp (usagestr, "default")
+          || !strcmp (usagestr, "-")))
+    {
+      /* Use default key parameters.  */
+      int algo, subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
+      err = parse_key_parameter_string (algostr, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize, &subkeyuse,
+                                        &subcurve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
+      if (*expirestr)
+        {
+          u32 expire;
+
+          expire = parse_expire_string (expirestr);
+          if (expire == (u32)-1 )
+            {
+              err = gpg_error (GPG_ERR_INV_VALUE);
+              log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+              goto leave;
+            }
+          r = xmalloc_clear (sizeof *r + 20);
+          r->key = pKEYEXPIRE;
+          r->u.expire = expire;
+          r->next = para;
+          para = r;
+        }
+    }
+  else
+    {
+      /* Extended unattended mode.  Creates only the primary key. */
+      int algo;
+      unsigned int use;
+      u32 expire;
+      unsigned int nbits;
+      char *curve;
+
+      err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
+          goto leave;
+        }
+
+      para = quickgen_set_para (para, 0, algo, nbits, curve, use);
+      r = xmalloc_clear (sizeof *r + 20);
+      r->key = pKEYEXPIRE;
+      r->u.expire = expire;
+      r->next = para;
+      para = r;
+    }
 
   /* If the pinentry loopback mode is not and we have a static
      passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
 
   /* If the pinentry loopback mode is not and we have a static
      passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
@@ -3520,6 +4061,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid)
     }
 
   proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
     }
 
   proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
+
  leave:
   release_parameter_list (para);
 }
  leave:
   release_parameter_list (para);
 }
@@ -3538,6 +4080,7 @@ void
 generate_keypair (ctrl_t ctrl, int full, const char *fname,
                   const char *card_serialno, int card_backup_key)
 {
 generate_keypair (ctrl_t ctrl, int full, const char *fname,
                   const char *card_serialno, int card_backup_key)
 {
+  gpg_error_t err;
   unsigned int nbits;
   char *uid = NULL;
   int algo;
   unsigned int nbits;
   char *uid = NULL;
   int algo;
@@ -3570,17 +4113,26 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
   if (card_serialno)
     {
 #ifdef ENABLE_CARD_SUPPORT
   if (card_serialno)
     {
 #ifdef ENABLE_CARD_SUPPORT
+      struct agent_card_info_s info;
+
+      memset (&info, 0, sizeof (info));
+      err = agent_scd_getattr ("KEY-ATTR", &info);
+      if (err)
+        {
+          log_error (_("error getting current key info: %s\n"),
+                     gpg_strerror (err));
+          return;
+        }
+
       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
       r->key = pSERIALNO;
       strcpy( r->u.value, card_serialno);
       r->next = para;
       para = r;
 
       r = xcalloc (1, sizeof *r + strlen (card_serialno) );
       r->key = pSERIALNO;
       strcpy( r->u.value, card_serialno);
       r->next = para;
       para = r;
 
-      algo = PUBKEY_ALGO_RSA;
-
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pKEYTYPE;
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      sprintf( r->u.value, "%d", info.key_attr[0].algo );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
@@ -3591,7 +4143,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      sprintf( r->u.value, "%d", info.key_attr[1].algo );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
       r->next = para;
       para = r;
       r = xcalloc (1, sizeof *r + 20 );
@@ -3599,10 +4151,28 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
       strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
       strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
+      if (info.key_attr[1].algo == PUBKEY_ALGO_RSA)
+        {
+          r = xcalloc (1, sizeof *r + 20 );
+          r->key = pSUBKEYLENGTH;
+          sprintf( r->u.value, "%u", info.key_attr[1].nbits);
+          r->next = para;
+          para = r;
+        }
+      else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA
+               || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA
+               || info.key_attr[1].algo == PUBKEY_ALGO_ECDH)
+        {
+          r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve));
+          r->key = pSUBKEYCURVE;
+          strcpy (r->u.value, info.key_attr[1].curve);
+          r->next = para;
+          para = r;
+        }
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pAUTHKEYTYPE;
 
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pAUTHKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      sprintf( r->u.value, "%d", info.key_attr[2].algo );
       r->next = para;
       para = r;
 
       r->next = para;
       para = r;
 
@@ -3619,154 +4189,203 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
   else if (full)  /* Full featured key generation.  */
     {
       int subkey_algo;
   else if (full)  /* Full featured key generation.  */
     {
       int subkey_algo;
-      char *curve = NULL;
-
-      /* Fixme: To support creating a primary key by keygrip we better
-         also define the keyword for the parameter file.  Note that
-         the subkey case will never be asserted if a keygrip has been
-         given.  */
-      algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL);
-      if (subkey_algo)
+      char *key_from_hexgrip = NULL;
+
+      algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip);
+      if (key_from_hexgrip)
         {
         {
-          /* Create primary and subkey at once.  */
-          both = 1;
-          if (algo == PUBKEY_ALGO_ECDSA
-              || algo == PUBKEY_ALGO_EDDSA
-              || algo == PUBKEY_ALGO_ECDH)
+          r = xmalloc_clear( sizeof *r + 20 );
+          r->key = pKEYTYPE;
+          sprintf( r->u.value, "%d", algo);
+          r->next = para;
+          para = r;
+
+          if (use)
             {
             {
-              curve = ask_curve (&algo, &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 = xmalloc_clear( sizeof *r + 25 );
+              r->key = pKEYUSAGE;
+              sprintf( r->u.value, "%s%s%s",
+                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
               r->next = para;
               para = r;
             }
               r->next = para;
               para = r;
             }
-          else
+
+          r = xmalloc_clear( sizeof *r + 40 );
+          r->key = pKEYGRIP;
+          strcpy (r->u.value, key_from_hexgrip);
+          r->next = para;
+          para = r;
+
+          xfree (key_from_hexgrip);
+        }
+      else
+        {
+          char *curve = NULL;
+
+          if (subkey_algo)
             {
             {
+              /* Create primary and subkey at once.  */
+              both = 1;
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
+                {
+                  curve = ask_curve (&algo, &subkey_algo);
+                  r = xmalloc_clear( sizeof *r + 20 );
+                  r->key = pKEYTYPE;
+                  sprintf( r->u.value, "%d", algo);
+                  r->next = para;
+                  para = r;
+                  nbits = 0;
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
+                }
+              else
+                {
+                  r = xmalloc_clear( sizeof *r + 20 );
+                  r->key = pKEYTYPE;
+                  sprintf( r->u.value, "%d", algo);
+                  r->next = para;
+                  para = r;
+                  nbits = ask_keysize (algo, 0);
+                  r = xmalloc_clear( sizeof *r + 20 );
+                  r->key = pKEYLENGTH;
+                  sprintf( r->u.value, "%u", nbits);
+                  r->next = para;
+                  para = r;
+                }
               r = xmalloc_clear( sizeof *r + 20 );
               r = xmalloc_clear( sizeof *r + 20 );
-              r->key = pKEYTYPE;
-              sprintf( r->u.value, "%d", algo);
+              r->key = pKEYUSAGE;
+              strcpy( r->u.value, "sign" );
               r->next = para;
               para = r;
               r->next = para;
               para = r;
-              nbits = ask_keysize (algo, 0);
+
               r = xmalloc_clear( sizeof *r + 20 );
               r = xmalloc_clear( sizeof *r + 20 );
-              r->key = pKEYLENGTH;
-              sprintf( r->u.value, "%u", nbits);
+              r->key = pSUBKEYTYPE;
+              sprintf( r->u.value, "%d", subkey_algo);
+              r->next = para;
+              para = r;
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pSUBKEYUSAGE;
+              strcpy( r->u.value, "encrypt" );
               r->next = para;
               para = r;
               r->next = para;
               para = r;
-            }
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYUSAGE;
-          strcpy( r->u.value, "sign" );
-          r->next = para;
-          para = r;
-
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pSUBKEYTYPE;
-          sprintf( r->u.value, "%d", subkey_algo);
-          r->next = para;
-          para = r;
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pSUBKEYUSAGE;
-          strcpy( r->u.value, "encrypt" );
-          r->next = para;
-          para = r;
 
 
-          if (algo == PUBKEY_ALGO_ECDSA
-              || algo == PUBKEY_ALGO_EDDSA
-              || algo == PUBKEY_ALGO_ECDH)
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
+                {
+                  if (algo == PUBKEY_ALGO_EDDSA
+                      && subkey_algo == PUBKEY_ALGO_ECDH)
+                    {
+                      /* Need to switch to a different curve for the
+                         encryption key.  */
+                      xfree (curve);
+                      curve = xstrdup ("Curve25519");
+                    }
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pSUBKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
+                }
+            }
+          else /* Create only a single key.  */
             {
             {
-              if (algo == PUBKEY_ALGO_EDDSA
-                  && subkey_algo == PUBKEY_ALGO_ECDH)
+              /* For ECC we need to ask for the curve before storing the
+                 algo because ask_curve may change the algo.  */
+              if (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA
+                  || algo == PUBKEY_ALGO_ECDH)
                 {
                 {
-                  /* Need to switch to a different curve for the
-                     encryption key.  */
-                  xfree (curve);
-                  curve = xstrdup ("Curve25519");
+                  curve = ask_curve (&algo, NULL);
+                  r = xmalloc_clear (sizeof *r + strlen (curve));
+                  r->key = pKEYCURVE;
+                  strcpy (r->u.value, curve);
+                  r->next = para;
+                  para = r;
                 }
                 }
-              r = xmalloc_clear (sizeof *r + strlen (curve));
-              r->key = pSUBKEYCURVE;
-              strcpy (r->u.value, curve);
+
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = pKEYTYPE;
+              sprintf( r->u.value, "%d", algo );
               r->next = para;
               para = r;
               r->next = para;
               para = r;
+
+              if (use)
+                {
+                  r = xmalloc_clear( sizeof *r + 25 );
+                  r->key = pKEYUSAGE;
+                  sprintf( r->u.value, "%s%s%s",
+                           (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                           (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
+                           (use & PUBKEY_USAGE_AUTH)? "auth":"" );
+                  r->next = para;
+                  para = r;
+                }
+              nbits = 0;
             }
             }
-        }
-      else /* Create only a single key.  */
-        {
-          /* For ECC we need to ask for the curve before storing the
-             algo because ask_curve may change the algo.  */
+
           if (algo == PUBKEY_ALGO_ECDSA
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
           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;
+              /* The curve has already been set.  */
             }
             }
-
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYTYPE;
-          sprintf( r->u.value, "%d", algo );
-          r->next = para;
-          para = r;
-
-          if (use)
+          else
             {
             {
-              r = xmalloc_clear( sizeof *r + 25 );
-              r->key = pKEYUSAGE;
-              sprintf( r->u.value, "%s%s%s",
-                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"",
-                       (use & PUBKEY_USAGE_AUTH)? "auth":"" );
+              nbits = ask_keysize (both? subkey_algo : algo, nbits);
+              r = xmalloc_clear( sizeof *r + 20 );
+              r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+              sprintf( r->u.value, "%u", nbits);
               r->next = para;
               para = r;
             }
               r->next = para;
               para = r;
             }
-          nbits = 0;
-        }
 
 
-      if (algo == PUBKEY_ALGO_ECDSA
-          || algo == PUBKEY_ALGO_EDDSA
-          || algo == PUBKEY_ALGO_ECDH)
-        {
-          /* The curve has already been set.  */
-        }
-      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);
         }
         }
-
-      xfree (curve);
     }
   else /* Default key generation.  */
     {
     }
   else /* Default key generation.  */
     {
+      int subalgo;
+      unsigned int size, subsize;
+      unsigned int keyuse, subkeyuse;
+      const char *curve, *subcurve;
+
       tty_printf ( _("Note: Use \"%s %s\""
                      " for a full featured key generation dialog.\n"),
       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);
+#if USE_GPG2_HACK
+                   GPG_NAME "2"
+#else
+                   GPG_NAME
+#endif
+                   , "--full-generate-key" );
+
+      err = parse_key_parameter_string (NULL, -1,
+                                        &algo, &size, &keyuse, &curve,
+                                        &subalgo, &subsize,
+                                        &subkeyuse, &subcurve);
+      if (err)
+        {
+          log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
+          return;
+        }
+      para = quickgen_set_para (para, 0, algo, size, curve, keyuse);
+      if (subalgo)
+        para = quickgen_set_para (para, 1,
+                                  subalgo, subsize, subcurve, subkeyuse);
+
+
     }
 
 
     }
 
 
-  expire = full? ask_expire_interval (0, NULL) : 0;
+  expire = full? ask_expire_interval (0, NULL)
+               : parse_expire_string (default_expiration_interval);
   r = xcalloc (1, sizeof *r + 20);
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
   r = xcalloc (1, sizeof *r + 20);
   r->key = pKEYEXPIRE;
   r->u.expire = expire;
@@ -3815,15 +4434,15 @@ card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
 {
   gpg_error_t err = 0;
   int rc;
 {
   gpg_error_t err = 0;
   int rc;
+  char keyid_buffer[2 * 8 + 1];
   char name_buffer[50];
   char *fname;
   IOBUF fp;
   mode_t oldmask;
   PACKET *pkt = NULL;
 
   char name_buffer[50];
   char *fname;
   IOBUF fp;
   mode_t oldmask;
   PACKET *pkt = NULL;
 
-  keyid_from_pk (sk, NULL);
-  snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg",
-            (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+  format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer));
+  snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer);
 
   fname = make_filename (backup_dir, name_buffer, NULL);
   /* Note that the umask call is not anymore needed because
 
   fname = make_filename (backup_dir, name_buffer, NULL);
   /* Note that the umask call is not anymore needed because
@@ -3864,6 +4483,11 @@ card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
       log_info (_("Note: backup of card key saved to '%s'\n"), fname);
 
       fprbuf = hexfingerprint (sk, NULL, 0);
       log_info (_("Note: backup of card key saved to '%s'\n"), fname);
 
       fprbuf = hexfingerprint (sk, NULL, 0);
+      if (!fprbuf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
       write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf,
                                     fname, strlen (fname), 0);
       xfree (fprbuf);
       write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf,
                                     fname, strlen (fname), 0);
       xfree (fprbuf);
@@ -3921,19 +4545,23 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
       goto leave;
     }
 
       goto leave;
     }
 
-  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0);
+  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
+                          GCRY_CIPHER_MODE_AESWRAP, 0);
   if (!err)
     err = gcry_cipher_setkey (cipherhd, kek, keklen);
   if (err)
     {
   if (!err)
     err = gcry_cipher_setkey (cipherhd, kek, keklen);
   if (err)
     {
-      log_error ("error setting up an encryption context: %s\n", gpg_strerror (err));
+      log_error ("error setting up an encryption context: %s\n",
+                 gpg_strerror (err));
       goto leave;
     }
 
       goto leave;
     }
 
-  err = receive_seckey_from_agent (ctrl, cipherhd, &cache_nonce, hexgrip, sk);
+  err = receive_seckey_from_agent (ctrl, cipherhd, 0,
+                                   &cache_nonce, hexgrip, sk);
   if (err)
     {
   if (err)
     {
-      log_error ("error getting secret key from agent: %s\n", gpg_strerror (err));
+      log_error ("error getting secret key from agent: %s\n",
+                 gpg_strerror (err));
       goto leave;
     }
 
       goto leave;
     }
 
@@ -3967,6 +4595,9 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
   int did_sub = 0;
   u32 timestamp;
   char *cache_nonce = NULL;
   int did_sub = 0;
   u32 timestamp;
   char *cache_nonce = NULL;
+  int algo;
+  u32 expire;
+  const char *key_from_hexgrip = NULL;
 
   if (outctrl->dryrun)
     {
 
   if (outctrl->dryrun)
     {
@@ -4006,7 +4637,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
               push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
             }
         }
               push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
             }
         }
-      assert( outctrl->pub.stream );
+      log_assert( outctrl->pub.stream );
       if (opt.verbose)
         log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
       if (opt.verbose)
         log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
@@ -4032,35 +4663,50 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
      node of the subkey but that is more work than just to pass the
      current timestamp.  */
 
      node of the subkey but that is more work than just to pass the
      current timestamp.  */
 
-  if (!card)
-    err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ),
+  algo = get_parameter_algo( para, pKEYTYPE, NULL );
+  expire = get_parameter_u32( para, pKEYEXPIRE );
+  key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
+  if (key_from_hexgrip)
+    err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
+                                  pub_root, timestamp, expire, 0);
+  else if (!card)
+    err = do_create (algo,
                      get_parameter_uint( para, pKEYLENGTH ),
                      get_parameter_value (para, pKEYCURVE),
                      pub_root,
                      timestamp,
                      get_parameter_uint( para, pKEYLENGTH ),
                      get_parameter_value (para, pKEYCURVE),
                      pub_root,
                      timestamp,
-                     get_parameter_u32( para, pKEYEXPIRE ), 0,
+                     expire, 0,
                      outctrl->keygen_flags,
                      get_parameter_passphrase (para),
                      outctrl->keygen_flags,
                      get_parameter_passphrase (para),
-                     &cache_nonce);
+                     &cache_nonce, NULL);
   else
   else
-    err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
-                        &timestamp,
-                        get_parameter_u32 (para, pKEYEXPIRE));
+    err = gen_card_key (1, algo,
+                        1, pub_root, &timestamp,
+                        expire);
 
   /* Get the pointer to the generated public key packet.  */
   if (!err)
     {
       pri_psk = pub_root->next->pkt->pkt.public_key;
 
   /* Get the pointer to the generated public key packet.  */
   if (!err)
     {
       pri_psk = pub_root->next->pkt->pkt.public_key;
-      assert (pri_psk);
+      log_assert (pri_psk);
+
+      /* Make sure a few fields are correctly set up before going
+         further.  */
+      pri_psk->flags.primary = 1;
+      keyid_from_pk (pri_psk, NULL);
+      /* We don't use pk_keyid to get keyid, because it also asserts
+         that main_keyid is set!  */
+      keyid_copy (pri_psk->main_keyid, pri_psk->keyid);
     }
 
   if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
     }
 
   if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
-    err = write_direct_sig (pub_root, pri_psk, revkey, timestamp, cache_nonce);
+    err = write_direct_sig (ctrl, pub_root, pri_psk,
+                            revkey, timestamp, cache_nonce);
 
   if (!err && (s = get_parameter_value (para, pUSERID)))
     {
       write_uid (pub_root, s );
 
   if (!err && (s = get_parameter_value (para, pUSERID)))
     {
       write_uid (pub_root, s );
-      err = write_selfsigs (pub_root, pri_psk,
+      err = write_selfsigs (ctrl, pub_root, pri_psk,
                             get_parameter_uint (para, pKEYUSAGE), timestamp,
                             cache_nonce);
     }
                             get_parameter_uint (para, pKEYUSAGE), timestamp,
                             cache_nonce);
     }
@@ -4074,21 +4720,27 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 
   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
     {
 
   if (!err && card && get_parameter (para, pAUTHKEYTYPE))
     {
-      err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root,
-                          &timestamp,
-                          get_parameter_u32 (para, pKEYEXPIRE));
+      err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
+                          0, pub_root, &timestamp, expire);
       if (!err)
       if (!err)
-        err = write_keybinding (pub_root, pri_psk, NULL,
+        err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
                                 PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
     }
 
   if (!err && get_parameter (para, pSUBKEYTYPE))
     {
                                 PUBKEY_USAGE_AUTH, timestamp, cache_nonce);
     }
 
   if (!err && get_parameter (para, pSUBKEYTYPE))
     {
-      sub_psk = NULL;
+      int subkey_algo = get_parameter_algo (para, pSUBKEYTYPE, NULL);
+
       s = NULL;
       s = NULL;
-      if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
+      key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
+      if (key_from_hexgrip)
+        err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip,
+                                      pub_root, timestamp,
+                                      get_parameter_u32 (para, pSUBKEYEXPIRE),
+                                      1);
+      else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
         {
         {
-          err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
+          err = do_create (subkey_algo,
                            get_parameter_uint (para, pSUBKEYLENGTH),
                            get_parameter_value (para, pSUBKEYCURVE),
                            pub_root,
                            get_parameter_uint (para, pSUBKEYLENGTH),
                            get_parameter_value (para, pSUBKEYCURVE),
                            pub_root,
@@ -4096,7 +4748,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
                            s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
                            get_parameter_passphrase (para),
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
                            s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
                            get_parameter_passphrase (para),
-                           &cache_nonce);
+                           &cache_nonce, NULL);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -4105,20 +4757,20 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
               for (node = pub_root; node; node = node->next)
                 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
                   sub_psk = node->pkt->pkt.public_key;
               for (node = pub_root; node; node = node->next)
                 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
                   sub_psk = node->pkt->pkt.public_key;
-              assert (sub_psk);
+              log_assert (sub_psk);
 
               if (s)
 
               if (s)
-                err = card_store_key_with_backup (ctrl, sub_psk, opt.homedir);
+                err = card_store_key_with_backup (ctrl,
+                                                  sub_psk, gnupg_homedir ());
             }
         }
       else
         {
             }
         }
       else
         {
-          err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, &timestamp,
-                              get_parameter_u32 (para, pKEYEXPIRE));
+          err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire);
         }
 
       if (!err)
         }
 
       if (!err)
-        err = write_keybinding (pub_root, pri_psk, sub_psk,
+        err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk,
                                 get_parameter_uint (para, pSUBKEYUSAGE),
                                 timestamp, cache_nonce);
       did_sub = 1;
                                 get_parameter_uint (para, pSUBKEYUSAGE),
                                 timestamp, cache_nonce);
       did_sub = 1;
@@ -4177,16 +4829,24 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
           keyid_from_pk (pk, pk->main_keyid);
           register_trusted_keyid (pk->main_keyid);
 
           keyid_from_pk (pk, pk->main_keyid);
           register_trusted_keyid (pk->main_keyid);
 
-          update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
-                                  | TRUST_ULTIMATE ));
+         update_ownertrust (ctrl, pk,
+                             ((get_ownertrust (ctrl, pk) & ~TRUST_MASK)
+                              | TRUST_ULTIMATE ));
+
+          gen_standard_revoke (ctrl, pk, cache_nonce);
 
 
-          gen_standard_revoke (pk, cache_nonce);
+          /* Get rid of the first empty packet.  */
+          commit_kbnode (&pub_root);
 
           if (!opt.batch)
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
 
           if (!opt.batch)
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
-              list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
+              merge_keys_and_selfsig (ctrl, pub_root);
+
+              list_keyblock_direct (ctrl, pub_root, 0, 1,
+                                    opt.fingerprint || opt.with_fingerprint,
+                                    1);
             }
 
 
             }
 
 
@@ -4225,12 +4885,90 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
 }
 
 
 }
 
 
+static gpg_error_t
+parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
+                         const char *algostr, const char *usagestr,
+                         const char *expirestr,
+                         int *r_algo, unsigned int *r_usage, u32 *r_expire,
+                         unsigned int *r_nbits, char **r_curve)
+{
+  gpg_error_t err;
+  int algo;
+  unsigned int use, nbits;
+  u32 expire;
+  int wantuse;
+  const char *curve = NULL;
+
+  *r_curve = NULL;
+
+  nbits = 0;
+
+  /* Parse the algo string.  */
+  if (algostr && *algostr == '&' && strlen (algostr) == 41)
+    {
+      /* Take algo from existing key.  */
+      algo = check_keygrip (ctrl, algostr+1);
+      /* FIXME: We need the curve name as well.  */
+      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+    }
+
+  err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
+                                    &algo, &nbits, &use, &curve,
+                                    NULL, NULL, NULL, NULL);
+  if (err)
+    return err;
+
+  /* Parse the usage string.  */
+  if (!usagestr || !*usagestr
+      || !strcmp (usagestr, "default") || !strcmp (usagestr, "-"))
+    ; /* Keep usage from parse_key_parameter_string.  */
+  else if ((wantuse = parse_usagestr (usagestr)) != -1)
+    use = wantuse;
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* Make sure a primary key has the CERT usage.  */
+  if (!for_subkey)
+    use |= PUBKEY_USAGE_CERT;
+
+  /* Check that usage is possible.  NB: We have the same check in
+   * parse_key_parameter_string but need it here again in case the
+   * separate usage value has been given. */
+  if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT))
+           && !pubkey_get_nsig (algo))
+       || ((use & PUBKEY_USAGE_ENC)
+           && !pubkey_get_nenc (algo))
+       || (for_subkey && (use & PUBKEY_USAGE_CERT)))
+    return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+
+  /* Parse the expire string.  */
+  expire = parse_expire_string (expirestr);
+  if (expire == (u32)-1 )
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (curve)
+    {
+      *r_curve = xtrystrdup (curve);
+      if (!*r_curve)
+        return gpg_error_from_syserror ();
+    }
+  *r_algo = algo;
+  *r_usage = use;
+  *r_expire = expire;
+  *r_nbits = nbits;
+  return 0;
+}
+
+
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
 /* Add a new subkey to an existing key.  Returns 0 if a new key has
-   been generated and put into the keyblocks.  */
+   been generated and put into the keyblocks.  If any of ALGOSTR,
+   USAGESTR, or EXPIRESTR is NULL interactive mode is used. */
 gpg_error_t
 gpg_error_t
-generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
+generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
+                     const char *usagestr, const char *expirestr)
 {
   gpg_error_t err = 0;
 {
   gpg_error_t err = 0;
+  int interactive;
   kbnode_t node;
   PKT_public_key *pri_psk = NULL;
   PKT_public_key *sub_psk = NULL;
   kbnode_t node;
   PKT_public_key *pri_psk = NULL;
   PKT_public_key *sub_psk = NULL;
@@ -4240,8 +4978,13 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   unsigned int nbits = 0;
   char *curve = NULL;
   u32 cur_time;
   unsigned int nbits = 0;
   char *curve = NULL;
   u32 cur_time;
+  char *key_from_hexgrip = NULL;
   char *hexgrip = NULL;
   char *serialno = NULL;
   char *hexgrip = NULL;
   char *serialno = NULL;
+  char *cache_nonce = NULL;
+  char *passwd_nonce = NULL;
+
+  interactive = (!algostr || !usagestr || !expirestr);
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
 
   /* Break out the primary key.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@@ -4280,42 +5023,92 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   err = hexkeygrip_from_pk (pri_psk, &hexgrip);
   if (err)
     goto leave;
   err = hexkeygrip_from_pk (pri_psk, &hexgrip);
   if (err)
     goto leave;
-  if (agent_get_keyinfo (NULL, hexgrip, &serialno))
+  if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
     {
     {
-      tty_printf (_("Secret parts of primary key are not available.\n"));
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are not available.\n"));
+      else
+        log_info (  _("Secret parts of primary key are not available.\n"));
+      err = gpg_error (GPG_ERR_NO_SECKEY);
       goto leave;
     }
   if (serialno)
       goto leave;
     }
   if (serialno)
-    tty_printf (_("Secret parts of primary key are stored on-card.\n"));
-
-  xfree (hexgrip);
-  hexgrip = NULL;
-  algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
-  assert (algo);
+    {
+      if (interactive)
+        tty_printf (_("Secret parts of primary key are stored on-card.\n"));
+      else
+        log_info (  _("Secret parts of primary key are stored on-card.\n"));
+    }
 
 
-  if (hexgrip)
-    nbits = 0;
-  else if (algo == PUBKEY_ALGO_ECDSA
-           || algo == PUBKEY_ALGO_EDDSA
-           || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo, NULL);
-  else
-    nbits = ask_keysize (algo, 0);
+  if (interactive)
+    {
+      algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip);
+      log_assert (algo);
+
+      if (key_from_hexgrip)
+        nbits = 0;
+      else if (algo == PUBKEY_ALGO_ECDSA
+               || algo == PUBKEY_ALGO_EDDSA
+               || algo == PUBKEY_ALGO_ECDH)
+        curve = ask_curve (&algo, NULL);
+      else
+        nbits = ask_keysize (algo, 0);
 
 
-  expire = ask_expire_interval (0, NULL);
-  if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
-                                               _("Really create? (y/N) ")))
+      expire = ask_expire_interval (0, NULL);
+      if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
+                                                   _("Really create? (y/N) ")))
+        {
+          err = gpg_error (GPG_ERR_CANCELED);
+          goto leave;
+        }
+    }
+  else /* Unattended mode.  */
     {
     {
-      err = gpg_error (GPG_ERR_CANCELED);
-      goto leave;
+      err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
+                                     &algo, &use, &expire, &nbits, &curve);
+      if (err)
+        goto leave;
     }
 
     }
 
-  if (hexgrip)
-    err = do_create_from_keygrip (ctrl, algo, hexgrip,
-                                  keyblock, cur_time, expire, 1);
+  /* Verify the passphrase now so that we get a cache item for the
+   * primary key passphrase.  The agent also returns a passphrase
+   * nonce, which we can use to set the passphrase for the subkey to
+   * that of the primary key.  */
+  {
+    char *desc = gpg_format_keydesc (ctrl, pri_psk, FORMAT_KEYDESC_NORMAL, 1);
+    err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/,
+                        &cache_nonce, &passwd_nonce);
+    xfree (desc);
+    if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED
+        && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
+      err = 0;  /* Very likely that the key is on a card.  */
+    if (err)
+      goto leave;
+  }
+
+  /* Start creation.  */
+  if (key_from_hexgrip)
+    {
+      err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip,
+                                    keyblock, cur_time, expire, 1);
+    }
   else
   else
-    err = do_create (algo, nbits, curve,
-                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
+    {
+      const char *passwd;
+
+      /* If the pinentry loopback mode is not and we have a static
+         passphrase (i.e. set with --passphrase{,-fd,-file} while in batch
+         mode), we use that passphrase for the new subkey.  */
+      if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK
+          && have_static_passphrase ())
+        passwd = get_static_passphrase ();
+      else
+        passwd = NULL;
+
+      err = do_create (algo, nbits, curve,
+                       keyblock, cur_time, expire, 1, 0,
+                       passwd, &cache_nonce, &passwd_nonce);
+    }
   if (err)
     goto leave;
 
   if (err)
     goto leave;
 
@@ -4325,16 +5118,21 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
       sub_psk = node->pkt->pkt.public_key;
 
   /* Write the binding signature.  */
       sub_psk = node->pkt->pkt.public_key;
 
   /* Write the binding signature.  */
-  err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL);
+  err = write_keybinding (ctrl, keyblock, pri_psk, sub_psk, use, cur_time,
+                          cache_nonce);
   if (err)
     goto leave;
 
   if (err)
     goto leave;
 
-  write_status_text (STATUS_KEY_CREATED, "S");
+  print_status_key_created ('S', sub_psk, NULL);
+
 
  leave:
 
  leave:
+  xfree (key_from_hexgrip);
   xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
   xfree (curve);
   xfree (hexgrip);
   xfree (serialno);
+  xfree (cache_nonce);
+  xfree (passwd_nonce);
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   return err;
@@ -4344,19 +5142,30 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
 #ifdef ENABLE_CARD_SUPPORT
 /* Generate a subkey on a card. */
 gpg_error_t
 #ifdef ENABLE_CARD_SUPPORT
 /* Generate a subkey on a card. */
 gpg_error_t
-generate_card_subkeypair (kbnode_t pub_keyblock,
+generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
                           int keyno, const char *serialno)
 {
   gpg_error_t err = 0;
   kbnode_t node;
   PKT_public_key *pri_pk = NULL;
                           int keyno, const char *serialno)
 {
   gpg_error_t err = 0;
   kbnode_t node;
   PKT_public_key *pri_pk = NULL;
-  int algo;
   unsigned int use;
   u32 expire;
   u32 cur_time;
   struct para_data_s *para = NULL;
   unsigned int use;
   u32 expire;
   u32 cur_time;
   struct para_data_s *para = NULL;
+  PKT_public_key *sub_pk = NULL;
+  int algo;
+  struct agent_card_info_s info;
 
 
-  assert (keyno >= 1 && keyno <= 3);
+  log_assert (keyno >= 1 && keyno <= 3);
+
+  memset (&info, 0, sizeof (info));
+  err = agent_scd_getattr ("KEY-ATTR", &info);
+  if (err)
+    {
+      log_error (_("error getting current key info: %s\n"), gpg_strerror (err));
+      return err;
+    }
+  algo = info.key_attr[keyno-1].algo;
 
   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
   if (!para)
 
   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
   if (!para)
@@ -4371,7 +5180,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
   node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
-      log_error ("Oops; publkic key lost!\n");
+      log_error ("Oops; public key lost!\n");
       err = gpg_error (GPG_ERR_INTERNAL);
       goto leave;
     }
       err = gpg_error (GPG_ERR_INTERNAL);
       goto leave;
     }
@@ -4400,7 +5209,6 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
       goto leave;
     }
 
       goto leave;
     }
 
-  algo = PUBKEY_ALGO_RSA;
   expire = ask_expire_interval (0, NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
   expire = ask_expire_interval (0, NULL);
   if (keyno == 1)
     use = PUBKEY_USAGE_SIG;
@@ -4417,17 +5225,15 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
 
   /* Note, that depending on the backend, the card key generation may
      update CUR_TIME.  */
 
   /* Note, that depending on the backend, the card key generation may
      update CUR_TIME.  */
-  err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire);
+  err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire);
   /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
   /* Get the pointer to the generated public subkey packet.  */
   if (!err)
     {
-      PKT_public_key *sub_pk = NULL;
-
       for (node = pub_keyblock; node; node = node->next)
         if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
           sub_pk = node->pkt->pkt.public_key;
       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,
+      log_assert (sub_pk);
+      err = write_keybinding (ctrl, pub_keyblock, pri_pk, sub_pk,
                               use, cur_time, NULL);
     }
 
                               use, cur_time, NULL);
     }
 
@@ -4435,7 +5241,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   else
   if (err)
     log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
   else
-    write_status_text (STATUS_KEY_CREATED, "S");
+    print_status_key_created ('S', sub_pk, NULL);
   release_parameter_list (para);
   return err;
 }
   release_parameter_list (para);
   return err;
 }
@@ -4467,17 +5273,18 @@ write_keyblock( IOBUF out, KBNODE node )
 
 /* Note that timestamp is an in/out arg. */
 static gpg_error_t
 
 /* Note that timestamp is an in/out arg. */
 static gpg_error_t
-gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
+gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
               u32 *timestamp, u32 expireval)
 {
 #ifdef ENABLE_CARD_SUPPORT
   gpg_error_t err;
               u32 *timestamp, u32 expireval)
 {
 #ifdef ENABLE_CARD_SUPPORT
   gpg_error_t err;
-  struct agent_card_genkey_s info;
   PACKET *pkt;
   PKT_public_key *pk;
   PACKET *pkt;
   PKT_public_key *pk;
+  char keyid[10];
+  unsigned char *public;
+  gcry_sexp_t s_key;
 
 
-  if (algo != PUBKEY_ALGO_RSA)
-    return gpg_error (GPG_ERR_PUBKEY_ALGO);
+  snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno);
 
   pk = xtrycalloc (1, sizeof *pk );
   if (!pk)
 
   pk = xtrycalloc (1, sizeof *pk );
   if (!pk)
@@ -4490,7 +5297,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
     }
 
   /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
     }
 
   /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
-  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
+  err = agent_scd_genkey (keyno, 1, timestamp);
   /*  The code below is not used because we force creation of
    *  the a card key (3rd arg).
    * if (gpg_err_code (rc) == GPG_ERR_EEXIST)
   /*  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)
@@ -4500,16 +5307,9 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
    *     tty_printf ("\n");
    *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
    *                                 _("Replace existing key? ")))
    *     tty_printf ("\n");
    *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
    *                                 _("Replace existing key? ")))
-   *       rc = agent_scd_genkey (&info, keyno, 1);
+   *       rc = agent_scd_genkey (keyno, 1, timestamp);
    *   }
   */
    *   }
   */
-  if (!err && (!info.n || !info.e))
-    {
-      log_error ("communication error with SCD\n");
-      gcry_mpi_release (info.n);
-      gcry_mpi_release (info.e);
-      err =  gpg_error (GPG_ERR_GENERAL);
-    }
   if (err)
     {
       log_error ("key generation failed: %s\n", gpg_strerror (err));
   if (err)
     {
       log_error ("key generation failed: %s\n", gpg_strerror (err));
@@ -4518,30 +5318,40 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
       return err;
     }
 
       return err;
     }
 
-  /* Send the learn command so that the agent creates a shadow key for
+  /* Send the READKEY command so that the agent creates a shadow key for
      card key.  We need to do that now so that we are able to create
      the self-signatures. */
      card key.  We need to do that now so that we are able to create
      the self-signatures. */
-  err = agent_scd_learn (NULL, 0);
+  err = agent_readkey (NULL, 1, keyid, &public);
+  if (err)
+    return err;
+  err = gcry_sexp_sscan (&s_key, NULL, public,
+                         gcry_sexp_canon_len (public, 0, NULL, NULL));
+  xfree (public);
+  if (err)
+    return err;
+
+  if (algo == PUBKEY_ALGO_RSA)
+    err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
+  else if (algo == PUBKEY_ALGO_ECDSA
+           || algo == PUBKEY_ALGO_EDDSA
+           || algo == PUBKEY_ALGO_ECDH )
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+  gcry_sexp_release (s_key);
+
   if (err)
     {
   if (err)
     {
-      /* Oops: Card removed during generation.  */
-      log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
-      xfree (pkt);
-      xfree (pk);
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      free_public_key (pk);
       return err;
     }
 
       return err;
     }
 
-  if (*timestamp != info.created_at)
-    log_info ("NOTE: the key does not use the suggested creation date\n");
-  *timestamp = info.created_at;
-
-  pk->timestamp = info.created_at;
+  pk->timestamp = *timestamp;
   pk->version = 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
   pk->version = 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
-  pk->pkey[0] = info.n;
-  pk->pkey[1] = info.e;
 
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
 
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
@@ -4549,7 +5359,6 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
 
   return 0;
 #else
 
   return 0;
 #else
-  (void)algo;
   (void)keyno;
   (void)is_primary;
   (void)pub_root;
   (void)keyno;
   (void)is_primary;
   (void)pub_root;