gpg: Re-enable the "Passphrase" parameter for batch key generation.
authorWerner Koch <wk@gnupg.org>
Wed, 21 Jan 2015 10:31:20 +0000 (11:31 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 21 Jan 2015 10:31:20 +0000 (11:31 +0100)
* agent/command.c (cmd_genkey): Add option --inq-passwd.
* agent/genkey.c (agent_genkey): Add new arg override_passphrase.
* g10/call-agent.c (inq_genkey_parms): Handle NEWPASSWD keyword.
(agent_genkey): Add arg optional arg "passphrase".
* g10/keygen.c (common_gen, gen_elg, gen_dsa, gen_ecc)
(gen_rsa, do_create): Add arg "passphrase" and pass it through.
(do_generate_keypair): Make use of pPASSPHRASE.
(release_parameter_list): Wipe out a passphrase parameter.

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
agent/agent.h
agent/command.c
agent/genkey.c
doc/gpg-agent.texi
doc/gpg.texi
g10/call-agent.c
g10/call-agent.h
g10/keygen.c

diff --git a/NEWS b/NEWS
index f4a6918..6f171aa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ Noteworthy changes in version 2.1.2 (unreleased)
  * agent: When setting --default-cache-ttl the value for
    --max-cache-ttl is adjusted to be not lower than the former.
 
+ * gpg: The parameter 'Passphrase' for batch key generation works
+   again.
+
 
 Noteworthy changes in version 2.1.1 (2014-12-16)
 ------------------------------------------------
index c7c65af..4be5925 100644 (file)
@@ -396,7 +396,8 @@ gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
                                       char **r_passphrase);
 int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
                   const char *keyparam, size_t keyparmlen,
-                  int no_protection, int preset, membuf_t *outbuf);
+                  int no_protection, const char *override_passphrase,
+                  int preset, membuf_t *outbuf);
 gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
                                      char **passphrase_addr);
 
index da7e508..d5644cb 100644 (file)
@@ -914,22 +914,23 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
 
 
 static const char hlp_genkey[] =
-  "GENKEY [--no-protection] [--preset] [<cache_nonce>]\n"
+  "GENKEY [--no-protection] [--preset] [--inq-passwd] [<cache_nonce>]\n"
   "\n"
   "Generate a new key, store the secret part and return the public\n"
   "part.  Here is an example transaction:\n"
   "\n"
   "  C: GENKEY\n"
   "  S: INQUIRE KEYPARAM\n"
-  "  C: D (genkey (rsa (nbits  1024)))\n"
+  "  C: D (genkey (rsa (nbits  2048)))\n"
   "  C: END\n"
   "  S: D (public-key\n"
   "  S: D   (rsa (n 326487324683264) (e 10001)))\n"
   "  S: OK key created\n"
   "\n"
   "When the --preset option is used the passphrase for the generated\n"
-  "key will be added to the cache.\n"
-  "\n";
+  "key will be added to the cache.  When --inq-passwd is used an inquire\n"
+  "with the keyword NEWPASSWD is used to request the passphrase for the\n"
+  "new key.\n";
 static gpg_error_t
 cmd_genkey (assuan_context_t ctx, char *line)
 {
@@ -938,16 +939,20 @@ cmd_genkey (assuan_context_t ctx, char *line)
   int no_protection;
   unsigned char *value;
   size_t valuelen;
+  unsigned char *newpasswd = NULL;
   membuf_t outbuf;
   char *cache_nonce = NULL;
   int opt_preset;
+  int opt_inq_passwd;
+  size_t n;
   char *p;
 
   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
 
-  opt_preset = has_option (line, "--preset");
   no_protection = has_option (line, "--no-protection");
+  opt_preset = has_option (line, "--preset");
+  opt_inq_passwd = has_option (line, "--inq-passwd");
   line = skip_options (line);
 
   p = line;
@@ -966,8 +971,37 @@ cmd_genkey (assuan_context_t ctx, char *line)
 
   init_membuf (&outbuf, 512);
 
+  /* If requested, ask for the password to be used for the key.  If
+     this is not used the regular Pinentry mechanism is used.  */
+  if (opt_inq_passwd && !no_protection)
+    {
+      /* (N is used as a dummy) */
+      assuan_begin_confidential (ctx);
+      rc = assuan_inquire (ctx, "NEWPASSWD", &newpasswd, &n, 256);
+      assuan_end_confidential (ctx);
+      if (rc)
+        goto leave;
+      if (!*newpasswd)
+        {
+          /* Empty password given - switch to no-protection mode.  */
+          xfree (newpasswd);
+          newpasswd = NULL;
+          no_protection = 1;
+        }
+
+    }
+
   rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
-                     opt_preset, &outbuf);
+                     newpasswd, opt_preset, &outbuf);
+
+ leave:
+  if (newpasswd)
+    {
+      /* Assuan_inquire does not allow us to read into secure memory
+         thus we need to wipe it ourself.  */
+      wipememory (newpasswd, strlen (newpasswd));
+      xfree (newpasswd);
+    }
   xfree (value);
   if (rc)
     clear_outbuf (&outbuf);
