gpg: Align notes about minimal keysize with actual checks.
[gnupg.git] / g10 / keygen.c
index 6143269..921e938 100644 (file)
@@ -1,4 +1,4 @@
-/* keygen.c - generate a key pair
+/* keygen.c - Generate a key pair
  * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
  * Copyright (C) 2014, 2015  Werner Koch
  *
@@ -43,6 +43,9 @@
 #include "call-agent.h"
 #include "pkglue.h"
 #include "../common/shareddefs.h"
+#include "host2net.h"
+#include "mbox-util.h"
+
 
 /* The default algorithms.  If you change them remember to change them
    also in gpg.c:gpgconf_list.  You should also check that the value
@@ -132,15 +135,12 @@ static byte zip_prefs[MAX_PREFS];
 static int nzip_prefs;
 static int mdc_available,ks_modify;
 
-static void do_generate_keypair( struct para_data_s *para,
+static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                                 struct output_control_s *outctrl, int card );
 static int write_keyblock (iobuf_t out, kbnode_t node);
 static gpg_error_t gen_card_key (int algo, int keyno, int is_primary,
                                  kbnode_t pub_root,
                                  u32 *timestamp, u32 expireval);
-static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
-                                     kbnode_t pub_root, u32 timestamp,
-                                     u32 expireval, struct para_data_s *para);
 
 
 static void
@@ -845,10 +845,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
                }
              else if (buf[1] == 255)
                {
-                 pktlen  = buf[2] << 24;
-                 pktlen |= buf[3] << 16;
-                 pktlen |= buf[4] << 8;
-                 pktlen |= buf[5];
+                  pktlen = buf32_to_size_t (buf+2);
                  buf += 6;
                }
              else
@@ -865,7 +862,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
                  break;
 
                case 2:
-                 pktlen  = buf[mark++] << 24;
+                 pktlen  = (size_t)buf[mark++] << 24;
                  pktlen |= buf[mark++] << 16;
 
                case 1:
@@ -1284,7 +1281,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 }
 
 
-/* Common code for the key generation fucntion gen_xxx.  */
+/* Common code for the key generation function gen_xxx.  */
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
@@ -1520,6 +1517,13 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
        (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
          && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
         " transient-key" : ""));
+  else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519"))
+    keyparms = xtryasprintf
+      ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
+       strlen (curve), curve,
+       (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+         && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+        " transient-key" : ""));
   else
     keyparms = xtryasprintf
       ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
@@ -1820,7 +1824,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           char **r_keygrip)
 {
   char *keygrip = NULL;
-  char *answer;
+  char *answer = NULL;
   int algo;
   int dummy_algo;
 
@@ -1875,84 +1879,86 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
     {
       *r_usage = 0;
       *r_subkey_algo = 0;
+      xfree (answer);
       answer = cpr_get ("keygen.algo", _("Your selection? "));
       cpr_kill_prompt ();
       algo = *answer? atoi (answer) : 1;
-      xfree(answer);
-      answer = NULL;
-      if (algo == 1 && !addmode)
+      if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_subkey_algo = PUBKEY_ALGO_RSA;
           break;
        }
-      else if (algo == 2 && !addmode)
+      else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode)
         {
           algo = PUBKEY_ALGO_DSA;
           *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E;
           break;
        }
-      else if (algo == 3)
+      else if (algo == 3 || !strcmp (answer, "dsa"))
         {
           algo = PUBKEY_ALGO_DSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 4)
+      else if (algo == 4 || !strcmp (answer, "rsa/s"))
         {
           algo = PUBKEY_ALGO_RSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 5 && addmode)
+      else if ((algo == 5 || !strcmp (answer, "elg")) && addmode)
         {
           algo = PUBKEY_ALGO_ELGAMAL_E;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 6 && addmode)
+      else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 7 && opt.expert)
+      else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_DSA;
           *r_usage = ask_key_flags (algo, addmode);
           break;
        }
-      else if (algo == 8 && opt.expert)
+      else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_RSA;
           *r_usage = ask_key_flags (algo, addmode);
           break;
        }
-      else if (algo == 9 && opt.expert && !addmode)
+      else if ((algo == 9 || !strcmp (answer, "ecc+ecc"))
+               && opt.expert && !addmode)
         {
           algo = PUBKEY_ALGO_ECDSA;
           *r_subkey_algo = PUBKEY_ALGO_ECDH;
           break;
        }
-      else if (algo == 10 && opt.expert)
+      else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
           *r_usage = PUBKEY_USAGE_SIG;
           break;
        }
