card: Cache the results from gpg and gpgsm.
authorWerner Koch <wk@gnupg.org>
Wed, 30 Jan 2019 16:48:41 +0000 (17:48 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 30 Jan 2019 16:51:32 +0000 (17:51 +0100)
* tools/card-tool-keys.c (keyblock_cache): New var.
(release_keyblock): Factor code out to a new do_release_keyblock.  Add
a cache.
(flush_keyblock_cache): New.
(get_matching_keys): Use the cache.
* tools/gpg-card-tool.c (cmds): Add command "reset".
(interactive_loop): Implement reset.
--

Signed-off-by: Werner Koch <wk@gnupg.org>
tools/card-tool-keys.c
tools/card-tool.h
tools/gpg-card-tool.c

index af2425c..e9edf98 100644 (file)
 #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)
index d502ecb..05d6ea4 100644 (file)
@@ -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);
index 321426b..07b8bc6 100644 (file)
@@ -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;