index 91917f7..d7b6007 100644 (file)
@@ -410,14 +410,16 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
 /* Generate a new keypair according to the parameters given in
    KEYPARAM.  If CACHE_NONCE is given first try to lookup a passphrase
    using the cache nonce.  If NO_PROTECTION is true the key will not
-   be protected by a passphrase.  */
+   be protected by a passphrase.  If OVERRIDE_PASSPHRASE is true that
+   passphrase will be used for the new key.  */
 int
 agent_genkey (ctrl_t ctrl, const char *cache_nonce,
               const char *keyparam, size_t keyparamlen, int no_protection,
-              int preset, membuf_t *outbuf)
+              const char *override_passphrase, int preset, membuf_t *outbuf)
 {
   gcry_sexp_t s_keyparam, s_key, s_private, s_public;
-  char *passphrase;
+  char *passphrase_buffer = NULL;
+  const char *passphrase;
   int rc;
   size_t len;
   char *buf;
@@ -430,27 +432,35 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
     }
 
   /* Get the passphrase now, cause key generation may take a while. */
-  if (no_protection || !cache_nonce)
+  if (override_passphrase)
+    passphrase = override_passphrase;
+  else if (no_protection || !cache_nonce)
     passphrase = NULL;
   else
-    passphrase = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+    {
+      passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+      passphrase = passphrase_buffer;
+    }
 
   if (passphrase || no_protection)
-    rc = 0;
+    ;
   else
-    rc = agent_ask_new_passphrase (ctrl,
-                                   _("Please enter the passphrase to%0A"
-                                     "protect your new key"),
-                                   &passphrase);
-  if (rc)
-    return rc;
+    {
+      rc = agent_ask_new_passphrase (ctrl,
+                                     _("Please enter the passphrase to%0A"
+                                       "protect your new key"),
+                                     &passphrase_buffer);
+      if (rc)
+        return rc;
+      passphrase = passphrase_buffer;
+    }
 
   rc = gcry_pk_genkey (&s_key, s_keyparam );
   gcry_sexp_release (s_keyparam);
   if (rc)
     {
       log_error ("key generation failed: %s\n", gpg_strerror (rc));
-      xfree (passphrase);
+      xfree (passphrase_buffer);
       return rc;
     }
 
@@ -460,7 +470,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
     {
       log_error ("key generation failed: invalid return value\n");
       gcry_sexp_release (s_key);
-      xfree (passphrase);
+      xfree (passphrase_buffer);
       return gpg_error (GPG_ERR_INV_DATA);
     }
   s_public = gcry_sexp_find_token (s_key, "public-key", 0);
@@ -469,7 +479,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
       log_error ("key generation failed: invalid return value\n");
       gcry_sexp_release (s_private);
       gcry_sexp_release (s_key);
-      xfree (passphrase);
+      xfree (passphrase_buffer);
       return gpg_error (GPG_ERR_INV_DATA);
     }
   gcry_sexp_release (s_key); s_key = NULL;
@@ -503,7 +513,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
            }
        }
     }
-  xfree (passphrase);
+  xfree (passphrase_buffer);
+  passphrase_buffer = NULL;
   passphrase = NULL;
   gcry_sexp_release (s_private);
   if (rc)
index 36bd0c2..7ac441f 100644 (file)
@@ -1134,6 +1134,13 @@ The @option{--no-protection} option may be used to prevent prompting for a
 passphrase to protect the secret key while leaving the secret key unprotected.
 The @option{--preset} option may be used to add the passphrase to the cache
 using the default cache parameters.
+
+The @option{--inq-passwd} option may be used to create the key with a
+supplied passphrase.  When used the agent does an inquiry with the
+keyword @code{NEWPASSWD} to retrieve that passphrase.  This option
+takes precedence over @option{--no-protection}; however if the client
+sends a empty (zero-length) passphrase, this is identical to
+@option{--no-protection}.
 @end ifset
 
 @node Agent IMPORT
