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:
parent
93e855553e
commit
f77913e0ff
26 changed files with 3508 additions and 80 deletions
186
g10/trustdb.c
186
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)
|
||||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue