diff --git a/common/iobuf.c b/common/iobuf.c index 3ba3582d0..a3058303d 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -2311,7 +2311,7 @@ iobuf_seek (iobuf_t a, off_t newpos) } clearerr (fp); } - else + else if (a->use != 3) /* Not a temp stream. */ { for (; a; a = a->chain) { @@ -2338,7 +2338,8 @@ iobuf_seek (iobuf_t a, off_t newpos) } #endif } - a->d.len = 0; /* discard buffer */ + if (a->use != 3) + a->d.len = 0; /* Discard the buffer unless it is a temp stream. */ a->d.start = 0; a->nbytes = 0; a->nlimit = 0; diff --git a/g10/keydb.c b/g10/keydb.c index 7166203c3..79ab5afc6 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -72,10 +72,42 @@ struct keydb_handle }; +/* This is a simple cache used to return the last result of a + successful long kid search. This works only for keybox resources + because (due to lack of a copy_keyblock function) we need to store + an image of the keyblock which is fortunately instantly available + for keyboxes. */ +enum keyblock_cache_states { + KEYBLOCK_CACHE_EMPTY, + KEYBLOCK_CACHE_PREPARED, + KEYBLOCK_CACHE_FILLED +}; + +struct { + enum keyblock_cache_states state; + u32 kid[2]; + iobuf_t iobuf; /* Image of the keyblock. */ + u32 *sigstatus; + int pk_no; + int uid_no; +} keyblock_cache; + + static int lock_all (KEYDB_HANDLE hd); static void unlock_all (KEYDB_HANDLE hd); +static void +keyblock_cache_clear (void) +{ + keyblock_cache.state = KEYBLOCK_CACHE_EMPTY; + xfree (keyblock_cache.sigstatus); + keyblock_cache.sigstatus = NULL; + iobuf_close (keyblock_cache.iobuf); + keyblock_cache.iobuf = NULL; +} + + /* Handle the creation of a keyring or a keybox if it does not yet exist. Take into acount that other processes might have the keyring/keybox already locked. This lock check does not work if @@ -427,6 +459,9 @@ keydb_new (void) KEYDB_HANDLE hd; int i, j; + if (DBG_CLOCK) + log_clock ("keydb_new"); + hd = xmalloc_clear (sizeof *hd); hd->found = -1; @@ -787,6 +822,19 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb) if (!hd) return gpg_error (GPG_ERR_INV_ARG); + if (keyblock_cache.state == KEYBLOCK_CACHE_FILLED) + { + iobuf_seek (keyblock_cache.iobuf, 0); + err = parse_keyblock_image (keyblock_cache.iobuf, + keyblock_cache.pk_no, + keyblock_cache.uid_no, + keyblock_cache.sigstatus, + ret_kb); + if (err) + keyblock_cache_clear (); + return err; + } + if (hd->found < 0 || hd->found >= hd->used) return gpg_error (GPG_ERR_VALUE_NOT_FOUND); @@ -810,13 +858,27 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb) { err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus, ret_kb); - xfree (sigstatus); - iobuf_close (iobuf); + if (!err && keyblock_cache.state == KEYBLOCK_CACHE_PREPARED) + { + keyblock_cache.state = KEYBLOCK_CACHE_FILLED; + keyblock_cache.sigstatus = sigstatus; + keyblock_cache.iobuf = iobuf; + keyblock_cache.pk_no = pk_no; + keyblock_cache.uid_no = uid_no; + } + else + { + xfree (sigstatus); + iobuf_close (iobuf); + } } } break; } + if (keyblock_cache.state != KEYBLOCK_CACHE_FILLED) + keyblock_cache_clear (); + return err; } @@ -914,6 +976,8 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) if (!hd) return gpg_error (GPG_ERR_INV_ARG); + keyblock_cache_clear (); + if (hd->found < 0 || hd->found >= hd->used) return gpg_error (GPG_ERR_VALUE_NOT_FOUND); @@ -957,6 +1021,8 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb) if (!hd) return gpg_error (GPG_ERR_INV_ARG); + keyblock_cache_clear (); + if (opt.dry_run) return 0; @@ -1017,6 +1083,8 @@ keydb_delete_keyblock (KEYDB_HANDLE hd) if (!hd) return gpg_error (GPG_ERR_INV_ARG); + keyblock_cache_clear (); + if (hd->found < 0 || hd->found >= hd->used) return gpg_error (GPG_ERR_VALUE_NOT_FOUND); @@ -1113,6 +1181,8 @@ keydb_rebuild_caches (int noisy) { int i, rc; + keyblock_cache_clear (); + for (i=0; i < used_resources; i++) { if (!keyring_is_writable (all_resources[i].token)) @@ -1145,6 +1215,11 @@ keydb_search_reset (KEYDB_HANDLE hd) if (!hd) return gpg_error (GPG_ERR_INV_ARG); + keyblock_cache_clear (); + + if (DBG_CLOCK) + log_clock ("keydb_search_reset"); + hd->current = 0; hd->found = -1; /* Now reset all resources. */ @@ -1166,6 +1241,52 @@ keydb_search_reset (KEYDB_HANDLE hd) } +static void +dump_search_desc (const char *text, KEYDB_SEARCH_DESC *desc, size_t ndesc) +{ + int n; + const char *s; + + for (n=0; n < ndesc; n++) + { + switch (desc[n].mode) + { + case KEYDB_SEARCH_MODE_NONE: s = "none"; break; + case KEYDB_SEARCH_MODE_EXACT: s = "exact"; break; + case KEYDB_SEARCH_MODE_SUBSTR: s = "substr"; break; + case KEYDB_SEARCH_MODE_MAIL: s = "mail"; break; + case KEYDB_SEARCH_MODE_MAILSUB: s = "mailsub"; break; + case KEYDB_SEARCH_MODE_MAILEND: s = "mailend"; break; + case KEYDB_SEARCH_MODE_WORDS: s = "words"; break; + case KEYDB_SEARCH_MODE_SHORT_KID: s = "short_kid"; break; + case KEYDB_SEARCH_MODE_LONG_KID: s = "long_kid"; break; + case KEYDB_SEARCH_MODE_FPR16: s = "fpr16"; break; + case KEYDB_SEARCH_MODE_FPR20: s = "fpr20"; break; + case KEYDB_SEARCH_MODE_FPR: s = "fpr"; break; + case KEYDB_SEARCH_MODE_ISSUER: s = "issuer"; break; + case KEYDB_SEARCH_MODE_ISSUER_SN: s = "issuer_sn"; break; + case KEYDB_SEARCH_MODE_SN: s = "sn"; break; + case KEYDB_SEARCH_MODE_SUBJECT: s = "subject"; break; + case KEYDB_SEARCH_MODE_KEYGRIP: s = "keygrip"; break; + case KEYDB_SEARCH_MODE_FIRST: s = "first"; break; + case KEYDB_SEARCH_MODE_NEXT: s = "next"; break; + default: s = "?"; break; + } + if (!n) + log_debug ("%s: mode=%s", text, s); + else + log_debug ("%*s mode=%s", (int)strlen (text), "", s); + if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID) + log_printf (" %08lX%08lX", (unsigned long)desc[n].u.kid[0], + (unsigned long)desc[n].u.kid[1]); + else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID) + log_printf (" %08lX", (unsigned long)desc[n].u.kid[1]); + else if (desc[n].mode == KEYDB_SEARCH_MODE_SUBSTR) + log_printf (" '%s'", desc[n].u.name); + } +} + + /* * Search through all keydb resources, starting at the current * position, for a keyblock which contains one of the keys described @@ -1184,6 +1305,19 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, if (DBG_CLOCK) log_clock ("keydb_search enter"); + if (DBG_CACHE) + dump_search_desc ("keydb_search", desc, ndesc); + + if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID + && keyblock_cache.state == KEYBLOCK_CACHE_FILLED + && keyblock_cache.kid[0] == desc[0].u.kid[0] + && keyblock_cache.kid[1] == desc[0].u.kid[1]) + { + if (DBG_CLOCK) + log_clock ("keydb_search leave (cached)"); + return 0; + } + rc = -1; while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) && hd->current >= 0 && hd->current < hd->used) @@ -1210,11 +1344,22 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, hd->found = hd->current; } + rc = ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) + ? gpg_error (GPG_ERR_NOT_FOUND) + : rc); + + keyblock_cache_clear (); + if (!rc && ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID) + { + keyblock_cache.state = KEYBLOCK_CACHE_PREPARED; + keyblock_cache.kid[0] = desc[0].u.kid[0]; + keyblock_cache.kid[1] = desc[0].u.kid[1]; + } + if (DBG_CLOCK) - log_clock ("keydb_search leave"); - return ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) - ? gpg_error (GPG_ERR_NOT_FOUND) - : rc); + log_clock (rc? "keydb_search leave (not found)" + : "keydb_search leave (found)"); + return rc; } diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 254e81091..a69536e1d 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -77,6 +77,9 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek) PKT_public_key *sk = NULL; int rc; + if (DBG_CLOCK) + log_clock ("get_session_key enter"); + rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); if (rc) goto leave; @@ -129,6 +132,8 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek) leave: free_public_key (sk); + if (DBG_CLOCK) + log_clock ("get_session_key leave"); return rc; } @@ -149,6 +154,9 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) size_t fpn; const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo); + if (DBG_CLOCK) + log_clock ("decryption start"); + /* Get the keygrip. */ err = hexkeygrip_from_pk (sk, &keygrip); if (err) @@ -321,6 +329,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } + if (DBG_CLOCK) + log_clock ("decryption ready"); if (DBG_CIPHER) log_printhex ("DEK is:", dek->key, dek->keylen);