mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-02 12:01:32 +01: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
@ -780,6 +780,12 @@ DL_LIBS=$LIBS
|
||||
AC_SUBST(DL_LIBS)
|
||||
LIBS="$gnupg_dlopen_save_libs"
|
||||
|
||||
# Checks for g10
|
||||
|
||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
||||
AC_SUBST(SQLITE3_CFLAGS)
|
||||
AC_SUBST(SQLITE3_LIBS)
|
||||
|
||||
# Checks for g13
|
||||
|
||||
AC_PATH_PROG(ENCFS, encfs, /usr/bin/encfs)
|
||||
|
@ -206,6 +206,10 @@ described here.
|
||||
|
||||
For pub, sub, sec, and ssb records this field is used for the ECC
|
||||
curve name.
|
||||
*** Field 18 - TOFU Policy
|
||||
|
||||
This is the TOFU policy. It is either good, bad, unknown, ask or
|
||||
auto. This is only shows for uid records.
|
||||
|
||||
** Special fields
|
||||
|
||||
|
@ -35,7 +35,8 @@ Published by The GnuPG Project@*
|
||||
@end iftex
|
||||
|
||||
@copyright{} 2002, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.@*
|
||||
@copyright{} 2013, 2014, 2015 Werner Koch.
|
||||
@copyright{} 2013, 2014, 2015 Werner Koch.@*
|
||||
@copyright{} 2015 g10code Gmbh.
|
||||
|
||||
@quotation
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
|
91
doc/gpg.texi
91
doc/gpg.texi
@ -525,6 +525,12 @@ Use the source, Luke :-). The output format is still subject to change.
|
||||
Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor.
|
||||
This is a GnuPG extension to OpenPGP and in general not very useful.
|
||||
|
||||
@item --tofu-set-policy @code{auto|good|unknown|bad|ask} @code{key...}
|
||||
@opindex tofu-set-policy
|
||||
Set the TOFU policy for all the bindings associated with the specified
|
||||
keys. For more information about the meaning of the policies,
|
||||
@pxref{trust-model-tofu}. The keys may be specified either by their
|
||||
fingerprint (preferred) or their keyid.
|
||||
|
||||
@c @item --server
|
||||
@c @opindex server
|
||||
@ -1408,7 +1414,7 @@ don't want to keep your secret keys (or one of them)
|
||||
online but still want to be able to check the validity of a given
|
||||
recipient's or signator's key.
|
||||
|
||||
@item --trust-model @code{pgp|classic|direct|always|auto}
|
||||
@item --trust-model @code{pgp|classic|tofu|tofu+pgp|direct|always|auto}
|
||||
@opindex trust-model
|
||||
Set what trust model GnuPG should follow. The models are:
|
||||
|
||||
@ -1424,6 +1430,65 @@ Set what trust model GnuPG should follow. The models are:
|
||||
@opindex trust-mode:classic
|
||||
This is the standard Web of Trust as introduced by PGP 2.
|
||||
|
||||
@item tofu
|
||||
@opindex trust-mode:tofu
|
||||
@anchor{trust-model-tofu}
|
||||
TOFU stands for Trust On First Use. In this trust model, the first
|
||||
time a key is seen, it is memorized. If later another key is seen
|
||||
with a user id with the same email address, a warning is displayed
|
||||
indicating that there is a conflict and that the key might be a
|
||||
forgery and an attempt at a man-in-the-middle attack.
|
||||
|
||||
Because a potential attacker is able to control the email address
|
||||
and thereby circumvent the conflict detection algorithm by using an
|
||||
email address that is similar in appearance to a trusted email
|
||||
address, whenever a message is verified, statistics about the number
|
||||
of messages signed with the key are shown. In this way, a user can
|
||||
easily identify attacks using fake keys for regular correspondents.
|
||||
|
||||
When compared with the Web of Trust, TOFU offers significantly
|
||||
weaker security guarantees. In particular, TOFU only helps ensure
|
||||
consistency (that is, that the binding between a key and email
|
||||
address doesn't change). A major advantage of TOFU is that it
|
||||
requires little maintenance to use correctly. To use the web of
|
||||
trust properly, you need to actively sign keys and mark users as
|
||||
trusted introducers. This is a time-consuming process and anecdotal
|
||||
evidence suggests that even security-conscious users rarely take the
|
||||
time to do this thoroughly and instead rely on an ad-hoc TOFU
|
||||
process.
|
||||
|
||||
In the TOFU model, policies are associated with bindings between
|
||||
keys and email addresses (which are extracted from user ids and
|
||||
normalized). There are five policies, which can be set manually
|
||||
using the @option{--tofu-policy} option. The default policy can be
|
||||
set using the @option{--tofu-default-policy} policy.
|
||||
|
||||
The TOFU policies are: @code{auto}, @code{good}, @code{unknown},
|
||||
@code{bad} and @code{ask}. The @code{auto} policy is used by
|
||||
default (unless overridden by @option{--tofu-default-policy}) and
|
||||
marks a binding as marginally trusted. The @code{good},
|
||||
@code{unknown} and @code{bad} policies mark a binding as fully
|
||||
trusted, as having unknown trust or as having trust never,
|
||||
respectively. The @code{unknown} policy is useful for just using
|
||||
TOFU to detect conflicts, but to never assign positive trust to a
|
||||
binding. The final policy, @code{ask} prompts the user to indicate
|
||||
the binding's trust. If batch mode is enabled (or input is
|
||||
inappropriate in the context), then the user is not prompted and the
|
||||
@code{undefined} trust level is returned.
|
||||
|
||||
@item tofu+pgp
|
||||
@opindex trust-mode:tofu+pgp
|
||||
This trust model combines TOFU with the Web of Trust. This is done
|
||||
by computing the trust level for each model and then taking the
|
||||
maximum trust level where the trust levels are ordered as follows:
|
||||
@code{unknown < undefined < marginal < fully < ultimate < expired <
|
||||
never}.
|
||||
|
||||
By setting @option{--tofu-default-policy=unknown}, this model can be
|
||||
used to implement the web of trust with TOFU's conflict detection
|
||||
algorithm, but without its assignment of positive trust values,
|
||||
which some security-conscious users don't like.
|
||||
|
||||
@item direct
|
||||
@opindex trust-mode:direct
|
||||
Key validity is set directly by the user and not calculated via the
|
||||
@ -1625,6 +1690,30 @@ key signer (defaults to 1).
|
||||
Number of marginally trusted users to introduce a new
|
||||
key signer (defaults to 3)
|
||||
|
||||
@item --tofu-default-policy @code{auto|good|unknown|bad|ask}
|
||||
@opindex tofu-default-policy
|
||||
The default TOFU policy (defaults to @code{auto}). For more
|
||||
information about the meaning of this option, @xref{trust-model-tofu}.
|
||||
|
||||
@item --tofu-db-format @code{auto|split|flat}
|
||||
@opindex tofu-default-policy
|
||||
The format for the TOFU DB.
|
||||
|
||||
The split file format splits the data across many DBs under the
|
||||
@code{tofu.d} directory (one per email address and one per key). This
|
||||
makes it easier to automatically synchronize the data using a tool
|
||||
such as Unison (@url{https://www.cis.upenn.edu/~bcpierce/unison/}),
|
||||
since the individual files change rarely.
|
||||
|
||||
The flat file format keeps all of the data in the single file
|
||||
@code{tofu.db}. This format results in better performance.
|
||||
|
||||
If set to auto (which is the default), GnuPG will first check for the
|
||||
existence of @code{tofu.d} and @code{tofu.db}. If one of these
|
||||
exists, the corresponding format is used. If neither or both of these
|
||||
exist, then GnuPG defaults to the @code{split} format. In the latter
|
||||
case, a warning is emitted.
|
||||
|
||||
@item --max-cert-depth @code{n}
|
||||
@opindex max-cert-depth
|
||||
Maximum depth of a certification chain (default is 5).
|
||||
|
@ -26,7 +26,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/common
|
||||
|
||||
include $(top_srcdir)/am/cmacros.am
|
||||
|
||||
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \
|
||||
AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
|
||||
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||
|
||||
needed_libs = ../kbx/libkeybox.a $(libcommon)
|
||||
@ -126,7 +126,8 @@ gpg2_SOURCES = gpg.c \
|
||||
call-agent.c call-agent.h \
|
||||
trust.c $(trust_source) \
|
||||
$(card_source) \
|
||||
exec.c exec.h
|
||||
exec.c exec.h \
|
||||
tofu.h tofu.c
|
||||
|
||||
gpgv2_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
@ -141,7 +142,7 @@ gpgv2_SOURCES = gpgv.c \
|
||||
|
||||
LDADD = $(needed_libs) ../common/libgpgrl.a \
|
||||
$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
|
||||
gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
|
||||
gpg2_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
|
||||
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
|
||||
gpg2_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
140
g10/gpg.c
140
g10/gpg.c
@ -59,6 +59,7 @@
|
||||
#include "gc-opt-flags.h"
|
||||
#include "asshelp.h"
|
||||
#include "call-dirmngr.h"
|
||||
#include "tofu.h"
|
||||
#include "../common/init.h"
|
||||
#include "../common/shareddefs.h"
|
||||
|
||||
@ -162,6 +163,7 @@ enum cmd_and_opt_values
|
||||
aChangePIN,
|
||||
aPasswd,
|
||||
aServer,
|
||||
aTOFUPolicy,
|
||||
|
||||
oTextmode,
|
||||
oNoTextmode,
|
||||
@ -385,6 +387,8 @@ enum cmd_and_opt_values
|
||||
oNoAutostart,
|
||||
oPrintPKARecords,
|
||||
oPrintDANERecords,
|
||||
oTOFUDefaultPolicy,
|
||||
oTOFUDBFormat,
|
||||
|
||||
oNoop
|
||||
};
|
||||
@ -475,6 +479,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_c (aPrimegen, "gen-prime", "@" ),
|
||||
ARGPARSE_c (aGenRandom,"gen-random", "@" ),
|
||||
ARGPARSE_c (aServer, "server", N_("run in server mode")),
|
||||
ARGPARSE_c (aTOFUPolicy, "tofu-policy",
|
||||
N_("|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)")),
|
||||
|
||||
ARGPARSE_group (301, N_("@\nOptions:\n ")),
|
||||
|
||||
@ -670,6 +676,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
|
||||
ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
|
||||
ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
|
||||
ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
|
||||
ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
|
||||
ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
|
||||
ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
|
||||
ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"),
|
||||
@ -1939,6 +1947,10 @@ parse_trust_model(const char *model)
|
||||
opt.trust_model=TM_ALWAYS;
|
||||
else if(ascii_strcasecmp(model,"direct")==0)
|
||||
opt.trust_model=TM_DIRECT;
|
||||
else if(ascii_strcasecmp(model,"tofu")==0)
|
||||
opt.trust_model=TM_TOFU;
|
||||
else if(ascii_strcasecmp(model,"tofu+pgp")==0)
|
||||
opt.trust_model=TM_TOFU_PGP;
|
||||
else if(ascii_strcasecmp(model,"auto")==0)
|
||||
opt.trust_model=TM_AUTO;
|
||||
else
|
||||
@ -1946,6 +1958,41 @@ parse_trust_model(const char *model)
|
||||
}
|
||||
#endif /*NO_TRUST_MODELS*/
|
||||
|
||||
static int
|
||||
parse_tofu_policy (const char *policy)
|
||||
{
|
||||
if (ascii_strcasecmp (policy, "auto") == 0)
|
||||
return TOFU_POLICY_AUTO;
|
||||
else if (ascii_strcasecmp (policy, "good") == 0)
|
||||
return TOFU_POLICY_GOOD;
|
||||
else if (ascii_strcasecmp (policy, "unknown") == 0)
|
||||
return TOFU_POLICY_UNKNOWN;
|
||||
else if (ascii_strcasecmp (policy, "bad") == 0)
|
||||
return TOFU_POLICY_BAD;
|
||||
else if (ascii_strcasecmp (policy, "ask") == 0)
|
||||
return TOFU_POLICY_ASK;
|
||||
else
|
||||
{
|
||||
log_error (_("unknown TOFU policy '%s'\n"), policy);
|
||||
g10_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
parse_tofu_db_format (const char *db_format)
|
||||
{
|
||||
if (ascii_strcasecmp (db_format, "auto") == 0)
|
||||
return TOFU_DB_AUTO;
|
||||
else if (ascii_strcasecmp (db_format, "split") == 0)
|
||||
return TOFU_DB_SPLIT;
|
||||
else if (ascii_strcasecmp (db_format, "flat") == 0)
|
||||
return TOFU_DB_FLAT;
|
||||
else
|
||||
{
|
||||
log_error (_("unknown TOFU DB format '%s'\n"), db_format);
|
||||
g10_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* This fucntion called to initialized a new control object. It is
|
||||
assumed that this object has been zeroed out before calling this
|
||||
@ -2150,6 +2197,8 @@ main (int argc, char **argv)
|
||||
#else
|
||||
opt.trust_model = TM_AUTO;
|
||||
#endif
|
||||
opt.tofu_default_policy = TOFU_POLICY_AUTO;
|
||||
opt.tofu_db_format = TOFU_DB_AUTO;
|
||||
opt.mangle_dos_filenames = 0;
|
||||
opt.min_cert_level = 2;
|
||||
set_screen_dimensions ();
|
||||
@ -2372,6 +2421,10 @@ main (int argc, char **argv)
|
||||
opt.batch = 1;
|
||||
break;
|
||||
|
||||
case aTOFUPolicy:
|
||||
set_cmd (&cmd, pargs.r_opt);
|
||||
break;
|
||||
|
||||
case oArmor: opt.armor = 1; opt.no_armor=0; break;
|
||||
case oOutput: opt.outfile = pargs.r.ret_str; break;
|
||||
case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
|
||||
@ -2553,6 +2606,12 @@ main (int argc, char **argv)
|
||||
parse_trust_model(pargs.r.ret_str);
|
||||
break;
|
||||
#endif /*!NO_TRUST_MODELS*/
|
||||
case oTOFUDefaultPolicy:
|
||||
opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
|
||||
break;
|
||||
case oTOFUDBFormat:
|
||||
opt.tofu_db_format = parse_tofu_db_format (pargs.r.ret_str);
|
||||
break;
|
||||
|
||||
case oForceOwnertrust:
|
||||
log_info(_("Note: %s is not for normal use!\n"),
|
||||
@ -4351,6 +4410,87 @@ main (int argc, char **argv)
|
||||
gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
|
||||
break;
|
||||
|
||||
case aTOFUPolicy:
|
||||
{
|
||||
int policy;
|
||||
int i;
|
||||
KEYDB_HANDLE hd;
|
||||
|
||||
if (argc < 2)
|
||||
wrong_args("--tofu-policy POLICY KEYID [KEYID...]");
|
||||
|
||||
policy = parse_tofu_policy (argv[0]);
|
||||
|
||||
hd = keydb_new ();
|
||||
if (! hd)
|
||||
{
|
||||
log_error (_("Failed to open the keyring DB.\n"));
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i ++)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
kbnode_t kb;
|
||||
|
||||
rc = classify_user_id (argv[i], &desc, 0);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("Failed to parse '%s'.\n"), argv[i]);
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
|
||||
|| desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|
||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|
||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|
||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR
|
||||
|| desc.mode == KEYDB_SEARCH_MODE_KEYGRIP))
|
||||
{
|
||||
log_error (_("'%s' does not appear to be a valid"
|
||||
" key id, fingerprint or key grip.\n"),
|
||||
argv[i]);
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
rc = keydb_search_reset (hd);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("Failed to reset keyring handle.\n"));
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
rc = keydb_search (hd, &desc, 1, NULL);
|
||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
||||
{
|
||||
log_error (_("Key '%s' is not available\n"), argv[i]);
|
||||
g10_exit (1);
|
||||
}
|
||||
else if (rc)
|
||||
{
|
||||
log_error (_("Failed to find key '%s'\n"), argv[i]);
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (hd, &kb);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("Failed to read key '%s' from the keyring\n"),
|
||||
argv[i]);
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
merge_keys_and_selfsig (kb);
|
||||
|
||||
if (tofu_set_policy (kb, policy))
|
||||
g10_exit (1);
|
||||
}
|
||||
|
||||
keydb_release (hd);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case aListPackets:
|
||||
opt.list_packets=2;
|
||||
default:
|
||||
|
28
g10/gpgv.c
28
g10/gpgv.c
@ -285,10 +285,13 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
|
||||
int may_ask)
|
||||
{
|
||||
(void)pk;
|
||||
(void)uid;
|
||||
(void)sig;
|
||||
(void)may_ask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -606,3 +609,26 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
|
||||
*r_datalen = 0;
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
enum tofu_policy
|
||||
{
|
||||
tofu_policy
|
||||
};
|
||||
|
||||
gpg_error_t
|
||||
tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
|
||||
enum tofu_policy *policy)
|
||||
{
|
||||
(void)pk;
|
||||
(void)user_id;
|
||||
(void)policy;
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
|
||||
const char *
|
||||
tofu_policy_str (enum tofu_policy policy)
|
||||
{
|
||||
(void)policy;
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "keyserver-internal.h"
|
||||
#include "call-agent.h"
|
||||
#include "host2net.h"
|
||||
#include "tofu.h"
|
||||
|
||||
static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
|
||||
int verbose);
|
||||
@ -2927,6 +2928,14 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
|
||||
if ((node->flag & NODFLG_MARK_A))
|
||||
es_putc ('m', fp);
|
||||
es_putc (':', fp);
|
||||
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
|
||||
{
|
||||
enum tofu_policy policy;
|
||||
if (! tofu_get_policy (primary, uid, &policy)
|
||||
&& policy != TOFU_POLICY_NONE)
|
||||
es_fprintf (fp, "%s", tofu_policy_str (policy));
|
||||
}
|
||||
es_putc (':', fp);
|
||||
es_putc ('\n', fp);
|
||||
}
|
||||
}
|
||||
@ -3042,7 +3051,8 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
|
||||
|
||||
/* Show a warning once */
|
||||
if (!did_warn
|
||||
&& (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK))
|
||||
&& (get_validity (pk, NULL, NULL, 0)
|
||||
& TRUST_FLAG_PENDING_CHECK))
|
||||
{
|
||||
did_warn = 1;
|
||||
do_warn = 1;
|
||||
@ -5334,7 +5344,7 @@ menu_revuid (KBNODE pub_keyblock)
|
||||
/* If the trustdb has an entry for this key+uid then the
|
||||
trustdb needs an update. */
|
||||
if (!update_trust
|
||||
&& (get_validity (pk, uid) & TRUST_MASK) >=
|
||||
&& (get_validity (pk, uid, NULL, 0) & TRUST_MASK) >=
|
||||
TRUST_UNDEFINED)
|
||||
update_trust = 1;
|
||||
#endif /*!NO_TRUST_MODELS*/
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "status.h"
|
||||
#include "call-agent.h"
|
||||
#include "mbox-util.h"
|
||||
#include "tofu.h"
|
||||
|
||||
|
||||
static void list_all (ctrl_t, int, int);
|
||||
@ -99,7 +100,8 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
|
||||
es_fprintf (es_stdout, "o");
|
||||
if (trust_model != opt.trust_model)
|
||||
es_fprintf (es_stdout, "t");
|
||||
if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC)
|
||||
if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC
|
||||
|| opt.trust_model == TM_TOFU_PGP)
|
||||
{
|
||||
if (marginals != opt.marginals_needed)
|
||||
es_fprintf (es_stdout, "m");
|
||||
@ -1067,7 +1069,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
|
||||
include, but it looks sort of confusing in the listing... */
|
||||
if (opt.list_options & LIST_SHOW_VALIDITY)
|
||||
{
|
||||
int validity = get_validity (pk, NULL);
|
||||
int validity = get_validity (pk, NULL, NULL, 0);
|
||||
es_fprintf (es_stdout, " [%s]", trust_value_to_string (validity));
|
||||
}
|
||||
#endif
|
||||
@ -1438,6 +1440,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
|
||||
xfree (curve);
|
||||
}
|
||||
es_putc (':', es_stdout); /* End of field 17. */
|
||||
es_putc (':', es_stdout); /* End of field 18. */
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
print_revokers (es_stdout, pk);
|
||||
@ -1495,6 +1498,14 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
|
||||
es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len);
|
||||
else
|
||||
es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
|
||||
es_fprintf (es_stdout, "::::::::");
|
||||
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
|
||||
{
|
||||
enum tofu_policy policy;
|
||||
if (! tofu_get_policy (pk, uid, &policy)
|
||||
&& policy != TOFU_POLICY_NONE)
|
||||
es_fprintf (es_stdout, "%s", tofu_policy_str (policy));
|
||||
}
|
||||
es_putc (':', es_stdout);
|
||||
es_putc ('\n', es_stdout);
|
||||
}
|
||||
|
@ -851,6 +851,7 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
|
||||
PKT_signature *sig;
|
||||
gcry_md_hd_t md = NULL;
|
||||
gcry_md_hd_t md2 = NULL;
|
||||
gcry_md_hd_t md_good = NULL;
|
||||
int algo, rc;
|
||||
|
||||
assert (node->pkt->pkttype == PKT_SIGNATURE);
|
||||
@ -926,8 +927,21 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
|
||||
return GPG_ERR_SIG_CLASS;
|
||||
|
||||
rc = signature_check2 (sig, md, NULL, is_expkey, is_revkey, NULL);
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
|
||||
rc = signature_check2 (sig, md2, NULL, is_expkey, is_revkey, NULL);
|
||||
if (! rc)
|
||||
md_good = md;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2)
|
||||
{
|
||||
rc = signature_check2 (sig, md2, NULL, is_expkey, is_revkey, NULL);
|
||||
if (! rc)
|
||||
md_good = md2;
|
||||
}
|
||||
|
||||
if (md_good)
|
||||
{
|
||||
unsigned char *buffer = gcry_md_read (md_good, 0);
|
||||
sig->digest_len = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (algo));
|
||||
memcpy (sig->digest, buffer, sig->digest_len);
|
||||
}
|
||||
|
||||
gcry_md_close (md);
|
||||
gcry_md_close (md2);
|
||||
@ -1848,9 +1862,10 @@ check_sig_and_print (CTX c, kbnode_t node)
|
||||
|
||||
assert (pk);
|
||||
|
||||
/* Get it before we print anything to avoid interrupting the
|
||||
output with the "please do a --check-trustdb" line. */
|
||||
valid = get_validity (pk, un->pkt->pkt.user_id);
|
||||
/* Since this is just informational, don't actually ask the
|
||||
user to update any trust information. (Note: we register
|
||||
the signature later.) */
|
||||
valid = get_validity (pk, un->pkt->pkt.user_id, NULL, 0);
|
||||
|
||||
keyid_str[17] = 0; /* cut off the "[uncertain]" part */
|
||||
|
||||
@ -1939,8 +1954,11 @@ check_sig_and_print (CTX c, kbnode_t node)
|
||||
else if (un->pkt->pkt.user_id->is_expired)
|
||||
valid = _("expired");
|
||||
else
|
||||
/* Since this is just informational, don't
|
||||
actually ask the user to update any trust
|
||||
information. */
|
||||
valid = (trust_value_to_string
|
||||
(get_validity (pk, un->pkt->pkt.user_id)));
|
||||
(get_validity (pk, un->pkt->pkt.user_id, sig, 0)));
|
||||
log_printf (" [%s]\n",valid);
|
||||
}
|
||||
else
|
||||
|
@ -118,8 +118,16 @@ struct
|
||||
we started storing the trust model inside the trustdb. */
|
||||
enum
|
||||
{
|
||||
TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2, TM_ALWAYS, TM_DIRECT, TM_AUTO
|
||||
TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2,
|
||||
TM_ALWAYS, TM_DIRECT, TM_AUTO, TM_TOFU, TM_TOFU_PGP
|
||||
} trust_model;
|
||||
enum
|
||||
{
|
||||
TOFU_DB_AUTO=0, TOFU_DB_SPLIT, TOFU_DB_FLAT
|
||||
} tofu_db_format;
|
||||
/* TOFU_BINDING_BAD, TOFU_BINDING_ASK, TOFU_BINDING_AUTO, or
|
||||
TOFU_BINDING_GOOD. */
|
||||
int tofu_default_policy;
|
||||
int force_ownertrust;
|
||||
enum
|
||||
{
|
||||
|
@ -175,6 +175,11 @@ typedef struct
|
||||
subpktarea_t *unhashed; /* Ditto for unhashed data. */
|
||||
byte digest_start[2]; /* First 2 bytes of the digest. */
|
||||
gcry_mpi_t data[PUBKEY_MAX_NSIG];
|
||||
/* The message digest and its length (in bytes). Note the maximum
|
||||
digest length is 512 bits (64 bytes). If DIGEST_LEN is 0, then
|
||||
the digest's value has not been saved here. */
|
||||
byte digest[512 / 8];
|
||||
int digest_len;
|
||||
} PKT_signature;
|
||||
|
||||
#define ATTRIB_IMAGE 1
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "status.h"
|
||||
#include "photoid.h"
|
||||
#include "i18n.h"
|
||||
#include "tofu.h"
|
||||
|
||||
#define CONTROL_D ('D' - 'A' + 1)
|
||||
|
||||
@ -507,13 +508,13 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
|
||||
|
||||
/****************
|
||||
* Check whether we can trust this signature.
|
||||
* Returns: Error if we shall not trust this signatures.
|
||||
* Returns an error code if we should not trust this signature.
|
||||
*/
|
||||
int
|
||||
check_signatures_trust( PKT_signature *sig )
|
||||
{
|
||||
PKT_public_key *pk = xmalloc_clear( sizeof *pk );
|
||||
unsigned int trustlevel;
|
||||
unsigned int trustlevel = TRUST_UNKNOWN;
|
||||
int rc=0;
|
||||
|
||||
rc = get_pubkey( pk, sig->keyid );
|
||||
@ -537,7 +538,7 @@ check_signatures_trust( PKT_signature *sig )
|
||||
log_info(_("WARNING: this key might be revoked (revocation key"
|
||||
" not present)\n"));
|
||||
|
||||
trustlevel = get_validity (pk, NULL);
|
||||
trustlevel = get_validity (pk, NULL, sig, 1);
|
||||
|
||||
if ( (trustlevel & TRUST_FLAG_REVOKED) )
|
||||
{
|
||||
@ -829,7 +830,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
||||
}
|
||||
|
||||
/* Key found and usable. Check validity. */
|
||||
trustlevel = get_validity (pk, pk->user_id);
|
||||
trustlevel = get_validity (pk, pk->user_id, NULL, 1);
|
||||
if ( (trustlevel & TRUST_FLAG_DISABLED) )
|
||||
{
|
||||
/* Key has been disabled. */
|
||||
@ -1114,7 +1115,7 @@ build_pk_list (ctrl_t ctrl,
|
||||
{ /* Check validity of this key. */
|
||||
int trustlevel;
|
||||
|
||||
trustlevel = get_validity (pk, pk->user_id);
|
||||
trustlevel = get_validity (pk, pk->user_id, NULL, 1);
|
||||
if ( (trustlevel & TRUST_FLAG_DISABLED) )
|
||||
{
|
||||
tty_printf (_("Public key is disabled.\n") );
|
||||
|
@ -104,10 +104,13 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
|
||||
int may_ask)
|
||||
{
|
||||
(void)pk;
|
||||
(void)uid;
|
||||
(void)sig;
|
||||
(void)may_ask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -425,3 +428,26 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
|
||||
*r_datalen = 0;
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
enum tofu_policy
|
||||
{
|
||||
tofu_policy
|
||||
};
|
||||
|
||||
gpg_error_t
|
||||
tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
|
||||
enum tofu_policy *policy)
|
||||
{
|
||||
(void)pk;
|
||||
(void)user_id;
|
||||
(void)policy;
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
|
||||
const char *
|
||||
tofu_policy_str (enum tofu_policy policy)
|
||||
{
|
||||
(void)policy;
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
2472
g10/tofu.c
Normal file
2472
g10/tofu.c
Normal file
File diff suppressed because it is too large
Load Diff
105
g10/tofu.h
Normal file
105
g10/tofu.h
Normal file
@ -0,0 +1,105 @@
|
||||
/* tofu.h - TOFU trust model.
|
||||
* Copyright (C) 2015 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef G10_TOFU_H
|
||||
#define G10_TOFU_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* For each binding, we have a trust policy. */
|
||||
enum tofu_policy
|
||||
{
|
||||
/* This value can be returned by tofu_get_policy to indicate that
|
||||
there is no policy set for the specified binding. */
|
||||
TOFU_POLICY_NONE = 0,
|
||||
|
||||
/* We made a default policy decision. This is only done if there
|
||||
is no conflict with another binding (that is, the email address
|
||||
is not part of another known key). The default policy is
|
||||
configurable (and specified using: --tofu-default-policy).
|
||||
|
||||
Note: when using the default policy, we save TOFU_POLICY_AUTO
|
||||
with the binding, not the policy that was in effect. This way,
|
||||
if the user invokes gpg again, but with a different value for
|
||||
--tofu-default-policy, a different decision is made. */
|
||||
TOFU_POLICY_AUTO = 1,
|
||||
|
||||
/* The user explicitly marked the binding as good. In this case,
|
||||
we return TRUST_FULLY. */
|
||||
TOFU_POLICY_GOOD = 2,
|
||||
|
||||
/* The user explicitly marked the binding as unknown. In this
|
||||
case, we return TRUST_UNKNOWN. */
|
||||
TOFU_POLICY_UNKNOWN = 3,
|
||||
|
||||
/* The user explicitly marked the binding as bad. In this case,
|
||||
we always return TRUST_NEVER. */
|
||||
TOFU_POLICY_BAD = 4,
|
||||
|
||||
/* The user deferred a definitive policy decision about the
|
||||
binding (by selecting accept once or reject once). The next
|
||||
time we see this binding, we should ask the user what to
|
||||
do. */
|
||||
TOFU_POLICY_ASK = 5
|
||||
};
|
||||
|
||||
/* Return a string representation of a trust policy. Returns "???" if
|
||||
POLICY is not valid. */
|
||||
const char *tofu_policy_str (enum tofu_policy policy);
|
||||
|
||||
/* Convert a binding policy (e.g., TOFU_POLICY_BAD) to a trust level
|
||||
(e.g., TRUST_BAD) in light of the current configuration. */
|
||||
int tofu_policy_to_trust_level (enum tofu_policy policy);
|
||||
|
||||
/* Register the binding <FINGERPRINT, USER_ID> and the signature
|
||||
described by SIGS_DIGEST and SIG_TIME, which it generated. Origin
|
||||
describes where the signed data came from, e.g., "email:claws"
|
||||
(default: "unknown"). If MAY_ASK is 1, then this function may
|
||||
interact with the user in the case of a conflict or if the
|
||||
binding's policy is ask. This function returns the binding's trust
|
||||
level. If an error occurs, it returns TRUST_UNKNOWN. */
|
||||
int tofu_register (const byte *fingerprint, const char *user_id,
|
||||
const byte *sigs_digest, int sigs_digest_len,
|
||||
time_t sig_time, const char *origin, int may_ask);
|
||||
|
||||
/* Combine a trust level returned from the TOFU trust model with a
|
||||
trust level returned by the PGP trust model. This is primarily of
|
||||
interest when the trust model is tofu+pgp (TM_TOFU_PGP). */
|
||||
int tofu_wot_trust_combine (int tofu, int wot);
|
||||
|
||||
/* Determine the validity (TRUST_NEVER, etc.) of the binding
|
||||
<FINGERPRINT, USER_ID>. If MAY_ASK is 1, then this function may
|
||||
interact with the user. If not, TRUST_UNKNOWN is returned. If an
|
||||
error occurs, TRUST_UNDEFINED is returned. */
|
||||
int tofu_get_validity (const byte *fingerprint, const char *user_id,
|
||||
int may_ask);
|
||||
|
||||
/* Set the policy for all non-revoked user ids in the keyblock KB to
|
||||
POLICY. */
|
||||
gpg_error_t tofu_set_policy (kbnode_t kb, enum tofu_policy policy);
|
||||
|
||||
/* Set the TOFU policy for all non-revoked users in the key with the
|
||||
key id KEYID to POLICY. */
|
||||
gpg_error_t tofu_set_policy_by_keyid (u32 *keyid, enum tofu_policy policy);
|
||||
|
||||
/* Return the TOFU policy for the specified binding in *POLICY. */
|
||||
gpg_error_t tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
|
||||
enum tofu_policy *policy);
|
||||
|
||||
#endif
|
11
g10/trust.c
11
g10/trust.c
@ -152,7 +152,7 @@ uid_trust_string_fixed (PKT_public_key *key, PKT_user_id *uid)
|
||||
return _("[ expired]");
|
||||
else if(key)
|
||||
{
|
||||
switch (get_validity(key,uid)&TRUST_MASK)
|
||||
switch (get_validity (key, uid, NULL, 0) & TRUST_MASK)
|
||||
{
|
||||
case TRUST_UNKNOWN: return _("[ unknown]");
|
||||
case TRUST_EXPIRED: return _("[ expired]");
|
||||
@ -298,7 +298,8 @@ check_or_update_trustdb (void)
|
||||
* otherwise, a reasonable value for the entire key is returned.
|
||||
*/
|
||||
unsigned int
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig,
|
||||
int may_ask)
|
||||
{
|
||||
int rc;
|
||||
unsigned int validity;
|
||||
@ -330,7 +331,7 @@ get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
#ifdef NO_TRUST_MODELS
|
||||
validity = TRUST_UNKNOWN;
|
||||
#else
|
||||
validity = tdb_get_validity_core (pk, uid, main_pk);
|
||||
validity = tdb_get_validity_core (pk, uid, main_pk, sig, may_ask);
|
||||
#endif
|
||||
|
||||
leave:
|
||||
@ -359,7 +360,7 @@ get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
|
||||
if (!pk)
|
||||
return '?'; /* Just in case a NULL PK is passed. */
|
||||
|
||||
trustlevel = get_validity (pk, uid);
|
||||
trustlevel = get_validity (pk, uid, NULL, 0);
|
||||
if ((trustlevel & TRUST_FLAG_REVOKED))
|
||||
return 'r';
|
||||
return trust_letter (trustlevel);
|
||||
@ -374,7 +375,7 @@ get_validity_string (PKT_public_key *pk, PKT_user_id *uid)
|
||||
if (!pk)
|
||||
return "err"; /* Just in case a NULL PK is passed. */
|
||||
|
||||
trustlevel = get_validity (pk, uid);
|
||||
trustlevel = get_validity (pk, uid, NULL, 0);
|
||||
if ((trustlevel & TRUST_FLAG_REVOKED))
|
||||
return _("revoked");
|
||||
return trust_value_to_string (trustlevel);
|
||||
|
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;
|
||||
|
@ -86,7 +86,8 @@ void revalidation_mark (void);
|
||||
void check_trustdb_stale (void);
|
||||
void check_or_update_trustdb (void);
|
||||
|
||||
unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid);
|
||||
unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid,
|
||||
PKT_signature *sig, int may_ask);
|
||||
int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
|
||||
const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
|
||||
|
||||
@ -120,7 +121,8 @@ void tdb_check_or_update (void);
|
||||
int tdb_cache_disabled_value (PKT_public_key *pk);
|
||||
|
||||
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);
|
||||
|
||||
void list_trust_path( const char *username );
|
||||
int enum_cert_paths( void **context, ulong *lid,
|
||||
|
@ -38,7 +38,8 @@ TESTS = version.test mds.test \
|
||||
armdetachm.test detachm.test genkey1024.test \
|
||||
conventional.test conventional-mdc.test \
|
||||
multisig.test verify.test armor.test \
|
||||
import.test ecc.test 4gb-packet.test finish.test
|
||||
import.test ecc.test 4gb-packet.test tofu.test \
|
||||
finish.test
|
||||
|
||||
|
||||
TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
|
||||
@ -46,7 +47,9 @@ TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
|
||||
pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc \
|
||||
gpg.conf.tmpl gpg-agent.conf.tmpl \
|
||||
bug537-test.data.asc bug894-test.asc \
|
||||
bug1223-good.asc bug1223-bogus.asc 4gb-packet.asc
|
||||
bug1223-good.asc bug1223-bogus.asc 4gb-packet.asc \
|
||||
tofu-keys.asc tofu-keys-secret.asc \
|
||||
tofu-2183839A-1.txt tofu-BC15C85A-1.txt tofu-EE37CF96-1.txt
|
||||
|
||||
data_files = data-500 data-9000 data-32000 data-80000 plain-large
|
||||
|
||||
@ -95,10 +98,10 @@ CLEANFILES = prepared.stamp x y yy z out err $(data_files) \
|
||||
*.test.log gpg_dearmor gpg.conf gpg-agent.conf S.gpg-agent \
|
||||
pubring.gpg pubring.gpg~ pubring.kbx pubring.kbx~ \
|
||||
secring.gpg pubring.pkr secring.skr \
|
||||
gnupg-test.stop random_seed gpg-agent.log
|
||||
gnupg-test.stop random_seed gpg-agent.log tofu.db
|
||||
|
||||
clean-local:
|
||||
-rm -rf private-keys-v1.d openpgp-revocs.d
|
||||
-rm -rf private-keys-v1.d openpgp-revocs.d tofu.d
|
||||
|
||||
|
||||
# We need to depend on a couple of programs so that the tests don't
|
||||
|
BIN
tests/openpgp/tofu-2183839A-1.txt
Normal file
BIN
tests/openpgp/tofu-2183839A-1.txt
Normal file
Binary file not shown.
9
tests/openpgp/tofu-BC15C85A-1.txt
Normal file
9
tests/openpgp/tofu-BC15C85A-1.txt
Normal file
@ -0,0 +1,9 @@
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: GnuPG v2
|
||||
|
||||
owGbwMvMwMF46tzNaXtET0QxnmZPYgj9/c+Sq2MOCwMjBwMbKxOIy8DFKQBTo/SK
|
||||
hWFThVuj19r3R/6VzQkpaZuQx7s3r9BQ46v8KXkjb58dSjmXyr7enlCzb7dg1zE7
|
||||
aynbc6YTF+wXZI4IlAgPuLJhUeSXo0+WllxbFXUz39407cv15TcXThLj+3tFkSnZ
|
||||
YFXwM9+nfAoHpt6I/ZY96SJT3XFZKzO1jeZNJhZsV4Vfrjp0UmnH3E4A
|
||||
=X9WM
|
||||
-----END PGP MESSAGE-----
|
9
tests/openpgp/tofu-EE37CF96-1.txt
Normal file
9
tests/openpgp/tofu-EE37CF96-1.txt
Normal file
@ -0,0 +1,9 @@
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: GnuPG v2
|
||||
|
||||
owGbwMvMwMEY0Tqz9J35+WmMp9mTGEJ//xPk6pjDwsDIwcDGygTiMnBxCsDULFZm
|
||||
/sk4S36iQ6FuZZPMPdOSe/rZOxNThTmzvJN4l1qe9XGdlLhtpumfzh0uhRnzT2Xc
|
||||
jmra+ZdN9+XBhml//i7v6XrfuWu56OuEI/fXH0i3P5HELb+j++6SO85VemLq/tvO
|
||||
hNvWtddvuZ7+z2JJaqnP4wiu2t+sEze/MWKZ9zz+u2FV6a3OIyJxjwA=
|
||||
=JMtb
|
||||
-----END PGP MESSAGE-----
|
95
tests/openpgp/tofu-keys-secret.asc
Executable file
95
tests/openpgp/tofu-keys-secret.asc
Executable file
@ -0,0 +1,95 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v2
|
||||
|
||||
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
|
||||
CQ==
|
||||
=2SlE
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
47
tests/openpgp/tofu-keys.asc
Executable file
47
tests/openpgp/tofu-keys.asc
Executable file
@ -0,0 +1,47 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2
|
||||
|
||||
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
|
||||
0v2sv67Ar70GR4vQwMvfCUAbnsVrL05eBjUJ
|
||||
=Btw1
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
245
tests/openpgp/tofu.test
Executable file
245
tests/openpgp/tofu.test
Executable file
@ -0,0 +1,245 @@
|
||||
#!/bin/sh
|
||||
|
||||
. $srcdir/defs.inc || exit 3
|
||||
|
||||
# set -x
|
||||
|
||||
KEYS="2183839A BC15C85A EE37CF96"
|
||||
|
||||
# Make sure $srcdir is set.
|
||||
if test "x$srcdir" = x
|
||||
then
|
||||
echo srcdir environment variable not set!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure $GNUPGHOME is set.
|
||||
if test "x$GNUPGHOME" = x
|
||||
then
|
||||
echo "GNUPGHOME not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Import the test keys.
|
||||
$GPG --import $srcdir/tofu-keys.asc
|
||||
|
||||
# Make sure the keys are imported.
|
||||
for k in $KEYS
|
||||
do
|
||||
if ! $GPG --list-keys $k >/dev/null 2>&1
|
||||
then
|
||||
echo Missing key $k
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
format=auto
|
||||
|
||||
debug()
|
||||
{
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
debug_exec()
|
||||
{
|
||||
debug "Running GNUPGHOME=$GNUPGHOME $@"
|
||||
${@:+"$@"}
|
||||
}
|
||||
|
||||
# $1 is the keyid of the policy to lookup. Any remaining arguments
|
||||
# are simply passed to GPG.
|
||||
#
|
||||
# This function only supports keys with a single user id.
|
||||
getpolicy()
|
||||
{
|
||||
keyid=$1
|
||||
if test x$keyid = x
|
||||
then
|
||||
echo No keyid supplied!
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
|
||||
policy=$(debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
|
||||
--with-colons $@ --list-keys "$keyid" \
|
||||
| awk -F: '/^uid:/ { print $18 }')
|
||||
if test $(echo "$policy" | wc -l) -ne 1
|
||||
then
|
||||
echo "Got: $policy" >&2
|
||||
echo "error"
|
||||
else
|
||||
case $policy in
|
||||
auto|good|unknown|bad|ask) echo $policy ;;
|
||||
*) echo "error" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 is the key id
|
||||
# $2 is the expected policy
|
||||
# The rest are additional options to pass to gpg.
|
||||
checkpolicy()
|
||||
{
|
||||
debug
|
||||
debug "checkpolicy($@)"
|
||||
|
||||
keyid=$1
|
||||
shift
|
||||
expected_policy=$1
|
||||
shift
|
||||
policy=$(getpolicy "$keyid" ${@:+"$@"})
|
||||
if test "x$policy" != "x$expected_policy"
|
||||
then
|
||||
echo "$keyid: Expected policy to be \`$expected_policy', but got \`$policy'."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 is the keyid of the trust level to lookup. Any remaining
|
||||
# arguments are simply passed to GPG.
|
||||
#
|
||||
# This function only supports keys with a single user id.
|
||||
gettrust()
|
||||
{
|
||||
keyid=$1
|
||||
if test x$keyid = x
|
||||
then
|
||||
echo No keyid supplied!
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
|
||||
trust=$(debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
|
||||
--with-colons $@ --list-keys "$keyid" \
|
||||
| awk -F: '/^pub:/ { print $2 }')
|
||||
if test $(echo "$trust" | wc -l) -ne 1
|
||||
then
|
||||
echo "error"
|
||||
else
|
||||
case $trust in
|
||||
[oidreqnmfuws-]) echo $trust ;;
|
||||
*) echo "Bad trust value: $trust" >&2; echo "error" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# $1 is the key id
|
||||
# $2 is the expected trust level
|
||||
# The rest are additional options to pass to gpg.
|
||||
checktrust()
|
||||
{
|
||||
debug
|
||||
debug "checktrust($@)"
|
||||
|
||||
keyid=$1
|
||||
shift
|
||||
expected_trust=$1
|
||||
shift
|
||||
trust=$(gettrust "$keyid" ${@:+"$@"})
|
||||
if test "x$trust" != "x$expected_trust"
|
||||
then
|
||||
echo "$keyid: Expected trust to be \`$expected_trust', but got \`$trust'."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Set key $1's policy to $2. Any remaining arguments are passed as
|
||||
# options to gpg.
|
||||
setpolicy()
|
||||
{
|
||||
debug
|
||||
debug "setpolicy($@)"
|
||||
|
||||
keyid=$1
|
||||
shift
|
||||
policy=$1
|
||||
shift
|
||||
|
||||
debug_exec $GPG --tofu-db-format=$format \
|
||||
--trust-model=tofu ${@:+"$@"} --tofu-policy $policy $keyid
|
||||
}
|
||||
|
||||
for format in split flat
|
||||
do
|
||||
debug
|
||||
debug "Testing with db format $format"
|
||||
|
||||
# Carefully remove the TOFU db.
|
||||
test -e $GNUPGHOME/tofu.db && rm $GNUPGHOME/tofu.db
|
||||
test -e $GNUPGHOME/tofu.d/email && rm -r $GNUPGHOME/tofu.d/email
|
||||
test -e $GNUPGHOME/tofu.d/key && rm -r $GNUPGHOME/tofu.d/key
|
||||
# This will fail if the directory is not empty.
|
||||
test -e $GNUPGHOME/tofu.d && rmdir $GNUPGHOME/tofu.d
|
||||
|
||||
# Verify a message. There should be no conflict and the trust policy
|
||||
# should be set to auto.
|
||||
debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
|
||||
--verify $srcdir/tofu-2183839A-1.txt
|
||||
|
||||
checkpolicy 2183839A auto
|
||||
|
||||
trust=$(gettrust 2183839A)
|
||||
debug "default trust = $trust"
|
||||
if test "x$trust" != xm
|
||||
then
|
||||
echo "Wrong default trust. Got: \`$trust', expected \`m'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Trust should be derived lazily. Thus, if the policy is set to auto
|
||||
# and we change --tofu-default-policy, then the trust should change as
|
||||
# well. Try it.
|
||||
checktrust 2183839A f --tofu-default-policy=good
|
||||
checktrust 2183839A - --tofu-default-policy=unknown
|
||||
checktrust 2183839A n --tofu-default-policy=bad
|
||||
|
||||
# Change the policy to something other than auto and make sure the
|
||||
# policy and the trust are correct.
|
||||
for policy in good unknown bad
|
||||
do
|
||||
if test $policy = good
|
||||
then
|
||||
expected_trust='f'
|
||||
elif test $policy = unknown
|
||||
then
|
||||
expected_trust='-'
|
||||
else
|
||||
expected_trust='n'
|
||||
fi
|
||||
|
||||
debug
|
||||
debug "Setting TOFU policy to $policy"
|
||||
setpolicy 2183839A $policy
|
||||
|
||||
# Since we have a fixed policy, the trust level shouldn't
|
||||
# change if we change the default policy.
|
||||
for default_policy in auto good unknown bad ask
|
||||
do
|
||||
checkpolicy 2183839A $policy --tofu-default-policy=$default_policy
|
||||
checktrust 2183839A $expected_trust \
|
||||
--tofu-default-policy=$default_policy
|
||||
done
|
||||
done
|
||||
|
||||
# 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.
|
||||
debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
|
||||
--verify $srcdir/tofu-BC15C85A-1.txt
|
||||
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.
|
||||
setpolicy BC15C85A auto
|
||||
checkpolicy BC15C85A auto
|
||||
debug_exec $GPG --tofu-db-format=$format --trust-model=tofu \
|
||||
--verify $srcdir/tofu-EE37CF96-1.txt
|
||||
checkpolicy BC15C85A ask
|
||||
checkpolicy 2183839A bad
|
||||
checkpolicy EE37CF96 ask
|
||||
done
|
||||
|
||||
exit 0
|
Loading…
x
Reference in New Issue
Block a user