-      else if (algo == 11 && opt.expert)
+      else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
           *r_usage = ask_key_flags (algo, addmode);
           break;
        }
-      else if (algo == 12 && opt.expert && addmode)
+      else if ((algo == 12 || !strcmp (answer, "ecc/e"))
+               && opt.expert && addmode)
         {
           algo = PUBKEY_ALGO_ECDH;
           *r_usage = PUBKEY_USAGE_ENC;
           break;
        }
-      else if (algo == 13 && opt.expert && r_keygrip)
+      else if ((algo == 13 || !strcmp (answer, "keygrip"))
+               && opt.expert && r_keygrip)
         {
           for (;;)
             {
@@ -1984,8 +1990,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
        }
       else
         tty_printf (_("Invalid selection.\n"));
+
     }
 
+  xfree(answer);
   if (r_keygrip)
     *r_keygrip = keygrip;
   return algo;
@@ -1998,15 +2006,13 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
 static unsigned
 ask_keysize (int algo, unsigned int primary_keysize)
 {
-  unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096;
+  unsigned int nbits;
+  unsigned int min = 1024;
+  unsigned int def = DEFAULT_STD_KEYSIZE;
+  unsigned int max = 4096;
   int for_subkey = !!primary_keysize;
   int autocomp = 0;
 
-  if(opt.expert)
-    min=512;
-  else
-    min=1024;
-
   if (primary_keysize && !opt.expert)
     {
       /* Deduce the subkey size from the primary key size.  */
@@ -2021,9 +2027,11 @@ ask_keysize (int algo, unsigned int primary_keysize)
       goto leave;
     }
 
+  /* Deviations from the standard values.  */
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
+      min = opt.expert? 768 : 1024;
       def=2048;
       max=3072;
       break;
@@ -2040,10 +2048,6 @@ ask_keysize (int algo, unsigned int primary_keysize)
       def=255;
       max=441;
       break;
-
-    case PUBKEY_ALGO_RSA:
-      min=1024;
-      break;
     }
 
   tty_printf(_("%s keys may be between %u and %u bits long.\n"),
@@ -2121,7 +2125,7 @@ ask_keysize (int algo, unsigned int primary_keysize)
    function may adjust.  Returns a malloced string with the name of
    the curve.  BOTH tells that gpg creates a primary and subkey. */
 static char *
-ask_curve (int *algo, int both)
+ask_curve (int *algo, int *subkey_algo)
 {
   struct {
     const char *name;
@@ -2172,7 +2176,7 @@ ask_curve (int *algo, int both)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
-      if (both && curves[idx].fix_curve)
+      if (subkey_algo && curves[idx].fix_curve)
         {
           /* Both Curve 25519 keys are to be created.  Check that
              Libgcrypt also supports the real Curve25519.  */
@@ -2237,6 +2241,11 @@ ask_curve (int *algo, int both)
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
               && curves[idx].fix_curve)
             {
+              if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
+                {
+                  *subkey_algo = PUBKEY_ALGO_EDDSA;
+                  result = xstrdup ("Ed25519");
+                }
               *algo = PUBKEY_ALGO_EDDSA;
               result = xstrdup ("Ed25519");
             }
@@ -2442,6 +2451,24 @@ uid_from_string (const char *string)
 }
 
 
+/* Return true if the user id UID already exists in the keyblock.  */
+static int
+uid_already_in_keyblock (kbnode_t keyblock, const char *uid)
+{
+  PKT_user_id *uidpkt = uid_from_string (uid);
+  kbnode_t node;
+  int result = 0;
+
+  for (node=keyblock; node && !result; node=node->next)
+    if (!is_deleted_kbnode (node)
+        && node->pkt->pkttype == PKT_USER_ID
+        && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id))
+      result = 1;
+  free_user_id (uidpkt);
+  return result;
+}
+
+
 /* Ask for a user ID.  With a MODE of 1 an extra help prompt is
    printed for use during a new key creation.  If KEYBLOCK is not NULL
    the function prevents the creation of an already existing user
@@ -2502,7 +2529,11 @@ ask_user_id (int mode, int full, KBNODE keyblock)
                    break;
 
                if( strpbrk( aname, "<>" ) )
+                  {
                    tty_printf(_("Invalid character in name\n"));
+                   tty_printf(_("The characters '%s' and '%s' may not "
+                                 "appear in name\n"), "<", ">");
+                  }
                else if( digitp(aname) )
                    tty_printf(_("Name may not start with a digit\n"));
                else if( strlen(aname) < 5 )
@@ -2579,17 +2610,11 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 
         if (!fail && keyblock)
           {
-            PKT_user_id *uidpkt = uid_from_string (uid);
-            KBNODE node;
-
-            for (node=keyblock; node && !fail; node=node->next)
-              if (!is_deleted_kbnode (node)
-                  && node->pkt->pkttype == PKT_USER_ID
-                  && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id))
-               fail = 1;
-            if (fail)
-              tty_printf (_("Such a user ID already exists on this key!\n"));
-            free_user_id (uidpkt);
+            if (uid_already_in_keyblock (keyblock, uid))
+              {
+                tty_printf (_("Such a user ID already exists on this key!\n"));
+                fail = 1;
+              }
           }
 
        for(;;) {
@@ -2672,56 +2697,6 @@ ask_user_id (int mode, int full, KBNODE keyblock)
 }
 
 
-/*  MODE  0 - standard
-          1 - Ask for passphrase of the card backup key.  */
-#if 0
-static DEK *
-do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
-{
-    DEK *dek = NULL;
-    STRING2KEY *s2k;
-    const char *errtext = NULL;
-    const char *custdesc = NULL;
-
-    tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
-
-    if (mode == 1)
-      custdesc = _("Please enter a passphrase to protect the off-card "
-                   "backup of the new encryption key.");
-
-    s2k = xmalloc_secure( sizeof *s2k );
-    for(;;) {
-       s2k->mode = opt.s2k_mode;
-       s2k->hash_algo = S2K_DIGEST_ALGO;
-       dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2,
-                                     errtext, custdesc, NULL, r_canceled);
-        if (!dek && *r_canceled) {
-           xfree(dek); dek = NULL;
-           xfree(s2k); s2k = NULL;
-            break;
-        }
-       else if( !dek ) {
-           errtext = N_("passphrase not correctly repeated; try again");
-           tty_printf(_("%s.\n"), _(errtext));
-       }
-       else if( !dek->keylen ) {
-           xfree(dek); dek = NULL;
-           xfree(s2k); s2k = NULL;
-           tty_printf(_(
-           "You don't want a passphrase - this is probably a *bad* idea!\n"
-           "I will do it anyway.  You can change your passphrase at any time,\n"
-           "using this program with the option \"--edit-key\".\n\n"));
-           break;
-       }
-       else
-           break; /* okay */
-    }
-    *ret_s2k = s2k;
-    return dek;
-}
-#endif /* 0 */
-
-
 /* Basic key generation.  Here we divert to the actual generation
    routines based on the requested algorithm.  */
 static int
