aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/card-tool-keys.c88
-rw-r--r--tools/card-tool.h1
-rw-r--r--tools/gpg-card-tool.c4
3 files changed, 90 insertions, 3 deletions
diff --git a/tools/card-tool-keys.c b/tools/card-tool-keys.c
index af2425cbf..e9edf9818 100644
--- a/tools/card-tool-keys.c
+++ b/tools/card-tool-keys.c
@@ -30,9 +30,22 @@
#include "../common/openpgpdefs.h"
#include "card-tool.h"
-/* Release a keyblocm object. */
-void
-release_keyblock (keyblock_t keyblock)
+
+/* It is quite common that all keys of an OpenPGP card belong to the
+ * the same OpenPGP keyblock. To avoid running several queries
+ * despite that we already got the information with the previous
+ * keyblock, we keep a small cache of of previous done queries. */
+static struct
+{
+ unsigned int lru;
+ keyblock_t keyblock;
+} keyblock_cache[5];
+
+
+
+/* Helper for release_keyblock. */
+static void
+do_release_keyblock (keyblock_t keyblock)
{
pubkey_t pubkey;
userid_t uid;
@@ -61,6 +74,62 @@ release_keyblock (keyblock_t keyblock)
}
+/* Release a keyblock object. */
+void
+release_keyblock (keyblock_t keyblock)
+{
+ static unsigned int lru_counter;
+ unsigned int lru;
+ int i, lru_idx;
+
+ if (!keyblock)
+ return;
+
+ lru = (unsigned int)(-1);
+ lru_idx = 0;
+ for (i=0; i < DIM (keyblock_cache); i++)
+ {
+ if (!keyblock_cache[i].keyblock)
+ {
+ keyblock_cache[i].keyblock = keyblock;
+ keyblock_cache[i].lru = ++lru_counter;
+ goto leave;
+ }
+ if (keyblock_cache[i].lru < lru)
+ {
+ lru = keyblock_cache[i].lru;
+ lru_idx = i;
+ }
+ }
+
+ /* No free slot. Replace one. */
+ do_release_keyblock (keyblock_cache[lru_idx].keyblock);
+ keyblock_cache[lru_idx].keyblock = keyblock;
+ keyblock_cache[lru_idx].lru = ++lru_counter;
+
+ leave:
+ if (!lru_counter)
+ {
+ /* Wrapped around. We simply clear the entire cache. */
+ flush_keyblock_cache ();
+ }
+}
+
+
+/* Flush the enire keyblock cache. */
+void
+flush_keyblock_cache (void)
+{
+ int i;
+
+ for (i=0; i < DIM (keyblock_cache); i++)
+ {
+ do_release_keyblock (keyblock_cache[i].keyblock);
+ keyblock_cache[i].keyblock = NULL;
+ }
+}
+
+
/* Object to communicate with the status_cb. */
struct status_cb_s
@@ -127,6 +196,7 @@ get_matching_keys (const unsigned char *keygrip, int protocol,
char **fields = NULL;
int nfields;
int first_seen;
+ int i;
keyblock_t keyblock_head, *keyblock_tail, kb;
pubkey_t pubkey, pk;
size_t n;
@@ -168,6 +238,18 @@ get_matching_keys (const unsigned char *keygrip, int protocol,
if (protocol != GNUPG_PROTOCOL_OPENPGP && protocol != GNUPG_PROTOCOL_CMS)
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+ /* Try to get it from our cache. */
+ for (i=0; i < DIM (keyblock_cache); i++)
+ for (kb = keyblock_cache[i].keyblock; kb; kb = kb->next)
+ if (kb->protocol == protocol)
+ for (pk = kb->keys; pk; pk = pk->next)
+ if (pk->grip_valid && !memcmp (pk->grip, keygrip, KEYGRIP_LEN))
+ {
+ *r_keyblock = keyblock_cache[i].keyblock;
+ keyblock_cache[i].keyblock = NULL;
+ return 0;
+ }
+
/* Open a memory stream. */
listing = es_fopenmem (0, "w+b");
if (!listing)
diff --git a/tools/card-tool.h b/tools/card-tool.h
index d502ecb58..05d6ea47d 100644
--- a/tools/card-tool.h
+++ b/tools/card-tool.h
@@ -181,6 +181,7 @@ typedef struct card_info_s *card_info_t;
/*-- card-tool-keys.c --*/
void release_keyblock (keyblock_t keyblock);
+void flush_keyblock_cache (void);
gpg_error_t get_matching_keys (const unsigned char *keygrip, int protocol,
keyblock_t *r_keyblock);
gpg_error_t test_get_matching_keys (const char *hexgrip);
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 321426bdd..07b8bc67b 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -312,6 +312,8 @@ main (int argc, char **argv)
break;
}
+ flush_keyblock_cache ();
+
if (err)
gnupg_status_printf (STATUS_FAILURE, "- %u", err);
else if (log_get_errorcount (0))
@@ -2639,6 +2641,7 @@ static struct
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
+ { "reset" , cmdRESET, 0, N_("send a reset to the card daemon")},
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
{ "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
@@ -2834,6 +2837,7 @@ interactive_loop (void)
"Send a RESET to the card daemon.", 0);
else
{
+ flush_keyblock_cache ();
err = scd_apdu (NULL, NULL);
}
break;