1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

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 <neal@g10code.com>.
This commit is contained in:
Neal H. Walfield 2015-10-18 18:44:05 +02:00
parent 93e855553e
commit f77913e0ff
26 changed files with 3508 additions and 80 deletions

View file

@ -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)
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
{
tdbio_invalid ();
return 0;
}
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
/* 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);
if(uid)
fingerprint_from_pk (main_pk, fingerprint, &fingerprint_len);
assert (fingerprint_len == sizeof (fingerprint));
/* 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;
}
}
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)
{
tdbio_invalid ();
return 0;
}
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
/* No record found. */
validity = TRUST_UNKNOWN;
goto leave;
}
/* Loop over all user IDs */
recno = trec.r.trust.validlist;
validity = 0;
while (recno)
{
read_record (recno, &vrec, RECTYPE_VALID);
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
{
/* 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);
}
recno = vrec.r.valid.next;
pk->flags.disabled = 0;
pk->flags.disabled_valid = 1;
}
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;
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;