@@ -2763,16 +2738,32 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
 /* Generate a new user id packet or return NULL if canceled.  If
    KEYBLOCK is not NULL the function prevents the creation of an
-   already existing user ID.  */
+   already existing user ID.  If UIDSTR is not NULL the user is not
+   asked but UIDSTR is used to create the user id packet; if the user
+   id already exists NULL is returned.  UIDSTR is expected to be utf-8
+   encoded and should have already been checked for a valid length
+   etc.  */
 PKT_user_id *
-generate_user_id (KBNODE keyblock)
+generate_user_id (KBNODE keyblock, const char *uidstr)
 {
+  PKT_user_id *uid;
   char *p;
 
-  p = ask_user_id (1, 1, keyblock);
-  if (!p)
-    return NULL;  /* Canceled. */
-  return uid_from_string (p);
+  if (uidstr)
+    {
+      if (uid_already_in_keyblock (keyblock, uidstr))
+        return NULL;  /* Already exists.  */
+      uid = uid_from_string (uidstr);
+    }
+  else
+    {
+      p = ask_user_id (1, 1, keyblock);
+      if (!p)
+        return NULL;  /* Canceled. */
+      uid = uid_from_string (p);
+      xfree (p);
+    }
+  return uid;
 }
 
 
@@ -2826,7 +2817,7 @@ static const char *
 get_parameter_passphrase (struct para_data_s *para)
 {
   struct para_data_s *r = get_parameter (para, pPASSPHRASE);
-  return r->u.value;
+  return r ? r->u.value : NULL;
 }
 
 
@@ -2992,7 +2983,7 @@ get_parameter_revkey( struct para_data_s *para, enum para_name key )
 }
 
 static int
