gpg: Extend --quick-set-expire to allow subkey expiration setting.

* g10/keyedit.c (keyedit_quick_set_expire): Add new arg subkeyfprs.
(menu_expire): Rename arg force_mainkey to unattended and allow
unattended changing of subkey expiration.
* g10/gpg.c (main): Extend --quick-set-expire.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-07-21 14:12:55 +02:00
parent e888f7af65
commit b55b72bb81
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 117 additions and 29 deletions

View File

@ -663,10 +663,16 @@ supplied passphrase is used for the new key and the agent does not ask
for it. To create a key without any protection @code{--passphrase ''}
may be used.
@item --quick-set-expire @code{fpr} @code{expire}
@item --quick-set-expire @var{fpr} @var{expire} [*|@var{subfprs}]
@opindex quick-set-expire
Directly set the expiration time of the primary key to @code{expire}.
To remove the expiration time @code{0} can be used.
With two arguments given, directly set the expiration time of the
primary key identified by @var{fpr} to @var{expire}. To remove the
expiration time @code{0} can be used. With three arguments and the
third given as an asterisk, the expiration time of all non-revoked and
not yet expired subkeys are set to @var{expire}. With more than two
arguments and a list of fingerprints given for @var{subfprs}, all
non-revoked subkeys matching these fingerprints are set to
@var{expire}.
@item --quick-add-key @code{fpr} [@code{algo} [@code{usage} [@code{expire}]]]

View File

@ -4491,11 +4491,11 @@ main (int argc, char **argv)
{
const char *x_fpr, *x_expire;
if (argc != 2)
wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE");
if (argc < 2)
wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE [SUBKEY-FPRS]");
x_fpr = *argv++; argc--;
x_expire = *argv++; argc--;
keyedit_quick_set_expire (ctrl, x_fpr, x_expire);
keyedit_quick_set_expire (ctrl, x_fpr, x_expire, argv);
}
break;

View File

