mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpg: New command --quick-revoke-sig
* g10/gpg.c (enum cmd_and_opt_values): Add aQuickRevSig. (opts): Add --quick-revoke-sig. (main): Implement. * g10/keyedit.c (quick_find_keyblock): Add arg 'want_secret' and adjust all callers. (keyedit_quick_revsig): new. * g10/revoke.c (get_default_sig_revocation_reason): New. * g10/keylist.c (cmp_signodes): New. -- GnuPG-bug-id: 5093 Backported-from-master: 243f9176e799b2328f2e5bed93099bfc474fdc5a
This commit is contained in:
parent
38040ffee8
commit
7ec56b0336
11
doc/gpg.texi
11
doc/gpg.texi
@ -1138,6 +1138,17 @@ you want to specify a different revocation reason, or to supply
|
||||
supplementary revocation text, you should use the interactive
|
||||
sub-command @code{revuid} of @option{--edit-key}.
|
||||
|
||||
@item --quick-revoke-sig @var{fpr} @var{signing-fpr} [@var{names}]
|
||||
@opindex quick-revoke-sig
|
||||
This command revokes the key signatures made by @var{signing-fpr} from
|
||||
the key specified by the fingerprint @var{fpr}. With @var{names}
|
||||
given only the signatures on user ids of the key matching any of the
|
||||
given names are affected (see @option{--quick-sign-key}). If a
|
||||
revocation already exists a notice is printed instead of creating a
|
||||
new revocation; no error is returned in this case. Note that key
|
||||
signature revocations may be superseded by a newer key signature and
|
||||
in turn again revoked.
|
||||
|
||||
@item --quick-set-primary-uid @var{user-id} @var{primary-user-id}
|
||||
@opindex quick-set-primary-uid
|
||||
This command sets or updates the primary user ID flag on an existing
|
||||
|
20
g10/gpg.c
20
g10/gpg.c
@ -125,6 +125,7 @@ enum cmd_and_opt_values
|
||||
aLSignKey,
|
||||
aQuickSignKey,
|
||||
aQuickLSignKey,
|
||||
aQuickRevSig,
|
||||
aQuickAddUid,
|
||||
aQuickAddKey,
|
||||
aQuickRevUid,
|
||||
@ -489,6 +490,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
N_("quickly sign a key")),
|
||||
ARGPARSE_c (aQuickLSignKey, "quick-lsign-key",
|
||||
N_("quickly sign a key locally")),
|
||||
ARGPARSE_c (aQuickRevSig, "quick-revoke-sig" ,
|
||||
N_("quickly revoke a key signature")),
|
||||
ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")),
|
||||
ARGPARSE_c (aLSignKey, "lsign-key" ,N_("sign a key locally")),
|
||||
ARGPARSE_c (aEditKey, "edit-key" ,N_("sign or edit a key")),
|
||||
@ -2610,6 +2613,7 @@ main (int argc, char **argv)
|
||||
case aSign:
|
||||
case aQuickSignKey:
|
||||
case aQuickLSignKey:
|
||||
case aQuickRevSig:
|
||||
case aSignKey:
|
||||
case aLSignKey:
|
||||
case aStore:
|
||||
@ -4382,6 +4386,22 @@ main (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
|
||||
case aQuickRevSig:
|
||||
{
|
||||
const char *userid, *siguserid;
|
||||
|
||||
if (argc < 2)
|
||||
wrong_args ("--quick-revoke-sig USER-ID SIG-USER-ID [userids]");
|
||||
userid = *argv++; argc--;
|
||||
siguserid = *argv++; argc--;
|
||||
sl = NULL;
|
||||
for( ; argc; argc--, argv++)
|
||||
append_to_strlist2 (&sl, *argv, utf8_strings);
|
||||
keyedit_quick_revsig (ctrl, userid, siguserid, sl);
|
||||
free_strlist (sl);
|
||||
}
|
||||
break;
|
||||
|
||||
case aSignKey:
|
||||
if( argc != 1 )
|
||||
wrong_args("--sign-key user-id");
|
||||
|
246
g10/keyedit.c
246
g10/keyedit.c
@ -2275,7 +2275,7 @@ leave:
|
||||
* Returns on success the key database handle at R_KDBHD and the
|
||||
* keyblock at R_KEYBLOCK. */
|
||||
static gpg_error_t
|
||||
quick_find_keyblock (ctrl_t ctrl, const char *username,
|
||||
quick_find_keyblock (ctrl_t ctrl, const char *username, int want_secret,
|
||||
KEYDB_HANDLE *r_kdbhd, kbnode_t *r_keyblock)
|
||||
{
|
||||
gpg_error_t err;
|
||||
@ -2318,7 +2318,7 @@ quick_find_keyblock (ctrl_t ctrl, const char *username,
|
||||
err = 0;
|
||||
keydb_pop_found_state (kdbhd);
|
||||
|
||||
if (!err)
|
||||
if (!err && want_secret)
|
||||
{
|
||||
/* We require the secret primary key to set the primary UID. */
|
||||
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
||||
@ -2375,7 +2375,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
|
||||
#endif
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. */
|
||||
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
|
||||
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -2418,7 +2418,7 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
|
||||
#endif
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. */
|
||||
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
|
||||
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -2498,7 +2498,7 @@ keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
|
||||
check_trustdb_stale (ctrl);
|
||||
#endif
|
||||
|
||||
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
|
||||
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -2771,6 +2771,240 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
|
||||
}
|
||||
|
||||
|
||||
/* Unattended revocation of a key signatures. USERNAME specifies the
|
||||
* key; this should best be a fingerprint. SIGTOREV is the user-id of
|
||||
* the key for which the key signature shall be removed. Only
|
||||
* non-self-signatures can be removed with this functions. If
|
||||
* AFFECTED_UIDS is not NULL only the key signatures on these user-ids
|
||||
* are revoked. */
|
||||
void
|
||||
keyedit_quick_revsig (ctrl_t ctrl, const char *username, const char *sigtorev,
|
||||
strlist_t affected_uids)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int no_signing_key = 0;
|
||||
KEYDB_HANDLE kdbhd = NULL;
|
||||
kbnode_t keyblock = NULL;
|
||||
PKT_public_key *primarypk; /* Points into KEYBLOCK. */
|
||||
u32 *primarykid;
|
||||
PKT_public_key *pksigtorev = NULL;
|
||||
u32 *pksigtorevkid;
|
||||
kbnode_t node, n;
|
||||
int skip_remaining;
|
||||
int consider_sig;
|
||||
strlist_t sl;
|
||||
struct sign_attrib attrib = { 0 };
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* See keyedit_menu for why we need this. */
|
||||
check_trustdb_stale (ctrl);
|
||||
#endif
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. Noet
|
||||
* that we are looking for the public key here. */
|
||||
err = quick_find_keyblock (ctrl, username, 0, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
goto leave;
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
primarypk = keyblock->pkt->pkt.public_key;
|
||||
primarykid = pk_keyid (primarypk);
|
||||
|
||||
/* Get the signing key we want to revoke. This must be one of our
|
||||
* signing keys. We will compare only the keyid because we don't
|
||||
* assume that we have duplicated keyids on our own secret keys. If
|
||||
* a there is a duplicated one we will notice this when creating the
|
||||
* revocation. */
|
||||
pksigtorev = xtrycalloc (1, sizeof *pksigtorev);
|
||||
if (!pksigtorev)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
pksigtorev->req_usage = PUBKEY_USAGE_CERT;
|
||||
err = getkey_byname (ctrl, NULL, pksigtorev, sigtorev, 1, NULL);
|
||||
if (err)
|
||||
{
|
||||
no_signing_key = 1;
|
||||
goto leave;
|
||||
}
|
||||
pksigtorevkid = pk_keyid (pksigtorev);
|
||||
|
||||
/* Find the signatures we want to revoke and set a mark. */
|
||||
skip_remaining = consider_sig = 0;
|
||||
for (node = keyblock; node; node = node->next)
|
||||
{
|
||||
node->flag &= ~NODFLG_MARK_A;
|
||||
if (skip_remaining)
|
||||
;
|
||||
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||
skip_remaining = 1;
|
||||
else if (node->pkt->pkttype == PKT_USER_ID)
|
||||
{
|
||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||
|
||||
consider_sig = !affected_uids;
|
||||
for (sl = affected_uids; !consider_sig && sl; sl = sl->next)
|
||||
{
|
||||
const char *name = sl->d;
|
||||
|
||||
if (uid->attrib_data)
|
||||
;
|
||||
else if (*name == '='
|
||||
&& strlen (name+1) == uid->len
|
||||
&& !memcmp (uid->name, name + 1, uid->len))
|
||||
{ /* Exact match. */
|
||||
consider_sig = 1;
|
||||
}
|
||||
else if (ascii_memistr (uid->name, uid->len,
|
||||
*name == '*'? name+1:name))
|
||||
{ /* Case-insensitive substring match. */
|
||||
consider_sig = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node->pkt->pkttype == PKT_SIGNATURE)
|
||||
{
|
||||
/* We need to sort the signatures so that we can figure out
|
||||
* whether the key signature has been revoked or the
|
||||
* revocation has been superseded by a new key
|
||||
* signature. */
|
||||
PKT_signature *sig;
|
||||
unsigned int sigcount = 0;
|
||||
kbnode_t *sigarray;
|
||||
|
||||
/* Allocate an array large enogh for all signatures. */
|
||||
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
|
||||
sigcount++;
|
||||
sigarray = xtrycalloc (sigcount, sizeof *sigarray);
|
||||
if (!sigarray)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Now fill the array with signatures we are interested in.
|
||||
* We also move NODE forward to the end. */
|
||||
sigcount = 0;
|
||||
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; node=n, n=n->next)
|
||||
{
|
||||
sig = node->pkt->pkt.signature;
|
||||
if (!keyid_cmp (primarykid, sig->keyid))
|
||||
continue; /* Ignore self-signatures. */
|
||||
|
||||
if (keyid_cmp (pksigtorevkid, sig->keyid))
|
||||
continue; /* Ignore non-matching signatures. */
|
||||
|
||||
n->flag &= ~NODFLG_MARK_B; /* Clear flag used by cmp_signode. */
|
||||
sigarray[sigcount++] = n;
|
||||
}
|
||||
|
||||
if (sigcount)
|
||||
{
|
||||
qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
|
||||
|
||||
/* log_debug ("Sorted signatures:\n"); */
|
||||
/* for (idx=0; idx < sigcount; idx++) */
|
||||
/* { */
|
||||
/* sig = sigarray[idx]->pkt->pkt.signature; */
|
||||
/* log_debug ("%s 0x%02x %s\n", keystr (sig->keyid), */
|
||||
/* sig->sig_class, datestr_from_sig (sig)); */
|
||||
/* } */
|
||||
sig = sigarray[sigcount-1]->pkt->pkt.signature;
|
||||
if ((consider_sig || !affected_uids) && IS_UID_REV (sig))
|
||||
{
|
||||
if (!opt.quiet)
|
||||
log_info ("sig by %s already revoked at %s\n",
|
||||
keystr (sig->keyid), datestr_from_sig (sig));
|
||||
}
|
||||
else if ((consider_sig && IS_UID_SIG (sig))
|
||||
|| (!affected_uids && IS_KEY_SIG (sig)))
|
||||
node->flag |= NODFLG_MARK_A; /* Select signature. */
|
||||
}
|
||||
|
||||
xfree (sigarray);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether any signatures were done by the given key. We do
|
||||
* not return an error if none were found. */
|
||||
for (node = keyblock; node; node = node->next)
|
||||
if ((node->flag & NODFLG_MARK_A))
|
||||
break;
|
||||
if (!node)
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info (_("Not signed by you.\n"));
|
||||
err = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Revoke all marked signatures. */
|
||||
attrib.reason = get_default_sig_revocation_reason ();
|
||||
|
||||
reloop: /* (we must repeat because we are modifying the list) */
|
||||
for (node = keyblock; node; node = node->next)
|
||||
{
|
||||
kbnode_t unode;
|
||||
PKT_signature *sig;
|
||||
PACKET *pkt;
|
||||
|
||||
if (!(node->flag & NODFLG_MARK_A))
|
||||
continue;
|
||||
node->flag &= ~NODFLG_MARK_A;
|
||||
|
||||
if (IS_KEY_SIG (node->pkt->pkt.signature))
|
||||
unode = NULL;
|
||||
else
|
||||
{
|
||||
unode = find_prev_kbnode (keyblock, node, PKT_USER_ID);
|
||||
log_assert (unode);
|
||||
}
|
||||
|
||||
attrib.non_exportable = !node->pkt->pkt.signature->flags.exportable;
|
||||
|
||||
err = make_keysig_packet (ctrl, &sig, primarypk,
|
||||
unode? unode->pkt->pkt.user_id : NULL,
|
||||
NULL, pksigtorev, 0x30, 0, 0, 0,
|
||||
sign_mk_attrib, &attrib, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("signing failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
pkt = xmalloc_clear (sizeof *pkt);
|
||||
pkt->pkttype = PKT_SIGNATURE;
|
||||
pkt->pkt.signature = sig;
|
||||
if (unode)
|
||||
insert_kbnode (unode, new_kbnode (pkt), 0);
|
||||
goto reloop;
|
||||
}
|
||||
|
||||
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
revalidation_mark (ctrl);
|
||||
|
||||
leave:
|
||||
if (err)
|
||||
{
|
||||
log_error (_("revoking the key signature failed: %s\n"),
|
||||
gpg_strerror (err));
|
||||
if (no_signing_key)
|
||||
print_further_info ("error getting key used to make the key signature");
|
||||
write_status_error ("keyedit.revoke.sig", err);
|
||||
}
|
||||
release_revocation_reason_info (attrib.reason);
|
||||
free_public_key (pksigtorev);
|
||||
release_kbnode (keyblock);
|
||||
keydb_release (kdbhd);
|
||||
}
|
||||
|
||||
|
||||
/* Unattended subkey creation function.
|
||||
*
|
||||
*/
|
||||
@ -5990,7 +6224,7 @@ core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
|
||||
memset (&attrib, 0, sizeof attrib);
|
||||
/* should not need to cast away const here; but
|
||||
revocation_reason_build_cb needs to take a non-const
|
||||
void* in order to meet the function signtuare for the
|
||||
void* in order to meet the function signature for the
|
||||
mksubpkt argument to make_keysig_packet */
|
||||
attrib.reason = (struct revocation_reason_info *)reason;
|
||||
|
||||
|
@ -33,6 +33,8 @@
|
||||
#define NODFLG_SELKEY (1<<9) /* Indicate the selected key. */
|
||||
#define NODFLG_SELSIG (1<<10) /* Indicate a selected signature. */
|
||||
|
||||
#define NODFLG_MARK_B (1<<11) /* Temporary mark in key listing code. */
|
||||
|
||||
/*-- keyedit.c --*/
|
||||
void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
||||
strlist_t commands, int quiet, int seckey_check );
|
||||
@ -45,6 +47,8 @@ void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
|
||||
const char *uidtorev);
|
||||
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
|
||||
strlist_t uids, strlist_t locusr, int local);
|
||||
void keyedit_quick_revsig (ctrl_t ctrl, const char *username,
|
||||
const char *sigtorev, strlist_t affected_uids);
|
||||
void keyedit_quick_set_expire (ctrl_t ctrl,
|
||||
const char *fpr, const char *expirestr,
|
||||
char **subkeyfprs);
|
||||
|
@ -893,6 +893,51 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
|
||||
}
|
||||
|
||||
|
||||
/* Order two signatures. We first order by keyid and then by creation
|
||||
* time. This is currently only used in keyedit.c */
|
||||
int
|
||||
cmp_signodes (const void *av, const void *bv)
|
||||
{
|
||||
const kbnode_t an = *(const kbnode_t *)av;
|
||||
const kbnode_t bn = *(const kbnode_t *)bv;
|
||||
const PKT_signature *a;
|
||||
const PKT_signature *b;
|
||||
int i;
|
||||
|
||||
/* log_assert (an->pkt->pkttype == PKT_SIGNATURE); */
|
||||
/* log_assert (bn->pkt->pkttype == PKT_SIGNATURE); */
|
||||
|
||||
a = an->pkt->pkt.signature;
|
||||
b = bn->pkt->pkt.signature;
|
||||
|
||||
/* Self-signatures are ordered first. */
|
||||
if ((an->flag & NODFLG_MARK_B) && !(bn->flag & NODFLG_MARK_B))
|
||||
return -1;
|
||||
if (!(an->flag & NODFLG_MARK_B) && (bn->flag & NODFLG_MARK_B))
|
||||
return 1;
|
||||
|
||||
/* then the keyids. (which are or course the same for self-sigs). */
|
||||
i = keyid_cmp (a->keyid, b->keyid);
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
/* Followed by creation time */
|
||||
if (a->timestamp > b->timestamp)
|
||||
return 1;
|
||||
if (a->timestamp < b->timestamp)
|
||||
return -1;
|
||||
|
||||
/* followed by the class in a way that a rev comes first. */
|
||||
if (a->sig_class > b->sig_class)
|
||||
return 1;
|
||||
if (a->sig_class < b->sig_class)
|
||||
return -1;
|
||||
|
||||
/* To make the sort stable we compare the entire structure as last resort. */
|
||||
return memcmp (a, b, sizeof *a);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
||||
struct keylist_context *listctx)
|
||||
|
@ -447,8 +447,9 @@ int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
|
||||
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
|
||||
struct revocation_reason_info *
|
||||
ask_revocation_reason( int key_rev, int cert_rev, int hint );
|
||||
struct revocation_reason_info * get_default_uid_revocation_reason(void);
|
||||
void release_revocation_reason_info( struct revocation_reason_info *reason );
|
||||
struct revocation_reason_info * get_default_uid_revocation_reason (void);
|
||||
struct revocation_reason_info * get_default_sig_revocation_reason (void);
|
||||
void release_revocation_reason_info (struct revocation_reason_info *reason);
|
||||
|
||||
/*-- keylist.c --*/
|
||||
void public_key_list (ctrl_t ctrl, strlist_t list,
|
||||
@ -458,6 +459,7 @@ void print_subpackets_colon(PKT_signature *sig);
|
||||
void reorder_keyblock (KBNODE keyblock);
|
||||
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
|
||||
int has_secret, int fpr, int no_validity);
|
||||
int cmp_signodes (const void *av, const void *bv);
|
||||
void print_fingerprint (ctrl_t ctrl, estream_t fp,
|
||||
PKT_public_key *pk, int mode);
|
||||
void print_revokers (estream_t fp, PKT_public_key *pk);
|
||||
|
10
g10/revoke.c
10
g10/revoke.c
@ -891,6 +891,16 @@ get_default_uid_revocation_reason(void)
|
||||
return reason;
|
||||
}
|
||||
|
||||
struct revocation_reason_info *
|
||||
get_default_sig_revocation_reason(void)
|
||||
{
|
||||
struct revocation_reason_info *reason;
|
||||
reason = xmalloc( sizeof *reason );
|
||||
reason->code = 0; /* No specific reason given. */
|
||||
reason->desc = strdup(""); /* no text */
|
||||
return reason;
|
||||
}
|
||||
|
||||
void
|
||||
release_revocation_reason_info( struct revocation_reason_info *reason )
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user