-proc_parameter_file( struct para_data_s *para, const char *fname,
+proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
                      struct output_control_s *outctrl, int card )
 {
   struct para_data_s *r;
@@ -3178,7 +3169,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       append_to_parameter (para, r);
     }
 
-  do_generate_keypair( para, outctrl, card );
+  do_generate_keypair (ctrl, para, outctrl, card );
   return 0;
 }
 
@@ -3189,7 +3180,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
  * Note, that string parameters are expected to be in UTF-8
  */
 static void
-read_parameter_file( const char *fname )
+read_parameter_file (ctrl_t ctrl, const char *fname )
 {
     static struct { const char *name;
                    enum para_name key;
@@ -3284,7 +3275,7 @@ read_parameter_file( const char *fname )
                 outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY;
            else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
                outctrl.lnr = lnr;
-               if (proc_parameter_file( para, fname, &outctrl, 0 ))
+               if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
                   print_status_key_not_created
                     (get_parameter_value (para, pHANDLE));
                release_parameter_list( para );
@@ -3340,7 +3331,7 @@ read_parameter_file( const char *fname )
 
        if( keywords[i].key == pKEYTYPE && para ) {
            outctrl.lnr = lnr;
-           if (proc_parameter_file( para, fname, &outctrl, 0 ))
+           if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
               print_status_key_not_created
                 (get_parameter_value (para, pHANDLE));
            release_parameter_list( para );
@@ -3370,7 +3361,7 @@ read_parameter_file( const char *fname )
     }
     else if( para ) {
        outctrl.lnr = lnr;
-       if (proc_parameter_file( para, fname, &outctrl, 0 ))
+       if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 ))
           print_status_key_not_created (get_parameter_value (para, pHANDLE));
     }
 
@@ -3435,7 +3426,7 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
  * Unattended generation of a standard key.
  */
 void
-quick_generate_keypair (const char *uid)
+quick_generate_keypair (ctrl_t ctrl, const char *uid)
 {
   gpg_error_t err;
   struct para_data_s *para = NULL;
@@ -3485,6 +3476,9 @@ quick_generate_keypair (const char *uid)
     desc.u.name = uid;
 
     kdbhd = keydb_new ();
+    if (!kdbhd)
+      goto leave;
+
     err = keydb_search (kdbhd, &desc, 1, NULL);
     keydb_release (kdbhd);
     if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
@@ -3525,7 +3519,7 @@ quick_generate_keypair (const char *uid)
       para = r;
     }
 
-  proc_parameter_file (para, "[internal]", &outctrl, 0);
+  proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
  leave:
   release_parameter_list (para);
 }
@@ -3569,7 +3563,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
 
   if (opt.batch)
     {
-      read_parameter_file( fname );
+      read_parameter_file (ctrl, fname);
       return;
     }
 
@@ -3640,7 +3634,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo, both);
+              curve = ask_curve (&algo, &subkey_algo);
               r = xmalloc_clear( sizeof *r + 20 );
               r->key = pKEYTYPE;
               sprintf( r->u.value, "%d", algo);
@@ -3711,7 +3705,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
               || algo == PUBKEY_ALGO_EDDSA
               || algo == PUBKEY_ALGO_ECDH)
             {
-              curve = ask_curve (&algo, 0);
+              curve = ask_curve (&algo, NULL);
               nbits = 0;
               r = xmalloc_clear (sizeof *r + strlen (curve));
               r->key = pKEYCURVE;
@@ -3797,124 +3791,171 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
   r->next = para;
   para = r;
 
-  proc_parameter_file (para, "[internal]", &outctrl, !!card_serialno);
+  proc_parameter_file (ctrl, para, "[internal]", &outctrl, !!card_serialno);
   release_parameter_list (para);
 }
 
 
-#if 0 /* not required */
-/* Generate a raw key and return it as a secret key packet.  The
-   function will ask for the passphrase and return a protected as well
-   as an unprotected copy of a new secret key packet.  0 is returned
-   on success and the caller must then free the returned values.  */
-static int
-generate_raw_key (int algo, unsigned int nbits, u32 created_at,
-                  PKT_secret_key **r_sk_unprotected,
-                  PKT_secret_key **r_sk_protected)
+/* Create and delete a dummy packet to start off a list of kbnodes. */
+static void
+start_tree(KBNODE *tree)
 {
-  int rc;
-  DEK *dek = NULL;
-  STRING2KEY *s2k = NULL;
-  PKT_secret_key *sk = NULL;
-  int i;
-  size_t nskey, npkey;
-  gcry_sexp_t s_parms, s_key;
-  int canceled;
+  PACKET *pkt;
 
-  npkey = pubkey_get_npkey (algo);
-  nskey = pubkey_get_nskey (algo);
-  assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey);
+  pkt=xmalloc_clear(sizeof(*pkt));
+  pkt->pkttype=PKT_NONE;
+  *tree=new_kbnode(pkt);
+  delete_kbnode(*tree);
+}
 
-  if (nbits < 512)
-    {
-      nbits = 512;
-      log_info (_("keysize invalid; using %u bits\n"), nbits );
-    }
 
-  if ((nbits % 32))
+/* Write the *protected* secret key to the file.  */
+static gpg_error_t
+card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
+{
+  gpg_error_t err = 0;
+  int rc;
+  char 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]);
+
+  fname = make_filename (backup_dir, name_buffer, NULL);
+  /* Note that the umask call is not anymore needed because
+     iobuf_create now takes care of it.  However, it does not harm
+     and thus we keep it.  */
+  oldmask = umask (077);
+  if (is_secured_filename (fname))
     {
-      nbits = ((nbits + 31) / 32) * 32;
-      log_info(_("keysize rounded up to %u bits\n"), nbits );
+      fp = NULL;
+      gpg_err_set_errno (EPERM);
     }
-
-  dek = do_ask_passphrase (&s2k, 1, &canceled);
-  if (canceled)
+  else
+    fp = iobuf_create (fname, 1);
+  umask (oldmask);
+  if (!fp)
     {
-      rc = gpg_error (GPG_ERR_CANCELED);
+      err = gpg_error_from_syserror ();
+      log_error (_("can't create backup file '%s': %s\n"), fname, strerror (errno) );
       goto leave;
     }
 
-  sk = xmalloc_clear (sizeof *sk);
-  sk->timestamp = created_at;
-  sk->version = 4;
-  sk->pubkey_algo = algo;
+  pkt = xcalloc (1, sizeof *pkt);
+  pkt->pkttype = PKT_SECRET_KEY;
+  pkt->pkt.secret_key = sk;
 
-  if ( !is_RSA (algo) )
+  rc = build_packet (fp, pkt);
+  if (rc)
     {
-      log_error ("only RSA is supported for offline generated keys\n");
-      rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-      goto leave;
+      log_error ("build packet failed: %s\n", gpg_strerror (rc));
+      iobuf_cancel (fp);
+    }
+  else
+    {
+      char *fprbuf;
+
+      iobuf_close (fp);
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+      log_info (_("Note: backup of card key saved to '%s'\n"), fname);
+
+      fprbuf = hexfingerprint (sk, NULL, 0);
+      write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf,
+                                    fname, strlen (fname), 0);
+      xfree (fprbuf);
     }
-  rc = gcry_sexp_build (&s_parms, NULL,
-                        "(genkey(rsa(nbits %d)))",
-                        (int)nbits);
+
+ leave:
+  xfree (pkt);
+  xfree (fname);
+  return err;
+}
+
+
+/* Store key to card and make a backup file in OpenPGP format.  */
+static gpg_error_t
+card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
+                            const char *backup_dir)
+{
+  PKT_public_key *sk;
+  gnupg_isotime_t timestamp;
+  gpg_error_t err;
+  char *hexgrip;
+  int rc;
+  struct agent_card_info_s info;
+  gcry_cipher_hd_t cipherhd = NULL;
+  char *cache_nonce = NULL;
+  void *kek = NULL;
+  size_t keklen;
+
+  sk = copy_public_key (NULL, sub_psk);
+  if (!sk)
+    return gpg_error_from_syserror ();
+
+  epoch2isotime (timestamp, (time_t)sk->timestamp);
+  err = hexkeygrip_from_pk (sk, &hexgrip);
+  if (err)
+    return err;
+
+  memset(&info, 0, sizeof (info));
+  rc = agent_scd_getattr ("SERIALNO", &info);
   if (rc)
-    log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc));
-  rc = gcry_pk_genkey (&s_key, s_parms);
-  gcry_sexp_release (s_parms);
+    return (gpg_error_t)rc;
+
+  rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp);
+  xfree (info.serialno);
   if (rc)
     {
-      log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) );
+      err = (gpg_error_t)rc;
       goto leave;
     }
-  rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu");
-  gcry_sexp_release (s_key);
-  if (rc)
+
+  err = agent_keywrap_key (ctrl, 1, &kek, &keklen);
+  if (err)
     {
-      log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) );
+      log_error ("error getting the KEK: %s\n", gpg_strerror (err));
       goto leave;
     }
 
-  for (i=npkey; i < nskey; i++)
-    sk->csum += checksum_mpi (sk->skey[i]);
-
-  if (r_sk_unprotected)
-    *r_sk_unprotected = copy_secret_key (NULL, sk);
-
-  rc = genhelp_protect (dek, s2k, sk);
-  if (rc)
-    goto leave;
-
-  if (r_sk_protected)
+  err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0);
+  if (!err)
+    err = gcry_cipher_setkey (cipherhd, kek, keklen);
+  if (err)
     {
-      *r_sk_protected = sk;
-      sk = NULL;
+      log_error ("error setting up an encryption context: %s\n", gpg_strerror (err));
+      goto leave;
     }
 
- leave:
-  if (sk)
-    free_secret_key (sk);
-  xfree (dek);
-  xfree (s2k);
-  return rc;
-}
-#endif /* ENABLE_CARD_SUPPORT */
+  err = receive_seckey_from_agent (ctrl, cipherhd, &cache_nonce, hexgrip, sk);
+  if (err)
+    {
+      log_error ("error getting secret key from agent: %s\n", gpg_strerror (err));
+      goto leave;
+    }
 
-/* Create and delete a dummy packet to start off a list of kbnodes. */
-static void
-start_tree(KBNODE *tree)
-{
-  PACKET *pkt;
+  err = card_write_key_to_backup_file (sk, backup_dir);
+  if (err)
+    log_error ("writing card key to backup file: %s\n", gpg_strerror (err));
+  else
+    /* Remove secret key data in agent side.  */
+    agent_scd_learn (NULL, 1);
 
-  pkt=xmalloc_clear(sizeof(*pkt));
-  pkt->pkttype=PKT_NONE;
-  *tree=new_kbnode(pkt);
-  delete_kbnode(*tree);
+ leave:
+  xfree (cache_nonce);
+  gcry_cipher_close (cipherhd);
+  xfree (kek);
+  xfree (hexgrip);
+  free_public_key (sk);
+  return err;
 }
 
 
 static void
-do_generate_keypair (struct para_data_s *para,
+do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
                     struct output_control_s *outctrl, int card)
 {
   gpg_error_t err;
@@ -4044,7 +4085,8 @@ do_generate_keypair (struct para_data_s *para,
   if (!err && get_parameter (para, pSUBKEYTYPE))
     {
       sub_psk = NULL;
-      if (!card)
+      s = NULL;
+      if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
         {
           err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL),
                            get_parameter_uint (para, pSUBKEYLENGTH),
@@ -4052,7 +4094,7 @@ do_generate_keypair (struct para_data_s *para,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           outctrl->keygen_flags,
+                           s ? KEYGEN_FLAG_NO_PROTECTION : outctrl->keygen_flags,
                            get_parameter_passphrase (para),
                            &cache_nonce);
           /* Get the pointer to the generated public subkey packet.  */
@@ -4064,25 +4106,15 @@ do_generate_keypair (struct para_data_s *para,
                 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
                   sub_psk = node->pkt->pkt.public_key;
               assert (sub_psk);
+
+              if (s)
+                err = card_store_key_with_backup (ctrl, sub_psk, opt.homedir);
             }
         }
       else
         {
-          if ((s = get_parameter_value (para, pCARDBACKUPKEY)))
-            {
-              /* A backup of the encryption key has been requested.
-                 Generate the key in software and import it then to
-                 the card.  Write a backup file. */
-              err = gen_card_key_with_backup
-                (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp,
-                 get_parameter_u32 (para, pKEYEXPIRE), para);
-            }
-          else
-            {
-              err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root,
-                                  &timestamp,
-                                  get_parameter_u32 (para, pKEYEXPIRE));
-            }
+          err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, &timestamp,
+                              get_parameter_u32 (para, pKEYEXPIRE));
         }
 
       if (!err)
@@ -4100,12 +4132,18 @@ do_generate_keypair (struct para_data_s *para,
     }
   else if (!err) /* Write to the standard keyrings.  */
     {
-      KEYDB_HANDLE pub_hd = keydb_new ();
+      KEYDB_HANDLE pub_hd;
 
-      err = keydb_locate_writable (pub_hd, NULL);
-      if (err)
-        log_error (_("no writable public keyring found: %s\n"),
-                   gpg_strerror (err));
+      pub_hd = keydb_new ();
+      if (!pub_hd)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          err = keydb_locate_writable (pub_hd);
+          if (err)
+            log_error (_("no writable public keyring found: %s\n"),
+                       gpg_strerror (err));
+        }
 
       if (!err && opt.verbose)
         {
@@ -4148,7 +4186,7 @@ do_generate_keypair (struct para_data_s *para,
             {
               tty_printf (_("public and secret key created and signed.\n") );
               tty_printf ("\n");
-              list_keyblock (pub_root, 0, 1, 1, NULL);
+              list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
             }
 
 
@@ -4260,7 +4298,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
-    curve = ask_curve (&algo, 0);
+    curve = ask_curve (&algo, NULL);
   else
     nbits = ask_keysize (algo, 0);
 
@@ -4483,7 +4521,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
   /* Send the learn command so that the agent creates a shadow key for
      card key.  We need to do that now so that we are able to create
      the self-signatures. */
-  err = agent_scd_learn (NULL);
+  err = agent_scd_learn (NULL, 0);
   if (err)
     {
       /* Oops: Card removed during generation.  */
@@ -4520,259 +4558,3 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
   return gpg_error (GPG_ERR_NOT_SUPPORTED);
 #endif /*!ENABLE_CARD_SUPPORT*/
 }
-
-
-
-static int
-gen_card_key_with_backup (int algo, int keyno, int is_primary,
-                          KBNODE pub_root, u32 timestamp,
-                          u32 expireval, struct para_data_s *para)
-{
-#if ENABLE_CARD_SUPPORT && 0
-  /* FIXME: Move this to gpg-agent.  */
-  int rc;
-  const char *s;
-  PACKET *pkt;
-  PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL;
-  PKT_public_key *pk;
-  size_t n;
-  int i;
-  unsigned int nbits;
-
-  /* Get the size of the key directly from the card.  */
-  {
-    struct agent_card_info_s info;
-
-    memset (&info, 0, sizeof info);
-    if (!agent_scd_getattr ("KEY-ATTR", &info)
-        && info.key_attr[1].algo)
-      nbits = info.key_attr[1].nbits;
-    else
-      nbits = 1024; /* All pre-v2.0 cards.  */
-    agent_release_card_info (&info);
-  }
-
-  /* Create a key of this size in memory.  */
-  rc = generate_raw_key (algo, nbits, timestamp,
-                         &sk_unprotected, &sk_protected);
-  if (rc)
-    return rc;
-
-  /* Store the key to the card. */
-  rc = save_unprotected_key_to_card (sk_unprotected, keyno);
-  if (rc)
-    {
-      log_error (_("storing key onto card failed: %s\n"), gpg_strerror (rc));
-      free_secret_key (sk_unprotected);
-      free_secret_key (sk_protected);
-      write_status_errcode ("save_key_to_card", rc);
-      return rc;
-    }
-
-  /* Get rid of the secret key parameters and store the serial numer. */
-  sk = sk_unprotected;
-  n = pubkey_get_nskey (sk->pubkey_algo);
-  for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
-    {
-      gcry_mpi_release (sk->skey[i]);
-      sk->skey[i] = NULL;
-    }
-  i = pubkey_get_npkey (sk->pubkey_algo);
-  sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
-  sk->is_protected = 1;
-  sk->protect.s2k.mode = 1002;
-  s = get_parameter_value (para, pSERIALNO);
-  assert (s);
-  for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
-       sk->protect.ivlen++, s += 2)
-    sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
-
-  /* Now write the *protected* secret key to the file.  */
-  {
-    char name_buffer[50];
-    char *fname;
-    IOBUF fp;
-    mode_t oldmask;
-
-    keyid_from_sk (sk, NULL);
-    snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg",
-              (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
-
-    fname = make_filename (backup_dir, name_buffer, NULL);
-    /* Note that the umask call is not anymore needed because
-       iobuf_create now takes care of it.  However, it does not harm
-       and thus we keep it.  */
-    oldmask = umask (077);
-    if (is_secured_filename (fname))
-      {
-        fp = NULL;
-        gpg_err_set_errno (EPERM);
-      }
-    else
-      fp = iobuf_create (fname, 1);
-    umask (oldmask);
-    if (!fp)
-      {
-        rc = gpg_error_from_syserror ();
-       log_error (_("can't create backup file '%s': %s\n"),
-                   fname, strerror(errno) );
-        xfree (fname);
-        free_secret_key (sk_unprotected);
-        free_secret_key (sk_protected);
-        return rc;
-      }
-
-    pkt = xcalloc (1, sizeof *pkt);
-    pkt->pkttype = PKT_SECRET_KEY;
-    pkt->pkt.secret_key = sk_protected;
-    sk_protected = NULL;
-
-    rc = build_packet (fp, pkt);
-    if (rc)
-      {
-        log_error("build packet failed: %s\n", gpg_strerror (rc));
-        iobuf_cancel (fp);
-      }
-    else
-      {
-        unsigned char array[MAX_FINGERPRINT_LEN];
-        char *fprbuf, *p;
-
-        iobuf_close (fp);
-        iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
-        log_info (_("Note: backup of card key saved to '%s'\n"), fname);
-
-        fingerprint_from_sk (sk, array, &n);
-        p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);
-        for (i=0; i < n ; i++, p += 2)
-          sprintf (p, "%02X", array[i]);
-        *p++ = ' ';
-        *p = 0;
-
-        write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED,
-                                      fprbuf,
-                                      fname, strlen (fname),
-                                      0);
-        xfree (fprbuf);
-      }
-    free_packet (pkt);
-    xfree (pkt);
-    xfree (fname);
-    if (rc)
-      {
-        free_secret_key (sk_unprotected);
-        return rc;
-      }
-  }
-
-  /* Create the public key from the secret key. */
-  pk = xcalloc (1, sizeof *pk );
-  pk->timestamp = sk->timestamp;
-  pk->version = sk->version;
-  if (expireval)
-      pk->expiredate = sk->expiredate = sk->timestamp + expireval;
-  pk->pubkey_algo = sk->pubkey_algo;
-  n = pubkey_get_npkey (sk->pubkey_algo);
-  for (i=0; i < n; i++)
-    pk->pkey[i] = mpi_copy (sk->skey[i]);
-
-  /* Build packets and add them to the node lists.  */
-  pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
-  pkt->pkt.public_key = pk;
-  add_kbnode(pub_root, new_kbnode( pkt ));
-
-  pkt = xcalloc (1,sizeof *pkt);
-  pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
-  pkt->pkt.secret_key = sk;
-  add_kbnode(sec_root, new_kbnode( pkt ));
-
-  return 0;
-#else
-# if __GCC__ && ENABLE_CARD_SUPPORT
-#  warning Card support still missing
-# endif
-  (void)algo;
-  (void)keyno;
-  (void)is_primary;
-  (void)pub_root;
-  (void)timestamp;
-  (void)expireval;
-  (void)para;
-  return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif /*!ENABLE_CARD_SUPPORT*/
-}
-
-
-#if 0
-int
-save_unprotected_key_to_card (PKT_public_key *sk, int keyno)
-{
-  int rc;
-  unsigned char *rsa_n = NULL;
-  unsigned char *rsa_e = NULL;
-  unsigned char *rsa_p = NULL;
-  unsigned char *rsa_q = NULL;
-  size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
-  unsigned char *sexp = NULL;
-  unsigned char *p;
-  char numbuf[55], numbuf2[50];
-
-  assert (is_RSA (sk->pubkey_algo));
-  assert (!sk->is_protected);
-
-  /* Copy the parameters into straight buffers. */
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]);
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]);
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]);
-  gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]);
-  if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
-    {
-      rc = GPG_ERR_INV_ARG;
-      goto leave;
-    }
-
-   /* Put the key into an S-expression. */
-  sexp = p = xmalloc_secure (30
-                             + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
-                             + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
-
-  p = stpcpy (p,"(11:private-key(3:rsa(1:n");
-  sprintf (numbuf, "%u:", (unsigned int)rsa_n_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_n, rsa_n_len);
-  p += rsa_n_len;
-
-  sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_e, rsa_e_len);
-  p += rsa_e_len;
-
-  sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_p, rsa_p_len);
-  p += rsa_p_len;
-
-  sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len);
-  p = stpcpy (p, numbuf);
-  memcpy (p, rsa_q, rsa_q_len);
-  p += rsa_q_len;
-
-  p = stpcpy (p,"))(10:created-at");
-  sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp);
-  sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2));
-  p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
-
-  /* Fixme: Unfortunately we don't have the serialnumber available -
-     thus we can't pass it down to the agent. */
-  rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
-
- leave:
-  xfree (sexp);
-  xfree (rsa_n);
-  xfree (rsa_e);
-  xfree (rsa_p);
-  xfree (rsa_q);
-  return rc;
-}
-#endif /*ENABLE_CARD_SUPPORT*/