aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-01-13 15:27:12 +0000
committerWerner Koch <[email protected]>2020-01-13 15:27:12 +0000
commit2e86cca7f4181310bebfd795c059369ba03a8d8b (patch)
treee854be013f1c6f8693734ae1ce530e46775491e9
parentagent: Replace free by xfree in recently added code. (diff)
downloadgnupg-2e86cca7f4181310bebfd795c059369ba03a8d8b.tar.gz
gnupg-2e86cca7f4181310bebfd795c059369ba03a8d8b.zip
agent: Avoid multiple calls to scd for KEYINFO.
* agent/command.c (struct server_local_s): Add last_card_keyinfo. (eventcounter): Add maybe_key_change. (cmd_genkey, cmd_scd, cmd_import_key, cmd_delete_key): Bump new counter. (cmd_keyinfo): Cache the keyinfo from the card. (start_command_handler): Release the cache. -- This cache speeds up processing of commands like "gpg -K" because scdaemon does not need to be asked for each key as long as nothing changed with the card. We should have a better notification service from scdaemon to make sure that we get only the relevant events. What we do right now is a bit course but sufficient. Signed-off-by: Werner Koch <[email protected]>
-rw-r--r--agent/command.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/agent/command.c b/agent/command.c
index 10eac94bd..5f29adbe6 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -112,6 +112,16 @@ struct server_local_s
/* Last PASSWD_NONCE sent as status (malloced). */
char *last_passwd_nonce;
+
+ /* Per connection cache of the keyinfo from the cards. The
+ * eventcounters for cards at the time the info was fetched is
+ * stored here as a freshness indicator. */
+ struct {
+ struct card_key_info_s *ki;
+ unsigned int eventno;
+ unsigned int maybe_key_change;
+ } last_card_keyinfo;
+
};
@@ -148,6 +158,11 @@ struct
detected. */
unsigned int card;
+ /* Internal counter to track possible changes to a key.
+ * FIXME: This should be replaced by generic notifications from scd.
+ */
+ unsigned int maybe_key_change;
+
} eventcounter;
@@ -927,6 +942,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
if (*line)
cache_nonce = xtrystrdup (line);
+ eventcounter.maybe_key_change++;
+
/* First inquire the parameters */
rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_KEYPARAM);
if (!rc)
@@ -1307,7 +1324,24 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
if (opt_with_ssh || list_mode == 2)
cf = ssh_open_control_file ();
- agent_card_keyinfo (ctrl, NULL, 0, &keyinfo_on_cards);
+ /* Take the keyinfo for cards from our local cache. Actually this
+ * cache could be a global one but then we would need to employ
+ * reference counting. */
+ if (ctrl->server_local->last_card_keyinfo.ki
+ && ctrl->server_local->last_card_keyinfo.eventno == eventcounter.card
+ && (ctrl->server_local->last_card_keyinfo.maybe_key_change
+ == eventcounter.maybe_key_change))
+ {
+ keyinfo_on_cards = ctrl->server_local->last_card_keyinfo.ki;
+ }
+ else if (!agent_card_keyinfo (ctrl, NULL, 0, &keyinfo_on_cards))
+ {
+ agent_card_free_keyinfo (ctrl->server_local->last_card_keyinfo.ki);
+ ctrl->server_local->last_card_keyinfo.ki = keyinfo_on_cards;
+ ctrl->server_local->last_card_keyinfo.eventno = eventcounter.card;
+ ctrl->server_local->last_card_keyinfo.maybe_key_change
+ = eventcounter.maybe_key_change;
+ }
if (list_mode == 2)
{
@@ -1413,7 +1447,6 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
}
leave:
- agent_card_free_keyinfo (keyinfo_on_cards);
ssh_close_control_file (cf);
if (dir)
closedir (dir);
@@ -2034,6 +2067,9 @@ cmd_scd (assuan_context_t ctx, char *line)
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ /* All SCD prefixed commands may change a key. */
+ eventcounter.maybe_key_change++;
+
rc = divert_generic_cmd (ctrl, line, ctx);
#else
(void)ctx; (void)line;
@@ -2152,6 +2188,8 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (*line)
cache_nonce = xtrystrdup (line);
+ eventcounter.maybe_key_change++;
+
assuan_begin_confidential (ctx);
err = assuan_inquire (ctx, "KEYDATA",
&wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA);
@@ -2495,6 +2533,8 @@ cmd_delete_key (assuan_context_t ctx, char *line)
stub_only = has_option (line, "--stub-only");
line = skip_options (line);
+ eventcounter.maybe_key_change++;
+
/* If the use of a loopback pinentry has been disabled, we assume
* that a silent deletion of keys shall also not be allowed. */
if (!opt.allow_loopback_pinentry)
@@ -3640,6 +3680,9 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
}
}
+ /* Clear the keyinfo cache. */
+ agent_card_free_keyinfo (ctrl->server_local->last_card_keyinfo.ki);
+
/* Reset the nonce caches. */
clear_nonce_cache (ctrl);