aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <[email protected]>2016-11-22 14:05:59 +0000
committerNeal H. Walfield <[email protected]>2016-11-22 14:24:05 +0000
commit44c17bcb003a3330f595a6ab144e8439b7b630cb (patch)
treeb64a6ba54422757471166b2a54f0aa773412681d
parentscd: Fix receive buffer size. (diff)
downloadgnupg-44c17bcb003a3330f595a6ab144e8439b7b630cb.tar.gz
gnupg-44c17bcb003a3330f595a6ab144e8439b7b630cb.zip
g10: If the set of UTKs changes, invalidate any changed policies.
* g10/trustdb.c (tdb_utks): New function. * g10/tofu.c (check_utks): New function. (initdb): Call it. * tests/openpgp/tofu.scm: Modify test to check the effective policy of keys whose effective policy changes when we change the set of UTKs. -- Signed-off-by: Neal H. Walfield <[email protected]> If the set of ultimately trusted keys changes, then it is possible that a binding's effective policy changes. To deal with this, we detect when the set of ultimately trusted keys changes and invalidate all cached policies.
-rw-r--r--g10/tofu.c149
-rw-r--r--g10/trustdb.c7
-rw-r--r--g10/trustdb.h3
-rwxr-xr-xtests/openpgp/tofu.scm21
4 files changed, 180 insertions, 0 deletions
diff --git a/g10/tofu.c b/g10/tofu.c
index 6eb7f5e99..d7730a360 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -506,6 +506,152 @@ version_check_cb (void *cookie, int argc, char **argv, char **azColName)
return 1;
}
+static int
+check_utks (sqlite3 *db)
+{
+ int rc;
+ char *err = NULL;
+ struct key_item *utks;
+ struct key_item *ki;
+ int utk_count;
+ char *utks_string = NULL;
+ char keyid_str[16+1];
+ long utks_unchanged = 0;
+
+ /* An early version of the v1 format did not include the list of
+ * known ultimately trusted keys.
+ *
+ * This list is used to detect when the set of ultimately trusted
+ * keys changes. We need to detect this to invalidate the effective
+ * policy, which can change if an ultimately trusted key is added or
+ * removed. */
+ rc = sqlite3_exec (db,
+ "create table if not exists ultimately_trusted_keys"
+ " (keyid);\n",
+ NULL, NULL, &err);
+ if (rc)
+ {
+ log_error (_("error creating 'ultimately_trusted_keys' TOFU table: %s\n"),
+ err);
+ sqlite3_free (err);
+ goto out;
+ }
+
+
+ utks = tdb_utks ();
+ for (ki = utks, utk_count = 0; ki; ki = ki->next, utk_count ++)
+ ;
+
+ if (utk_count)
+ {
+ /* Build a list of keyids of the form "XXX","YYY","ZZZ". */
+ int len = (1 + 16 + 1 + 1) * utk_count;
+ int o = 0;
+
+ utks_string = xmalloc (len);
+ *utks_string = 0;
+ for (ki = utks, utk_count = 0; ki; ki = ki->next, utk_count ++)
+ {
+ utks_string[o ++] = '\'';
+ format_keyid (ki->kid, KF_LONG,
+ keyid_str, sizeof (keyid_str));
+ memcpy (&utks_string[o], keyid_str, 16);
+ o += 16;
+ utks_string[o ++] = '\'';
+ utks_string[o ++] = ',';
+ }
+ utks_string[o - 1] = 0;
+ log_assert (o == len);
+ }
+
+ rc = gpgsql_exec_printf
+ (db, get_single_unsigned_long_cb, &utks_unchanged, &err,
+ "select"
+ /* Removed UTKs? (Known UTKs in current UTKs.) */
+ " ((select count(*) from ultimately_trusted_keys"
+ " where (keyid in (%s))) == %d)"
+ " and"
+ /* New UTKs? */
+ " ((select count(*) from ultimately_trusted_keys"
+ " where keyid not in (%s)) == 0);",
+ utks_string ? utks_string : "",
+ utk_count,
+ utks_string ? utks_string : "");
+ xfree (utks_string);
+ if (rc)
+ {
+ log_error (_("TOFU DB error"));
+ print_further_info ("checking if ultimately trusted keys changed: %s",
+ err);
+ sqlite3_free (err);
+ goto out;
+ }
+
+ if (utks_unchanged)
+ goto out;
+
+ if (DBG_TRUST)
+ log_debug ("TOFU: ultimately trusted keys changed.\n");
+
+ /* Given that the set of ultimately trusted keys
+ * changed, clear any cached policies. */
+ rc = gpgsql_exec_printf
+ (db, NULL, NULL, &err,
+ "update bindings set effective_policy = %d;",
+ TOFU_POLICY_NONE);
+ if (rc)
+ {
+ log_error (_("TOFU DB error"));
+ print_further_info ("clearing cached policies: %s", err);
+ sqlite3_free (err);
+ goto out;
+ }
+
+ /* Now, update the UTK table. */
+ rc = sqlite3_exec (db,
+ "drop table ultimately_trusted_keys;",
+ NULL, NULL, &err);
+ if (rc)
+ {
+ log_error (_("TOFU DB error"));
+ print_further_info ("dropping ultimately_trusted_keys: %s", err);
+ sqlite3_free (err);
+ goto out;
+ }
+
+ rc = sqlite3_exec (db,
+ "create table if not exists"
+ " ultimately_trusted_keys (keyid);\n",
+ NULL, NULL, &err);
+ if (rc)
+ {
+ log_error (_("TOFU DB error"));
+ print_further_info ("creating ultimately_trusted_keys: %s", err);
+ sqlite3_free (err);
+ goto out;
+ }
+
+ for (ki = utks; ki; ki = ki->next)
+ {
+ format_keyid (ki->kid, KF_LONG,
+ keyid_str, sizeof (keyid_str));
+ rc = gpgsql_exec_printf
+ (db, NULL, NULL, &err,
+ "insert into ultimately_trusted_keys values ('%s');",
+ keyid_str);
+ if (rc)
+ {
+ log_error (_("TOFU DB error"));
+ print_further_info ("updating ultimately_trusted_keys: %s",
+ err);
+ sqlite3_free (err);
+ goto out;
+ }
+ }
+
+ out:
+ return rc;
+}
/* If the DB is new, initialize it. Otherwise, check the DB's
version.
@@ -727,6 +873,9 @@ initdb (sqlite3 *db)
}
}
+ if (! rc)
+ rc = check_utks (db);
+
if (rc)
{
rc = sqlite3_exec (db, "rollback;", NULL, NULL, &err);
diff --git a/g10/trustdb.c b/g10/trustdb.c
index edae6ef45..51a8f2217 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -324,6 +324,13 @@ tdb_keyid_is_utk (u32 *kid)
return 0;
}
+
+/* Return the list of ultimately trusted keys. */
+struct key_item *
+tdb_utks (void)
+{
+ return utk_list;
+}
/*********************************************
*********** TrustDB stuff *******************
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 77aa79da6..45ecc56ab 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -117,6 +117,9 @@ void tdb_register_trusted_keyid (u32 *keyid);
void tdb_register_trusted_key (const char *string);
/* Returns whether KID is on the list of ultimately trusted keys. */
int tdb_keyid_is_utk (u32 *kid);
+/* Return the list of ultimately trusted keys. The caller must not
+ * modify this list nor must it free the list. */
+struct key_item *tdb_utks (void);
void check_trustdb (ctrl_t ctrl);
void update_trustdb (ctrl_t ctrl);
int setup_trustdb( int level, const char *dbname );
diff --git a/tests/openpgp/tofu.scm b/tests/openpgp/tofu.scm
index 2a04d13a2..e1fa00191 100755
--- a/tests/openpgp/tofu.scm
+++ b/tests/openpgp/tofu.scm
@@ -248,6 +248,21 @@
;; Alice has an ultimately trusted key and she signs Bob's key. Then
;; Bob adds a new user id, "Alice". TOFU should now detect a
;; conflict, because Alice only signed Bob's "Bob" user id.
+;;
+;;
+;; The Alice key:
+;; pub rsa2048 2016-10-11 [SC]
+;; 1938C3A0E4674B6C217AC0B987DB2814EC38277E
+;; uid [ultimate] Spy Cow <[email protected]>
+;; sub rsa2048 2016-10-11 [E]
+;;
+;; The Bob key:
+;;
+;; pub rsa2048 2016-10-11 [SC]
+;; DC463A16E42F03240D76E8BA8B48C6BD871C2247
+;; uid [ full ] Spy R. Cow <[email protected]>
+;; uid [ full ] Spy R. Cow <[email protected]>
+;; sub rsa2048 2016-10-11 [E]
(display "Checking UTK sigs...\n")
(define GPG `(,(tool 'gpg) --no-permission-warning
@@ -279,12 +294,18 @@
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYIDB "-1.gpg"))))
(display "<\n")
+(checkpolicy KEYA "auto")
+(checkpolicy KEYB "auto")
+
;; Import the cross sigs.
(display " > Adding cross signatures. ")
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYIDA "-2.gpg"))))
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYIDB "-2.gpg"))))
(display "<\n")
+(checkpolicy KEYA "auto")
+(checkpolicy KEYB "auto")
+
;; Make KEYA ultimately trusted.
(display (string-append " > Marking " KEYA " as ultimately trusted. "))
(pipe:do