index 71ffaf8..6921fd9 100644 (file)
@@ -3341,17 +3341,13 @@ ignored and instead the usual passphrase dialog is used.  This does
 not make sense for batch key generation; however the unattended key
 generation feature is also used by GUIs and this feature relinquishes
 the GUI from implementing its own passphrase entry code.  These are
-global control statements and affect all future key genrations.
+global control statements and affect all future key generations.
 @end ifclear
 @ifset gpgtwoone
 This option is a no-op for GnuPG 2.1 and later.
 @end ifset
 
-
 @item %no-protection
-Since GnuPG version 2.1 it is not anymore possible to specify a
-passphrase for unattended key generation.  The passphrase command is
-simply ignored and @samp{%ask-passpharse} is thus implicitly enabled.
 Using this option allows the creation of keys without any passphrase
 protection.  This option is mainly intended for regression tests.
 
@@ -3409,8 +3405,8 @@ by running the command @samp{gpg2 --gpgconf-list}".
 Key usage lists for a subkey; similar to @samp{Key-Usage}.
 
 @item Passphrase: @var{string}
-If you want to specify a passphrase for the secret key,
-enter it here. Default is not to use any passphrase.
+If you want to specify a passphrase for the secret key, enter it here.
+Default is to use the Pinentry dialog to ask for a passphrase.
 
 @item Name-Real: @var{name}
 @itemx Name-Comment: @var{comment}
index a98a177..dc9d157 100644 (file)
@@ -1,7 +1,6 @@
 /* call-agent.c - Divert GPG operations to the agent.
- * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009,
- *               2010, 2011, 2013 Free Software Foundation, Inc.
- * Copyright (C) 2013, 2014  Werner Koch
+ * Copyright (C) 2001-2003, 2006-2011, 2013 Free Software Foundation, Inc.
+ * Copyright (C) 2013-2015  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -90,6 +89,7 @@ struct genkey_parm_s
 {
   struct default_inq_parm_s *dflt;
   const char *keyparms;
+  const char *passphrase;
 };
 
 struct import_key_parm_s
@@ -1737,6 +1737,11 @@ inq_genkey_parms (void *opaque, const char *line)
       err = assuan_send_data (parm->dflt->ctx,
                               parm->keyparms, strlen (parm->keyparms));
     }
+  else if (has_leading_keyword (line, "NEWPASSWD") && parm->passphrase)
+    {
+      err = assuan_send_data (parm->dflt->ctx,
+                              parm->passphrase,  strlen (parm->passphrase));
+    }
   else
     err = default_inq_cb (parm->dflt, line);
 
@@ -1747,10 +1752,13 @@ inq_genkey_parms (void *opaque, const char *line)
 /* Call the agent to generate a new key.  KEYPARMS is the usual
    S-expression giving the parameters of the key.  gpg-agent passes it
    gcry_pk_genkey.  If NO_PROTECTION is true the agent is advised not
-   to protect the generated key. */
+   to protect the generated key.  If NO_PROTECTION is not set and
+   PASSPHRASE is not NULL the agent is requested to protect the key
+   with that passphrase instead of asking for one.  */
 gpg_error_t
 agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
-              const char *keyparms, int no_protection, gcry_sexp_t *r_pubkey)
+              const char *keyparms, int no_protection,
+              const char *passphrase, gcry_sexp_t *r_pubkey)
 {
   gpg_error_t err;
   struct genkey_parm_s gk_parm;
@@ -1778,8 +1786,11 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
   init_membuf (&data, 1024);
   gk_parm.dflt     = &dfltparm;
   gk_parm.keyparms = keyparms;
+  gk_parm.passphrase = passphrase;
   snprintf (line, sizeof line, "GENKEY%s%s%s",
-            no_protection? " --no-protection":"",
+            no_protection? " --no-protection" :
+            passphrase   ? " --inq-passwd" :
+            /*          */ "",
             cache_nonce_addr && *cache_nonce_addr? " ":"",
             cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
   cn_parm.cache_nonce_addr = cache_nonce_addr;
index bcb5ae9..9c104e8 100644 (file)
@@ -154,6 +154,7 @@ gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
 /* Generate a new key.  */
 gpg_error_t agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
                           const char *keyparms, int no_protection,
+                          const char *passphrase,
                           gcry_sexp_t *r_pubkey);
 
 /* Read a public key.  */
index fa466a8..a3dbed8 100644 (file)
@@ -1,7 +1,6 @@
 /* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- *               2007, 2009, 2010, 2011  Free Software Foundation, Inc.
- * Copyright (C) 2014  Werner Koch
+ * Copyright (C) 1998-2007, 2009-2011  Free Software Foundation, Inc.
+ * Copyright (C) 2014, 2015  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -1287,7 +1286,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip,
 static int
 common_gen (const char *keyparms, int algo, const char *algoelem,
             kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
-            int keygen_flags, char **cache_nonce_addr)
+            int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   int err;
   PACKET *pkt;
@@ -1295,7 +1294,9 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
   gcry_sexp_t s_key;
 
   err = agent_genkey (NULL, cache_nonce_addr, keyparms,
-                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), &s_key);
+                      !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
+                      passphrase,
+                      &s_key);
   if (err)
     {
       log_error ("agent_genkey failed: %s\n", gpg_strerror (err) );
@@ -1353,7 +1354,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
 static int
 gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   int err;
   char *keyparms;
@@ -1394,7 +1395,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "pgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase, cache_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1408,7 +1409,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_dsa (unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   int err;
   unsigned int qbits;
@@ -1481,7 +1482,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase, cache_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1496,7 +1497,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 static gpg_error_t
 gen_ecc (int algo, const char *curve, kbnode_t pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   gpg_error_t err;
   char *keyparms;
@@ -1531,7 +1532,7 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
     {
       err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase, cache_nonce_addr);
       xfree (keyparms);
     }
 
@@ -1545,7 +1546,7 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
 static int
 gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
-         int keygen_flags, char **cache_nonce_addr)
+         int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   int err;
   char *keyparms;
@@ -1586,7 +1587,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
     {
       err = common_gen (keyparms, algo, "ne",
                         pub_root, timestamp, expireval, is_subkey,
-                        keygen_flags, cache_nonce_addr);
+                        keygen_flags, passphrase, cache_nonce_addr);
       xfree (keyparms);
     }
 
@@ -2724,7 +2725,7 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled)
 static int
 do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
            u32 timestamp, u32 expiredate, int is_subkey,
-           int keygen_flags, char **cache_nonce_addr)
+           int keygen_flags, const char *passphrase, char **cache_nonce_addr)
 {
   gpg_error_t err;
 
@@ -2739,18 +2740,18 @@ do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root,
 
   if (algo == PUBKEY_ALGO_ELGAMAL_E)
     err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_DSA)
     err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_ECDSA
            || algo == PUBKEY_ALGO_EDDSA
            || algo == PUBKEY_ALGO_ECDH)
     err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase, cache_nonce_addr);
   else if (algo == PUBKEY_ALGO_RSA)
     err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
-                   keygen_flags, cache_nonce_addr);
+                   keygen_flags, passphrase, cache_nonce_addr);
   else
     BUG();
 
@@ -2792,6 +2793,8 @@ release_parameter_list (struct para_data_s *r)
   for (; r ; r = r2)
     {
       r2 = r->next;
+      if (r->key == pPASSPHRASE && *r->u.value)
+        wipememory (r->u.value, strlen (r->u.value));
       xfree (r);
     }
 }
@@ -3966,7 +3969,9 @@ do_generate_keypair (struct para_data_s *para,
                      pub_root,
                      timestamp,
                      get_parameter_u32( para, pKEYEXPIRE ), 0,
-                     outctrl->keygen_flags, &cache_nonce);
+                     outctrl->keygen_flags,
+                     get_parameter_value (para, pPASSPHRASE),
+                     &cache_nonce);
   else
     err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root,
                         &timestamp,
@@ -4018,7 +4023,9 @@ do_generate_keypair (struct para_data_s *para,
                            pub_root,
                            timestamp,
                            get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
-                           outctrl->keygen_flags, &cache_nonce);
+                           outctrl->keygen_flags,
+                           get_parameter_value (para, pPASSPHRASE),
+                           &cache_nonce);
           /* Get the pointer to the generated public subkey packet.  */
           if (!err)
             {
@@ -4241,7 +4248,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
                                   keyblock, cur_time, expire, 1);
   else
     err = do_create (algo, nbits, curve,
-                     keyblock, cur_time, expire, 1, 0, NULL);
+                     keyblock, cur_time, expire, 1, 0, NULL, NULL);
   if (err)
     goto leave;