mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-14 21:47:19 +02:00
Merge branch 'master' into gniibe/decryption-key
This commit is contained in:
commit
e8caa282d3
49 changed files with 2059 additions and 1979 deletions
|
@ -152,6 +152,7 @@ gpg_sources = server.c \
|
|||
trust.c $(trust_source) $(tofu_source) \
|
||||
$(card_source) \
|
||||
exec.c exec.h \
|
||||
key-clean.c key-clean.h \
|
||||
key-check.c key-check.h
|
||||
|
||||
gpg_SOURCES = gpg.c \
|
||||
|
|
|
@ -851,6 +851,7 @@ fetch_url (ctrl_t ctrl)
|
|||
}
|
||||
}
|
||||
|
||||
agent_release_card_info (&info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
19
g10/export.c
19
g10/export.c
|
@ -41,6 +41,8 @@
|
|||
#include "../common/init.h"
|
||||
#include "trustdb.h"
|
||||
#include "call-agent.h"
|
||||
#include "key-clean.h"
|
||||
|
||||
|
||||
/* An object to keep track of subkeys. */
|
||||
struct subkey_list_s
|
||||
|
@ -2001,12 +2003,19 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
|
|||
}
|
||||
|
||||
/* Always do the cleaning on the public key part if requested.
|
||||
* Note that both export-clean and export-minimal only apply to
|
||||
* UID sigs (0x10, 0x11, 0x12, and 0x13). A designated
|
||||
* revocation is never stripped, even with export-minimal set. */
|
||||
* A designated revocation is never stripped, even with
|
||||
* export-minimal set. */
|
||||
if ((options & EXPORT_CLEAN))
|
||||
clean_key (ctrl, keyblock, opt.verbose,
|
||||
(options&EXPORT_MINIMAL), NULL, NULL);
|
||||
{
|
||||
merge_keys_and_selfsig (ctrl, keyblock);
|
||||
clean_all_uids (ctrl, keyblock, opt.verbose,
|
||||
(options&EXPORT_MINIMAL), NULL, NULL);
|
||||
clean_all_subkeys (ctrl, keyblock, opt.verbose,
|
||||
(options&EXPORT_MINIMAL)? KEY_CLEAN_ALL
|
||||
/**/ : KEY_CLEAN_AUTHENCR,
|
||||
NULL, NULL);
|
||||
commit_kbnode (&keyblock);
|
||||
}
|
||||
|
||||
if (export_keep_uid)
|
||||
{
|
||||
|
|
49
g10/getkey.c
49
g10/getkey.c
|
@ -677,6 +677,24 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
|
|||
}
|
||||
|
||||
|
||||
/* Specialized version of get_pubkey which retrieves the key based on
|
||||
* information in SIG. In contrast to get_pubkey PK is required. */
|
||||
gpg_error_t
|
||||
get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
|
||||
{
|
||||
const byte *fpr;
|
||||
size_t fprlen;
|
||||
|
||||
/* First try the new ISSUER_FPR info. */
|
||||
fpr = issuer_fpr_raw (sig, &fprlen);
|
||||
if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen))
|
||||
return 0;
|
||||
|
||||
/* Fallback to use the ISSUER_KEYID. */
|
||||
return get_pubkey (ctrl, pk, sig->keyid);
|
||||
}
|
||||
|
||||
|
||||
/* Return the public key with the key id KEYID and store it at PK.
|
||||
* The resources in *PK should be released using
|
||||
* release_public_key_parts(). This function also stores a copy of
|
||||
|
@ -739,8 +757,9 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|||
/* Do a lookup. */
|
||||
{
|
||||
struct getkey_ctx_s ctx;
|
||||
KBNODE kb = NULL;
|
||||
KBNODE found_key = NULL;
|
||||
kbnode_t kb = NULL;
|
||||
kbnode_t found_key = NULL;
|
||||
|
||||
memset (&ctx, 0, sizeof ctx);
|
||||
ctx.exact = 1; /* Use the key ID exactly as given. */
|
||||
ctx.not_allocated = 1;
|
||||
|
@ -863,6 +882,28 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
|
|||
}
|
||||
|
||||
|
||||
/* Return the entire keyblock used to create SIG. This is a
|
||||
* specialized version of get_pubkeyblock.
|
||||
*
|
||||
* FIXME: This is a hack because get_pubkey_for_sig was already called
|
||||
* and it could have used a cache to hold the key. */
|
||||
kbnode_t
|
||||
get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig)
|
||||
{
|
||||
const byte *fpr;
|
||||
size_t fprlen;
|
||||
kbnode_t keyblock;
|
||||
|
||||
/* First try the new ISSUER_FPR info. */
|
||||
fpr = issuer_fpr_raw (sig, &fprlen);
|
||||
if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen))
|
||||
return keyblock;
|
||||
|
||||
/* Fallback to use the ISSUER_KEYID. */
|
||||
return get_pubkeyblock (ctrl, sig->keyid);
|
||||
}
|
||||
|
||||
|
||||
/* Return the key block for the key with key id KEYID or NULL, if an
|
||||
* error occurs. Use release_kbnode() to release the key block.
|
||||
*
|
||||
|
@ -1802,6 +1843,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
|||
memset (&ctx, 0, sizeof ctx);
|
||||
ctx.exact = 1;
|
||||
ctx.not_allocated = 1;
|
||||
/* FIXME: We should get the handle from the cache like we do in
|
||||
* get_pubkey. */
|
||||
ctx.kr_handle = keydb_new ();
|
||||
if (!ctx.kr_handle)
|
||||
return gpg_error_from_syserror ();
|
||||
|
@ -3142,7 +3185,7 @@ buf_to_sig (const byte * buf, size_t len)
|
|||
|
||||
if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0)
|
||||
{
|
||||
xfree (sig);
|
||||
free_seckey_enc (sig);
|
||||
sig = NULL;
|
||||
}
|
||||
|
||||
|
|
17
g10/gpg.c
17
g10/gpg.c
|
@ -150,6 +150,7 @@ enum cmd_and_opt_values
|
|||
aSearchKeys,
|
||||
aRefreshKeys,
|
||||
aFetchKeys,
|
||||
aShowKeys,
|
||||
aExport,
|
||||
aExportSecret,
|
||||
aExportSecretSub,
|
||||
|
@ -500,6 +501,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||
N_("update all keys from a keyserver")),
|
||||
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
|
||||
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
|
||||
ARGPARSE_c (aShowKeys, "show-keys" , "@" ),
|
||||
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
|
||||
ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
|
||||
ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
|
||||
|
@ -740,6 +742,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||
ARGPARSE_c (aListKeys, "list-key", "@"), /* alias */
|
||||
ARGPARSE_c (aListSigs, "list-sig", "@"), /* alias */
|
||||
ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */
|
||||
ARGPARSE_c (aShowKeys, "show-key", "@"), /* alias */
|
||||
ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
|
||||
ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
|
||||
ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
|
||||
|
@ -2642,6 +2645,17 @@ main (int argc, char **argv)
|
|||
greeting=1;
|
||||
break;
|
||||
|
||||
case aShowKeys:
|
||||
set_cmd (&cmd, pargs.r_opt);
|
||||
opt.import_options |= IMPORT_SHOW;
|
||||
opt.import_options |= IMPORT_DRY_RUN;
|
||||
opt.import_options &= ~IMPORT_REPAIR_KEYS;
|
||||
opt.list_options |= LIST_SHOW_UNUSABLE_UIDS;
|
||||
opt.list_options |= LIST_SHOW_UNUSABLE_SUBKEYS;
|
||||
opt.list_options |= LIST_SHOW_NOTATIONS;
|
||||
opt.list_options |= LIST_SHOW_POLICY_URLS;
|
||||
break;
|
||||
|
||||
case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
|
||||
|
||||
case aDecryptFiles: multifile=1; /* fall through */
|
||||
|
@ -3611,7 +3625,7 @@ main (int argc, char **argv)
|
|||
else
|
||||
{
|
||||
pargs.err = ARGPARSE_PRINT_ERROR;
|
||||
/* The argparse fucntion calls a plain exit and thus
|
||||
/* The argparse function calls a plain exit and thus
|
||||
* we need to print a status here. */
|
||||
write_status_failure ("option-parser",
|
||||
gpg_error(GPG_ERR_GENERAL));
|
||||
|
@ -4638,6 +4652,7 @@ main (int argc, char **argv)
|
|||
case aFastImport:
|
||||
opt.import_options |= IMPORT_FAST; /* fall through */
|
||||
case aImport:
|
||||
case aShowKeys:
|
||||
import_keys (ctrl, argc? argv:NULL, argc, NULL,
|
||||
opt.import_options, opt.key_origin, opt.key_origin_url);
|
||||
break;
|
||||
|
|
|
@ -1835,7 +1835,7 @@ signature (const char *option, int argc, char *argv[], void *cookie)
|
|||
debug ("Wrote signature packet:\n");
|
||||
dump_component (&pkt);
|
||||
|
||||
xfree (sig);
|
||||
free_seckey_enc (sig);
|
||||
release_kbnode (si.issuer_kb);
|
||||
xfree (si.revocation_key);
|
||||
|
||||
|
|
15
g10/gpgv.c
15
g10/gpgv.c
|
@ -772,3 +772,18 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
char **r_comment, size_t *r_commentlen)
|
||||
{
|
||||
(void)sig;
|
||||
(void)r_commentlen;
|
||||
|
||||
if (r_reason)
|
||||
*r_reason = NULL;
|
||||
if (r_comment)
|
||||
*r_comment = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
550
g10/import.c
550
g10/import.c
|
@ -41,6 +41,7 @@
|
|||
#include "../common/init.h"
|
||||
#include "../common/mbox-util.h"
|
||||
#include "key-check.h"
|
||||
#include "key-clean.h"
|
||||
|
||||
|
||||
struct import_stats_s
|
||||
|
@ -113,8 +114,8 @@ static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
|||
struct import_stats_s *stats, int batch,
|
||||
unsigned int options, int for_migration,
|
||||
import_screener_t screener, void *screener_arg);
|
||||
static int import_revoke_cert (ctrl_t ctrl,
|
||||
kbnode_t node, struct import_stats_s *stats);
|
||||
static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
||||
struct import_stats_s *stats);
|
||||
static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
||||
int *non_self);
|
||||
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
||||
|
@ -494,7 +495,9 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
|
|||
|
||||
if (!stats_handle)
|
||||
{
|
||||
import_print_stats (stats);
|
||||
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN))
|
||||
!= (IMPORT_SHOW | IMPORT_DRY_RUN))
|
||||
import_print_stats (stats);
|
||||
import_release_stats_handle (stats);
|
||||
}
|
||||
|
||||
|
@ -588,7 +591,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
|
|||
screener, screener_arg);
|
||||
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
|
||||
&& IS_KEY_REV (keyblock->pkt->pkt.signature) )
|
||||
rc = import_revoke_cert (ctrl, keyblock, stats);
|
||||
rc = import_revoke_cert (ctrl, keyblock, options, stats);
|
||||
else
|
||||
{
|
||||
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
|
||||
|
@ -778,7 +781,7 @@ read_block( IOBUF a, int with_meta,
|
|||
struct parse_packet_ctx_s parsectx;
|
||||
PACKET *pkt;
|
||||
kbnode_t root = NULL;
|
||||
int in_cert, in_v3key;
|
||||
int in_cert, in_v3key, skip_sigs;
|
||||
|
||||
*r_v3keys = 0;
|
||||
|
||||
|
@ -797,6 +800,7 @@ read_block( IOBUF a, int with_meta,
|
|||
if (!with_meta)
|
||||
parsectx.skip_meta = 1;
|
||||
in_v3key = 0;
|
||||
skip_sigs = 0;
|
||||
while ((rc=parse_packet (&parsectx, pkt)) != -1)
|
||||
{
|
||||
if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
|
||||
|
@ -811,8 +815,25 @@ read_block( IOBUF a, int with_meta,
|
|||
}
|
||||
else if (rc ) /* (ignore errors) */
|
||||
{
|
||||
skip_sigs = 0;
|
||||
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET)
|
||||
; /* Do not show a diagnostic. */
|
||||
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
||||
&& (pkt->pkttype == PKT_USER_ID
|
||||
|| pkt->pkttype == PKT_ATTRIBUTE))
|
||||
{
|
||||
/* This indicates a too large user id or attribute
|
||||
* packet. We skip this packet and all following
|
||||
* signatures. Sure, this won't allow to repair a
|
||||
* garbled keyring in case one of the signatures belong
|
||||
* to another user id. However, this better mitigates
|
||||
* DoS using inserted user ids. */
|
||||
skip_sigs = 1;
|
||||
}
|
||||
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
||||
&& (pkt->pkttype == PKT_OLD_COMMENT
|
||||
|| pkt->pkttype == PKT_COMMENT))
|
||||
; /* Ignore too large comment packets. */
|
||||
else
|
||||
{
|
||||
log_error("read_block: read error: %s\n", gpg_strerror (rc) );
|
||||
|
@ -824,76 +845,88 @@ read_block( IOBUF a, int with_meta,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| pkt->pkttype == PKT_SECRET_KEY))
|
||||
{
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
continue;
|
||||
}
|
||||
in_v3key = 0;
|
||||
if (skip_sigs)
|
||||
{
|
||||
if (pkt->pkttype == PKT_SIGNATURE)
|
||||
{
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet (pkt);
|
||||
continue;
|
||||
}
|
||||
skip_sigs = 0;
|
||||
}
|
||||
|
||||
if (!root && pkt->pkttype == PKT_SIGNATURE
|
||||
&& IS_KEY_REV (pkt->pkt.signature) )
|
||||
{
|
||||
/* This is a revocation certificate which is handled in a
|
||||
* special way. */
|
||||
root = new_kbnode( pkt );
|
||||
pkt = NULL;
|
||||
goto ready;
|
||||
}
|
||||
if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| pkt->pkttype == PKT_SECRET_KEY))
|
||||
{
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
continue;
|
||||
}
|
||||
in_v3key = 0;
|
||||
|
||||
/* Make a linked list of all packets. */
|
||||
switch (pkt->pkttype)
|
||||
{
|
||||
case PKT_COMPRESSED:
|
||||
if (check_compress_algo (pkt->pkt.compressed->algorithm))
|
||||
{
|
||||
rc = GPG_ERR_COMPR_ALGO;
|
||||
goto ready;
|
||||
}
|
||||
else
|
||||
{
|
||||
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
||||
pkt->pkt.compressed->buf = NULL;
|
||||
if (push_compress_filter2 (a, cfx,
|
||||
pkt->pkt.compressed->algorithm, 1))
|
||||
xfree (cfx); /* e.g. in case of compression_algo NONE. */
|
||||
}
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
break;
|
||||
if (!root && pkt->pkttype == PKT_SIGNATURE
|
||||
&& IS_KEY_REV (pkt->pkt.signature) )
|
||||
{
|
||||
/* This is a revocation certificate which is handled in a
|
||||
* special way. */
|
||||
root = new_kbnode( pkt );
|
||||
pkt = NULL;
|
||||
goto ready;
|
||||
}
|
||||
|
||||
case PKT_RING_TRUST:
|
||||
/* Skip those packets unless we are in restore mode. */
|
||||
if ((opt.import_options & IMPORT_RESTORE))
|
||||
goto x_default;
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
break;
|
||||
/* Make a linked list of all packets. */
|
||||
switch (pkt->pkttype)
|
||||
{
|
||||
case PKT_COMPRESSED:
|
||||
if (check_compress_algo (pkt->pkt.compressed->algorithm))
|
||||
{
|
||||
rc = GPG_ERR_COMPR_ALGO;
|
||||
goto ready;
|
||||
}
|
||||
else
|
||||
{
|
||||
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
||||
pkt->pkt.compressed->buf = NULL;
|
||||
if (push_compress_filter2 (a, cfx,
|
||||
pkt->pkt.compressed->algorithm, 1))
|
||||
xfree (cfx); /* e.g. in case of compression_algo NONE. */
|
||||
}
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
break;
|
||||
|
||||
case PKT_PUBLIC_KEY:
|
||||
case PKT_SECRET_KEY:
|
||||
if (in_cert ) /* Store this packet. */
|
||||
{
|
||||
*pending_pkt = pkt;
|
||||
pkt = NULL;
|
||||
goto ready;
|
||||
}
|
||||
in_cert = 1; /* fall through */
|
||||
default:
|
||||
x_default:
|
||||
if (in_cert && valid_keyblock_packet (pkt->pkttype))
|
||||
{
|
||||
if (!root )
|
||||
root = new_kbnode (pkt);
|
||||
else
|
||||
add_kbnode (root, new_kbnode (pkt));
|
||||
pkt = xmalloc (sizeof *pkt);
|
||||
}
|
||||
init_packet(pkt);
|
||||
break;
|
||||
}
|
||||
case PKT_RING_TRUST:
|
||||
/* Skip those packets unless we are in restore mode. */
|
||||
if ((opt.import_options & IMPORT_RESTORE))
|
||||
goto x_default;
|
||||
free_packet (pkt, &parsectx);
|
||||
init_packet(pkt);
|
||||
break;
|
||||
|
||||
case PKT_PUBLIC_KEY:
|
||||
case PKT_SECRET_KEY:
|
||||
if (in_cert ) /* Store this packet. */
|
||||
{
|
||||
*pending_pkt = pkt;
|
||||
pkt = NULL;
|
||||
goto ready;
|
||||
}
|
||||
in_cert = 1;
|
||||
/* fall through */
|
||||
default:
|
||||
x_default:
|
||||
if (in_cert && valid_keyblock_packet (pkt->pkttype))
|
||||
{
|
||||
if (!root )
|
||||
root = new_kbnode (pkt);
|
||||
else
|
||||
add_kbnode (root, new_kbnode (pkt));
|
||||
pkt = xmalloc (sizeof *pkt);
|
||||
}
|
||||
init_packet(pkt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ready:
|
||||
|
@ -1312,6 +1345,16 @@ impex_filter_getval (void *cookie, const char *propname)
|
|||
{
|
||||
result = pk_is_disabled (pk)? "1":"0";
|
||||
}
|
||||
else if (!strcmp (propname, "usage"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%s%s%s%s%s",
|
||||
(pk->pubkey_usage & PUBKEY_USAGE_ENC)?"e":"",
|
||||
(pk->pubkey_usage & PUBKEY_USAGE_SIG)?"s":"",
|
||||
(pk->pubkey_usage & PUBKEY_USAGE_CERT)?"c":"",
|
||||
(pk->pubkey_usage & PUBKEY_USAGE_AUTH)?"a":"",
|
||||
(pk->pubkey_usage & PUBKEY_USAGE_UNKNOWN)?"?":"");
|
||||
result = numbuf;
|
||||
}
|
||||
else
|
||||
result = NULL;
|
||||
}
|
||||
|
@ -1653,6 +1696,10 @@ import_one (ctrl_t ctrl,
|
|||
int any_filter = 0;
|
||||
KEYDB_HANDLE hd = NULL;
|
||||
|
||||
/* If show-only is active we don't won't any extra output. */
|
||||
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN)))
|
||||
silent = 1;
|
||||
|
||||
/* Get the key and print some info about it. */
|
||||
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
||||
if (!node )
|
||||
|
@ -1712,9 +1759,14 @@ import_one (ctrl_t ctrl,
|
|||
that we have to clean later. This has no practical impact on the
|
||||
end result, but does result in less logging which might confuse
|
||||
the user. */
|
||||
if (options&IMPORT_CLEAN)
|
||||
clean_key (ctrl, keyblock,
|
||||
opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
|
||||
if ((options & IMPORT_CLEAN))
|
||||
{
|
||||
merge_keys_and_selfsig (ctrl, keyblock);
|
||||
clean_all_uids (ctrl, keyblock,
|
||||
opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
|
||||
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
clear_kbnode_flags( keyblock );
|
||||
|
||||
|
@ -1855,8 +1907,13 @@ import_one (ctrl_t ctrl,
|
|||
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
||||
|
||||
if ((options & IMPORT_CLEAN))
|
||||
clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
||||
&n_uids_cleaned,&n_sigs_cleaned);
|
||||
{
|
||||
merge_keys_and_selfsig (ctrl, keyblock);
|
||||
clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
||||
&n_uids_cleaned,&n_sigs_cleaned);
|
||||
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/* Unless we are in restore mode apply meta data to the
|
||||
* keyblock. Note that this will never change the first packet
|
||||
|
@ -1941,8 +1998,14 @@ import_one (ctrl_t ctrl,
|
|||
goto leave;
|
||||
|
||||
if ((options & IMPORT_CLEAN))
|
||||
clean_key (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL),
|
||||
&n_uids_cleaned,&n_sigs_cleaned);
|
||||
{
|
||||
merge_keys_and_selfsig (ctrl, keyblock_orig);
|
||||
clean_all_uids (ctrl, keyblock_orig, opt.verbose,
|
||||
(options&IMPORT_MINIMAL),
|
||||
&n_uids_cleaned,&n_sigs_cleaned);
|
||||
clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned)
|
||||
{
|
||||
|
@ -2616,11 +2679,216 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Return the recocation reason from signature SIG. If no revocation
|
||||
* reason is availabale 0 is returned, in other cases the reason
|
||||
* (0..255). If R_REASON is not NULL a malloced textual
|
||||
* representation of the code is stored there. If R_COMMENT is not
|
||||
* NULL the comment from the reason is stored there and its length at
|
||||
* R_COMMENTLEN. Note that the value at R_COMMENT is not filtered but
|
||||
* user supplied data in UTF8; thus it needs to be escaped for display
|
||||
* purposes. Both return values are either NULL or a malloced
|
||||
* string/buffer. */
|
||||
int
|
||||
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
char **r_comment, size_t *r_commentlen)
|
||||
{
|
||||
int reason_seq = 0;
|
||||
size_t reason_n;
|
||||
const byte *reason_p;
|
||||
char reason_code_buf[20];
|
||||
const char *reason_text = NULL;
|
||||
int reason_code = 0;
|
||||
|
||||
if (r_reason)
|
||||
*r_reason = NULL;
|
||||
if (r_comment)
|
||||
*r_comment = NULL;
|
||||
|
||||
/* Skip over empty reason packets. */
|
||||
while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
|
||||
&reason_n, &reason_seq, NULL))
|
||||
&& !reason_n)
|
||||
;
|
||||
if (reason_p)
|
||||
{
|
||||
reason_code = *reason_p;
|
||||
reason_n--; reason_p++;
|
||||
switch (reason_code)
|
||||
{
|
||||
case 0x00: reason_text = _("No reason specified"); break;
|
||||
case 0x01: reason_text = _("Key is superseded"); break;
|
||||
case 0x02: reason_text = _("Key has been compromised"); break;
|
||||
case 0x03: reason_text = _("Key is no longer used"); break;
|
||||
case 0x20: reason_text = _("User ID is no longer valid"); break;
|
||||
default:
|
||||
snprintf (reason_code_buf, sizeof reason_code_buf,
|
||||
"code=%02x", reason_code);
|
||||
reason_text = reason_code_buf;
|
||||
break;
|
||||
}
|
||||
|
||||
if (r_reason)
|
||||
*r_reason = xstrdup (reason_text);
|
||||
|
||||
if (r_comment && reason_n)
|
||||
{
|
||||
*r_comment = xmalloc (reason_n);
|
||||
memcpy (*r_comment, reason_p, reason_n);
|
||||
*r_commentlen = reason_n;
|
||||
}
|
||||
}
|
||||
|
||||
return reason_code;
|
||||
}
|
||||
|
||||
|
||||
/* List the recocation signature as a "rvs" record. SIGRC shows the
|
||||
* character from the signature verification or 0 if no public key was
|
||||
* found. */
|
||||
static void
|
||||
list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc)
|
||||
{
|
||||
char *siguid = NULL;
|
||||
size_t siguidlen = 0;
|
||||
char *issuer_fpr = NULL;
|
||||
int reason_code = 0;
|
||||
char *reason_text = NULL;
|
||||
char *reason_comment = NULL;
|
||||
size_t reason_commentlen;
|
||||
|
||||
if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode)
|
||||
{
|
||||
int nouid;
|
||||
siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid);
|
||||
if (nouid)
|
||||
sigrc = '?';
|
||||
}
|
||||
|
||||
reason_code = get_revocation_reason (sig, &reason_text,
|
||||
&reason_comment, &reason_commentlen);
|
||||
|
||||
if (opt.with_colons)
|
||||
{
|
||||
es_fputs ("rvs:", es_stdout);
|
||||
if (sigrc)
|
||||
es_putc (sigrc, es_stdout);
|
||||
es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:::",
|
||||
sig->pubkey_algo,
|
||||
(ulong) sig->keyid[0], (ulong) sig->keyid[1],
|
||||
colon_datestr_from_sig (sig),
|
||||
colon_expirestr_from_sig (sig));
|
||||
|
||||
if (siguid)
|
||||
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
||||
|
||||
es_fprintf (es_stdout, ":%02x%c", sig->sig_class,
|
||||
sig->flags.exportable ? 'x' : 'l');
|
||||
if (reason_text)
|
||||
es_fprintf (es_stdout, ",%02x", reason_code);
|
||||
es_fputs ("::", es_stdout);
|
||||
|
||||
if ((issuer_fpr = issuer_fpr_string (sig)))
|
||||
es_fputs (issuer_fpr, es_stdout);
|
||||
|
||||
es_fprintf (es_stdout, ":::%d:", sig->digest_algo);
|
||||
|
||||
if (reason_comment)
|
||||
{
|
||||
es_fputs ("::::", es_stdout);
|
||||
es_write_sanitized (es_stdout, reason_comment, reason_commentlen,
|
||||
":", NULL);
|
||||
es_putc (':', es_stdout);
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (opt.show_subpackets)
|
||||
print_subpackets_colon (sig);
|
||||
}
|
||||
else /* Human readable. */
|
||||
{
|
||||
es_fputs ("rvs", es_stdout);
|
||||
es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
|
||||
sigrc, (sig->sig_class - 0x10 > 0 &&
|
||||
sig->sig_class - 0x10 <
|
||||
4) ? '0' + sig->sig_class - 0x10 : ' ',
|
||||
sig->flags.exportable ? ' ' : 'L',
|
||||
sig->flags.revocable ? ' ' : 'R',
|
||||
sig->flags.policy_url ? 'P' : ' ',
|
||||
sig->flags.notation ? 'N' : ' ',
|
||||
sig->flags.expired ? 'X' : ' ',
|
||||
(sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
|
||||
0) ? '0' +
|
||||
sig->trust_depth : ' ', keystr (sig->keyid),
|
||||
datestr_from_sig (sig));
|
||||
if (siguid)
|
||||
{
|
||||
es_fprintf (es_stdout, " ");
|
||||
print_utf8_buffer (es_stdout, siguid, siguidlen);
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (sig->flags.policy_url
|
||||
&& (opt.list_options & LIST_SHOW_POLICY_URLS))
|
||||
show_policy_url (sig, 3, 0);
|
||||
|
||||
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
||||
show_notation (sig, 3, 0,
|
||||
((opt.list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
|
||||
+
|
||||
((opt.list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
|
||||
|
||||
if (sig->flags.pref_ks
|
||||
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||
show_keyserver_url (sig, 3, 0);
|
||||
|
||||
if (reason_text)
|
||||
{
|
||||
es_fprintf (es_stdout, " %s%s\n",
|
||||
_("reason for revocation: "), reason_text);
|
||||
if (reason_comment)
|
||||
{
|
||||
const byte *s, *s_lf;
|
||||
size_t n, n_lf;
|
||||
|
||||
s = reason_comment;
|
||||
n = reason_commentlen;
|
||||
s_lf = NULL;
|
||||
do
|
||||
{
|
||||
/* We don't want any empty lines, so we skip them. */
|
||||
for (;n && *s == '\n'; s++, n--)
|
||||
;
|
||||
if (n)
|
||||
{
|
||||
s_lf = memchr (s, '\n', n);
|
||||
n_lf = s_lf? s_lf - s : n;
|
||||
es_fprintf (es_stdout, " %s",
|
||||
_("revocation comment: "));
|
||||
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||
es_putc ('\n', es_stdout);
|
||||
s += n_lf; n -= n_lf;
|
||||
}
|
||||
} while (s_lf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
es_fflush (es_stdout);
|
||||
|
||||
xfree (reason_text);
|
||||
xfree (reason_comment);
|
||||
xfree (siguid);
|
||||
xfree (issuer_fpr);
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Import a revocation certificate; this is a single signature packet.
|
||||
*/
|
||||
static int
|
||||
import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
||||
import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
||||
struct import_stats_s *stats)
|
||||
{
|
||||
PKT_public_key *pk = NULL;
|
||||
kbnode_t onode;
|
||||
|
@ -2628,6 +2896,11 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
KEYDB_HANDLE hd = NULL;
|
||||
u32 keyid[2];
|
||||
int rc = 0;
|
||||
int sigrc = 0;
|
||||
int silent;
|
||||
|
||||
/* No error output for --show-keys. */
|
||||
silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN));
|
||||
|
||||
log_assert (!node->next );
|
||||
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
|
||||
|
@ -2640,15 +2913,16 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
rc = get_pubkey (ctrl, pk, keyid );
|
||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY )
|
||||
{
|
||||
log_error(_("key %s: no public key -"
|
||||
" can't apply revocation certificate\n"), keystr(keyid));
|
||||
if (!silent)
|
||||
log_error (_("key %s: no public key -"
|
||||
" can't apply revocation certificate\n"), keystr(keyid));
|
||||
rc = 0;
|
||||
goto leave;
|
||||
}
|
||||
else if (rc )
|
||||
{
|
||||
log_error(_("key %s: public key not found: %s\n"),
|
||||
keystr(keyid), gpg_strerror (rc));
|
||||
log_error (_("key %s: public key not found: %s\n"),
|
||||
keystr(keyid), gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
@ -2685,12 +2959,21 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
|
||||
/* it is okay, that node is not in keyblock because
|
||||
* check_key_signature works fine for sig_class 0x20 (KEY_REV) in
|
||||
* this special case. */
|
||||
* this special case. SIGRC is only used for IMPORT_SHOW. */
|
||||
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
||||
switch (gpg_err_code (rc))
|
||||
{
|
||||
case 0: sigrc = '!'; break;
|
||||
case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break;
|
||||
case GPG_ERR_NO_PUBKEY: sigrc = '?'; break;
|
||||
case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break;
|
||||
default: sigrc = '%'; break;
|
||||
}
|
||||
if (rc )
|
||||
{
|
||||
log_error( _("key %s: invalid revocation certificate"
|
||||
": %s - rejected\n"), keystr(keyid), gpg_strerror (rc));
|
||||
if (!silent)
|
||||
log_error (_("key %s: invalid revocation certificate"
|
||||
": %s - rejected\n"), keystr(keyid), gpg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
@ -2710,33 +2993,39 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
/* insert it */
|
||||
insert_kbnode( keyblock, clone_kbnode(node), 0 );
|
||||
|
||||
/* and write the keyblock back */
|
||||
rc = keydb_update_keyblock (ctrl, hd, keyblock );
|
||||
if (rc)
|
||||
log_error (_("error writing keyring '%s': %s\n"),
|
||||
keydb_get_resource_name (hd), gpg_strerror (rc) );
|
||||
keydb_release (hd);
|
||||
hd = NULL;
|
||||
|
||||
/* we are ready */
|
||||
if (!opt.quiet )
|
||||
/* and write the keyblock back unless in dry run mode. */
|
||||
if (!(opt.dry_run || (options & IMPORT_DRY_RUN)))
|
||||
{
|
||||
char *p=get_user_id_native (ctrl, keyid);
|
||||
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
||||
keystr(keyid),p);
|
||||
xfree(p);
|
||||
rc = keydb_update_keyblock (ctrl, hd, keyblock );
|
||||
if (rc)
|
||||
log_error (_("error writing keyring '%s': %s\n"),
|
||||
keydb_get_resource_name (hd), gpg_strerror (rc) );
|
||||
keydb_release (hd);
|
||||
hd = NULL;
|
||||
|
||||
/* we are ready */
|
||||
if (!opt.quiet )
|
||||
{
|
||||
char *p=get_user_id_native (ctrl, keyid);
|
||||
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
||||
keystr(keyid),p);
|
||||
xfree(p);
|
||||
}
|
||||
|
||||
/* If the key we just revoked was ultimately trusted, remove its
|
||||
* ultimate trust. This doesn't stop the user from putting the
|
||||
* ultimate trust back, but is a reasonable solution for now. */
|
||||
if (get_ownertrust (ctrl, pk) == TRUST_ULTIMATE)
|
||||
clear_ownertrusts (ctrl, pk);
|
||||
|
||||
revalidation_mark (ctrl);
|
||||
}
|
||||
stats->n_revoc++;
|
||||
|
||||
/* If the key we just revoked was ultimately trusted, remove its
|
||||
ultimate trust. This doesn't stop the user from putting the
|
||||
ultimate trust back, but is a reasonable solution for now. */
|
||||
if (get_ownertrust (ctrl, pk) == TRUST_ULTIMATE)
|
||||
clear_ownertrusts (ctrl, pk);
|
||||
|
||||
revalidation_mark (ctrl);
|
||||
|
||||
leave:
|
||||
if ((options & IMPORT_SHOW))
|
||||
list_standalone_revocation (ctrl, node->pkt->pkt.signature, sigrc);
|
||||
|
||||
keydb_release (hd);
|
||||
release_kbnode( keyblock );
|
||||
free_public_key( pk );
|
||||
|
@ -2744,8 +3033,9 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
}
|
||||
|
||||
|
||||
/* Loop over the keyblock and check all self signatures. On return
|
||||
* the following bis in the node flags are set:
|
||||
/* Loop over the KEYBLOCK and check all self signatures. KEYID is the
|
||||
* keyid of the primary key for reporting purposes. On return the
|
||||
* following bits in the node flags are set:
|
||||
*
|
||||
* - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
|
||||
* - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
|
||||
|
@ -2760,17 +3050,22 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||
static int
|
||||
chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
||||
{
|
||||
kbnode_t n, knode = NULL;
|
||||
kbnode_t knode = NULL; /* The node of the current subkey. */
|
||||
PKT_public_key *subpk = NULL; /* and its packet. */
|
||||
kbnode_t bsnode = NULL; /* Subkey binding signature node. */
|
||||
u32 bsdate = 0; /* Timestamp of that node. */
|
||||
kbnode_t rsnode = NULL; /* Subkey recocation signature node. */
|
||||
u32 rsdate = 0; /* Timestamp of tha node. */
|
||||
PKT_signature *sig;
|
||||
int rc;
|
||||
u32 bsdate=0, rsdate=0;
|
||||
kbnode_t bsnode = NULL, rsnode = NULL;
|
||||
kbnode_t n;
|
||||
|
||||
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
|
||||
{
|
||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||
{
|
||||
knode = n;
|
||||
subpk = knode->pkt->pkt.public_key;
|
||||
bsdate = 0;
|
||||
rsdate = 0;
|
||||
bsnode = NULL;
|
||||
|
@ -2859,11 +3154,14 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
|||
if ( rc )
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
||||
_("key %s: unsupported public key"
|
||||
" algorithm\n"):
|
||||
_("key %s: invalid subkey binding\n"),
|
||||
keystr (keyid));
|
||||
{
|
||||
keyid_from_pk (subpk, NULL);
|
||||
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
||||
_("key %s: unsupported public key"
|
||||
" algorithm\n"):
|
||||
_("key %s: invalid subkey binding\n"),
|
||||
keystr_with_sub (keyid, subpk->keyid));
|
||||
}
|
||||
n->flag |= NODE_DELETION_MARK;
|
||||
}
|
||||
else
|
||||
|
@ -2878,8 +3176,12 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
|||
one is newer */
|
||||
bsnode->flag |= NODE_DELETION_MARK;
|
||||
if (opt.verbose)
|
||||
log_info (_("key %s: removed multiple subkey"
|
||||
" binding\n"),keystr(keyid));
|
||||
{
|
||||
keyid_from_pk (subpk, NULL);
|
||||
log_info (_("key %s: removed multiple subkey"
|
||||
" binding\n"),
|
||||
keystr_with_sub (keyid, subpk->keyid));
|
||||
}
|
||||
}
|
||||
|
||||
bsnode = n;
|
||||
|
@ -2958,6 +3260,7 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||
{
|
||||
kbnode_t node;
|
||||
int nvalid=0, uid_seen=0, subkey_seen=0;
|
||||
PKT_public_key *pk;
|
||||
|
||||
for (node=keyblock->next; node; node = node->next )
|
||||
{
|
||||
|
@ -2995,7 +3298,12 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||
|| !(node->flag & NODE_GOOD_SELFSIG))
|
||||
{
|
||||
if (opt.verbose )
|
||||
log_info( _("key %s: skipped subkey\n"),keystr(keyid));
|
||||
{
|
||||
pk = node->pkt->pkt.public_key;
|
||||
keyid_from_pk (pk, NULL);
|
||||
log_info (_("key %s: skipped subkey\n"),
|
||||
keystr_with_sub (keyid, pk->keyid));
|
||||
}
|
||||
|
||||
delete_kbnode( node ); /* the subkey */
|
||||
/* and all following signature packets */
|
||||
|
|
241
g10/key-check.c
241
g10/key-check.c
|
@ -1,7 +1,7 @@
|
|||
/* key-check.c - Detect and fix various problems with keys
|
||||
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1998-2017 Werner Koch
|
||||
* Copyright (C) 2015-2017 g10 Code GmbH
|
||||
* Copyright (C) 2015-2018 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
|
@ -72,6 +72,13 @@ sig_comparison (const void *av, const void *bv)
|
|||
a = an->pkt->pkt.signature;
|
||||
b = bn->pkt->pkt.signature;
|
||||
|
||||
/* Signatures with a different help counter are not identical for
|
||||
* our purpose. */
|
||||
if (a->help_counter < b->help_counter)
|
||||
return -1;
|
||||
if (a->help_counter > b->help_counter)
|
||||
return 1;
|
||||
|
||||
if (a->digest_algo < b->digest_algo)
|
||||
return -1;
|
||||
if (a->digest_algo > b->digest_algo)
|
||||
|
@ -94,6 +101,125 @@ sig_comparison (const void *av, const void *bv)
|
|||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
remove_duplicate_sigs (kbnode_t kb, int *dups, int *modified)
|
||||
{
|
||||
gpg_error_t err;
|
||||
kbnode_t n;
|
||||
int nsigs;
|
||||
kbnode_t *sigs; /* Allocated array with the signature packet. */
|
||||
int i;
|
||||
int last_i;
|
||||
int block;
|
||||
PKT_signature *sig;
|
||||
|
||||
/* Count the sigs. */
|
||||
for (nsigs = 0, n = kb; n; n = n->next)
|
||||
{
|
||||
if (is_deleted_kbnode (n))
|
||||
continue;
|
||||
else if (n->pkt->pkttype == PKT_SIGNATURE)
|
||||
nsigs ++;
|
||||
}
|
||||
|
||||
if (!nsigs)
|
||||
return 0; /* No signatures at all. */
|
||||
|
||||
/* Add them all to the SIGS array. */
|
||||
sigs = xtrycalloc (nsigs, sizeof *sigs);
|
||||
if (!sigs)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error (_("error allocating memory: %s\n"), gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
block = 0;
|
||||
i = 0;
|
||||
for (n = kb; n; n = n->next)
|
||||
{
|
||||
if (is_deleted_kbnode (n))
|
||||
continue;
|
||||
|
||||
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||
{
|
||||
switch (n->pkt->pkttype)
|
||||
{
|
||||
case PKT_PUBLIC_SUBKEY:
|
||||
case PKT_SECRET_SUBKEY:
|
||||
case PKT_USER_ID:
|
||||
case PKT_ATTRIBUTE:
|
||||
/* Bump the block number so that we only consider
|
||||
* signatures below the same object as duplicates. */
|
||||
block++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
sig = n->pkt->pkt.signature;
|
||||
sig->help_counter = block;
|
||||
sigs[i++] = n;
|
||||
}
|
||||
log_assert (i == nsigs);
|
||||
|
||||
qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
|
||||
|
||||
last_i = 0;
|
||||
for (i = 1; i < nsigs; i ++)
|
||||
{
|
||||
log_assert (sigs[last_i]);
|
||||
log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
|
||||
log_assert (sigs[i]);
|
||||
log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
|
||||
|
||||
if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
|
||||
{
|
||||
/* They are the same. Kill the latter. */
|
||||
if (DBG_PACKET)
|
||||
{
|
||||
sig = sigs[i]->pkt->pkt.signature;
|
||||
|
||||
log_debug ("Signature appears multiple times, "
|
||||
"deleting duplicate:\n");
|
||||
log_debug (" sig: class 0x%x, issuer: %s,"
|
||||
" timestamp: %s (%lld), digest: %02x %02x\n",
|
||||
sig->sig_class, keystr (sig->keyid),
|
||||
isotimestamp (sig->timestamp),
|
||||
(long long) sig->timestamp,
|
||||
sig->digest_start[0], sig->digest_start[1]);
|
||||
}
|
||||
|
||||
/* Remove sigs[i] from the keyblock. */
|
||||
{
|
||||
kbnode_t z, *prevp;
|
||||
int to_kill = last_i;
|
||||
last_i = i;
|
||||
|
||||
for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
|
||||
if (z == sigs[to_kill])
|
||||
break;
|
||||
|
||||
*prevp = sigs[to_kill]->next;
|
||||
|
||||
sigs[to_kill]->next = NULL;
|
||||
release_kbnode (sigs[to_kill]);
|
||||
sigs[to_kill] = NULL;
|
||||
|
||||
++*dups;
|
||||
*modified = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
last_i = i;
|
||||
}
|
||||
|
||||
xfree (sigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Perform a few sanity checks on a keyblock is okay and possibly
|
||||
* repair some damage. Concretely:
|
||||
*
|
||||
|
@ -133,108 +259,17 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||
int bad_signature = 0;
|
||||
int missing_selfsig = 0;
|
||||
int modified = 0;
|
||||
PKT_signature *sig;
|
||||
|
||||
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
||||
pk = kb->pkt->pkt.public_key;
|
||||
|
||||
/* First we look for duplicates. */
|
||||
{
|
||||
int nsigs;
|
||||
kbnode_t *sigs;
|
||||
int i;
|
||||
int last_i;
|
||||
if (remove_duplicate_sigs (kb, &dups, &modified))
|
||||
goto leave; /* Error */
|
||||
|
||||
/* Count the sigs. */
|
||||
for (nsigs = 0, n = kb; n; n = n->next)
|
||||
{
|
||||
if (is_deleted_kbnode (n))
|
||||
continue;
|
||||
else if (n->pkt->pkttype == PKT_SIGNATURE)
|
||||
nsigs ++;
|
||||
}
|
||||
|
||||
if (!nsigs)
|
||||
return 0; /* No signatures at all. */
|
||||
|
||||
/* Add them all to the SIGS array. */
|
||||
sigs = xtrycalloc (nsigs, sizeof *sigs);
|
||||
if (!sigs)
|
||||
{
|
||||
log_error (_("error allocating memory: %s\n"),
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (n = kb; n; n = n->next)
|
||||
{
|
||||
if (is_deleted_kbnode (n))
|
||||
continue;
|
||||
|
||||
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||
continue;
|
||||
|
||||
sigs[i] = n;
|
||||
i ++;
|
||||
}
|
||||
log_assert (i == nsigs);
|
||||
|
||||
qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
|
||||
|
||||
last_i = 0;
|
||||
for (i = 1; i < nsigs; i ++)
|
||||
{
|
||||
log_assert (sigs[last_i]);
|
||||
log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
|
||||
log_assert (sigs[i]);
|
||||
log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
|
||||
|
||||
if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
|
||||
/* They are the same. Kill the latter. */
|
||||
{
|
||||
if (DBG_PACKET)
|
||||
{
|
||||
PKT_signature *sig = sigs[i]->pkt->pkt.signature;
|
||||
|
||||
log_debug ("Signature appears multiple times, "
|
||||
"deleting duplicate:\n");
|
||||
log_debug (" sig: class 0x%x, issuer: %s,"
|
||||
" timestamp: %s (%lld), digest: %02x %02x\n",
|
||||
sig->sig_class, keystr (sig->keyid),
|
||||
isotimestamp (sig->timestamp),
|
||||
(long long) sig->timestamp,
|
||||
sig->digest_start[0], sig->digest_start[1]);
|
||||
}
|
||||
|
||||
/* Remove sigs[i] from the keyblock. */
|
||||
{
|
||||
KBNODE z, *prevp;
|
||||
int to_kill = last_i;
|
||||
last_i = i;
|
||||
|
||||
for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
|
||||
if (z == sigs[to_kill])
|
||||
break;
|
||||
|
||||
*prevp = sigs[to_kill]->next;
|
||||
|
||||
sigs[to_kill]->next = NULL;
|
||||
release_kbnode (sigs[to_kill]);
|
||||
sigs[to_kill] = NULL;
|
||||
|
||||
dups ++;
|
||||
modified = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
last_i = i;
|
||||
}
|
||||
|
||||
xfree (sigs);
|
||||
}
|
||||
|
||||
/* Make sure the sigs occur after the component (public key, subkey,
|
||||
user id) that they sign. */
|
||||
/* Now make sure the sigs occur after the component (aka block)
|
||||
* (public key, subkey, user id) that they sign. */
|
||||
issuer = NULL;
|
||||
last_printed_component = NULL;
|
||||
for (n_prevp = &kb, n = kb;
|
||||
|
@ -244,7 +279,6 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||
{
|
||||
PACKET *p;
|
||||
int processed_current_component;
|
||||
PKT_signature *sig;
|
||||
int rc;
|
||||
int dump_sig_params = 0;
|
||||
|
||||
|
@ -573,11 +607,18 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||
free_public_key (issuer);
|
||||
issuer = NULL;
|
||||
|
||||
/* If we reordered signatures we need to de-duplicate again because
|
||||
* a signature can now be a duplicate in another block. */
|
||||
if (reordered)
|
||||
{
|
||||
if (remove_duplicate_sigs (kb, &dups, &modified))
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Identify keys / uids that don't have a self-sig. */
|
||||
{
|
||||
int has_selfsig = 0;
|
||||
PACKET *p;
|
||||
PKT_signature *sig;
|
||||
|
||||
current_component = NULL;
|
||||
for (n = kb; n; n = n->next)
|
||||
|
@ -643,6 +684,8 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
leave:
|
||||
if (!opt.quiet)
|
||||
{
|
||||
char prefix[100];
|
||||
|
|
614
g10/key-clean.c
Normal file
614
g10/key-clean.c
Normal file
|
@ -0,0 +1,614 @@
|
|||
/* key-clean.c - Functions to clean a keyblock
|
||||
* Copyright (C) 1998-2008, 2010-2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014, 2016-2018 Werner Koch
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gpg.h"
|
||||
#include "keydb.h"
|
||||
#include "../common/util.h"
|
||||
#include "../common/host2net.h"
|
||||
#include "../common/i18n.h"
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "main.h"
|
||||
#include "key-clean.h"
|
||||
|
||||
|
||||
/*
|
||||
* Mark the signature of the given UID which are used to certify it.
|
||||
* To do this, we first revmove all signatures which are not valid and
|
||||
* from the remain ones we look for the latest one. If this is not a
|
||||
* certification revocation signature we mark the signature by setting
|
||||
* node flag bit 8. Revocations are marked with flag 11, and sigs
|
||||
* from unavailable keys are marked with flag 12. Note that flag bits
|
||||
* 9 and 10 are used for internal purposes.
|
||||
*/
|
||||
void
|
||||
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
u32 *main_kid, struct key_item *klist,
|
||||
u32 curtime, u32 *next_expire)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_signature *sig;
|
||||
|
||||
/* First check all signatures. */
|
||||
for (node=uidnode->next; node; node = node->next)
|
||||
{
|
||||
int rc;
|
||||
|
||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||
if (node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break; /* ready */
|
||||
if (node->pkt->pkttype != PKT_SIGNATURE)
|
||||
continue;
|
||||
sig = node->pkt->pkt.signature;
|
||||
if (main_kid
|
||||
&& sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
|
||||
continue; /* ignore self-signatures if we pass in a main_kid */
|
||||
if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
|
||||
continue; /* we only look at these signature classes */
|
||||
if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
|
||||
sig->sig_class-0x10<opt.min_cert_level)
|
||||
continue; /* treat anything under our min_cert_level as an
|
||||
invalid signature */
|
||||
if (klist && !is_in_klist (klist, sig))
|
||||
continue; /* no need to check it then */
|
||||
if ((rc=check_key_signature (ctrl, keyblock, node, NULL)))
|
||||
{
|
||||
/* we ignore anything that won't verify, but tag the
|
||||
no_pubkey case */
|
||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
||||
node->flag |= 1<<12;
|
||||
continue;
|
||||
}
|
||||
node->flag |= 1<<9;
|
||||
}
|
||||
/* Reset the remaining flags. */
|
||||
for (; node; node = node->next)
|
||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||
|
||||
/* kbnode flag usage: bit 9 is here set for signatures to consider,
|
||||
* bit 10 will be set by the loop to keep track of keyIDs already
|
||||
* processed, bit 8 will be set for the usable signatures, and bit
|
||||
* 11 will be set for usable revocations. */
|
||||
|
||||
/* For each cert figure out the latest valid one. */
|
||||
for (node=uidnode->next; node; node = node->next)
|
||||
{
|
||||
KBNODE n, signode;
|
||||
u32 kid[2];
|
||||
u32 sigdate;
|
||||
|
||||
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break;
|
||||
if ( !(node->flag & (1<<9)) )
|
||||
continue; /* not a node to look at */
|
||||
if ( (node->flag & (1<<10)) )
|
||||
continue; /* signature with a keyID already processed */
|
||||
node->flag |= (1<<10); /* mark this node as processed */
|
||||
sig = node->pkt->pkt.signature;
|
||||
signode = node;
|
||||
sigdate = sig->timestamp;
|
||||
kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
|
||||
|
||||
/* Now find the latest and greatest signature */
|
||||
for (n=uidnode->next; n; n = n->next)
|
||||
{
|
||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break;
|
||||
if ( !(n->flag & (1<<9)) )
|
||||
continue;
|
||||
if ( (n->flag & (1<<10)) )
|
||||
continue; /* shortcut already processed signatures */
|
||||
sig = n->pkt->pkt.signature;
|
||||
if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
|
||||
continue;
|
||||
n->flag |= (1<<10); /* mark this node as processed */
|
||||
|
||||
/* If signode is nonrevocable and unexpired and n isn't,
|
||||
then take signode (skip). It doesn't matter which is
|
||||
older: if signode was older then we don't want to take n
|
||||
as signode is nonrevocable. If n was older then we're
|
||||
automatically fine. */
|
||||
|
||||
if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||
!signode->pkt->pkt.signature->flags.revocable &&
|
||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||
(!(IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||
!n->pkt->pkt.signature->flags.revocable &&
|
||||
(n->pkt->pkt.signature->expiredate==0 ||
|
||||
n->pkt->pkt.signature->expiredate>curtime))))
|
||||
continue;
|
||||
|
||||
/* If n is nonrevocable and unexpired and signode isn't,
|
||||
then take n. Again, it doesn't matter which is older: if
|
||||
n was older then we don't want to take signode as n is
|
||||
nonrevocable. If signode was older then we're
|
||||
automatically fine. */
|
||||
|
||||
if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||
!signode->pkt->pkt.signature->flags.revocable &&
|
||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||
((IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||
!n->pkt->pkt.signature->flags.revocable &&
|
||||
(n->pkt->pkt.signature->expiredate==0 ||
|
||||
n->pkt->pkt.signature->expiredate>curtime))))
|
||||
{
|
||||
signode = n;
|
||||
sigdate = sig->timestamp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* At this point, if it's newer, it goes in as the only
|
||||
remaining possibilities are signode and n are both either
|
||||
revocable or expired or both nonrevocable and unexpired.
|
||||
If the timestamps are equal take the later ordered
|
||||
packet, presuming that the key packets are hopefully in
|
||||
their original order. */
|
||||
|
||||
if (sig->timestamp >= sigdate)
|
||||
{
|
||||
signode = n;
|
||||
sigdate = sig->timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
sig = signode->pkt->pkt.signature;
|
||||
if (IS_UID_SIG (sig))
|
||||
{ /* this seems to be a usable one which is not revoked.
|
||||
* Just need to check whether there is an expiration time,
|
||||
* We do the expired certification after finding a suitable
|
||||
* certification, the assumption is that a signator does not
|
||||
* want that after the expiration of his certificate the
|
||||
* system falls back to an older certification which has a
|
||||
* different expiration time */
|
||||
const byte *p;
|
||||
u32 expire;
|
||||
|
||||
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
|
||||
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
|
||||
|
||||
if (expire==0 || expire > curtime )
|
||||
{
|
||||
signode->flag |= (1<<8); /* yeah, found a good cert */
|
||||
if (next_expire && expire && expire < *next_expire)
|
||||
*next_expire = expire;
|
||||
}
|
||||
}
|
||||
else
|
||||
signode->flag |= (1<<11);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only)
|
||||
{
|
||||
int deleted = 0;
|
||||
kbnode_t node;
|
||||
u32 keyid[2];
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
|
||||
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
||||
|
||||
/* Passing in a 0 for current time here means that we'll never weed
|
||||
out an expired sig. This is correct behavior since we want to
|
||||
keep the most recent expired sig in a series. */
|
||||
mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL);
|
||||
|
||||
/* What we want to do here is remove signatures that are not
|
||||
considered as part of the trust calculations. Thus, all invalid
|
||||
signatures are out, as are any signatures that aren't the last of
|
||||
a series of uid sigs or revocations It breaks down like this:
|
||||
coming out of mark_usable_uid_certs, if a sig is unflagged, it is
|
||||
not even a candidate. If a sig has flag 9 or 10, that means it
|
||||
was selected as a candidate and vetted. If a sig has flag 8 it
|
||||
is a usable signature. If a sig has flag 11 it is a usable
|
||||
revocation. If a sig has flag 12 it was issued by an unavailable
|
||||
key. "Usable" here means the most recent valid
|
||||
signature/revocation in a series from a particular signer.
|
||||
|
||||
Delete everything that isn't a usable uid sig (which might be
|
||||
expired), a usable revocation, or a sig from an unavailable
|
||||
key. */
|
||||
|
||||
for (node=uidnode->next;
|
||||
node && node->pkt->pkttype==PKT_SIGNATURE;
|
||||
node=node->next)
|
||||
{
|
||||
int keep;
|
||||
|
||||
keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
||||
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
|
||||
|
||||
/* Keep usable uid sigs ... */
|
||||
if ((node->flag & (1<<8)) && keep)
|
||||
continue;
|
||||
|
||||
/* ... and usable revocations... */
|
||||
if ((node->flag & (1<<11)) && keep)
|
||||
continue;
|
||||
|
||||
/* ... and sigs from unavailable keys. */
|
||||
/* disabled for now since more people seem to want sigs from
|
||||
unavailable keys removed altogether. */
|
||||
/*
|
||||
if(node->flag & (1<<12))
|
||||
continue;
|
||||
*/
|
||||
|
||||
/* Everything else we delete */
|
||||
|
||||
/* At this point, if 12 is set, the signing key was unavailable.
|
||||
If 9 or 10 is set, it's superseded. Otherwise, it's
|
||||
invalid. */
|
||||
|
||||
if (noisy)
|
||||
log_info ("removing signature from key %s on user ID \"%s\": %s\n",
|
||||
keystr (node->pkt->pkt.signature->keyid),
|
||||
uidnode->pkt->pkt.user_id->name,
|
||||
node->flag&(1<<12)? "key unavailable":
|
||||
node->flag&(1<<9)? "signature superseded"
|
||||
/* */ :"invalid signature" );
|
||||
|
||||
delete_kbnode (node);
|
||||
deleted++;
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
/* This is substantially easier than clean_sigs_from_uid since we just
|
||||
have to establish if the uid has a valid self-sig, is not revoked,
|
||||
and is not expired. Note that this does not take into account
|
||||
whether the uid has a trust path to it - just whether the keyholder
|
||||
themselves has certified the uid. Returns true if the uid was
|
||||
compacted. To "compact" a user ID, we simply remove ALL signatures
|
||||
except the self-sig that caused the user ID to be remove-worthy.
|
||||
We don't actually remove the user ID packet itself since it might
|
||||
be resurrected in a later merge. Note that this function requires
|
||||
that the caller has already done a merge_keys_and_selfsig().
|
||||
|
||||
TODO: change the import code to allow importing a uid with only a
|
||||
revocation if the uid already exists on the keyring. */
|
||||
|
||||
static int
|
||||
clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
|
||||
int deleted = 0;
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||
|
||||
/* Skip valid user IDs, compacted user IDs, and non-self-signed user
|
||||
IDs if --allow-non-selfsigned-uid is set. */
|
||||
if (uid->created
|
||||
|| uid->flags.compacted
|
||||
|| (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid))
|
||||
return 0;
|
||||
|
||||
for (node=uidnode->next;
|
||||
node && node->pkt->pkttype == PKT_SIGNATURE;
|
||||
node=node->next)
|
||||
{
|
||||
if (!node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||
{
|
||||
delete_kbnode (node);
|
||||
deleted = 1;
|
||||
uidnode->pkt->pkt.user_id->flags.compacted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (noisy)
|
||||
{
|
||||
const char *reason;
|
||||
char *user = utf8_to_native (uid->name, uid->len, 0);
|
||||
|
||||
if (uid->flags.revoked)
|
||||
reason = _("revoked");
|
||||
else if (uid->flags.expired)
|
||||
reason = _("expired");
|
||||
else
|
||||
reason = _("invalid");
|
||||
|
||||
log_info ("compacting user ID \"%s\" on key %s: %s\n",
|
||||
user, keystr_from_pk (keyblock->pkt->pkt.public_key),
|
||||
reason);
|
||||
|
||||
xfree (user);
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
/* Needs to be called after a merge_keys_and_selfsig() */
|
||||
void
|
||||
clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
|
||||
{
|
||||
int dummy = 0;
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||
|
||||
if (!uids_cleaned)
|
||||
uids_cleaned = &dummy;
|
||||
|
||||
if (!sigs_cleaned)
|
||||
sigs_cleaned = &dummy;
|
||||
|
||||
/* Do clean_uid_from_key first since if it fires off, we don't have
|
||||
to bother with the other. */
|
||||
*uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
|
||||
if (!uidnode->pkt->pkt.user_id->flags.compacted)
|
||||
*sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
|
||||
noisy, self_only);
|
||||
}
|
||||
|
||||
|
||||
/* NB: This function marks the deleted nodes only and the caller is
|
||||
* responsible to skip or remove them. Needs to be called after a
|
||||
* merge_keys_and_selfsig(). */
|
||||
void
|
||||
clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||
int *uids_cleaned, int *sigs_cleaned)
|
||||
{
|
||||
kbnode_t node;
|
||||
|
||||
for (node = keyblock->next;
|
||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
node = node->next)
|
||||
{
|
||||
if (node->pkt->pkttype == PKT_USER_ID)
|
||||
clean_one_uid (ctrl, keyblock, node, noisy, self_only,
|
||||
uids_cleaned, sigs_cleaned);
|
||||
}
|
||||
|
||||
/* Remove bogus subkey binding signatures: The only signatures
|
||||
* allowed are of class 0x18 and 0x28. */
|
||||
log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY));
|
||||
}
|
||||
|
||||
|
||||
/* Helper for clean_all_subkeys. */
|
||||
static int
|
||||
clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_public_key *pk = subkeynode->pkt->pkt.public_key;
|
||||
unsigned int use = pk->pubkey_usage;
|
||||
int do_clean = 0;
|
||||
|
||||
(void)ctrl;
|
||||
(void)noisy;
|
||||
|
||||
log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tchecking subkey %08lX [%c%c%c%c%c]\n",
|
||||
(ulong) keyid_from_pk (pk, NULL),
|
||||
(use & PUBKEY_USAGE_ENC)? 'e':'-',
|
||||
(use & PUBKEY_USAGE_SIG)? 's':'-',
|
||||
(use & PUBKEY_USAGE_CERT)? 'c':'-',
|
||||
(use & PUBKEY_USAGE_AUTH)? 'a':'-',
|
||||
(use & PUBKEY_USAGE_UNKNOWN)? '?':'-');
|
||||
|
||||
if (!pk->flags.valid)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tsubkey not valid\n");
|
||||
if (clean_level == KEY_CLEAN_INVALID)
|
||||
do_clean = 1;
|
||||
}
|
||||
if (pk->has_expired)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tsubkey has expired\n");
|
||||
if (clean_level == KEY_CLEAN_ALL)
|
||||
do_clean = 1;
|
||||
else if (clean_level == KEY_CLEAN_AUTHENCR
|
||||
&& (use & (PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH))
|
||||
&& !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT)))
|
||||
do_clean = 1;
|
||||
else if (clean_level == KEY_CLEAN_ENCR
|
||||
&& (use & PUBKEY_USAGE_ENC)
|
||||
&& !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT
|
||||
| PUBKEY_USAGE_AUTH)))
|
||||
do_clean = 1;
|
||||
}
|
||||
if (pk->flags.revoked)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tsubkey has been revoked (keeping)\n");
|
||||
/* Avoid any cleaning because revocations are important. */
|
||||
do_clean = 0;
|
||||
}
|
||||
if (!do_clean)
|
||||
return 0;
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\t=> removing this subkey\n");
|
||||
|
||||
delete_kbnode (subkeynode);
|
||||
for (node = subkeynode->next;
|
||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
node = node->next)
|
||||
delete_kbnode (node);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for clean_all_subkeys. Here duplicate signatures from a
|
||||
* subkey are removed. This should in general not happen because
|
||||
* import takes care of that. However, sometimes other tools are used
|
||||
* to manage a keyring or key has been imported a long time ago. */
|
||||
static int
|
||||
clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_public_key *pk = subkeynode->pkt->pkt.public_key;
|
||||
int any_choosen = 0;
|
||||
int count = 0;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tchecking subkey %08lX for dupsigs\n",
|
||||
(ulong) keyid_from_pk (pk, NULL));
|
||||
|
||||
/* First check that the choosen flag has been set. Note that we
|
||||
* only look at plain signatures so to keep all revocation
|
||||
* signatures which may carry important information. */
|
||||
for (node = subkeynode->next;
|
||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
node = node->next)
|
||||
{
|
||||
if (!is_deleted_kbnode (node)
|
||||
&& node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||
&& node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||
{
|
||||
any_choosen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!any_choosen)
|
||||
return 0; /* Ooops no choosen flag set - we can't decide. */
|
||||
|
||||
for (node = subkeynode->next;
|
||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
node = node->next)
|
||||
{
|
||||
if (!is_deleted_kbnode (node)
|
||||
&& node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||
&& !node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||
{
|
||||
delete_kbnode (node);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* This function only marks the deleted nodes and the caller is
|
||||
* responsible to skip or remove them. Needs to be called after a
|
||||
* merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_*
|
||||
* values. */
|
||||
void
|
||||
clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level,
|
||||
int *subkeys_cleaned, int *sigs_cleaned)
|
||||
{
|
||||
kbnode_t first_subkey, node;
|
||||
int n;
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("clean_all_subkeys: checking key %08lX\n",
|
||||
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL));
|
||||
|
||||
for (node = keyblock->next; node; node = node->next)
|
||||
if (!is_deleted_kbnode (node)
|
||||
&& (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY))
|
||||
break;
|
||||
first_subkey = node;
|
||||
|
||||
/* Remove bogus subkey binding signatures: The only signatures
|
||||
* allowed are of class 0x18 and 0x28. */
|
||||
for (node = first_subkey; node; node = node->next)
|
||||
{
|
||||
if (is_deleted_kbnode (node))
|
||||
continue;
|
||||
if (node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& !(IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||
|| IS_SUBKEY_REV (node->pkt->pkt.signature)))
|
||||
{
|
||||
delete_kbnode (node);
|
||||
if (sigs_cleaned)
|
||||
++*sigs_cleaned;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the selected cleaning. */
|
||||
if (clean_level > KEY_CLEAN_NONE)
|
||||
{
|
||||
/* Clean enitre subkeys. */
|
||||
for (node = first_subkey; node; node = node->next)
|
||||
{
|
||||
if (is_deleted_kbnode (node))
|
||||
continue;
|
||||
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
{
|
||||
if (clean_one_subkey (ctrl, node, noisy, clean_level))
|
||||
{
|
||||
if (subkeys_cleaned)
|
||||
++*subkeys_cleaned;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean duplicate signatures from a subkey. */
|
||||
for (node = first_subkey; node; node = node->next)
|
||||
{
|
||||
if (is_deleted_kbnode (node))
|
||||
continue;
|
||||
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
{
|
||||
n = clean_one_subkey_dupsigs (ctrl, node);
|
||||
if (sigs_cleaned)
|
||||
*sigs_cleaned += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
g10/key-clean.h
Normal file
52
g10/key-clean.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* key-clean.h - Functions to clean a keyblock
|
||||
* Copyright (C) 2018 Werner Koch
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef GNUPG_G10_KEY_CLEAN_H
|
||||
#define GNUPG_G10_KEY_CLEAN_H
|
||||
|
||||
#include "gpg.h"
|
||||
|
||||
/* No explict cleaning. */
|
||||
#define KEY_CLEAN_NONE 0
|
||||
/* Remove only invalid subkeys (ie. missing key-bindings) */
|
||||
#define KEY_CLEAN_INVALID 1
|
||||
/* Remove expired encryption keys */
|
||||
#define KEY_CLEAN_ENCR 2
|
||||
/* Remove expired authentication and encryption keys. */
|
||||
#define KEY_CLEAN_AUTHENCR 3
|
||||
/* Remove all expired subkeys. */
|
||||
#define KEY_CLEAN_ALL 4
|
||||
|
||||
|
||||
void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
u32 *main_kid, struct key_item *klist,
|
||||
u32 curtime, u32 *next_expire);
|
||||
|
||||
void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only,
|
||||
int *uids_cleaned, int *sigs_cleaned);
|
||||
void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||
int *uids_cleaned,int *sigs_cleaned);
|
||||
void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock,
|
||||
int noisy, int clean_level,
|
||||
int *subkeys_cleaned, int *sigs_cleaned);
|
||||
|
||||
|
||||
#endif /*GNUPG_G10_KEY_CLEAN_H*/
|
38
g10/keydb.h
38
g10/keydb.h
|
@ -64,6 +64,20 @@ struct kbnode_struct {
|
|||
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
|
||||
|
||||
|
||||
/*
|
||||
* A structure to store key identification as well as some stuff
|
||||
* needed for key validation.
|
||||
*/
|
||||
struct key_item {
|
||||
struct key_item *next;
|
||||
unsigned int ownertrust,min_ownertrust;
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
char *trust_regexp;
|
||||
u32 kid[2];
|
||||
};
|
||||
|
||||
|
||||
/* Bit flags used with build_pk_list. */
|
||||
enum
|
||||
{
|
||||
|
@ -133,6 +147,22 @@ enum
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check whether the signature SIG is in the klist K.
|
||||
*/
|
||||
static inline struct key_item *
|
||||
is_in_klist (struct key_item *k, PKT_signature *sig)
|
||||
{
|
||||
for (; k; k = k->next)
|
||||
{
|
||||
if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-- keydb.c --*/
|
||||
|
||||
#define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */
|
||||
|
@ -283,6 +313,10 @@ void cache_public_key( PKT_public_key *pk );
|
|||
/* Disable and drop the public key cache. */
|
||||
void getkey_disable_caches(void);
|
||||
|
||||
/* Return the public key used for signature SIG and store it at PK. */
|
||||
gpg_error_t get_pubkey_for_sig (ctrl_t ctrl,
|
||||
PKT_public_key *pk, PKT_signature *sig);
|
||||
|
||||
/* Return the public key with the key id KEYID and store it at PK. */
|
||||
int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
||||
|
||||
|
@ -291,6 +325,10 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
|||
also only considers primary keys. */
|
||||
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
|
||||
|
||||
/* Return the entire keyblock used to create SIG. This is a
|
||||
* specialized version of get_pubkeyblock. */
|
||||
kbnode_t get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig);
|
||||
|
||||
/* Return the key block for the key with KEYID. */
|
||||
kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid);
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "../common/host2net.h"
|
||||
#include "tofu.h"
|
||||
#include "key-check.h"
|
||||
#include "key-clean.h"
|
||||
#include "keyedit.h"
|
||||
|
||||
static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
|
||||
|
|
|
@ -3293,7 +3293,7 @@ parse_key_parameter_string (const char *string, int part,
|
|||
* part consider this to be the subkey algo. In case a
|
||||
* SUGGESTED_USE has been given and the usage of the secondary
|
||||
* part does not match SUGGESTED_USE try again using the primary
|
||||
* part. Noet thar when falling back to the primary key we need
|
||||
* part. Note that when falling back to the primary key we need
|
||||
* to force clearing the cert usage. */
|
||||
if (secondary)
|
||||
{
|
||||
|
|
|
@ -1107,6 +1107,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
int sigrc;
|
||||
char *sigstr;
|
||||
char *reason_text = NULL;
|
||||
char *reason_comment = NULL;
|
||||
size_t reason_commentlen;
|
||||
|
||||
if (listctx->check_sigs)
|
||||
{
|
||||
|
@ -1143,7 +1146,11 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
|
||||
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
||||
|| sig->sig_class == 0x30)
|
||||
sigstr = "rev";
|
||||
{
|
||||
sigstr = "rev";
|
||||
get_revocation_reason (sig, &reason_text,
|
||||
&reason_comment, &reason_commentlen);
|
||||
}
|
||||
else if ((sig->sig_class & ~3) == 0x10)
|
||||
sigstr = "sig";
|
||||
else if (sig->sig_class == 0x18)
|
||||
|
@ -1205,6 +1212,40 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||
show_keyserver_url (sig, 3, 0);
|
||||
|
||||
if (reason_text)
|
||||
{
|
||||
es_fprintf (es_stdout, " %s%s\n",
|
||||
_("reason for revocation: "), reason_text);
|
||||
if (reason_comment)
|
||||
{
|
||||
const byte *s, *s_lf;
|
||||
size_t n, n_lf;
|
||||
|
||||
s = reason_comment;
|
||||
n = reason_commentlen;
|
||||
s_lf = NULL;
|
||||
do
|
||||
{
|
||||
/* We don't want any empty lines, so we skip them. */
|
||||
for (;n && *s == '\n'; s++, n--)
|
||||
;
|
||||
if (n)
|
||||
{
|
||||
s_lf = memchr (s, '\n', n);
|
||||
n_lf = s_lf? s_lf - s : n;
|
||||
es_fprintf (es_stdout, " %s",
|
||||
_("revocation comment: "));
|
||||
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||
es_putc ('\n', es_stdout);
|
||||
s += n_lf; n -= n_lf;
|
||||
}
|
||||
} while (s_lf);
|
||||
}
|
||||
}
|
||||
|
||||
xfree (reason_text);
|
||||
xfree (reason_comment);
|
||||
|
||||
/* fixme: check or list other sigs here */
|
||||
}
|
||||
}
|
||||
|
@ -1554,10 +1595,19 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||
char *siguid;
|
||||
size_t siguidlen;
|
||||
char *issuer_fpr = NULL;
|
||||
char *reason_text = NULL;
|
||||
char *reason_comment = NULL;
|
||||
size_t reason_commentlen;
|
||||
int reason_code;
|
||||
|
||||
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
||||
|| sig->sig_class == 0x30)
|
||||
sigstr = "rev";
|
||||
{
|
||||
sigstr = "rev";
|
||||
reason_code = get_revocation_reason (sig, &reason_text,
|
||||
&reason_comment,
|
||||
&reason_commentlen);
|
||||
}
|
||||
else if ((sig->sig_class & ~3) == 0x10)
|
||||
sigstr = "sig";
|
||||
else if (sig->sig_class == 0x18)
|
||||
|
@ -1651,8 +1701,11 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||
else if (siguid)
|
||||
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
||||
|
||||
es_fprintf (es_stdout, ":%02x%c::", sig->sig_class,
|
||||
es_fprintf (es_stdout, ":%02x%c", sig->sig_class,
|
||||
sig->flags.exportable ? 'x' : 'l');
|
||||
if (reason_text)
|
||||
es_fprintf (es_stdout, ",%02x", reason_code);
|
||||
es_fputs ("::", es_stdout);
|
||||
|
||||
if (opt.no_sig_cache && opt.check_sigs && fprokay)
|
||||
{
|
||||
|
@ -1662,12 +1715,23 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||
else if ((issuer_fpr = issuer_fpr_string (sig)))
|
||||
es_fputs (issuer_fpr, es_stdout);
|
||||
|
||||
es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo);
|
||||
es_fprintf (es_stdout, ":::%d:", sig->digest_algo);
|
||||
|
||||
if (reason_comment)
|
||||
{
|
||||
es_fputs ("::::", es_stdout);
|
||||
es_write_sanitized (es_stdout, reason_comment, reason_commentlen,
|
||||
":", NULL);
|
||||
es_putc (':', es_stdout);
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (opt.show_subpackets)
|
||||
print_subpackets_colon (sig);
|
||||
|
||||
/* fixme: check or list other sigs here */
|
||||
xfree (reason_text);
|
||||
xfree (reason_comment);
|
||||
xfree (siguid);
|
||||
xfree (issuer_fpr);
|
||||
}
|
||||
|
|
|
@ -396,6 +396,9 @@ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
|
|||
|
||||
int collapse_uids( KBNODE *keyblock );
|
||||
|
||||
int get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
char **r_comment, size_t *r_commentlen);
|
||||
|
||||
|
||||
/*-- export.c --*/
|
||||
struct export_stats_s;
|
||||
|
|
|
@ -533,6 +533,14 @@ static void
|
|||
proc_encrypted (CTX c, PACKET *pkt)
|
||||
{
|
||||
int result = 0;
|
||||
int early_plaintext = literals_seen;
|
||||
|
||||
if (early_plaintext)
|
||||
{
|
||||
log_info (_("WARNING: multiple plaintexts seen\n"));
|
||||
write_status_errcode ("decryption.early_plaintext", GPG_ERR_BAD_DATA);
|
||||
/* We fail only later so that we can print some more info first. */
|
||||
}
|
||||
|
||||
if (!opt.quiet)
|
||||
{
|
||||
|
@ -683,6 +691,10 @@ proc_encrypted (CTX c, PACKET *pkt)
|
|||
if (!result)
|
||||
result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek );
|
||||
|
||||
/* Trigger the deferred error. */
|
||||
if (!result && early_plaintext)
|
||||
result = gpg_error (GPG_ERR_BAD_DATA);
|
||||
|
||||
if (result == -1)
|
||||
;
|
||||
else if (!result
|
||||
|
@ -788,7 +800,14 @@ proc_plaintext( CTX c, PACKET *pkt )
|
|||
if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8))
|
||||
log_info (_("Note: sender requested \"for-your-eyes-only\"\n"));
|
||||
else if (opt.verbose)
|
||||
log_info (_("original file name='%.*s'\n"), pt->namelen, pt->name);
|
||||
{
|
||||
/* We don't use print_utf8_buffer because that would require a
|
||||
* string change which we don't want in 2.2. It is also not
|
||||
* clear whether the filename is always utf-8 encoded. */
|
||||
char *tmp = make_printable_string (pt->name, pt->namelen, 0);
|
||||
log_info (_("original file name='%.*s'\n"), (int)strlen (tmp), tmp);
|
||||
xfree (tmp);
|
||||
}
|
||||
|
||||
free_md_filter_context (&c->mfx);
|
||||
if (gcry_md_open (&c->mfx.md, 0, 0))
|
||||
|
@ -1681,7 +1700,7 @@ akl_has_wkd_method (void)
|
|||
/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
|
||||
* Returns NULL if not available. The returned buffer is valid as
|
||||
* long as SIG is not modified. */
|
||||
static const byte *
|
||||
const byte *
|
||||
issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
||||
{
|
||||
const byte *p;
|
||||
|
@ -1698,7 +1717,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
|||
}
|
||||
|
||||
|
||||
/* Return the ISSUER fingerprint string in human readbale format if
|
||||
/* Return the ISSUER fingerprint string in human readable format if
|
||||
* available. Caller must release the string. */
|
||||
/* FIXME: Move to another file. */
|
||||
char *
|
||||
|
@ -2064,7 +2083,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||
* keyblock has already been fetched. Thus we could use the
|
||||
* fingerprint or PK itself to lookup the entire keyblock. That
|
||||
* would best be done with a cache. */
|
||||
keyblock = get_pubkeyblock (c->ctrl, sig->keyid);
|
||||
keyblock = get_pubkeyblock_for_sig (c->ctrl, sig);
|
||||
|
||||
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
|
||||
(ulong)sig->keyid[0], (ulong)sig->keyid[1]);
|
||||
|
|
|
@ -244,6 +244,7 @@ typedef struct
|
|||
const byte *trust_regexp;
|
||||
struct revocation_key *revkey;
|
||||
int numrevkeys;
|
||||
int help_counter; /* Used internally bu some fucntions. */
|
||||
pka_info_t *pka_info; /* Malloced PKA data or NULL if not
|
||||
available. See also flags.pka_tried. */
|
||||
char *signers_uid; /* Malloced value of the SIGNERS_UID
|
||||
|
@ -630,6 +631,7 @@ int proc_signature_packets_by_fd (ctrl_t ctrl,
|
|||
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
|
||||
int list_packets( iobuf_t a );
|
||||
|
||||
const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len);
|
||||
char *issuer_fpr_string (PKT_signature *sig);
|
||||
|
||||
/*-- parse-packet.c --*/
|
||||
|
|
|
@ -113,7 +113,7 @@ void
|
|||
show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode)
|
||||
{
|
||||
/* Hmmm, this is not so easy because we have to duplicate the code
|
||||
* used in the trustbd to calculate the keyflags. We need to find
|
||||
* used in the trustdb to calculate the keyflags. We need to find
|
||||
* a clean way to check revocation certificates on keys and
|
||||
* signatures. And there should be no duplicate code. Because we
|
||||
* enter this function only when the trustdb told us that we have
|
||||
|
@ -548,7 +548,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
|
|||
unsigned int trustlevel = TRUST_UNKNOWN;
|
||||
int rc=0;
|
||||
|
||||
rc = get_pubkey (ctrl, pk, sig->keyid );
|
||||
rc = get_pubkey_for_sig (ctrl, pk, sig);
|
||||
if (rc)
|
||||
{ /* this should not happen */
|
||||
log_error("Ooops; the key vanished - can't check the trust\n");
|
||||
|
|
|
@ -156,7 +156,7 @@ check_signature2 (ctrl_t ctrl,
|
|||
log_info(_("WARNING: signature digest conflict in message\n"));
|
||||
rc = gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
else if (get_pubkey (ctrl, pk, sig->keyid))
|
||||
else if (get_pubkey_for_sig (ctrl, pk, sig))
|
||||
rc = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||
else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
||||
pk->pubkey_algo, pk->pkey,
|
||||
|
@ -478,8 +478,17 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
|
|||
sig->sig_class, pk->pubkey_usage);
|
||||
return rc;
|
||||
}
|
||||
/* Fixme: Should we also check the signing capability here for data
|
||||
* signature? */
|
||||
|
||||
/* For data signatures check that the key has sign usage. */
|
||||
if (IS_SIG (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_SIG))
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||
if (!opt.quiet)
|
||||
log_info (_("bad data signature from key %s: %s (0x%02x, 0x%x)\n"),
|
||||
keystr_from_pk (pk), gpg_strerror (rc),
|
||||
sig->sig_class, pk->pubkey_usage);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Make sure the digest algo is enabled (in case of a detached
|
||||
* signature). */
|
||||
|
@ -917,7 +926,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
|
|||
if (IS_CERT (sig))
|
||||
signer->req_usage = PUBKEY_USAGE_CERT;
|
||||
|
||||
rc = get_pubkey (ctrl, signer, sig->keyid);
|
||||
rc = get_pubkey_for_sig (ctrl, signer, sig);
|
||||
if (rc)
|
||||
{
|
||||
xfree (signer);
|
||||
|
|
|
@ -772,7 +772,7 @@ write_signature_packets (ctrl_t ctrl,
|
|||
gpg_strerror (rc));
|
||||
}
|
||||
else
|
||||
xfree (sig);
|
||||
free_seckey_enc (sig);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
|
@ -535,3 +535,17 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
char **r_comment, size_t *r_commentlen)
|
||||
{
|
||||
(void)sig;
|
||||
(void)r_commentlen;
|
||||
|
||||
if (r_reason)
|
||||
*r_reason = NULL;
|
||||
if (r_comment)
|
||||
*r_comment = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
|
388
g10/trust.c
388
g10/trust.c
|
@ -437,391 +437,3 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
|
|||
return _("revoked");
|
||||
return trust_value_to_string (trustlevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Mark the signature of the given UID which are used to certify it.
|
||||
* To do this, we first revmove all signatures which are not valid and
|
||||
* from the remain ones we look for the latest one. If this is not a
|
||||
* certification revocation signature we mark the signature by setting
|
||||
* node flag bit 8. Revocations are marked with flag 11, and sigs
|
||||
* from unavailable keys are marked with flag 12. Note that flag bits
|
||||
* 9 and 10 are used for internal purposes.
|
||||
*/
|
||||
void
|
||||
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
u32 *main_kid, struct key_item *klist,
|
||||
u32 curtime, u32 *next_expire)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_signature *sig;
|
||||
|
||||
/* First check all signatures. */
|
||||
for (node=uidnode->next; node; node = node->next)
|
||||
{
|
||||
int rc;
|
||||
|
||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||
if (node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break; /* ready */
|
||||
if (node->pkt->pkttype != PKT_SIGNATURE)
|
||||
continue;
|
||||
sig = node->pkt->pkt.signature;
|
||||
if (main_kid
|
||||
&& sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
|
||||
continue; /* ignore self-signatures if we pass in a main_kid */
|
||||
if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
|
||||
continue; /* we only look at these signature classes */
|
||||
if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
|
||||
sig->sig_class-0x10<opt.min_cert_level)
|
||||
continue; /* treat anything under our min_cert_level as an
|
||||
invalid signature */
|
||||
if (klist && !is_in_klist (klist, sig))
|
||||
continue; /* no need to check it then */
|
||||
if ((rc=check_key_signature (ctrl, keyblock, node, NULL)))
|
||||
{
|
||||
/* we ignore anything that won't verify, but tag the
|
||||
no_pubkey case */
|
||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
||||
node->flag |= 1<<12;
|
||||
continue;
|
||||
}
|
||||
node->flag |= 1<<9;
|
||||
}
|
||||
/* Reset the remaining flags. */
|
||||
for (; node; node = node->next)
|
||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||
|
||||
/* kbnode flag usage: bit 9 is here set for signatures to consider,
|
||||
* bit 10 will be set by the loop to keep track of keyIDs already
|
||||
* processed, bit 8 will be set for the usable signatures, and bit
|
||||
* 11 will be set for usable revocations. */
|
||||
|
||||
/* For each cert figure out the latest valid one. */
|
||||
for (node=uidnode->next; node; node = node->next)
|
||||
{
|
||||
KBNODE n, signode;
|
||||
u32 kid[2];
|
||||
u32 sigdate;
|
||||
|
||||
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break;
|
||||
if ( !(node->flag & (1<<9)) )
|
||||
continue; /* not a node to look at */
|
||||
if ( (node->flag & (1<<10)) )
|
||||
continue; /* signature with a keyID already processed */
|
||||
node->flag |= (1<<10); /* mark this node as processed */
|
||||
sig = node->pkt->pkt.signature;
|
||||
signode = node;
|
||||
sigdate = sig->timestamp;
|
||||
kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
|
||||
|
||||
/* Now find the latest and greatest signature */
|
||||
for (n=uidnode->next; n; n = n->next)
|
||||
{
|
||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
break;
|
||||
if ( !(n->flag & (1<<9)) )
|
||||
continue;
|
||||
if ( (n->flag & (1<<10)) )
|
||||
continue; /* shortcut already processed signatures */
|
||||
sig = n->pkt->pkt.signature;
|
||||
if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
|
||||
continue;
|
||||
n->flag |= (1<<10); /* mark this node as processed */
|
||||
|
||||
/* If signode is nonrevocable and unexpired and n isn't,
|
||||
then take signode (skip). It doesn't matter which is
|
||||
older: if signode was older then we don't want to take n
|
||||
as signode is nonrevocable. If n was older then we're
|
||||
automatically fine. */
|
||||
|
||||
if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||
!signode->pkt->pkt.signature->flags.revocable &&
|
||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||
(!(IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||
!n->pkt->pkt.signature->flags.revocable &&
|
||||
(n->pkt->pkt.signature->expiredate==0 ||
|
||||
n->pkt->pkt.signature->expiredate>curtime))))
|
||||
continue;
|
||||
|
||||
/* If n is nonrevocable and unexpired and signode isn't,
|
||||
then take n. Again, it doesn't matter which is older: if
|
||||
n was older then we don't want to take signode as n is
|
||||
nonrevocable. If signode was older then we're
|
||||
automatically fine. */
|
||||
|
||||
if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||
!signode->pkt->pkt.signature->flags.revocable &&
|
||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||
((IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||
!n->pkt->pkt.signature->flags.revocable &&
|
||||
(n->pkt->pkt.signature->expiredate==0 ||
|
||||
n->pkt->pkt.signature->expiredate>curtime))))
|
||||
{
|
||||
signode = n;
|
||||
sigdate = sig->timestamp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* At this point, if it's newer, it goes in as the only
|
||||
remaining possibilities are signode and n are both either
|
||||
revocable or expired or both nonrevocable and unexpired.
|
||||
If the timestamps are equal take the later ordered
|
||||
packet, presuming that the key packets are hopefully in
|
||||
their original order. */
|
||||
|
||||
if (sig->timestamp >= sigdate)
|
||||
{
|
||||
signode = n;
|
||||
sigdate = sig->timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
sig = signode->pkt->pkt.signature;
|
||||
if (IS_UID_SIG (sig))
|
||||
{ /* this seems to be a usable one which is not revoked.
|
||||
* Just need to check whether there is an expiration time,
|
||||
* We do the expired certification after finding a suitable
|
||||
* certification, the assumption is that a signator does not
|
||||
* want that after the expiration of his certificate the
|
||||
* system falls back to an older certification which has a
|
||||
* different expiration time */
|
||||
const byte *p;
|
||||
u32 expire;
|
||||
|
||||
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
|
||||
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
|
||||
|
||||
if (expire==0 || expire > curtime )
|
||||
{
|
||||
signode->flag |= (1<<8); /* yeah, found a good cert */
|
||||
if (next_expire && expire && expire < *next_expire)
|
||||
*next_expire = expire;
|
||||
}
|
||||
}
|
||||
else
|
||||
signode->flag |= (1<<11);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only)
|
||||
{
|
||||
int deleted = 0;
|
||||
kbnode_t node;
|
||||
u32 keyid[2];
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
|
||||
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
||||
|
||||
/* Passing in a 0 for current time here means that we'll never weed
|
||||
out an expired sig. This is correct behavior since we want to
|
||||
keep the most recent expired sig in a series. */
|
||||
mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL);
|
||||
|
||||
/* What we want to do here is remove signatures that are not
|
||||
considered as part of the trust calculations. Thus, all invalid
|
||||
signatures are out, as are any signatures that aren't the last of
|
||||
a series of uid sigs or revocations It breaks down like this:
|
||||
coming out of mark_usable_uid_certs, if a sig is unflagged, it is
|
||||
not even a candidate. If a sig has flag 9 or 10, that means it
|
||||
was selected as a candidate and vetted. If a sig has flag 8 it
|
||||
is a usable signature. If a sig has flag 11 it is a usable
|
||||
revocation. If a sig has flag 12 it was issued by an unavailable
|
||||
key. "Usable" here means the most recent valid
|
||||
signature/revocation in a series from a particular signer.
|
||||
|
||||
Delete everything that isn't a usable uid sig (which might be
|
||||
expired), a usable revocation, or a sig from an unavailable
|
||||
key. */
|
||||
|
||||
for (node=uidnode->next;
|
||||
node && node->pkt->pkttype==PKT_SIGNATURE;
|
||||
node=node->next)
|
||||
{
|
||||
int keep;
|
||||
|
||||
keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
||||
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
|
||||
|
||||
/* Keep usable uid sigs ... */
|
||||
if ((node->flag & (1<<8)) && keep)
|
||||
continue;
|
||||
|
||||
/* ... and usable revocations... */
|
||||
if ((node->flag & (1<<11)) && keep)
|
||||
continue;
|
||||
|
||||
/* ... and sigs from unavailable keys. */
|
||||
/* disabled for now since more people seem to want sigs from
|
||||
unavailable keys removed altogether. */
|
||||
/*
|
||||
if(node->flag & (1<<12))
|
||||
continue;
|
||||
*/
|
||||
|
||||
/* Everything else we delete */
|
||||
|
||||
/* At this point, if 12 is set, the signing key was unavailable.
|
||||
If 9 or 10 is set, it's superseded. Otherwise, it's
|
||||
invalid. */
|
||||
|
||||
if (noisy)
|
||||
log_info ("removing signature from key %s on user ID \"%s\": %s\n",
|
||||
keystr (node->pkt->pkt.signature->keyid),
|
||||
uidnode->pkt->pkt.user_id->name,
|
||||
node->flag&(1<<12)? "key unavailable":
|
||||
node->flag&(1<<9)? "signature superseded"
|
||||
/* */ :"invalid signature" );
|
||||
|
||||
delete_kbnode (node);
|
||||
deleted++;
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
/* This is substantially easier than clean_sigs_from_uid since we just
|
||||
have to establish if the uid has a valid self-sig, is not revoked,
|
||||
and is not expired. Note that this does not take into account
|
||||
whether the uid has a trust path to it - just whether the keyholder
|
||||
themselves has certified the uid. Returns true if the uid was
|
||||
compacted. To "compact" a user ID, we simply remove ALL signatures
|
||||
except the self-sig that caused the user ID to be remove-worthy.
|
||||
We don't actually remove the user ID packet itself since it might
|
||||
be resurrected in a later merge. Note that this function requires
|
||||
that the caller has already done a merge_keys_and_selfsig().
|
||||
|
||||
TODO: change the import code to allow importing a uid with only a
|
||||
revocation if the uid already exists on the keyring. */
|
||||
|
||||
static int
|
||||
clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
|
||||
{
|
||||
kbnode_t node;
|
||||
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
|
||||
int deleted = 0;
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||
|
||||
/* Skip valid user IDs, compacted user IDs, and non-self-signed user
|
||||
IDs if --allow-non-selfsigned-uid is set. */
|
||||
if (uid->created
|
||||
|| uid->flags.compacted
|
||||
|| (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid))
|
||||
return 0;
|
||||
|
||||
for (node=uidnode->next;
|
||||
node && node->pkt->pkttype == PKT_SIGNATURE;
|
||||
node=node->next)
|
||||
{
|
||||
if (!node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||
{
|
||||
delete_kbnode (node);
|
||||
deleted = 1;
|
||||
uidnode->pkt->pkt.user_id->flags.compacted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (noisy)
|
||||
{
|
||||
const char *reason;
|
||||
char *user = utf8_to_native (uid->name, uid->len, 0);
|
||||
|
||||
if (uid->flags.revoked)
|
||||
reason = _("revoked");
|
||||
else if (uid->flags.expired)
|
||||
reason = _("expired");
|
||||
else
|
||||
reason = _("invalid");
|
||||
|
||||
log_info ("compacting user ID \"%s\" on key %s: %s\n",
|
||||
user, keystr_from_pk (keyblock->pkt->pkt.public_key),
|
||||
reason);
|
||||
|
||||
xfree (user);
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
|
||||
/* Needs to be called after a merge_keys_and_selfsig() */
|
||||
void
|
||||
clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
|
||||
{
|
||||
int dummy = 0;
|
||||
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||
|
||||
if (!uids_cleaned)
|
||||
uids_cleaned = &dummy;
|
||||
|
||||
if (!sigs_cleaned)
|
||||
sigs_cleaned = &dummy;
|
||||
|
||||
/* Do clean_uid_from_key first since if it fires off, we don't have
|
||||
to bother with the other. */
|
||||
*uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
|
||||
if (!uidnode->pkt->pkt.user_id->flags.compacted)
|
||||
*sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
|
||||
noisy, self_only);
|
||||
}
|
||||
|
||||
|
||||
/* NB: This function marks the deleted nodes only and the caller is
|
||||
* responsible to skip or remove them. */
|
||||
void
|
||||
clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||
int *uids_cleaned, int *sigs_cleaned)
|
||||
{
|
||||
kbnode_t node;
|
||||
|
||||
merge_keys_and_selfsig (ctrl, keyblock);
|
||||
|
||||
for (node = keyblock->next;
|
||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||
node = node->next)
|
||||
{
|
||||
if (node->pkt->pkttype == PKT_USER_ID)
|
||||
clean_one_uid (ctrl, keyblock, node, noisy, self_only,
|
||||
uids_cleaned, sigs_cleaned);
|
||||
}
|
||||
|
||||
/* Remove bogus subkey binding signatures: The only signatures
|
||||
* allowed are of class 0x18 and 0x28. */
|
||||
log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY));
|
||||
for (; node; node = node->next)
|
||||
{
|
||||
if (is_deleted_kbnode (node))
|
||||
continue;
|
||||
if (node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& !(IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||
|| IS_SUBKEY_REV (node->pkt->pkt.signature)))
|
||||
{
|
||||
delete_kbnode (node);
|
||||
if (sigs_cleaned)
|
||||
++*sigs_cleaned;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "tdbio.h"
|
||||
#include "trustdb.h"
|
||||
#include "tofu.h"
|
||||
#include "key-clean.h"
|
||||
|
||||
|
||||
typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
|
||||
|
|
|
@ -46,36 +46,6 @@
|
|||
#define NAMEHASH_LEN 20
|
||||
|
||||
|
||||
/*
|
||||
* A structure to store key identification as well as some stuff needed
|
||||
* for validation
|
||||
*/
|
||||
struct key_item {
|
||||
struct key_item *next;
|
||||
unsigned int ownertrust,min_ownertrust;
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
char *trust_regexp;
|
||||
u32 kid[2];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check whether the signature SIG is in the klist K.
|
||||
*/
|
||||
static inline struct key_item *
|
||||
is_in_klist (struct key_item *k, PKT_signature *sig)
|
||||
{
|
||||
for (; k; k = k->next)
|
||||
{
|
||||
if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-- trust.c --*/
|
||||
int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk);
|
||||
void register_trusted_keyid (u32 *keyid);
|
||||
|
@ -103,17 +73,6 @@ int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk,
|
|||
const char *get_validity_string (ctrl_t ctrl,
|
||||
PKT_public_key *pk, PKT_user_id *uid);
|
||||
|
||||
void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
u32 *main_kid, struct key_item *klist,
|
||||
u32 curtime, u32 *next_expire);
|
||||
|
||||
void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||
int noisy, int self_only,
|
||||
int *uids_cleaned, int *sigs_cleaned);
|
||||
void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||
int *uids_cleaned,int *sigs_cleaned);
|
||||
|
||||
|
||||
|
||||
/*-- trustdb.c --*/
|
||||
void tdb_register_trusted_keyid (u32 *keyid);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue