gpg: Avoid extra pinentries for each subkey in --export-secret-keys.
authorWerner Koch <wk@gnupg.org>
Sun, 2 Nov 2014 16:51:30 +0000 (17:51 +0100)
committerWerner Koch <wk@gnupg.org>
Sun, 2 Nov 2014 16:51:30 +0000 (17:51 +0100)
* agent/command.c (cmd_export_key): Actually implement the cache_nonce
feature.
* g10/export.c (do_export_stream): Make use of a cache_nonce.

Signed-off-by: Werner Koch <wk@gnupg.org>
agent/command.c
g10/call-agent.c
g10/export.c

index 8c68498..7f8759d 100644 (file)
@@ -2127,16 +2127,19 @@ cmd_export_key (assuan_context_t ctx, char *line)
   char *cache_nonce;
   char *passphrase = NULL;
   unsigned char *shadow_info = NULL;
+  char *pend;
+  int c;
 
   openpgp = has_option (line, "--openpgp");
   cache_nonce = option_value (line, "--cache-nonce");
   if (cache_nonce)
     {
-      for (; *line && !spacep (line); line++)
+      for (pend = cache_nonce; *pend && !spacep (pend); pend++)
         ;
-      if (*line)
-        *line++ = '\0';
+      c = *pend;
+      *pend = '\0';
       cache_nonce = xtrystrdup (cache_nonce);
+      *pend = c;
       if (!cache_nonce)
         {
           err = gpg_error_from_syserror ();
@@ -2163,7 +2166,8 @@ cmd_export_key (assuan_context_t ctx, char *line)
 
   /* Get the key from the file.  With the openpgp flag we also ask for
      the passphrase so that we can use it to re-encrypt it.  */
-  err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
+  err = agent_key_from_file (ctrl, cache_nonce,
+                             ctrl->server_local->keydesc, grip,
                              &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
                              openpgp ? &passphrase : NULL);
   if (err)
@@ -2190,6 +2194,24 @@ cmd_export_key (assuan_context_t ctx, char *line)
             goto leave;
         }
       err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
+      if (!err && passphrase)
+        {
+          if (!cache_nonce)
+            {
+              char buf[12];
+              gcry_create_nonce (buf, 12);
+              cache_nonce = bin2hex (buf, 12, NULL);
+            }
+          if (cache_nonce
+              && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+                                   passphrase, CACHE_TTL_NONCE))
+            {
+              assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
+              xfree (ctrl->server_local->last_cache_nonce);
+              ctrl->server_local->last_cache_nonce = cache_nonce;
+              cache_nonce = NULL;
+            }
+        }
     }
   else
     {
index cadc02c..bacb9d5 100644 (file)
@@ -2152,8 +2152,10 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
 \f
 /* Receive a secret key from the agent.  HEXKEYGRIP is the hexified
    keygrip, DESC a prompt to be displayed with the agent's passphrase
-   question (needs to be plus+percent escaped).  On success the key is
-   stored as a canonical S-expression at R_RESULT and R_RESULTLEN.  */
+   question (needs to be plus+percent escaped).  If CACHE_NONCE_ADDR
+   is not NULL the agent is advised to first try a passphrase
+   associated with that nonce.  On success the key is stored as a
+   canonical S-expression at R_RESULT and R_RESULTLEN.  */
 gpg_error_t
 agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
                   char **cache_nonce_addr,
index b4f1a2e..a92eace 100644 (file)
@@ -777,6 +777,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   strlist_t sl;
   int indent = 0;
   gcry_cipher_hd_t cipherhd = NULL;
+  char *cache_nonce = NULL;
 
   *any = 0;
   init_packet (&pkt);
@@ -914,6 +915,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
         clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
 
       /* And write it. */
+      xfree (cache_nonce);
+      cache_nonce = NULL;
       for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
         {
           if (skip_until_subkey)
@@ -1124,7 +1127,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   {
                     char *prompt = gpg_format_keydesc (pk,
                                                        FORMAT_KEYDESC_EXPORT,1);
-                    err = agent_export_key (ctrl, hexgrip, prompt, NULL,
+                    err = agent_export_key (ctrl, hexgrip, prompt, &cache_nonce,
                                             &wrappedkey, &wrappedkeylen);
                     xfree (prompt);
                   }
@@ -1246,6 +1249,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   keydb_release (kdbhd);
   if (err || !keyblock_out)
     release_kbnode( keyblock );
+  xfree (cache_nonce);
   if( !*any )
     log_info(_("WARNING: nothing exported\n"));
   return err;