aboutsummaryrefslogtreecommitdiffstats
path: root/g10/trustdb.c
diff options
context:
space:
mode:
authorNeal H. Walfield <[email protected]>2015-10-18 16:44:05 +0000
committerNeal H. Walfield <[email protected]>2015-10-18 16:45:40 +0000
commitf77913e0ff7be4cd9c6337a70ac715e6f4a43572 (patch)
treed54aafd73b9f88111d953413c5e0b90c67a79239 /g10/trustdb.c
parentcommon: Prefix the mkdir functions with gnupg_. Make args const. (diff)
downloadgnupg-f77913e0ff7be4cd9c6337a70ac715e6f4a43572.tar.gz
gnupg-f77913e0ff7be4cd9c6337a70ac715e6f4a43572.zip
g10: Add TOFU support.
* configure.ac: Check for sqlite3. (SQLITE3_CFLAGS): AC_SUBST it. (SQLITE3_LIBS): Likewise. * g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS). (gpg2_SOURCES): Add tofu.h and tofu.c. (gpg2_LDADD): Add $(SQLITE3_LIBS). * g10/tofu.c: New file. * g10/tofu.h: New file. * g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP. (tofu_db_format): Define. * g10/packet.h (PKT_signature): Add fields digest and digest_len. * g10/gpg.c: Include "tofu.h". (cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy, oTOFUDBFormat. (opts): Add them. (parse_trust_model): Recognize the tofu and tofu+pgp trust models. (parse_tofu_policy): New function. (parse_tofu_db_format): New function. (main): Initialize opt.tofu_default_policy and opt.tofu_db_format. Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat. * g10/mainproc.c (do_check_sig): If the signature is good, copy the hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately. * g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update callers. (tdb_get_validity_core): Add arguments sig and may_ask. Update callers. * g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them to tdb_get_validity_core. * g10/trustdb.c: Include "tofu.h". (trust_model_string): Handle TM_TOFU and TM_TOFU_PGP. (tdb_get_validity_core): Add arguments sig and may_ask. If OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust level. Combine it with the computed PGP trust level, if appropriate. * g10/keyedit.c: Include "tofu.h". (show_key_with_all_names_colon): If the trust mode is tofu or tofu+pgp, then show the trust policy. * g10/keylist.c: Include "tofu.h". (public_key_list): Also show the PGP stats if the trust model is TM_TOFU_PGP. (list_keyblock_colon): If the trust mode is tofu or tofu+pgp, then show the trust policy. * g10/pkclist.c: Include "tofu.h". * g10/gpgv.c (get_validity): Add arguments sig and may_ask. (enum tofu_policy): Define. (tofu_get_policy): New stub. (tofu_policy_str): Likewise. * g10/test-stubs.c (get_validity): Add arguments sig and may_ask. (enum tofu_policy): Define. (tofu_get_policy): New stub. (tofu_policy_str): Likewise. * doc/DETAILS: Describe the TOFU Policy field. * doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu, --trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format. * tests/openpgp/Makefile.am (TESTS): Add tofu.test. (TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc, tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt. (CLEANFILES): Add tofu.db. (clean-local): Add tofu.d. * tests/openpgp/tofu.test: New file. * tests/openpgp/tofu-2183839A-1.txt: New file. * tests/openpgp/tofu-BC15C85A-1.txt: New file. * tests/openpgp/tofu-EE37CF96-1.txt: New file. * tests/openpgp/tofu-keys.asc: New file. * tests/openpgp/tofu-keys-secret.asc: New file. -- Signed-off-by: Neal H. Walfield <[email protected]>.
Diffstat (limited to 'g10/trustdb.c')
-rw-r--r--g10/trustdb.c180
1 files changed, 137 insertions, 43 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c
index b16682da1..170c04122 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -40,6 +40,7 @@
#include "i18n.h"
#include "tdbio.h"
#include "trustdb.h"
+#include "tofu.h"
typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
@@ -379,6 +380,8 @@ trust_model_string(void)
case TM_CLASSIC: return "classic";
case TM_PGP: return "PGP";
case TM_EXTERNAL: return "external";
+ case TM_TOFU: return "TOFU";
+ case TM_TOFU_PGP: return "TOFU+PGP";
case TM_ALWAYS: return "always";
case TM_DIRECT: return "direct";
default: return "unknown";
@@ -963,16 +966,21 @@ tdb_check_trustdb_stale (void)
/*
* Return the validity information for PK. This is the core of
- * get_validity.
+ * get_validity. If SIG is not NULL, then the trust is being
+ * evaluated in the context of the provided signature. This is used
+ * by the TOFU code to record statistics.
*/
unsigned int
tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
- PKT_public_key *main_pk)
+ PKT_public_key *main_pk,
+ PKT_signature *sig,
+ int may_ask)
{
TRUSTREC trec, vrec;
gpg_error_t err;
ulong recno;
- unsigned int validity;
+ unsigned int tofu_validity = TRUST_UNKNOWN;
+ unsigned int validity = TRUST_UNKNOWN;
init_trustdb ();
@@ -993,60 +1001,146 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
goto leave;
}
- err = read_trust_record (main_pk, &trec);
- if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
- {
- tdbio_invalid ();
- return 0;
- }
- if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
{
- /* No record found. */
- validity = TRUST_UNKNOWN;
- goto leave;
- }
+ kbnode_t user_id_node;
+ int user_ids = 0;
+ int user_ids_expired = 0;
- /* Loop over all user IDs */
- recno = trec.r.trust.validlist;
- validity = 0;
- while (recno)
- {
- read_record (recno, &vrec, RECTYPE_VALID);
+ char fingerprint[MAX_FINGERPRINT_LEN];
+ size_t fingerprint_len = sizeof (fingerprint);
+
+ fingerprint_from_pk (main_pk, fingerprint, &fingerprint_len);
+ assert (fingerprint_len == sizeof (fingerprint));
- if(uid)
+ /* If the caller didn't supply a user id then iterate over all
+ uids. */
+ if (! uid)
+ user_id_node = get_pubkeyblock (main_pk->keyid);
+
+ while (uid
+ || (user_id_node = find_next_kbnode (user_id_node, PKT_USER_ID)))
{
- /* If a user ID is given we return the validity for that
- user ID ONLY. If the namehash is not found, then there
- is no validity at all (i.e. the user ID wasn't
- signed). */
- if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+ unsigned int tl;
+ PKT_user_id *user_id;
+
+ if (uid)
+ user_id = uid;
+ else
+ user_id = user_id_node->pkt->pkt.user_id;
+
+ if (user_id->is_revoked || user_id->is_expired)
+ /* If the user id is revoked or expired, then skip it. */
{
- validity=(vrec.r.valid.validity & TRUST_MASK);
- break;
+ char *s;
+ if (user_id->is_revoked && user_id->is_expired)
+ s = "revoked and expired";
+ else if (user_id->is_revoked)
+ s = "revoked";
+ else
+ s = "expire";
+
+ log_info ("TOFU: Ignoring %s user id (%s)\n", s, user_id->name);
+
+ continue;
}
+
+ user_ids ++;
+
+ if (sig)
+ tl = tofu_register (fingerprint, user_id->name,
+ sig->digest, sig->digest_len,
+ sig->timestamp, "unknown",
+ may_ask);
+ else
+ tl = tofu_get_validity (fingerprint, user_id->name, may_ask);
+
+ if (tl == TRUST_EXPIRED)
+ user_ids_expired ++;
+ else if (tl == TRUST_UNDEFINED || tl == TRUST_UNKNOWN)
+ ;
+ else if (tl == TRUST_NEVER)
+ tofu_validity = TRUST_NEVER;
+ else
+ {
+ assert (tl == TRUST_MARGINAL
+ || tl == TRUST_FULLY
+ || tl == TRUST_ULTIMATE);
+
+ if (tl > tofu_validity)
+ /* XXX: We we really want the max? */
+ tofu_validity = tl;
+ }
+
+ if (uid)
+ /* If the caller specified a user id, then we stop
+ now. */
+ break;
}
- else
+ }
+
+ if (opt.trust_model == TM_TOFU_PGP
+ || opt.trust_model == TM_CLASSIC
+ || opt.trust_model == TM_PGP)
+ {
+ err = read_trust_record (main_pk, &trec);
+ if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
{
- /* If no namehash is given, we take the maximum validity
- over all user IDs */
- if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
- validity = (vrec.r.valid.validity & TRUST_MASK);
+ tdbio_invalid ();
+ return 0;
+ }
+ if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ {
+ /* No record found. */
+ validity = TRUST_UNKNOWN;
+ goto leave;
}
- recno = vrec.r.valid.next;
- }
+ /* Loop over all user IDs */
+ recno = trec.r.trust.validlist;
+ validity = 0;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
- if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
- {
- validity |= TRUST_FLAG_DISABLED;
- pk->flags.disabled = 1;
+ if(uid)
+ {
+ /* If a user ID is given we return the validity for that
+ user ID ONLY. If the namehash is not found, then
+ there is no validity at all (i.e. the user ID wasn't
+ signed). */
+ if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
+ {
+ validity=(vrec.r.valid.validity & TRUST_MASK);
+ break;
+ }
+ }
+ else
+ {
+ /* If no user ID is given, we take the maximum validity
+ over all user IDs */
+ if (validity < (vrec.r.valid.validity & TRUST_MASK))
+ validity = (vrec.r.valid.validity & TRUST_MASK);
+ }
+
+ recno = vrec.r.valid.next;
+ }
+
+ if ((trec.r.trust.ownertrust & TRUST_FLAG_DISABLED))
+ {
+ validity |= TRUST_FLAG_DISABLED;
+ pk->flags.disabled = 1;
+ }
+ else
+ pk->flags.disabled = 0;
+ pk->flags.disabled_valid = 1;
}
- else
- pk->flags.disabled = 0;
- pk->flags.disabled_valid = 1;
leave:
- if (pending_check_trustdb)
+ validity = tofu_wot_trust_combine (tofu_validity, validity);
+
+ if (opt.trust_model != TM_TOFU
+ && pending_check_trustdb)
validity |= TRUST_FLAG_PENDING_CHECK;
return validity;