diff --git a/doc/gpg.texi b/doc/gpg.texi index b01d0a353..9d51dcb8b 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -632,6 +632,12 @@ 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} +@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. + + @item --quick-addkey @code{fpr} [@code{algo} [@code{usage} [@code{expire}]]] @opindex quick-addkey Directly add a subkey to the key identified by the fingerprint diff --git a/g10/export.c b/g10/export.c index 6a5597ce1..ad42b41b5 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1144,9 +1144,9 @@ print_status_exported (PKT_public_key *pk) /* * Receive a secret key from agent specified by HEXGRIP. * - * Since the key data from agant is encrypted, decrypt it by CIPHERHD. - * Then, parse the decrypted key data in transfer format, and put - * secret parameters into PK. + * Since the key data from the agent is encrypted, decrypt it using + * CIPHERHD context. Then, parse the decrypted key data into transfer + * format, and put secret parameters into PK. * * If CLEARTEXT is 0, store the secret key material * passphrase-protected. Otherwise, store secret key material in the diff --git a/g10/gpg.c b/g10/gpg.c index 7cf51f252..2deb27aeb 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -123,6 +123,7 @@ enum cmd_and_opt_values aQuickAddUid, aQuickAddKey, aQuickRevUid, + aQuickSetExpire, aListConfig, aListGcryptConfig, aGPGConfList, @@ -448,6 +449,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"), ARGPARSE_c (aQuickRevUid, "quick-revuid", N_("quickly revoke a user-id")), + ARGPARSE_c (aQuickSetExpire, "quick-set-expire", + N_("quickly set a new expiration date")), ARGPARSE_c (aFullKeygen, "full-gen-key" , N_("full featured key pair generation")), ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")), @@ -2549,6 +2552,7 @@ main (int argc, char **argv) case aQuickAddUid: case aQuickAddKey: case aQuickRevUid: + case aQuickSetExpire: case aExportOwnerTrust: case aImportOwnerTrust: case aRebuildKeydbCaches: @@ -4384,6 +4388,18 @@ main (int argc, char **argv) } break; + case aQuickSetExpire: + { + const char *x_fpr, *x_expire; + + if (argc != 2) + wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE"); + x_fpr = *argv++; argc--; + x_expire = *argv++; argc--; + keyedit_quick_set_expire (ctrl, x_fpr, x_expire); + } + break; + case aFastImport: opt.import_options |= IMPORT_FAST; case aImport: diff --git a/g10/keyedit.c b/g10/keyedit.c index 94fa8c49a..dadf58685 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -69,7 +69,8 @@ static int menu_delsig (KBNODE pub_keyblock); static int menu_clean (KBNODE 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 int menu_expire (KBNODE pub_keyblock); +static gpg_error_t menu_expire (kbnode_t pub_keyblock, + int force_mainkey, u32 newexpiration); static int menu_changeusage (kbnode_t keyblock); static int menu_backsign (KBNODE pub_keyblock); static int menu_set_primary_uid (KBNODE pub_keyblock); @@ -2599,7 +2600,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, break; case cmdEXPIRE: - if (menu_expire (keyblock)) + if (gpg_err_code (menu_expire (keyblock, 0, 0)) == GPG_ERR_TRUE) { merge_keys_and_selfsig (keyblock); run_subkey_warnings = 1; @@ -3342,6 +3343,86 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr, } +/* Unattended expiration setting function for the main key. + * + */ +void +keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr) +{ + gpg_error_t err; + kbnode_t keyblock; + KEYDB_HANDLE kdbhd; + int modified = 0; + PKT_public_key *pk; + u32 expire; + +#ifdef HAVE_W32_SYSTEM + /* See keyedit_menu for why we need this. */ + check_trustdb_stale (ctrl); +#endif + + /* We require a fingerprint because only this uniquely identifies a + * key and may thus be used to select a key for unattended + * expiration setting. */ + err = find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd); + if (err) + goto leave; + + if (fix_keyblock (&keyblock)) + modified++; + + pk = keyblock->pkt->pkt.public_key; + if (pk->flags.revoked) + { + if (!opt.verbose) + show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1); + log_error ("%s%s", _("Key is revoked."), "\n"); + err = gpg_error (GPG_ERR_CERT_REVOKED); + goto leave; + } + + + expire = parse_expire_string (expirestr); + if (expire == (u32)-1 ) + { + log_error (_("'%s' is not a valid expiration time\n"), expirestr); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + if (expire) + expire += make_timestamp (); + + /* Set the new expiration date. */ + err = menu_expire (keyblock, 1, expire); + if (gpg_err_code (err) == GPG_ERR_TRUE) + modified = 1; + else if (err) + goto leave; + es_fflush (es_stdout); + + /* Store. */ + if (modified) + { + err = keydb_update_keyblock (ctrl, kdbhd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); + goto leave; + } + if (update_trust) + revalidation_mark (); + } + else + log_info (_("Key not changed so no update needed.\n")); + + leave: + release_kbnode (keyblock); + keydb_release (kdbhd); + if (err) + write_status_error ("set_expire", err); +} + + static void tty_print_notations (int indent, PKT_signature * sig) @@ -4736,36 +4817,50 @@ fail: } -static int -menu_expire (KBNODE pub_keyblock) +/* With FORCE_MAINKEY cleared this function handles the interactive + * menu option "expire". With FORCE_MAINKEY set this functions only + * sets the expiration date of the primary key to NEWEXPIRATION and + * avoid all interactivity. Retirns 0 if nothing was done, + * GPG_ERR_TRUE if the key was modified, or any other error code. */ +static gpg_error_t +menu_expire (kbnode_t pub_keyblock, int force_mainkey, u32 newexpiration) { - int n1, signumber, rc; + int signumber, rc; u32 expiredate; int mainkey = 0; PKT_public_key *main_pk, *sub_pk; PKT_user_id *uid; - KBNODE node; + kbnode_t node; u32 keyid[2]; - n1 = count_selected_keys (pub_keyblock); - if (n1 > 1) + if (force_mainkey) { - if (!cpr_get_answer_is_yes - ("keyedit.expire_multiple_subkeys.okay", - _("Are you sure you want to change the" - " expiration time for multiple subkeys? (y/N) "))) - return 0; + mainkey = 1; + expiredate = newexpiration; } - else if (n1) - tty_printf (_("Changing expiration time for a subkey.\n")); else { - tty_printf (_("Changing expiration time for the primary key.\n")); - mainkey = 1; - no_primary_warning (pub_keyblock); + int n1 = count_selected_keys (pub_keyblock); + if (n1 > 1) + { + if (!cpr_get_answer_is_yes + ("keyedit.expire_multiple_subkeys.okay", + _("Are you sure you want to change the" + " expiration time for multiple subkeys? (y/N) "))) + return gpg_error (GPG_ERR_CANCELED);; + } + else if (n1) + tty_printf (_("Changing expiration time for a subkey.\n")); + else + { + tty_printf (_("Changing expiration time for the primary key.\n")); + mainkey = 1; + no_primary_warning (pub_keyblock); + } + + expiredate = ask_expiredate (); } - expiredate = ask_expiredate (); /* Now we can actually change the self-signature(s) */ main_pk = sub_pk = NULL; @@ -4781,7 +4876,7 @@ menu_expire (KBNODE pub_keyblock) } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { - if (node->flag & NODFLG_SELKEY) + if ((node->flag & NODFLG_SELKEY) && !force_mainkey) { sub_pk = node->pkt->pkt.public_key; sub_pk->expiredate = expiredate; @@ -4795,6 +4890,7 @@ menu_expire (KBNODE pub_keyblock) && (mainkey || sub_pk)) { PKT_signature *sig = node->pkt->pkt.signature; + if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && ((mainkey && uid && uid->created && (sig->sig_class & ~3) == 0x10) @@ -4812,7 +4908,7 @@ menu_expire (KBNODE pub_keyblock) { log_info (_("You can't change the expiration date of a v3 key\n")); - return 0; + return gpg_error (GPG_ERR_LEGACY_KEY); } if (mainkey) @@ -4827,7 +4923,9 @@ menu_expire (KBNODE pub_keyblock) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (rc)); - return 0; + if (gpg_err_code (rc) == GPG_ERR_TRUE) + rc = GPG_ERR_GENERAL; + return rc; } /* Replace the packet. */ @@ -4843,7 +4941,7 @@ menu_expire (KBNODE pub_keyblock) } update_trust = 1; - return 1; + return gpg_error (GPG_ERR_TRUE); } diff --git a/g10/main.h b/g10/main.h index 63aec4712..1822ee473 100644 --- a/g10/main.h +++ b/g10/main.h @@ -295,6 +295,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_set_expire (ctrl_t ctrl, + const char *fpr, const char *expirestr); void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/