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
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue