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;