g10: Cache the effective policy. Recompute it when required.

* g10/tofu.c (initdb): Add column effective_policy to the bindings
table.
(record_binding): New parameters effective_policy and set_conflict.
Save the effective policy.  If SET_CONFLICT is set, then set conflict
according to CONFLICT.  Otherwise, preserve the current value of
conflict.  Update callers.
(get_trust): Don't compute the effective policy here...
(get_policy): ... do it here, if it was not cached.  Take new
parameters, PK, the public key, and NOW, the time that the operation
started.  Update callers.
(show_statistics): New parameter PK.  Pass it to get_policy.  Update
callers.
(tofu_notice_key_changed): New function.
* g10/gpgv.c (tofu_notice_key_changed): New stub.
* g10/import.c (import_revoke_cert): Take additional argument CTRL.
Pass it to keydb_update_keyblock.
* g10/keydb.c (keydb_update_keyblock): Take additional argument CTRL.
Update callers.
[USE_TOFU]: Call tofu_notice_key_changed.
* g10/test-stubs.c (tofu_notice_key_changed): New stub.
* tests/openpgp/tofu.scm: Assume that manually setting a binding's
policy to auto does not cause the tofu engine to forget about any
conflict.

--
Signed-off-by: Neal H. Walfield <neal@g10code.com>

We now store the computed policy in the tofu DB (in the
effective_policy column of the bindings table) to avoid computing it
every time, which is expensive.  Further, policy is never overridden
in case of a conflict.  Instead, we detect a conflict if CONFLICT is
not empty.

This change is backwards compatible to existing DBs.  The only minor
incompatibility is that unresolved conflicts won't be automatically
resolved in case we import a direct signature, or cross signatures.
This commit is contained in:
Neal H. Walfield 2016-11-21 22:47:30 +01:00
parent 182efc5b5d
commit 037f9de092
9 changed files with 559 additions and 379 deletions

View File

@ -713,3 +713,12 @@ tofu_end_batch_update (ctrl_t ctrl)
{
(void)ctrl;
}
gpg_error_t
tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
{
(void) ctrl;
(void) kb;
return 0;
}

View File

@ -111,7 +111,8 @@ static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
struct import_stats_s *stats, int batch,
unsigned int options, int for_migration,
import_screener_t screener, void *screener_arg);
static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
static int import_revoke_cert (ctrl_t ctrl,
kbnode_t node, struct import_stats_s *stats);
static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
static int delete_inv_parts (kbnode_t keyblock,
u32 *keyid, unsigned int options);
@ -562,7 +563,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
screener, screener_arg);
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert (keyblock, stats);
rc = import_revoke_cert (ctrl, keyblock, stats);
else
{
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@ -1642,7 +1643,7 @@ import_one (ctrl_t ctrl,
{
mod_key = 1;
/* KEYBLOCK_ORIG has been updated; write */
rc = keydb_update_keyblock (hd, keyblock_orig);
rc = keydb_update_keyblock (ctrl, hd, keyblock_orig);
if (rc)
log_error (_("error writing keyring '%s': %s\n"),
keydb_get_resource_name (hd), gpg_strerror (rc) );
@ -2288,7 +2289,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
* Import a revocation certificate; this is a single signature packet.
*/
static int
import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
{
PKT_public_key *pk = NULL;
kbnode_t onode;
@ -2379,7 +2380,7 @@ import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
insert_kbnode( keyblock, clone_kbnode(node), 0 );
/* and write the keyblock back */
rc = keydb_update_keyblock (hd, keyblock );
rc = keydb_update_keyblock (ctrl, hd, keyblock );
if (rc)
log_error (_("error writing keyring '%s': %s\n"),
keydb_get_resource_name (hd), gpg_strerror (rc) );

View File

@ -1518,7 +1518,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
* you should use keydb_push_found_state and keydb_pop_found_state to
* save and restore it. */
gpg_error_t
keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
{
gpg_error_t err;
PKT_public_key *pk;
@ -1542,6 +1542,10 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
if (err)
return err;
#ifdef USE_TOFU
tofu_notice_key_changed (ctrl, kb);
#endif
memset (&desc, 0, sizeof (desc));
fingerprint_from_pk (pk, desc.u.fpr, &len);
if (len == 20)

View File

@ -181,7 +181,7 @@ const char *keydb_get_resource_name (KEYDB_HANDLE hd);
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
/* Update the keyblock KB. */
gpg_error_t keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
/* Insert a keyblock into one of the underlying keyrings or keyboxes. */
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);

View File

@ -2782,7 +2782,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
case cmdSAVE:
if (modified)
{
err = keydb_update_keyblock (kdbhd, keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
@ -2936,7 +2936,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
{
err = keydb_update_keyblock (kdbhd, keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
@ -3039,7 +3039,7 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
gpg_strerror (err));
goto leave;
}
err = keydb_update_keyblock (kdbhd, keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
@ -3261,7 +3261,7 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
if (modified)
{
err = keydb_update_keyblock (kdbhd, keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
@ -3326,7 +3326,7 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
/* Store. */
if (modified)
{
err = keydb_update_keyblock (kdbhd, keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));

View File

@ -517,3 +517,12 @@ tofu_end_batch_update (ctrl_t ctrl)
{
(void)ctrl;
}
gpg_error_t
tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
{
(void) ctrl;
(void) kb;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -139,4 +139,9 @@ void tofu_end_batch_update (ctrl_t ctrl);
/* Release all of the resources associated with a DB meta-handle. */
void tofu_closedbs (ctrl_t ctrl);
/* Whenever a key is modified (e.g., a user id is added or revoked, a
* new signature, etc.), this function should be called to cause TOFU
* to update its world view. */
gpg_error_t tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb);
#endif /*G10_TOFU_H*/

View File

@ -20,7 +20,7 @@
(load (with-path "defs.scm"))
(setup-environment)
;; Redefine GPG without --always-trust and a fixed time.
;; Redefine GPG without --always-trust and a fixed time.
(define GPG `(,(tool 'gpg) --no-permission-warning
--faked-system-time=1466684990))
(define GNUPGHOME (getenv "GNUPGHOME"))
@ -141,20 +141,23 @@
'("auto" "good" "unknown" "bad" "ask"))))
'("good" "unknown" "bad"))
;; BC15C85A conflicts with 2183839A. On conflict, this will set
;; BC15C85A to ask. If 2183839A is auto (it's not, it's bad), then
;; it will be set to ask.
(call-check `(,@GPG --trust-model=tofu
--verify ,(in-srcdir "tofu-BC15C85A-1.txt")))
;; At the end, 2183839A's policy should be bad.
(checkpolicy "2183839A" "bad")
;; BC15C85A and 2183839A conflict. A policy setting of "auto"
;; (BC15C85A's state) will result in an effective policy of ask. But,
;; a policy setting of "bad" will result in an effective policy of
;; bad.
(setpolicy "BC15C85A" "auto")
(checkpolicy "BC15C85A" "ask")
(checkpolicy "2183839A" "bad")
;; EE37CF96 conflicts with 2183839A and BC15C85A. We change
;; BC15C85A's policy to auto and leave 2183839A's policy at bad.
;; This conflict should cause BC15C85A's policy to be changed to
;; ask (since it is auto), but not affect 2183839A's policy.
;; EE37CF96, 2183839A, and BC15C85A conflict. We change BC15C85A's
;; policy to auto and leave 2183839A's policy at bad. This conflict
;; should cause BC15C85A's policy to be changed to ask (since it is
;; auto), but not affect 2183839A's policy.
(setpolicy "BC15C85A" "auto")
(checkpolicy "BC15C85A" "auto")
(checkpolicy "BC15C85A" "ask")
(call-check `(,@GPG --trust-model=tofu
--verify ,(in-srcdir "tofu-EE37CF96-1.txt")))
(checkpolicy "BC15C85A" "ask")
@ -225,7 +228,8 @@
(checkpolicy KEYA "ask")
(checkpolicy KEYB "ask")
;; Import Alice's signature on the conflicting user id.
;; Import Alice's signature on the conflicting user id. Since there
;; is now a cross signature, we should revert to the default policy.
(display " > Adding cross signature on user id. ")
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYIDB "-4.gpg"))))
(verify-messages)