@ -73,7 +73,7 @@ static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
static void menu_delkey (KBNODE pub_keyblock);
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
int force_mainkey, u32 newexpiration);
int unattended, u32 newexpiration);
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock);
static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock);
@ -2808,18 +2808,24 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
}
/* Unattended expiration setting function for the main key.
*
/* Unattended expiration setting function for the main key. If
* SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
* expected to be an array of fingerprints for subkeys to change. It
* may also be an array which just one item "*" to indicate that all
* keys shall be set to that expiration date.
*/
void
keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr,
char **subkeyfprs)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t keyblock, node;
KEYDB_HANDLE kdbhd;
int modified = 0;
PKT_public_key *pk;
u32 expire;
int primary_only = 0;
int idx;
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
@ -2846,7 +2852,6 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
goto leave;
}
expire = parse_expire_string (expirestr);
if (expire == (u32)-1 )
{
@ -2857,8 +2862,78 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
if (expire)
expire += make_timestamp ();
/* Check whether a subkey's expiration time shall be changed or the
* expiration time of all keys. */
if (!subkeyfprs || !subkeyfprs[0])
primary_only = 1;
else if ( !strcmp (subkeyfprs[0], "*") && !subkeyfprs[1])
{
/* Change all subkeys keys which have not been revoked and are
* not yet expired. */
merge_keys_and_selfsig (ctrl, keyblock);
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
&& (pk = node->pkt->pkt.public_key)
&& !pk->flags.revoked
&& !pk->has_expired)
node->flag |= NODFLG_SELKEY;
}
}
else
{
/* Change specified subkeys. */
KEYDB_SEARCH_DESC desc;
byte fprbin[MAX_FINGERPRINT_LEN];
size_t fprlen;
err = 0;
merge_keys_and_selfsig (ctrl, keyblock);
for (idx=0; subkeyfprs[idx]; idx++)
{
int any = 0;
/* Parse the fingerprint. */
if (classify_user_id (subkeyfprs[idx], &desc, 1)
|| !(desc.mode == KEYDB_SEARCH_MODE_FPR
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
{
log_error (_("\"%s\" is not a proper fingerprint\n"),
subkeyfprs[idx] );
if (!err)
err = gpg_error (GPG_ERR_INV_NAME);
continue;
}
/* Set the flag for the matching non revoked subkey. */
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
&& (pk = node->pkt->pkt.public_key)
&& !pk->flags.revoked )
{
fingerprint_from_pk (pk, fprbin, &fprlen);
if (fprlen == 20 && !memcmp (fprbin, desc.u.fpr, 20))
{
node->flag |= NODFLG_SELKEY;
any = 1;
}
}
}
if (!any)
{
log_error (_("subkey \"%s\" not found\n"), subkeyfprs[idx]);
if (!err)
err = gpg_error (GPG_ERR_NOT_FOUND);
}
}
if (err)
goto leave;
}
/* Set the new expiration date. */
err = menu_expire (ctrl, keyblock, 1, expire);
err = menu_expire (ctrl, keyblock, primary_only? 1 : 2, expire);
if (gpg_err_code (err) == GPG_ERR_TRUE)
modified = 1;
else if (err)
@ -4283,30 +4358,34 @@ fail:
/* With FORCE_MAINKEY cleared this function handles the interactive
* menu option "expire". With FORCE_MAINKEY set this functions only
* menu option "expire". With UNATTENDED set to 1 this function only
* sets the expiration date of the primary key to NEWEXPIRATION and
* avoid all interactivity. Retirns 0 if nothing was done,
* avoid all interactivity; with a value of 2 only the flagged subkeys
* are set to NEWEXPIRATION. Returns 0 if nothing was done,
* GPG_ERR_TRUE if the key was modified, or any other error code. */
static gpg_error_t
menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
int force_mainkey, u32 newexpiration)
int unattended, u32 newexpiration)
{
int signumber, rc;
u32 expiredate;
int mainkey = 0;
int only_mainkey; /* Set if only the mainkey is to be updated. */
PKT_public_key *main_pk, *sub_pk;
PKT_user_id *uid;
kbnode_t node;
u32 keyid[2];
if (force_mainkey)
if (unattended)
{
mainkey = 1;
only_mainkey = (unattended == 1);
expiredate = newexpiration;
}
else
{
int n1 = count_selected_keys (pub_keyblock);
int n1;
only_mainkey = 0;
n1 = count_selected_keys (pub_keyblock);
if (n1 > 1)
{
if (!cpr_get_answer_is_yes
@ -4320,7 +4399,7 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
else
{
tty_printf (_("Changing expiration time for the primary key.\n"));
mainkey = 1;
only_mainkey = 1;
no_primary_warning (pub_keyblock);
}
@ -4342,8 +4421,10 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
}
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
if ((node->flag & NODFLG_SELKEY) && !force_mainkey)
if ((node->flag & NODFLG_SELKEY) && unattended != 1)
{
/* The flag is set and we do not want to set the
* expiration date only for the main key. */
sub_pk = node->pkt->pkt.public_key;
sub_pk->expiredate = expiredate;
}
@ -4353,14 +4434,14 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
else if (node->pkt->pkttype == PKT_USER_ID)
uid = node->pkt->pkt.user_id;
else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
&& (mainkey || sub_pk))
&& (only_mainkey || sub_pk))
{
PKT_signature *sig = node->pkt->pkt.signature;
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
&& ((mainkey && uid
&& ((only_mainkey && uid
&& uid->created && (sig->sig_class & ~3) == 0x10)
|| (!mainkey && sig->sig_class == 0x18))
|| (!only_mainkey && sig->sig_class == 0x18))
&& sig->flags.chosen_selfsig)
{
/* This is a self-signature which is to be replaced. */
@ -4369,15 +4450,15 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
signumber++;
if ((mainkey && main_pk->version < 4)
|| (!mainkey && sub_pk->version < 4))
if ((only_mainkey && main_pk->version < 4)
|| (!only_mainkey && sub_pk->version < 4))
{
log_info
(_("You can't change the expiration date of a v3 key\n"));
return gpg_error (GPG_ERR_LEGACY_KEY);
}
if (mainkey)
if (only_mainkey)
rc = update_keysig_packet (ctrl,
&newsig, sig, main_pk, uid, NULL,
main_pk, keygen_add_key_expire,

View File

@ -46,7 +46,8 @@ void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
strlist_t uids, strlist_t locusr, int local);
void keyedit_quick_set_expire (ctrl_t ctrl,
const char *fpr, const char *expirestr);
const char *fpr, const char *expirestr,
char **subkeyfprs);
void keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
const char *primaryuid);
void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock);