2015-05-08 16:08:57 +02:00
|
|
|
|
/* keyedit.c - Edit properties of a key
|
|
|
|
|
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
2017-03-21 14:47:21 +01:00
|
|
|
|
* Copyright (C) 1998-2017 Werner Koch
|
2023-03-01 17:22:20 +01:00
|
|
|
|
* Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*
|
|
|
|
|
* 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
|
2007-07-04 21:49:40 +02:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* (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
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <ctype.h>
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef HAVE_LIBREADLINE
|
2010-04-20 20:19:19 +02:00
|
|
|
|
# define GNUPG_LIBREADLINE_H_INCLUDED
|
|
|
|
|
# include <readline/readline.h>
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#endif
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2003-06-18 21:56:13 +02:00
|
|
|
|
#include "gpg.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "options.h"
|
|
|
|
|
#include "packet.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/status.h"
|
|
|
|
|
#include "../common/iobuf.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "keydb.h"
|
|
|
|
|
#include "photoid.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/util.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "trustdb.h"
|
|
|
|
|
#include "filter.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/ttyio.h"
|
|
|
|
|
#include "../common/status.h"
|
|
|
|
|
#include "../common/i18n.h"
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#include "keyserver-internal.h"
|
2010-04-21 18:26:17 +02:00
|
|
|
|
#include "call-agent.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/host2net.h"
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
#include "tofu.h"
|
2017-06-13 15:34:03 +02:00
|
|
|
|
#include "key-check.h"
|
2018-07-06 11:40:16 +02:00
|
|
|
|
#include "key-clean.h"
|
2017-06-13 15:27:43 +02:00
|
|
|
|
#include "keyedit.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
|
|
|
|
|
int verbose);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
static void show_names (ctrl_t ctrl, estream_t fp,
|
|
|
|
|
kbnode_t keyblock, PKT_public_key * pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
unsigned int flag, int with_prefs);
|
2015-07-28 18:21:47 +02:00
|
|
|
|
static void show_key_with_all_names (ctrl_t ctrl, estream_t fp,
|
2014-03-27 12:59:55 +01:00
|
|
|
|
KBNODE keyblock, int only_marked,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int with_revoker, int with_fpr,
|
2014-03-27 16:33:40 +01:00
|
|
|
|
int with_subkeys, int with_prefs,
|
|
|
|
|
int nowarn);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static void show_key_and_fingerprint (ctrl_t ctrl,
|
|
|
|
|
kbnode_t keyblock, int with_subkeys);
|
2015-08-06 18:00:12 +02:00
|
|
|
|
static void show_key_and_grip (kbnode_t keyblock);
|
2014-09-17 16:27:37 +02:00
|
|
|
|
static void subkey_expire_warning (kbnode_t keyblock);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
static int menu_adduid (ctrl_t ctrl, kbnode_t keyblock,
|
|
|
|
|
int photo, const char *photo_name, const char *uidstr);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
static void menu_deluid (KBNODE pub_keyblock);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
|
2024-03-04 14:22:42 +01:00
|
|
|
|
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, unsigned int options);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
static void menu_delkey (KBNODE pub_keyblock);
|
2010-10-01 22:33:53 +02:00
|
|
|
|
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock,
|
|
|
|
|
const char *adskfpr);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
|
2017-07-21 14:12:55 +02:00
|
|
|
|
int unattended, u32 newexpiration);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
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);
|
2022-11-04 15:26:15 +01:00
|
|
|
|
static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock,
|
|
|
|
|
int unattended);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int menu_set_keyserver_url (ctrl_t ctrl,
|
|
|
|
|
const char *url, kbnode_t pub_keyblock);
|
|
|
|
|
static int menu_set_notation (ctrl_t ctrl,
|
|
|
|
|
const char *string, kbnode_t pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static int menu_select_uid (KBNODE keyblock, int idx);
|
|
|
|
|
static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash);
|
2015-11-17 21:21:03 +01:00
|
|
|
|
static int menu_select_key (KBNODE keyblock, int idx, char *p);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static int count_uids (KBNODE keyblock);
|
|
|
|
|
static int count_uids_with_flag (KBNODE keyblock, unsigned flag);
|
|
|
|
|
static int count_keys_with_flag (KBNODE keyblock, unsigned flag);
|
|
|
|
|
static int count_selected_uids (KBNODE keyblock);
|
|
|
|
|
static int real_uids_left (KBNODE keyblock);
|
|
|
|
|
static int count_selected_keys (KBNODE keyblock);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int menu_revsig (ctrl_t ctrl, kbnode_t keyblock);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
|
2016-06-17 00:05:57 +02:00
|
|
|
|
static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
|
|
|
|
|
const struct revocation_reason_info *reason,
|
|
|
|
|
int *modified);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock);
|
|
|
|
|
static int menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock);
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable);
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2016-05-21 11:41:49 +02:00
|
|
|
|
static void menu_showphoto (ctrl_t ctrl, kbnode_t keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
static int update_trust = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
#define CONTROL_D ('D' - 'A' + 1)
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
struct sign_attrib
|
|
|
|
|
{
|
|
|
|
|
int non_exportable, non_revocable;
|
|
|
|
|
struct revocation_reason_info *reason;
|
|
|
|
|
byte trust_depth, trust_value;
|
|
|
|
|
char *trust_regexp;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
};
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO: Fix duplicated code between here and the check-sigs/list-sigs
|
|
|
|
|
code in keylist.c. */
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_and_check_one_sig_colon (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
|
2006-04-19 13:26:11 +02:00
|
|
|
|
int *inv_sigs, int *no_key, int *oth_err,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int *is_selfsig, int print_without_key)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
int rc, sigrc;
|
|
|
|
|
|
|
|
|
|
/* TODO: Make sure a cached sig record here still has the pk that
|
|
|
|
|
issued it. See also keylist.c:list_keyblock_print */
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, node, is_selfsig);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
switch (gpg_err_code (rc))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
case 0:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
sigrc = '!';
|
|
|
|
|
break;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
case GPG_ERR_BAD_SIGNATURE:
|
2006-04-19 13:26:11 +02:00
|
|
|
|
node->flag = NODFLG_BADSIG;
|
|
|
|
|
sigrc = '-';
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (inv_sigs)
|
|
|
|
|
++ * inv_sigs;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
case GPG_ERR_NO_PUBKEY:
|
|
|
|
|
case GPG_ERR_UNUSABLE_PUBKEY:
|
2006-04-19 13:26:11 +02:00
|
|
|
|
node->flag = NODFLG_NOKEY;
|
|
|
|
|
sigrc = '?';
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (no_key)
|
|
|
|
|
++ * no_key;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
node->flag = NODFLG_SIGERR;
|
|
|
|
|
sigrc = '%';
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (oth_err)
|
|
|
|
|
++ * oth_err;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sigrc != '?' || print_without_key)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:",
|
|
|
|
|
sigrc, sig->pubkey_algo, (ulong) sig->keyid[0],
|
|
|
|
|
(ulong) sig->keyid[1], (ulong) sig->timestamp,
|
|
|
|
|
(ulong) sig->expiredate);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->trust_depth || sig->trust_value)
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf ("%d %d", sig->trust_depth, sig->trust_value);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf (":");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->trust_regexp)
|
|
|
|
|
es_write_sanitized (es_stdout,
|
|
|
|
|
sig->trust_regexp, strlen (sig->trust_regexp),
|
|
|
|
|
":", NULL);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf ("::%02x%c\n", sig->sig_class,
|
|
|
|
|
sig->flags.exportable ? 'x' : 'l');
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.show_subpackets)
|
|
|
|
|
print_subpackets_colon (sig);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (sigrc == '!');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2016-02-19 15:13:22 +01:00
|
|
|
|
* Print information about a signature (rc is its status), check it
|
|
|
|
|
* and return true if the signature is okay. NODE must be a signature
|
|
|
|
|
* packet. With EXTENDED set all possible signature list options will
|
|
|
|
|
* always be printed.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
2017-06-13 15:27:43 +02:00
|
|
|
|
int
|
2017-07-27 11:37:00 +02:00
|
|
|
|
keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
|
|
|
|
|
int rc, kbnode_t keyblock, kbnode_t node,
|
2017-06-13 15:27:43 +02:00
|
|
|
|
int *inv_sigs, int *no_key, int *oth_err,
|
|
|
|
|
int is_selfsig, int print_without_key, int extended)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2016-02-19 15:13:22 +01:00
|
|
|
|
int sigrc;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int is_rev = sig->sig_class == 0x30;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* TODO: Make sure a cached sig record here still has the pk that
|
|
|
|
|
issued it. See also keylist.c:list_keyblock_print */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-01-22 12:06:11 +01:00
|
|
|
|
switch (gpg_err_code (rc))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR);
|
|
|
|
|
sigrc = '!';
|
|
|
|
|
break;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
case GPG_ERR_BAD_SIGNATURE:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag = NODFLG_BADSIG;
|
|
|
|
|
sigrc = '-';
|
|
|
|
|
if (inv_sigs)
|
|
|
|
|
++ * inv_sigs;
|
|
|
|
|
break;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
case GPG_ERR_NO_PUBKEY:
|
|
|
|
|
case GPG_ERR_UNUSABLE_PUBKEY:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag = NODFLG_NOKEY;
|
|
|
|
|
sigrc = '?';
|
|
|
|
|
if (no_key)
|
|
|
|
|
++ * no_key;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
node->flag = NODFLG_SIGERR;
|
|
|
|
|
sigrc = '%';
|
|
|
|
|
if (oth_err)
|
|
|
|
|
++ * oth_err;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sigrc != '?' || print_without_key)
|
|
|
|
|
{
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, "%s%c%c %c%c%c%c%c%c %s %s",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
is_rev ? "rev" : "sig", 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' +
|
2015-10-01 16:22:29 +02:00
|
|
|
|
sig->trust_depth : ' ',
|
|
|
|
|
keystr (sig->keyid),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
datestr_from_sig (sig));
|
2015-10-01 16:22:29 +02:00
|
|
|
|
if ((opt.list_options & LIST_SHOW_SIG_EXPIRE) || extended )
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, " %s", expirestr_from_sig (sig));
|
|
|
|
|
tty_fprintf (fp, " ");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sigrc == '%')
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, "[%s] ", gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (sigrc == '?')
|
|
|
|
|
;
|
2016-02-19 15:13:22 +01:00
|
|
|
|
else if (is_selfsig)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, is_rev ? _("[revocation]") : _("[self-signature]"));
|
2015-10-01 16:22:29 +02:00
|
|
|
|
if (extended && sig->flags.chosen_selfsig)
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, "*");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t n;
|
2018-04-12 17:53:17 +02:00
|
|
|
|
char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_print_utf8_string2 (fp, p, n,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
opt.screen_columns - keystrlen () - 26 -
|
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_SIG_EXPIRE) ? 11
|
|
|
|
|
: 0));
|
|
|
|
|
xfree (p);
|
|
|
|
|
}
|
2017-07-27 11:37:00 +02:00
|
|
|
|
if (fp == log_get_stream ())
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
else
|
|
|
|
|
tty_fprintf (fp, "\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-10-01 16:22:29 +02:00
|
|
|
|
if (sig->flags.policy_url
|
|
|
|
|
&& ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended))
|
2017-07-27 11:37:00 +02:00
|
|
|
|
show_policy_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-10-01 16:22:29 +02:00
|
|
|
|
if (sig->flags.notation
|
|
|
|
|
&& ((opt.list_options & LIST_SHOW_NOTATIONS) || extended))
|
2017-07-27 11:37:00 +02:00
|
|
|
|
show_notation (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
|
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2015-10-01 16:22:29 +02:00
|
|
|
|
if (sig->flags.pref_ks
|
|
|
|
|
&& ((opt.list_options & LIST_SHOW_KEYSERVER_URLS) || extended))
|
2017-07-27 11:37:00 +02:00
|
|
|
|
show_keyserver_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
|
2015-10-01 17:57:39 +02:00
|
|
|
|
|
|
|
|
|
if (extended)
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
const unsigned char *s;
|
|
|
|
|
|
2019-09-05 20:36:38 +02:00
|
|
|
|
s = parse_sig_subpkt (sig, 1, SIGSUBPKT_PRIMARY_UID, NULL);
|
2015-10-01 17:57:39 +02:00
|
|
|
|
if (s && *s)
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, " [primary]\n");
|
2015-10-01 17:57:39 +02:00
|
|
|
|
|
2019-09-05 20:36:38 +02:00
|
|
|
|
s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
|
2015-10-01 17:57:39 +02:00
|
|
|
|
if (s && buf32_to_u32 (s))
|
2017-07-27 11:37:00 +02:00
|
|
|
|
tty_fprintf (fp, " [expires: %s]\n",
|
|
|
|
|
isotimestamp (pk->timestamp + buf32_to_u32 (s)));
|
2015-10-01 17:57:39 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return (sigrc == '!');
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-15 09:22:24 +01:00
|
|
|
|
|
2016-02-19 15:13:22 +01:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_and_check_one_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
|
2016-02-19 15:13:22 +01:00
|
|
|
|
int *inv_sigs, int *no_key, int *oth_err,
|
|
|
|
|
int *is_selfsig, int print_without_key, int extended)
|
|
|
|
|
{
|
2016-03-15 09:22:24 +01:00
|
|
|
|
int rc;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, node, is_selfsig);
|
2017-07-27 11:37:00 +02:00
|
|
|
|
return keyedit_print_one_sig (ctrl, NULL, rc,
|
2017-06-13 15:27:43 +02:00
|
|
|
|
keyblock, node, inv_sigs, no_key, oth_err,
|
|
|
|
|
*is_selfsig, print_without_key, extended);
|
2016-02-19 15:13:22 +01:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sign_mk_attrib (PKT_signature * sig, void *opaque)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
struct sign_attrib *attrib = opaque;
|
|
|
|
|
byte buf[8];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (attrib->non_exportable)
|
|
|
|
|
{
|
|
|
|
|
buf[0] = 0; /* not exportable */
|
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, buf, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (attrib->non_revocable)
|
|
|
|
|
{
|
|
|
|
|
buf[0] = 0; /* not revocable */
|
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (attrib->reason)
|
|
|
|
|
revocation_reason_build_cb (sig, attrib->reason);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (attrib->trust_depth)
|
|
|
|
|
{
|
|
|
|
|
/* Not critical. If someone doesn't understand trust sigs,
|
|
|
|
|
this can still be a valid regular signature. */
|
|
|
|
|
buf[0] = attrib->trust_depth;
|
|
|
|
|
buf[1] = attrib->trust_value;
|
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_TRUST, buf, 2);
|
|
|
|
|
|
|
|
|
|
/* Critical. If someone doesn't understands regexps, this
|
|
|
|
|
whole sig should be invalid. Note the +1 for the length -
|
|
|
|
|
regexps are null terminated. */
|
|
|
|
|
if (attrib->trust_regexp)
|
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_FLAG_CRITICAL | SIGSUBPKT_REGEXP,
|
|
|
|
|
attrib->trust_regexp,
|
|
|
|
|
strlen (attrib->trust_regexp) + 1);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*trust_value = 0;
|
|
|
|
|
*trust_depth = 0;
|
|
|
|
|
*regexp = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Same string as pkclist.c:do_edit_ownertrust */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_
|
|
|
|
|
("Please decide how far you trust this user to correctly verify"
|
2006-04-19 13:26:11 +02:00
|
|
|
|
" other users' keys\n(by looking at passports, checking"
|
|
|
|
|
" fingerprints from different sources, etc.)\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
tty_printf (_(" %d = I trust marginally\n"), 1);
|
|
|
|
|
tty_printf (_(" %d = I trust fully\n"), 2);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
while (*trust_value == 0)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
p = cpr_get ("trustsig_prompt.trust_value", _("Your selection? "));
|
|
|
|
|
trim_spaces (p);
|
|
|
|
|
cpr_kill_prompt ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* 60 and 120 are as per RFC2440 */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (p[0] == '1' && !p[1])
|
|
|
|
|
*trust_value = 60;
|
|
|
|
|
else if (p[0] == '2' && !p[1])
|
|
|
|
|
*trust_value = 120;
|
|
|
|
|
xfree (p);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Please enter the depth of this trust signature.\n"
|
2016-05-04 11:04:43 +02:00
|
|
|
|
"A depth greater than 1 allows the key you are"
|
|
|
|
|
" signing to make\n"
|
2010-04-20 20:19:19 +02:00
|
|
|
|
"trust signatures on your behalf.\n"));
|
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
while (*trust_depth == 0)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
p = cpr_get ("trustsig_prompt.trust_depth", _("Your selection? "));
|
|
|
|
|
trim_spaces (p);
|
|
|
|
|
cpr_kill_prompt ();
|
|
|
|
|
*trust_depth = atoi (p);
|
|
|
|
|
xfree (p);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Please enter a domain to restrict this signature, "
|
|
|
|
|
"or enter for none.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
p = cpr_get ("trustsig_prompt.trust_regexp", _("Your selection? "));
|
|
|
|
|
trim_spaces (p);
|
|
|
|
|
cpr_kill_prompt ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (strlen (p) > 0)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *q = p;
|
|
|
|
|
int regexplen = 100, ind;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*regexp = xmalloc (regexplen);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Now mangle the domain the user entered into a regexp. To do
|
2010-04-20 20:19:19 +02:00
|
|
|
|
this, \-escape everything that isn't alphanumeric, and attach
|
|
|
|
|
"<[^>]+[@.]" to the front, and ">$" to the end. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
strcpy (*regexp, "<[^>]+[@.]");
|
|
|
|
|
ind = strlen (*regexp);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
while (*q)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!((*q >= 'A' && *q <= 'Z')
|
|
|
|
|
|| (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9')))
|
|
|
|
|
(*regexp)[ind++] = '\\';
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(*regexp)[ind++] = *q;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((regexplen - ind) < 3)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
regexplen += 100;
|
|
|
|
|
*regexp = xrealloc (*regexp, regexplen);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q++;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(*regexp)[ind] = '\0';
|
|
|
|
|
strcat (*regexp, ">$");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (p);
|
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2017-02-20 22:19:50 +01:00
|
|
|
|
* Loop over all LOCUSR and sign the uids after asking. If no
|
2014-03-27 16:33:40 +01:00
|
|
|
|
* user id is marked, all user ids will be signed; if some user_ids
|
|
|
|
|
* are marked only those will be signed. If QUICK is true the
|
|
|
|
|
* function won't ask the user and use sensible defaults.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2015-07-28 18:21:47 +02:00
|
|
|
|
sign_uids (ctrl_t ctrl, estream_t fp,
|
2014-03-27 16:33:40 +01:00
|
|
|
|
kbnode_t keyblock, strlist_t locusr, int *ret_modified,
|
|
|
|
|
int local, int nonrevocable, int trust, int interactive,
|
|
|
|
|
int quick)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int rc = 0;
|
|
|
|
|
SK_LIST sk_list = NULL;
|
|
|
|
|
SK_LIST sk_rover = NULL;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
KBNODE node, uidnode;
|
|
|
|
|
PKT_public_key *primary_pk = NULL;
|
|
|
|
|
int select_all = !count_selected_uids (keyblock) || interactive;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Build a list of all signators.
|
2011-02-04 12:57:53 +01:00
|
|
|
|
*
|
2010-04-20 20:19:19 +02:00
|
|
|
|
* We use the CERT flag to request the primary which must always
|
|
|
|
|
* be one which is capable of signing keys. I can't see a reason
|
|
|
|
|
* why to sign keys using a subkey. Implementation of USAGE_CERT
|
|
|
|
|
* is just a hack in getkey.c and does not mean that a subkey
|
|
|
|
|
* marked as certification capable will be used. */
|
2015-11-03 23:15:27 +01:00
|
|
|
|
rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* Loop over all signators. */
|
|
|
|
|
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
|
|
|
|
|
{
|
|
|
|
|
u32 sk_keyid[2], pk_keyid[2];
|
|
|
|
|
char *p, *trust_regexp = NULL;
|
2014-10-12 20:07:12 +02:00
|
|
|
|
int class = 0, selfsig = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
u32 duration = 0, timestamp = 0;
|
|
|
|
|
byte trust_depth = 0, trust_value = 0;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
pk = sk_rover->pk;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (pk, sk_keyid);
|
|
|
|
|
|
|
|
|
|
/* Set mark A for all selected user ids. */
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (select_all || (node->flag & NODFLG_SELUID))
|
|
|
|
|
node->flag |= NODFLG_MARK_A;
|
|
|
|
|
else
|
|
|
|
|
node->flag &= ~NODFLG_MARK_A;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Reset mark for uids which are already signed. */
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
primary_pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (primary_pk, pk_keyid);
|
|
|
|
|
|
|
|
|
|
/* Is this a self-sig? */
|
|
|
|
|
if (pk_keyid[0] == sk_keyid[0] && pk_keyid[1] == sk_keyid[1])
|
2014-10-12 20:07:12 +02:00
|
|
|
|
selfsig = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
uidnode = (node->flag & NODFLG_MARK_A) ? node : NULL;
|
|
|
|
|
if (uidnode)
|
|
|
|
|
{
|
|
|
|
|
int yesreally = 0;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
char *user;
|
|
|
|
|
|
|
|
|
|
user = utf8_to_native (uidnode->pkt->pkt.user_id->name,
|
|
|
|
|
uidnode->pkt->pkt.user_id->len, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-11-06 13:14:57 +01:00
|
|
|
|
if (opt.only_sign_text_ids
|
|
|
|
|
&& uidnode->pkt->pkt.user_id->attribs)
|
|
|
|
|
{
|
2015-12-03 10:39:29 +01:00
|
|
|
|
tty_fprintf (fp, _("Skipping user ID \"%s\","
|
2015-11-06 13:14:57 +01:00
|
|
|
|
" which is not a text ID.\n"),
|
|
|
|
|
user);
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
}
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uidnode->pkt->pkt.user_id->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("User ID \"%s\" is revoked."), user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
else if (opt.expert && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* No, so remove the mark and continue */
|
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.revoke_okay",
|
2003-06-05 09:14:21 +02:00
|
|
|
|
_("Are you sure you "
|
|
|
|
|
"still want to sign "
|
|
|
|
|
"it? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (interactive)
|
|
|
|
|
yesreally = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" Unable to sign.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uidnode->pkt->pkt.user_id->flags.expired)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("User ID \"%s\" is expired."), user);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
else if (opt.expert && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* No, so remove the mark and continue */
|
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.expire_okay",
|
2003-09-23 19:48:33 +02:00
|
|
|
|
_("Are you sure you "
|
|
|
|
|
"still want to sign "
|
|
|
|
|
"it? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (interactive)
|
|
|
|
|
yesreally = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" Unable to sign.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!uidnode->pkt->pkt.user_id->created && !selfsig)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("User ID \"%s\" is not self-signed."),
|
|
|
|
|
user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (opt.expert && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* No, so remove the mark and continue */
|
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.nosig_okay",
|
2003-09-23 19:48:33 +02:00
|
|
|
|
_("Are you sure you "
|
|
|
|
|
"still want to sign "
|
|
|
|
|
"it? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (interactive)
|
|
|
|
|
yesreally = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" Unable to sign.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (uidnode && interactive && !yesreally && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("User ID \"%s\" is signable. "), user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.sign_okay",
|
2006-04-19 13:26:11 +02:00
|
|
|
|
_("Sign it? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
uidnode = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (uidnode && node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& (node->pkt->pkt.signature->sig_class & ~3) == 0x10)
|
|
|
|
|
{
|
|
|
|
|
if (sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
|
|
|
|
|
&& sk_keyid[1] == node->pkt->pkt.signature->keyid[1])
|
|
|
|
|
{
|
|
|
|
|
char buf[50];
|
2010-04-21 18:26:17 +02:00
|
|
|
|
char *user;
|
|
|
|
|
|
|
|
|
|
user = utf8_to_native (uidnode->pkt->pkt.user_id->name,
|
|
|
|
|
uidnode->pkt->pkt.user_id->len, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* It's a v3 self-sig. Make it into a v4 self-sig? */
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (node->pkt->pkt.signature->version < 4
|
|
|
|
|
&& selfsig && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("The self-signature on \"%s\"\n"
|
|
|
|
|
"is a PGP 2.x-style signature.\n"), user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* Note that the regular PGP2 warning below
|
|
|
|
|
still applies if there are no v4 sigs on
|
|
|
|
|
this key at all. */
|
|
|
|
|
|
|
|
|
|
if (opt.expert)
|
|
|
|
|
if (cpr_get_answer_is_yes ("sign_uid.v4_promote_okay",
|
2003-06-05 09:14:21 +02:00
|
|
|
|
_("Do you want to promote "
|
|
|
|
|
"it to an OpenPGP self-"
|
|
|
|
|
"signature? (y/N) ")))
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag |= NODFLG_DELSIG;
|
|
|
|
|
xfree (user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Is the current signature expired? */
|
|
|
|
|
if (node->pkt->pkt.signature->flags.expired)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("Your current signature on \"%s\"\n"
|
|
|
|
|
"has expired.\n"), user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (quick || cpr_get_answer_is_yes
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("sign_uid.replace_expired_okay",
|
|
|
|
|
_("Do you want to issue a "
|
|
|
|
|
"new signature to replace "
|
|
|
|
|
"the expired one? (y/N) ")))
|
|
|
|
|
{
|
|
|
|
|
/* Mark these for later deletion. We
|
|
|
|
|
don't want to delete them here, just in
|
|
|
|
|
case the replacement signature doesn't
|
|
|
|
|
happen for some reason. We only delete
|
|
|
|
|
these after the replacement is already
|
|
|
|
|
in place. */
|
|
|
|
|
|
|
|
|
|
node->flag |= NODFLG_DELSIG;
|
|
|
|
|
xfree (user);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node->pkt->pkt.signature->flags.exportable && !local)
|
|
|
|
|
{
|
|
|
|
|
/* It's a local sig, and we want to make a
|
|
|
|
|
exportable sig. */
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("Your current signature on \"%s\"\n"
|
|
|
|
|
"is a local signature.\n"), user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-07-23 12:18:19 +02:00
|
|
|
|
if (quick || cpr_get_answer_is_yes
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("sign_uid.local_promote_okay",
|
|
|
|
|
_("Do you want to promote "
|
|
|
|
|
"it to a full exportable " "signature? (y/N) ")))
|
|
|
|
|
{
|
|
|
|
|
/* Mark these for later deletion. We
|
|
|
|
|
don't want to delete them here, just in
|
|
|
|
|
case the replacement signature doesn't
|
|
|
|
|
happen for some reason. We only delete
|
|
|
|
|
these after the replacement is already
|
|
|
|
|
in place. */
|
|
|
|
|
|
|
|
|
|
node->flag |= NODFLG_DELSIG;
|
|
|
|
|
xfree (user);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fixme: see whether there is a revocation in which
|
More cleanup of "allow to".
* README, agent/command.c, agent/keyformat.txt, common/i18n.c,
common/iobuf.c, common/keyserver.h, dirmngr/cdblib.c,
dirmngr/ldap-wrapper.c, doc/DETAILS, doc/TRANSLATE,
doc/announce-2.1.txt, doc/gpg.texi, doc/gpgsm.texi,
doc/scdaemon.texi, doc/tools.texi, doc/whats-new-in-2.1.txt,
g10/export.c, g10/getkey.c, g10/import.c, g10/keyedit.c, m4/ksba.m4,
m4/libgcrypt.m4, m4/ntbtls.m4, po/ca.po, po/cs.po, po/da.po,
po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po,
po/fr.po, po/gl.po, po/hu.po, po/id.po, po/it.po, po/ja.po,
po/nb.po, po/pl.po, po/pt.po, po/ro.po, po/ru.po, po/sk.po,
po/sv.po, po/tr.po, po/uk.po, po/zh_CN.po, po/zh_TW.po,
scd/app-p15.c, scd/ccid-driver.c, scd/command.c, sm/gpgsm.c,
sm/sign.c, tools/gpgconf-comp.c, tools/gpgtar.h: replace "Allow to"
with clearer text.
In standard English, the normal construction is "${XXX} allows ${YYY}
to" -- that is, the subject (${XXX}) of the sentence is allowing the
object (${YYY}) to do something. When the object is missing, the
phrasing sounds awkward, even if the object is implied by context.
There's almost always a better construction that isn't as awkward.
These changes should make the language a bit clearer.
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2016-08-02 04:19:17 +02:00
|
|
|
|
* case we should allow signing it again. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!node->pkt->pkt.signature->flags.exportable && local)
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf ( fp,
|
|
|
|
|
_("\"%s\" was already locally signed by key %s\n"),
|
2010-04-21 18:26:17 +02:00
|
|
|
|
user, keystr_from_pk (pk));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("\"%s\" was already signed by key %s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
user, keystr_from_pk (pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2021-03-11 11:27:07 +01:00
|
|
|
|
if (opt.flags.force_sign_key
|
|
|
|
|
|| (opt.expert && !quick
|
|
|
|
|
&& cpr_get_answer_is_yes ("sign_uid.dupe_okay",
|
|
|
|
|
_("Do you want to sign it "
|
|
|
|
|
"again anyway? (y/N) "))))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
/* Don't delete the old sig here since this is
|
|
|
|
|
an --expert thing. */
|
|
|
|
|
xfree (user);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
snprintf (buf, sizeof buf, "%08lX%08lX",
|
|
|
|
|
(ulong) pk->keyid[0], (ulong) pk->keyid[1]);
|
|
|
|
|
write_status_text (STATUS_ALREADY_SIGNED, buf);
|
|
|
|
|
uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Check whether any uids are left for signing. */
|
|
|
|
|
if (!count_uids_with_flag (keyblock, NODFLG_MARK_A))
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("Nothing to sign with key %s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keystr_from_pk (pk));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Ask whether we really should sign these user id(s). */
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, fp, keyblock, 1, 0, 1, 0, 0, 0);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (primary_pk->expiredate && !selfsig)
|
|
|
|
|
{
|
2016-01-06 08:42:07 +01:00
|
|
|
|
/* Static analyzer note: A claim that PRIMARY_PK might be
|
|
|
|
|
NULL is not correct because it set from the public key
|
|
|
|
|
packet which is always the first packet in a keyblock and
|
|
|
|
|
parsed in the above loop over the keyblock. In case the
|
|
|
|
|
keyblock has no packets at all and thus the loop was not
|
|
|
|
|
entered the above count_uids_with_flag would have
|
|
|
|
|
detected this case. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
u32 now = make_timestamp ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (primary_pk->expiredate <= now)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("This key has expired!"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (opt.expert && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, " ");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.expired_okay",
|
2003-06-05 09:14:21 +02:00
|
|
|
|
_("Are you sure you still "
|
|
|
|
|
"want to sign it? (y/N) ")))
|
|
|
|
|
continue;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" Unable to sign.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("This key is due to expire on %s.\n"),
|
|
|
|
|
expirestr_from_pk (primary_pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (opt.ask_cert_expire && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
char *answer = cpr_get ("sign_uid.expire",
|
|
|
|
|
_("Do you want your signature to "
|
|
|
|
|
"expire at the same time? (Y/n) "));
|
|
|
|
|
if (answer_is_yes_no_default (answer, 1))
|
|
|
|
|
{
|
|
|
|
|
/* This fixes the signature timestamp we're
|
|
|
|
|
going to make as now. This is so the
|
|
|
|
|
expiration date is exactly correct, and not
|
|
|
|
|
a few seconds off (due to the time it takes
|
|
|
|
|
to answer the questions, enter the
|
|
|
|
|
passphrase, etc). */
|
|
|
|
|
timestamp = now;
|
|
|
|
|
duration = primary_pk->expiredate - now;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
cpr_kill_prompt ();
|
|
|
|
|
xfree (answer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Only ask for duration if we haven't already set it to match
|
|
|
|
|
the expiration of the pk */
|
|
|
|
|
if (!duration && !selfsig)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (opt.ask_cert_expire && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
duration = ask_expire_interval (1, opt.def_cert_expire);
|
|
|
|
|
else
|
|
|
|
|
duration = parse_expire_string (opt.def_cert_expire);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (opt.batch || !opt.ask_cert_level || quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
class = 0x10 + opt.def_cert_level;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *answer;
|
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("How carefully have you verified the key you are "
|
2010-04-20 20:19:19 +02:00
|
|
|
|
"about to sign actually belongs\nto the person "
|
|
|
|
|
"named above? If you don't know what to "
|
|
|
|
|
"answer, enter \"0\".\n"));
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _(" (0) I will not answer.%s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
opt.def_cert_level == 0 ? " (default)" : "");
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" (1) I have not checked at all.%s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
opt.def_cert_level == 1 ? " (default)" : "");
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _(" (2) I have done casual checking.%s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
opt.def_cert_level == 2 ? " (default)" : "");
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_(" (3) I have done very careful checking.%s\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
opt.def_cert_level == 3 ? " (default)" : "");
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
while (class == 0)
|
|
|
|
|
{
|
|
|
|
|
answer = cpr_get ("sign_uid.class",
|
|
|
|
|
_("Your selection? "
|
2012-06-05 19:29:22 +02:00
|
|
|
|
"(enter '?' for more information): "));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (answer[0] == '\0')
|
|
|
|
|
class = 0x10 + opt.def_cert_level; /* Default */
|
|
|
|
|
else if (ascii_strcasecmp (answer, "0") == 0)
|
|
|
|
|
class = 0x10; /* Generic */
|
|
|
|
|
else if (ascii_strcasecmp (answer, "1") == 0)
|
|
|
|
|
class = 0x11; /* Persona */
|
|
|
|
|
else if (ascii_strcasecmp (answer, "2") == 0)
|
|
|
|
|
class = 0x12; /* Casual */
|
|
|
|
|
else if (ascii_strcasecmp (answer, "3") == 0)
|
|
|
|
|
class = 0x13; /* Positive */
|
|
|
|
|
else
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, _("Invalid selection.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (trust && !quick)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
trustsig_prompt (&trust_value, &trust_depth, &trust_regexp);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (!quick)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
p = get_user_id_native (ctrl, sk_keyid);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("Are you sure that you want to sign this key with your\n"
|
|
|
|
|
"key \"%s\" (%s)\n"), p, keystr_from_pk (pk));
|
|
|
|
|
xfree (p);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("This will be a self-signature.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (local)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("WARNING: the signature will not be marked "
|
|
|
|
|
"as non-exportable.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (nonrevocable)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("WARNING: the signature will not be marked "
|
|
|
|
|
"as non-revocable.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (local)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("The signature will be marked as non-exportable.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (nonrevocable)
|
|
|
|
|
{
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("The signature will be marked as non-revocable.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
switch (class)
|
|
|
|
|
{
|
|
|
|
|
case 0x11:
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("I have not checked this key at all.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case 0x12:
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("I have checked this key casually.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x13:
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
|
|
|
|
tty_fprintf (fp, _("I have checked this key very carefully.\n"));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (opt.batch && opt.answer_yes)
|
|
|
|
|
;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
else if (quick)
|
|
|
|
|
;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (!cpr_get_answer_is_yes ("sign_uid.okay",
|
|
|
|
|
_("Really sign? (y/N) ")))
|
|
|
|
|
continue;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Now we can sign the user ids. */
|
2017-04-28 03:06:33 +02:00
|
|
|
|
reloop: /* (Must use this, because we are modifying the list.) */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
primary_pk = NULL;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
primary_pk = node->pkt->pkt.public_key;
|
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& (node->flag & NODFLG_MARK_A))
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
struct sign_attrib attrib;
|
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (primary_pk);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
memset (&attrib, 0, sizeof attrib);
|
|
|
|
|
attrib.non_exportable = local;
|
|
|
|
|
attrib.non_revocable = nonrevocable;
|
|
|
|
|
attrib.trust_depth = trust_depth;
|
|
|
|
|
attrib.trust_value = trust_value;
|
|
|
|
|
attrib.trust_regexp = trust_regexp;
|
|
|
|
|
node->flag &= ~NODFLG_MARK_A;
|
|
|
|
|
|
|
|
|
|
/* We force creation of a v4 signature for local
|
|
|
|
|
* signatures, otherwise we would not generate the
|
|
|
|
|
* subpacket with v3 keys and the signature becomes
|
|
|
|
|
* exportable. */
|
|
|
|
|
|
|
|
|
|
if (selfsig)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, primary_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->pkt->pkt.user_id,
|
|
|
|
|
NULL,
|
|
|
|
|
pk,
|
2019-05-13 12:38:32 +02:00
|
|
|
|
0x13,
|
|
|
|
|
0, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
keygen_add_std_prefs, primary_pk,
|
|
|
|
|
NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, primary_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->pkt->pkt.user_id,
|
|
|
|
|
NULL,
|
|
|
|
|
pk,
|
2019-05-13 12:38:32 +02:00
|
|
|
|
class,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
timestamp, duration,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
sign_mk_attrib, &attrib,
|
|
|
|
|
NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", rc);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*ret_modified = 1; /* We changed the keyblock. */
|
|
|
|
|
update_trust = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
|
insert_kbnode (node, new_kbnode (pkt), PKT_SIGNATURE);
|
|
|
|
|
goto reloop;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Delete any sigs that got promoted */
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->flag & NODFLG_DELSIG)
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
} /* End loop over signators. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
leave:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_sk_list (sk_list);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2010-10-26 11:10:29 +02:00
|
|
|
|
* Change the passphrase of the primary and all secondary keys. Note
|
|
|
|
|
* that it is common to use only one passphrase for the primary and
|
|
|
|
|
* all subkeys. However, this is now (since GnuPG 2.1) all up to the
|
|
|
|
|
* gpg-agent. Returns 0 on success or an error code.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
2010-10-26 11:10:29 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-10-26 11:10:29 +02:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
PKT_public_key *pk;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int any;
|
2010-10-26 11:10:29 +02:00
|
|
|
|
u32 keyid[2], subid[2];
|
|
|
|
|
char *hexgrip = NULL;
|
|
|
|
|
char *cache_nonce = NULL;
|
|
|
|
|
char *passwd_nonce = NULL;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!node)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_error ("Oops; public key missing!\n");
|
2010-10-26 11:10:29 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_INTERNAL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-10-26 11:10:29 +02:00
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (pk, keyid);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
/* Check whether it is likely that we will be able to change the
|
|
|
|
|
passphrase for any subkey. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (any = 0, node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2010-10-26 11:10:29 +02:00
|
|
|
|
char *serialno;
|
|
|
|
|
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (pk, subid);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
err = hexkeygrip_from_pk (pk, &hexgrip);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2024-04-05 12:02:32 +02:00
|
|
|
|
/* FIXME: Handle dual keys. */
|
2016-06-10 22:15:33 +02:00
|
|
|
|
err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
|
2010-10-26 11:10:29 +02:00
|
|
|
|
if (!err && serialno)
|
|
|
|
|
; /* Key on card. */
|
|
|
|
|
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
|
|
|
|
; /* Maybe stub key. */
|
|
|
|
|
else if (!err)
|
|
|
|
|
any = 1; /* Key is known. */
|
|
|
|
|
else
|
|
|
|
|
log_error ("key %s: error getting keyinfo from agent: %s\n",
|
|
|
|
|
keystr_with_sub (keyid, subid), gpg_strerror (err));
|
|
|
|
|
xfree (serialno);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-10-26 11:10:29 +02:00
|
|
|
|
err = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!any)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Key has only stub or on-card key items - "
|
|
|
|
|
"no passphrase to change.\n"));
|
|
|
|
|
goto leave;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
/* Change the passphrase for all keys. */
|
2016-01-06 08:45:01 +01:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2010-10-26 11:10:29 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2010-10-26 11:10:29 +02:00
|
|
|
|
char *desc;
|
|
|
|
|
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (pk, subid);
|
|
|
|
|
|
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
err = hexkeygrip_from_pk (pk, &hexgrip);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2018-03-22 10:23:00 +01:00
|
|
|
|
/* Note that when using --dry-run we don't change the
|
|
|
|
|
* passphrase but merely verify the current passphrase. */
|
2017-03-31 20:03:52 +02:00
|
|
|
|
desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
|
2018-03-22 10:23:00 +01:00
|
|
|
|
err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
|
2016-06-02 21:21:08 +02:00
|
|
|
|
&cache_nonce, &passwd_nonce);
|
2010-10-26 11:10:29 +02:00
|
|
|
|
xfree (desc);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
if (err)
|
|
|
|
|
log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
|
2017-12-11 10:37:30 +01:00
|
|
|
|
? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
|
2010-10-26 11:10:29 +02:00
|
|
|
|
_("key %s: error changing passphrase: %s\n"),
|
|
|
|
|
keystr_with_sub (keyid, subid),
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
leave:
|
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
xfree (cache_nonce);
|
|
|
|
|
xfree (passwd_nonce);
|
|
|
|
|
return err;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2015-05-08 12:05:52 +02:00
|
|
|
|
/* Fix various problems in the keyblock. Returns true if the keyblock
|
|
|
|
|
was changed. Note that a pointer to the keyblock must be given and
|
|
|
|
|
the function may change it (i.e. replacing the first node). */
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp)
|
2015-05-08 12:05:52 +02:00
|
|
|
|
{
|
|
|
|
|
int changed = 0;
|
|
|
|
|
|
|
|
|
|
if (collapse_uids (keyblockp))
|
|
|
|
|
changed++;
|
2020-08-25 10:33:57 +02:00
|
|
|
|
if (collapse_subkeys (keyblockp))
|
|
|
|
|
changed++;
|
2017-07-27 11:37:00 +02:00
|
|
|
|
if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
|
2016-02-19 15:52:08 +01:00
|
|
|
|
changed++;
|
2015-05-08 12:05:52 +02:00
|
|
|
|
reorder_keyblock (*keyblockp);
|
|
|
|
|
/* If we modified the keyblock, make sure the flags are right. */
|
|
|
|
|
if (changed)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, *keyblockp);
|
2015-05-08 12:05:52 +02:00
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
parse_sign_type (const char *str, int *localsig, int *nonrevokesig,
|
|
|
|
|
int *trustsig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
const char *p = str;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
while (*p)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (ascii_strncasecmp (p, "l", 1) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*localsig = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
p++;
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (ascii_strncasecmp (p, "nr", 2) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*nonrevokesig = 1;
|
|
|
|
|
p += 2;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (ascii_strncasecmp (p, "t", 1) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
*trustsig = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2006-04-19 13:26:11 +02:00
|
|
|
|
* Menu driven key editor. If seckey_check is true, then a secret key
|
|
|
|
|
* that matches username will be looked for. If it is false, not all
|
|
|
|
|
* commands will be available.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*
|
2010-04-20 20:19:19 +02:00
|
|
|
|
* Note: to keep track of certain selections we use node->mark MARKBIT_xxxx.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Need an SK for this command */
|
|
|
|
|
#define KEYEDIT_NEED_SK 1
|
2017-10-24 10:56:13 +02:00
|
|
|
|
/* Need an SUB KEY for this command */
|
|
|
|
|
#define KEYEDIT_NEED_SUBSK 2
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Match the tail of the string */
|
|
|
|
|
#define KEYEDIT_TAIL_MATCH 8
|
|
|
|
|
|
|
|
|
|
enum cmdids
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
cmdNONE = 0,
|
|
|
|
|
cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
|
|
|
|
|
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
|
|
|
|
|
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
|
|
|
|
|
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
|
2023-03-01 17:22:20 +01:00
|
|
|
|
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
|
|
|
|
cmdENABLEKEY, cmdDISABLEKEY,
|
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
|
|
|
|
cmdSHOWPREF,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
|
2021-03-09 22:50:30 +01:00
|
|
|
|
cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdKEYTOTPM, cmdBKUPTOCARD,
|
2015-08-06 18:00:12 +02:00
|
|
|
|
cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP
|
2010-04-20 20:19:19 +02:00
|
|
|
|
};
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
|
|
|
|
enum cmdids id;
|
|
|
|
|
int flags;
|
|
|
|
|
const char *desc;
|
|
|
|
|
} cmds[] =
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
{ "quit", cmdQUIT, 0, N_("quit this menu")},
|
|
|
|
|
{ "q", cmdQUIT, 0, NULL},
|
|
|
|
|
{ "save", cmdSAVE, 0, N_("save and quit")},
|
|
|
|
|
{ "help", cmdHELP, 0, N_("show this help")},
|
|
|
|
|
{ "?", cmdHELP, 0, NULL},
|
|
|
|
|
{ "fpr", cmdFPR, 0, N_("show key fingerprint")},
|
2015-08-06 18:00:12 +02:00
|
|
|
|
{ "grip", cmdGRIP, 0, N_("show the keygrip")},
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "list", cmdLIST, 0, N_("list key and user IDs")},
|
|
|
|
|
{ "l", cmdLIST, 0, NULL},
|
|
|
|
|
{ "uid", cmdSELUID, 0, N_("select user ID N")},
|
|
|
|
|
{ "key", cmdSELKEY, 0, N_("select subkey N")},
|
|
|
|
|
{ "check", cmdCHECK, 0, N_("check signatures")},
|
|
|
|
|
{ "c", cmdCHECK, 0, NULL},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "change-usage", cmdCHANGEUSAGE, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "cross-certify", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "backsign", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "sign", cmdSIGN, KEYEDIT_TAIL_MATCH,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("sign selected user IDs [* see below for related commands]")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "s", cmdSIGN, 0, NULL},
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* "lsign" and friends will never match since "sign" comes first
|
|
|
|
|
and it is a tail match. They are just here so they show up in
|
|
|
|
|
the help menu. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "lsign", cmdNOP, 0, N_("sign selected user IDs locally")},
|
|
|
|
|
{ "tsign", cmdNOP, 0, N_("sign selected user IDs with a trust signature")},
|
|
|
|
|
{ "nrsign", cmdNOP, 0,
|
|
|
|
|
N_("sign selected user IDs with a non-revocable signature")},
|
|
|
|
|
{ "debug", cmdDEBUG, 0, NULL},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "adduid", cmdADDUID, KEYEDIT_NEED_SK, N_("add a user ID")},
|
|
|
|
|
{ "addphoto", cmdADDPHOTO, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("add a photo ID")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "deluid", cmdDELUID, 0, N_("delete selected user IDs")},
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* delphoto is really deluid in disguise */
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "delphoto", cmdDELUID, 0, NULL},
|
|
|
|
|
{ "addkey", cmdADDKEY, KEYEDIT_NEED_SK, N_("add a subkey")},
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef ENABLE_CARD_SUPPORT
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "addcardkey", cmdADDCARDKEY, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("add a key to a smartcard")},
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{ "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("move a key to a smartcard")},
|
2021-03-09 22:50:30 +01:00
|
|
|
|
{ "keytotpm", cmdKEYTOTPM, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
|
|
|
|
N_("convert a key to TPM form using the local TPM")},
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{ "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("move a backup key to a smartcard")},
|
|
|
|
|
#endif /*ENABLE_CARD_SUPPORT */
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
|
|
|
|
|
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("add a revocation key")},
|
2023-03-01 17:22:20 +01:00
|
|
|
|
{ "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
|
2023-03-21 16:30:18 +01:00
|
|
|
|
N_("add an additional decryption subkey")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "delsig", cmdDELSIG, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("delete signatures from the selected user IDs")},
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("change the expiration date for the key or selected subkeys")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "primary", cmdPRIMARY, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("flag the selected user ID as primary")},
|
2015-07-28 17:43:29 +02:00
|
|
|
|
{ "toggle", cmdTOGGLE, KEYEDIT_NEED_SK, NULL}, /* Dummy command. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "pref", cmdPREF, 0, N_("list preferences (expert)")},
|
|
|
|
|
{ "showpref", cmdSHOWPREF, 0, N_("list preferences (verbose)")},
|
|
|
|
|
{ "setpref", cmdSETPREF, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("set preference list for the selected user IDs")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "updpref", cmdSETPREF, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "keyserver", cmdPREFKS, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("set the preferred keyserver URL for the selected user IDs")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "notation", cmdNOTATION, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("set a notation for the selected user IDs")},
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{ "passwd", cmdPASSWD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("change the passphrase")},
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{ "password", cmdPASSWD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, NULL},
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "trust", cmdTRUST, 0, N_("change the ownertrust")},
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "revsig", cmdREVSIG, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("revoke signatures on the selected user IDs")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "revuid", cmdREVUID, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("revoke selected user IDs")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "revphoto", cmdREVUID, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "revkey", cmdREVKEY, KEYEDIT_NEED_SK,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("revoke key or selected subkeys")},
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "enable", cmdENABLEKEY, 0, N_("enable key")},
|
|
|
|
|
{ "disable", cmdDISABLEKEY, 0, N_("disable key")},
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "clean", cmdCLEAN, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("compact unusable user IDs and remove unusable signatures from key")},
|
2017-10-24 09:31:49 +02:00
|
|
|
|
{ "minimize", cmdMINIMIZE, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
N_("compact unusable user IDs and remove all signatures from key")},
|
|
|
|
|
|
|
|
|
|
{ NULL, cmdNONE, 0, NULL}
|
|
|
|
|
};
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef HAVE_LIBREADLINE
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
|
|
|
|
These two functions are used by readline for command completion.
|
|
|
|
|
*/
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
static char *
|
2010-04-20 20:19:19 +02:00
|
|
|
|
command_generator (const char *text, int state)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static int list_index, len;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
|
|
/* If this is a new word to complete, initialize now. This includes
|
|
|
|
|
saving the length of TEXT for efficiency, and initializing the
|
|
|
|
|
index variable to 0. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!state)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
list_index = 0;
|
|
|
|
|
len = strlen (text);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the next partial match */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
while ((name = cmds[list_index].name))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* Only complete commands that have help text */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (cmds[list_index++].desc && strncmp (name, text, len) == 0)
|
|
|
|
|
return strdup (name);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char **
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyedit_completion (const char *text, int start, int end)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* If we are at the start of a line, we try and command-complete.
|
|
|
|
|
If not, just do nothing for now. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(void) end;
|
2008-10-20 15:53:23 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (start == 0)
|
|
|
|
|
return rl_completion_matches (text, command_generator);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
rl_attempted_completion_over = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif /* HAVE_LIBREADLINE */
|
|
|
|
|
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Main function of the menu driven key editor. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
void
|
2010-10-01 22:33:53 +02:00
|
|
|
|
keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
strlist_t commands, int quiet, int seckey_check)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
enum cmdids cmd = 0;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
int have_seckey = 0;
|
2017-10-24 10:56:13 +02:00
|
|
|
|
int have_anyseckey = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *answer = NULL;
|
|
|
|
|
int redisplay = 1;
|
|
|
|
|
int modified = 0;
|
2015-04-03 10:39:59 +02:00
|
|
|
|
int sec_shadowing = 0;
|
2014-09-17 16:27:37 +02:00
|
|
|
|
int run_subkey_warnings = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int have_commands = !!commands;
|
2023-03-15 09:36:36 +01:00
|
|
|
|
strlist_t delseckey_list = NULL;
|
|
|
|
|
int delseckey_list_warn = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (opt.command_fd != -1)
|
|
|
|
|
;
|
|
|
|
|
else if (opt.batch && !have_commands)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("can't do this in batch mode\n"));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Due to Windows peculiarities we need to make sure that the
|
|
|
|
|
trustdb stale check is done before we open another file
|
|
|
|
|
(i.e. by searching for a key). In theory we could make sure
|
|
|
|
|
that the files are closed after use but the open/close caches
|
|
|
|
|
inhibits that and flushing the cache right before the stale
|
|
|
|
|
check is not easy to implement. Thus we take the easy way out
|
|
|
|
|
and run the stale check as early as possible. Note, that for
|
2024-05-13 00:09:23 +02:00
|
|
|
|
non- W32 platforms it is run indirectly through a call to
|
2010-04-20 20:19:19 +02:00
|
|
|
|
get_validity (). */
|
2016-05-21 11:41:49 +02:00
|
|
|
|
check_trustdb_stale (ctrl);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Get the public key */
|
2019-07-04 10:42:48 +02:00
|
|
|
|
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
|
|
|
|
|
NULL, NULL, username, &keyblock, &kdbhd, 1);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (err)
|
2013-10-04 18:34:56 +02:00
|
|
|
|
{
|
|
|
|
|
log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2015-05-08 12:05:52 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (fix_keyblock (ctrl, &keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified++;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* See whether we have a matching secret key. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (seckey_check)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2017-10-24 10:56:13 +02:00
|
|
|
|
have_anyseckey = !agent_probe_any_secret_key (ctrl, keyblock);
|
|
|
|
|
if (have_anyseckey
|
2020-01-17 07:11:02 +01:00
|
|
|
|
&& agent_probe_secret_key (ctrl, keyblock->pkt->pkt.public_key))
|
2017-10-24 10:56:13 +02:00
|
|
|
|
{
|
|
|
|
|
/* The primary key is also available. */
|
|
|
|
|
have_seckey = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (have_seckey && !quiet)
|
2017-10-24 10:56:13 +02:00
|
|
|
|
tty_printf (_("Secret key is available.\n"));
|
|
|
|
|
else if (have_anyseckey && !quiet)
|
|
|
|
|
tty_printf (_("Secret subkeys are available.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Main command loop. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (;;)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int i, arg_number, photo;
|
|
|
|
|
const char *arg_string = "";
|
|
|
|
|
char *p;
|
|
|
|
|
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (redisplay && !quiet)
|
|
|
|
|
{
|
2015-07-28 17:43:29 +02:00
|
|
|
|
/* Show using flags: with_revoker, with_subkeys. */
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, NULL, keyblock, 0, 1, 0, 1, 0, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
redisplay = 0;
|
|
|
|
|
}
|
2014-09-17 16:27:37 +02:00
|
|
|
|
|
|
|
|
|
if (run_subkey_warnings)
|
|
|
|
|
{
|
|
|
|
|
run_subkey_warnings = 0;
|
|
|
|
|
if (!count_selected_keys (keyblock))
|
|
|
|
|
subkey_expire_warning (keyblock);
|
2023-05-08 13:10:47 +02:00
|
|
|
|
no_usable_encr_subkeys_warning (keyblock);
|
2014-09-17 16:27:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-15 09:36:36 +01:00
|
|
|
|
if (delseckey_list_warn)
|
|
|
|
|
{
|
|
|
|
|
delseckey_list_warn = 0;
|
|
|
|
|
tty_printf
|
|
|
|
|
(_("Note: the local copy of the secret key"
|
|
|
|
|
" will only be deleted with \"save\".\n"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
xfree (answer);
|
|
|
|
|
if (have_commands)
|
|
|
|
|
{
|
|
|
|
|
if (commands)
|
|
|
|
|
{
|
|
|
|
|
answer = xstrdup (commands->d);
|
|
|
|
|
commands = commands->next;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (opt.batch)
|
|
|
|
|
{
|
|
|
|
|
answer = xstrdup ("quit");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
have_commands = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!have_commands)
|
|
|
|
|
{
|
2006-10-10 13:11:04 +02:00
|
|
|
|
#ifdef HAVE_LIBREADLINE
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_enable_completion (keyedit_completion);
|
2006-10-10 13:11:04 +02:00
|
|
|
|
#endif
|
2014-05-07 18:18:27 +02:00
|
|
|
|
answer = cpr_get_no_help ("keyedit.prompt", GPG_NAME "> ");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
cpr_kill_prompt ();
|
|
|
|
|
tty_disable_completion ();
|
|
|
|
|
}
|
|
|
|
|
trim_spaces (answer);
|
|
|
|
|
}
|
|
|
|
|
while (*answer == '#');
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
arg_number = 0; /* Here is the init which egcc complains about. */
|
|
|
|
|
photo = 0; /* Same here. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!*answer)
|
|
|
|
|
cmd = cmdLIST;
|
|
|
|
|
else if (*answer == CONTROL_D)
|
|
|
|
|
cmd = cmdQUIT;
|
|
|
|
|
else if (digitp (answer))
|
|
|
|
|
{
|
|
|
|
|
cmd = cmdSELUID;
|
|
|
|
|
arg_number = atoi (answer);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((p = strchr (answer, ' ')))
|
|
|
|
|
{
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
trim_spaces (answer);
|
|
|
|
|
trim_spaces (p);
|
|
|
|
|
arg_number = atoi (p);
|
|
|
|
|
arg_string = p;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0; cmds[i].name; i++)
|
|
|
|
|
{
|
|
|
|
|
if (cmds[i].flags & KEYEDIT_TAIL_MATCH)
|
|
|
|
|
{
|
|
|
|
|
size_t l = strlen (cmds[i].name);
|
|
|
|
|
size_t a = strlen (answer);
|
|
|
|
|
if (a >= l)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (!ascii_strcasecmp (&answer[a - l], cmds[i].name))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
answer[a - l] = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!ascii_strcasecmp (answer, cmds[i].name))
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-24 10:56:13 +02:00
|
|
|
|
if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
|
|
|
|
|
&& !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
|
|
|
|
|
|| ((cmds[i].flags & KEYEDIT_NEED_SUBSK) && have_anyseckey)))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Need the secret key to do this.\n"));
|
|
|
|
|
cmd = cmdNOP;
|
|
|
|
|
}
|
2017-10-24 10:56:13 +02:00
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
cmd = cmds[i].id;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/* Dispatch the command. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
switch (cmd)
|
|
|
|
|
{
|
|
|
|
|
case cmdHELP:
|
|
|
|
|
for (i = 0; cmds[i].name; i++)
|
|
|
|
|
{
|
2017-10-24 10:56:13 +02:00
|
|
|
|
if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
|
|
|
|
|
&& !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
|
|
|
|
|
||((cmds[i].flags&KEYEDIT_NEED_SUBSK)&&have_anyseckey)))
|
2010-04-21 18:26:17 +02:00
|
|
|
|
; /* Skip those item if we do not have the secret key. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (cmds[i].desc)
|
|
|
|
|
tty_printf ("%-11s %s\n", cmds[i].name, _(cmds[i].desc));
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf
|
2012-06-05 19:29:22 +02:00
|
|
|
|
(_("* The 'sign' command may be prefixed with an 'l' for local "
|
2010-04-20 20:19:19 +02:00
|
|
|
|
"signatures (lsign),\n"
|
2012-06-05 19:29:22 +02:00
|
|
|
|
" a 't' for trust signatures (tsign), an 'nr' for "
|
2010-04-20 20:19:19 +02:00
|
|
|
|
"non-revocable signatures\n"
|
|
|
|
|
" (nrsign), or any combination thereof (ltsign, "
|
|
|
|
|
"tnrsign, etc.).\n"));
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdLIST:
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdFPR:
|
2015-08-06 18:00:12 +02:00
|
|
|
|
show_key_and_fingerprint
|
2017-03-31 20:03:52 +02:00
|
|
|
|
(ctrl,
|
|
|
|
|
keyblock, (*arg_string == '*'
|
2015-08-06 18:00:12 +02:00
|
|
|
|
&& (!arg_string[1] || spacep (arg_string + 1))));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdGRIP:
|
|
|
|
|
show_key_and_grip (keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSELUID:
|
|
|
|
|
if (strlen (arg_string) == NAMEHASH_LEN * 2)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
redisplay = menu_select_uid_namehash (keyblock, arg_string);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (*arg_string == '*'
|
|
|
|
|
&& (!arg_string[1] || spacep (arg_string + 1)))
|
|
|
|
|
arg_number = -1; /* Select all. */
|
2010-04-21 18:26:17 +02:00
|
|
|
|
redisplay = menu_select_uid (keyblock, arg_number);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSELKEY:
|
|
|
|
|
{
|
|
|
|
|
if (*arg_string == '*'
|
|
|
|
|
&& (!arg_string[1] || spacep (arg_string + 1)))
|
|
|
|
|
arg_number = -1; /* Select all. */
|
2015-11-17 21:21:03 +01:00
|
|
|
|
if (menu_select_key (keyblock, arg_number, p))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdCHECK:
|
2017-07-27 11:37:00 +02:00
|
|
|
|
if (key_check_all_keysigs (ctrl, -1, keyblock,
|
2017-06-13 15:34:03 +02:00
|
|
|
|
count_selected_uids (keyblock),
|
|
|
|
|
!strcmp (arg_string, "selfsig")))
|
2016-05-09 20:57:20 +02:00
|
|
|
|
modified = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
case cmdSIGN:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
int localsig = 0, nonrevokesig = 0, trustsig = 0, interactive = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (pk->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Key is revoked."));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
if (!cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.sign_revoked.okay",
|
|
|
|
|
_("Are you sure you still want to sign it? (y/N) ")))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_(" Unable to sign.\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-11-06 13:14:57 +01:00
|
|
|
|
if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock))
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
if (opt.only_sign_text_ids)
|
|
|
|
|
result = cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.sign_all.okay",
|
2018-02-15 06:22:06 +01:00
|
|
|
|
_("Really sign all text user IDs? (y/N) "));
|
2015-11-06 13:14:57 +01:00
|
|
|
|
else
|
|
|
|
|
result = cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.sign_all.okay",
|
2018-02-15 06:22:06 +01:00
|
|
|
|
_("Really sign all user IDs? (y/N) "));
|
2015-11-06 13:14:57 +01:00
|
|
|
|
|
|
|
|
|
if (! result)
|
|
|
|
|
{
|
|
|
|
|
if (opt.interactive)
|
|
|
|
|
interactive = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Hint: Select the user IDs to sign\n"));
|
|
|
|
|
have_commands = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* What sort of signing are we doing? */
|
|
|
|
|
if (!parse_sign_type
|
|
|
|
|
(answer, &localsig, &nonrevokesig, &trustsig))
|
|
|
|
|
{
|
2012-06-05 19:29:22 +02:00
|
|
|
|
tty_printf (_("Unknown signature type '%s'\n"), answer);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-07-28 18:21:47 +02:00
|
|
|
|
sign_uids (ctrl, NULL, keyblock, locusr, &modified,
|
2014-03-27 16:33:40 +01:00
|
|
|
|
localsig, nonrevokesig, trustsig, interactive, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdDEBUG:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
dump_kbnode (keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdTOGGLE:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* The toggle command is a leftover from old gpg versions
|
|
|
|
|
where we worked with a secret and a public keyring. It
|
|
|
|
|
is not necessary anymore but we keep this command for the
|
|
|
|
|
sake of scripts using it. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdADDPHOTO:
|
2014-08-12 10:36:30 +02:00
|
|
|
|
if (RFC2440)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
tty_printf (_("This command is not allowed while in %s mode.\n"),
|
2017-06-07 12:33:36 +02:00
|
|
|
|
gnupg_compliance_option_string (opt.compliance));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
photo = 1;
|
|
|
|
|
/* fall through */
|
|
|
|
|
case cmdADDUID:
|
2016-05-21 11:41:49 +02:00
|
|
|
|
if (menu_adduid (ctrl, keyblock, photo, arg_string, NULL))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
update_trust = 1;
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdDELUID:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
|
|
|
|
|
|
|
|
|
if (!(n1 = count_selected_uids (keyblock)))
|
2015-09-16 18:55:27 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
|
|
|
|
if (!opt.expert)
|
|
|
|
|
tty_printf (_("(Use the '%s' command.)\n"), "uid");
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (real_uids_left (keyblock) < 1)
|
|
|
|
|
tty_printf (_("You can't delete the last user ID!\n"));
|
|
|
|
|
else if (cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.remove.uid.okay",
|
|
|
|
|
n1 > 1 ? _("Really remove all selected user IDs? (y/N) ")
|
|
|
|
|
: _("Really remove this user ID? (y/N) ")))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_deluid (keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
redisplay = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdDELSIG:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!(n1 = count_selected_uids (keyblock)))
|
2015-09-16 18:55:27 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
|
|
|
|
if (!opt.expert)
|
|
|
|
|
tty_printf (_("(Use the '%s' command.)\n"), "uid");
|
|
|
|
|
}
|
2017-03-31 20:03:52 +02:00
|
|
|
|
else if (menu_delsig (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* No redisplay here, because it may scroll away some
|
|
|
|
|
* of the status output of this command. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdADDKEY:
|
2016-06-02 15:54:48 +02:00
|
|
|
|
if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef ENABLE_CARD_SUPPORT
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdADDCARDKEY:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (!card_generate_subkey (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2021-03-09 22:50:30 +01:00
|
|
|
|
case cmdKEYTOTPM:
|
|
|
|
|
/* FIXME need to store the key and not commit until later */
|
|
|
|
|
{
|
|
|
|
|
kbnode_t node = NULL;
|
|
|
|
|
switch (count_selected_keys (keyblock))
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
if (cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.keytocard.use_primary",
|
|
|
|
|
/* TRANSLATORS: Please take care: This is about
|
|
|
|
|
moving the key and not about removing it. */
|
|
|
|
|
_("Really move the primary key? (y/N) ")))
|
|
|
|
|
node = keyblock;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& node->flag & NODFLG_SELKEY)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
tty_printf (_("You must select exactly one key.\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *xxpk = node->pkt->pkt.public_key;
|
|
|
|
|
char *hexgrip;
|
|
|
|
|
|
|
|
|
|
hexkeygrip_from_pk (xxpk, &hexgrip);
|
|
|
|
|
if (!agent_keytotpm (ctrl, hexgrip))
|
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdKEYTOCARD:
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node = NULL;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
switch (count_selected_keys (keyblock))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
case 0:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (cpr_get_answer_is_yes
|
2009-06-30 13:29:03 +02:00
|
|
|
|
("keyedit.keytocard.use_primary",
|
|
|
|
|
/* TRANSLATORS: Please take care: This is about
|
|
|
|
|
moving the key and not about removing it. */
|
|
|
|
|
_("Really move the primary key? (y/N) ")))
|
2010-04-21 18:26:17 +02:00
|
|
|
|
node = keyblock;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
2006-04-19 13:26:11 +02:00
|
|
|
|
&& node->flag & NODFLG_SELKEY)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("You must select exactly one key.\n"));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (node)
|
|
|
|
|
{
|
2010-11-17 14:21:24 +01:00
|
|
|
|
PKT_public_key *xxpk = node->pkt->pkt.public_key;
|
2023-03-15 09:36:36 +01:00
|
|
|
|
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0,
|
|
|
|
|
&delseckey_list))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2015-04-03 10:39:59 +02:00
|
|
|
|
sec_shadowing = 1;
|
2023-03-15 09:36:36 +01:00
|
|
|
|
delseckey_list_warn = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdBKUPTOCARD:
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Ask for a filename, check whether this is really a
|
|
|
|
|
backup key as generated by the card generation, parse
|
|
|
|
|
that key and store it on card. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
KBNODE node;
|
2015-12-24 02:41:23 +01:00
|
|
|
|
char *fname;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PACKET *pkt;
|
|
|
|
|
IOBUF a;
|
2017-03-29 10:02:40 +02:00
|
|
|
|
struct parse_packet_ctx_s parsectx;
|
2024-01-22 16:52:22 +01:00
|
|
|
|
int lastmode;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2015-12-24 02:41:23 +01:00
|
|
|
|
if (!*arg_string)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Command expects a filename argument\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-24 02:41:23 +01:00
|
|
|
|
if (*arg_string == DIRSEP_C)
|
|
|
|
|
fname = xstrdup (arg_string);
|
|
|
|
|
else if (*arg_string == '~')
|
|
|
|
|
fname = make_filename (arg_string, NULL);
|
|
|
|
|
else
|
2016-06-07 10:59:46 +02:00
|
|
|
|
fname = make_filename (gnupg_homedir (), arg_string, NULL);
|
2015-12-24 02:41:23 +01:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Open that file. */
|
|
|
|
|
a = iobuf_open (fname);
|
|
|
|
|
if (a && is_secured_file (iobuf_get_fd (a)))
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (a);
|
|
|
|
|
a = NULL;
|
|
|
|
|
gpg_err_set_errno (EPERM);
|
|
|
|
|
}
|
2015-12-24 02:41:23 +01:00
|
|
|
|
if (!a)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Can't open '%s': %s\n"),
|
|
|
|
|
fname, strerror (errno));
|
|
|
|
|
xfree (fname);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* Parse and check that file. */
|
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
|
|
|
|
init_packet (pkt);
|
2017-03-29 10:02:40 +02:00
|
|
|
|
init_parse_packet (&parsectx, a);
|
|
|
|
|
err = parse_packet (&parsectx, pkt);
|
2017-03-29 11:57:40 +02:00
|
|
|
|
deinit_parse_packet (&parsectx);
|
|
|
|
|
iobuf_close (a);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname);
|
|
|
|
|
if (!err && pkt->pkttype != PKT_SECRET_KEY
|
2010-04-20 20:19:19 +02:00
|
|
|
|
&& pkt->pkttype != PKT_SECRET_SUBKEY)
|
2015-01-22 12:06:11 +01:00
|
|
|
|
err = GPG_ERR_NO_SECKEY;
|
2015-12-24 02:41:23 +01:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Error reading backup key from '%s': %s\n"),
|
|
|
|
|
fname, gpg_strerror (err));
|
|
|
|
|
xfree (fname);
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (pkt, NULL);
|
2015-12-24 02:41:23 +01:00
|
|
|
|
xfree (pkt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xfree (fname);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node = new_kbnode (pkt);
|
|
|
|
|
|
2024-01-22 16:52:22 +01:00
|
|
|
|
err = agent_set_ephemeral_mode (ctrl, 1, &lastmode);
|
|
|
|
|
if (err)
|
|
|
|
|
log_error ("error switching to ephemeral mode: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
else
|
2015-12-24 03:37:42 +01:00
|
|
|
|
{
|
2024-01-22 16:52:22 +01:00
|
|
|
|
/* Transfer it to gpg-agent which handles secret keys. */
|
|
|
|
|
err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0);
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
/* Treat the pkt as a public key. */
|
|
|
|
|
pkt->pkttype = PKT_PUBLIC_KEY;
|
|
|
|
|
|
|
|
|
|
/* Ask gpg-agent to store the secret key to card. */
|
|
|
|
|
if (card_store_subkey (node, 0, NULL))
|
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
sec_shadowing = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!lastmode && agent_set_ephemeral_mode (ctrl, 0, NULL))
|
|
|
|
|
log_error ("error clearing the ephemeral mode\n");
|
2015-12-24 01:54:23 +01:00
|
|
|
|
}
|
|
|
|
|
release_kbnode (node);
|
2015-12-24 03:37:42 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#endif /* ENABLE_CARD_SUPPORT */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdDELKEY:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
|
|
|
|
|
|
|
|
|
if (!(n1 = count_selected_keys (keyblock)))
|
2015-09-16 18:55:27 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You must select at least one key.\n"));
|
|
|
|
|
if (!opt.expert)
|
|
|
|
|
tty_printf (_("(Use the '%s' command.)\n"), "key");
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (!cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.remove.subkey.okay",
|
|
|
|
|
n1 > 1 ? _("Do you really want to delete the "
|
|
|
|
|
"selected keys? (y/N) ")
|
|
|
|
|
: _("Do you really want to delete this key? (y/N) ")))
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_delkey (keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = 1;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdADDREVOKER:
|
|
|
|
|
{
|
|
|
|
|
int sensitive = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (ascii_strcasecmp (arg_string, "sensitive") == 0)
|
|
|
|
|
sensitive = 1;
|
2010-10-01 22:33:53 +02:00
|
|
|
|
if (menu_addrevoker (ctrl, keyblock, sensitive))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2023-03-01 17:22:20 +01:00
|
|
|
|
case cmdADDADSK:
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if (menu_addadsk (ctrl, keyblock, NULL))
|
2023-03-01 17:22:20 +01:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
modified = 1;
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdREVUID:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
|
|
|
|
|
|
|
|
|
if (!(n1 = count_selected_uids (keyblock)))
|
2015-09-16 18:55:27 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
|
|
|
|
if (!opt.expert)
|
|
|
|
|
tty_printf (_("(Use the '%s' command.)\n"), "uid");
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else if (cpr_get_answer_is_yes
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("keyedit.revoke.uid.okay",
|
|
|
|
|
n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ")
|
|
|
|
|
: _("Really revoke this user ID? (y/N) ")))
|
|
|
|
|
{
|
2016-05-21 11:41:49 +02:00
|
|
|
|
if (menu_revuid (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdREVKEY:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!(n1 = count_selected_keys (keyblock)))
|
|
|
|
|
{
|
|
|
|
|
if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay",
|
2006-04-19 13:26:11 +02:00
|
|
|
|
_("Do you really want to revoke"
|
|
|
|
|
" the entire key? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_revkey (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay",
|
|
|
|
|
n1 > 1 ?
|
2006-04-19 13:26:11 +02:00
|
|
|
|
_("Do you really want to revoke"
|
2010-04-20 20:19:19 +02:00
|
|
|
|
" the selected subkeys? (y/N) ")
|
|
|
|
|
: _("Do you really want to revoke"
|
|
|
|
|
" this subkey? (y/N) ")))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_revsubkey (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (modified)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdEXPIRE:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (gpg_err_code (menu_expire (ctrl, keyblock, 0, 0)) == GPG_ERR_TRUE)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2014-09-17 16:27:37 +02:00
|
|
|
|
run_subkey_warnings = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-02-14 15:50:12 +01:00
|
|
|
|
case cmdCHANGEUSAGE:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_changeusage (ctrl, keyblock))
|
2016-02-14 15:50:12 +01:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2016-02-14 15:50:12 +01:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdBACKSIGN:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_backsign (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdPRIMARY:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_set_primary_uid (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdPASSWD:
|
2010-10-26 11:10:29 +02:00
|
|
|
|
change_passphrase (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdTRUST:
|
|
|
|
|
if (opt.trust_model == TM_EXTERNAL)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Owner trust may not be set while "
|
|
|
|
|
"using a user provided trust database\n"));
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, NULL, keyblock, 0, 0, 0, 1, 0, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2016-05-21 11:41:49 +02:00
|
|
|
|
if (edit_ownertrust (ctrl, find_kbnode (keyblock,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_PUBLIC_KEY)->pkt->pkt.
|
|
|
|
|
public_key, 1))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = 1;
|
|
|
|
|
/* No real need to set update_trust here as
|
|
|
|
|
edit_ownertrust() calls revalidation_mark()
|
|
|
|
|
anyway. */
|
|
|
|
|
update_trust = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdPREF:
|
|
|
|
|
{
|
|
|
|
|
int count = count_selected_uids (keyblock);
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count ? NODFLG_SELUID : 0, 1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSHOWPREF:
|
|
|
|
|
{
|
|
|
|
|
int count = count_selected_uids (keyblock);
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count ? NODFLG_SELUID : 0, 2);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSETPREF:
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *tempuid;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keygen_set_std_prefs (!*arg_string ? "default" : arg_string, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tempuid = keygen_get_std_prefs ();
|
|
|
|
|
tty_printf (_("Set preference list to:\n"));
|
|
|
|
|
show_prefs (tempuid, NULL, 1);
|
|
|
|
|
free_user_id (tempuid);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.setpref.okay",
|
|
|
|
|
count_selected_uids (keyblock) ?
|
|
|
|
|
_("Really update the preferences"
|
|
|
|
|
" for the selected user IDs? (y/N) ")
|
|
|
|
|
: _("Really update the preferences? (y/N) ")))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2022-11-04 15:26:15 +01:00
|
|
|
|
if (menu_set_preferences (ctrl, keyblock, 0))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdPREFKS:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_set_keyserver_url (ctrl, *arg_string ? arg_string : NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdNOTATION:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_set_notation (ctrl, *arg_string ? arg_string : NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdNOP:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdREVSIG:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_revsig (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
modified = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdENABLEKEY:
|
|
|
|
|
case cmdDISABLEKEY:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (enable_disable_key (ctrl, keyblock, cmd == cmdDISABLEKEY))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSHOWPHOTO:
|
2016-05-21 11:41:49 +02:00
|
|
|
|
menu_showphoto (ctrl, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdCLEAN:
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (menu_clean (ctrl, keyblock, 0))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = modified = 1;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdMINIMIZE:
|
2024-03-04 14:22:42 +01:00
|
|
|
|
if (menu_clean (ctrl, keyblock, EXPORT_MINIMAL))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
redisplay = modified = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdQUIT:
|
|
|
|
|
if (have_commands)
|
|
|
|
|
goto leave;
|
2015-04-03 10:39:59 +02:00
|
|
|
|
if (!modified && !sec_shadowing)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
if (!cpr_get_answer_is_yes ("keyedit.save.okay",
|
|
|
|
|
_("Save changes? (y/N) ")))
|
|
|
|
|
{
|
|
|
|
|
if (cpr_enabled ()
|
|
|
|
|
|| cpr_get_answer_is_yes ("keyedit.cancel.okay",
|
|
|
|
|
_("Quit without saving? (y/N) ")))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto leave;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
Fix more spelling
* NEWS, acinclude.m4, agent/command-ssh.c, agent/command.c,
agent/gpg-agent.c, agent/keyformat.txt, agent/protect-tool.c,
common/asshelp.c, common/b64enc.c, common/recsel.c, doc/DETAILS,
doc/HACKING, doc/Notes, doc/TRANSLATE, doc/dirmngr.texi,
doc/faq.org, doc/gpg-agent.texi, doc/gpg.texi, doc/gpgsm.texi,
doc/instguide.texi, g10/armor.c, g10/gpg.c, g10/keyedit.c,
g10/mainproc.c, g10/pkclist.c, g10/tofu.c, g13/sh-cmd.c,
g13/sh-dmcrypt.c, kbx/keybox-init.c, m4/pkg.m4, sm/call-dirmngr.c,
sm/gpgsm.c, tests/Makefile.am, tests/gpgscm/Manual.txt,
tests/gpgscm/scheme.c, tests/openpgp/gpgv-forged-keyring.scm,
tests/openpgp/multisig.test, tests/openpgp/verify.scm,
tests/pkits/README, tools/applygnupgdefaults,
tools/gpg-connect-agent.c, tools/mime-maker.c, tools/mime-parser.c:
minor spelling cleanup.
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2016-09-15 20:21:15 +02:00
|
|
|
|
/* fall through */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSAVE:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (modified)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
g10: Cache the effective policy. Recompute it when required.
* g10/tofu.c (initdb): Add column effective_policy to the bindings
table.
(record_binding): New parameters effective_policy and set_conflict.
Save the effective policy. If SET_CONFLICT is set, then set conflict
according to CONFLICT. Otherwise, preserve the current value of
conflict. Update callers.
(get_trust): Don't compute the effective policy here...
(get_policy): ... do it here, if it was not cached. Take new
parameters, PK, the public key, and NOW, the time that the operation
started. Update callers.
(show_statistics): New parameter PK. Pass it to get_policy. Update
callers.
(tofu_notice_key_changed): New function.
* g10/gpgv.c (tofu_notice_key_changed): New stub.
* g10/import.c (import_revoke_cert): Take additional argument CTRL.
Pass it to keydb_update_keyblock.
* g10/keydb.c (keydb_update_keyblock): Take additional argument CTRL.
Update callers.
[USE_TOFU]: Call tofu_notice_key_changed.
* g10/test-stubs.c (tofu_notice_key_changed): New stub.
* tests/openpgp/tofu.scm: Assume that manually setting a binding's
policy to auto does not cause the tofu engine to forget about any
conflict.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
We now store the computed policy in the tofu DB (in the
effective_policy column of the bindings table) to avoid computing it
every time, which is expensive. Further, policy is never overridden
in case of a conflict. Instead, we detect a conflict if CONFLICT is
not empty.
This change is backwards compatible to existing DBs. The only minor
incompatibility is that unresolved conflicts won't be automatically
resolved in case we import a direct signature, or cross signatures.
2016-11-21 22:47:30 +01:00
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
2010-04-21 18:26:17 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2015-04-03 10:39:59 +02:00
|
|
|
|
|
2023-03-15 09:36:36 +01:00
|
|
|
|
if (delseckey_list)
|
|
|
|
|
{
|
|
|
|
|
strlist_t sl;
|
|
|
|
|
for (err = 0, sl = delseckey_list; sl; sl = sl->next)
|
|
|
|
|
{
|
|
|
|
|
if (*sl->d)
|
|
|
|
|
{
|
|
|
|
|
err = agent_delete_key (ctrl, sl->d, NULL, 1/*force*/);
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
|
|
|
|
*sl->d = 0; /* Mark deleted. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("deleting copy of secret key failed: %s\n"),
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
break; /* the "save". */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-03 10:39:59 +02:00
|
|
|
|
if (sec_shadowing)
|
|
|
|
|
{
|
|
|
|
|
err = agent_scd_learn (NULL, 1);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!modified && !sec_shadowing)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Key not changed so no update needed.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (update_trust)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
update_trust = 0;
|
|
|
|
|
}
|
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdINVCMD:
|
|
|
|
|
default:
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("Invalid command (try \"help\")\n"));
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
} /* End of the main command loop. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
leave:
|
2023-03-15 09:36:36 +01:00
|
|
|
|
free_strlist (delseckey_list);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
xfree (answer);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-01-08 20:18:49 +01:00
|
|
|
|
|
|
|
|
|
/* Change the passphrase of the secret key identified by USERNAME. */
|
|
|
|
|
void
|
2010-10-26 11:10:29 +02:00
|
|
|
|
keyedit_passwd (ctrl_t ctrl, const char *username)
|
2010-01-08 20:18:49 +01:00
|
|
|
|
{
|
2010-02-02 15:06:19 +01:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
|
|
|
|
|
pk = xtrycalloc (1, sizeof *pk);
|
|
|
|
|
if (!pk)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2015-11-03 23:15:27 +01:00
|
|
|
|
err = getkey_byname (ctrl, NULL, pk, username, 1, &keyblock);
|
2010-02-02 15:06:19 +01:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2010-01-08 20:18:49 +01:00
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
err = change_passphrase (ctrl, keyblock);
|
2010-02-02 15:06:19 +01:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
leave:
|
2010-02-02 15:06:19 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2011-09-20 19:24:52 +02:00
|
|
|
|
free_public_key (pk);
|
2010-02-02 15:06:19 +01:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("error changing the passphrase for '%s': %s\n",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
username, gpg_strerror (err));
|
2010-02-02 15:06:19 +01:00
|
|
|
|
write_status_error ("keyedit.passwd", err);
|
|
|
|
|
}
|
2010-03-15 12:15:45 +01:00
|
|
|
|
else
|
|
|
|
|
write_status_text (STATUS_SUCCESS, "keyedit.passwd");
|
2010-01-08 20:18:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
/* Helper for quick commands to find the keyblock for USERNAME.
|
|
|
|
|
* Returns on success the key database handle at R_KDBHD and the
|
|
|
|
|
* keyblock at R_KEYBLOCK. */
|
|
|
|
|
static gpg_error_t
|
2020-10-28 17:06:27 +01:00
|
|
|
|
quick_find_keyblock (ctrl_t ctrl, const char *username, int want_secret,
|
2017-03-21 14:47:21 +01:00
|
|
|
|
KEYDB_HANDLE *r_kdbhd, kbnode_t *r_keyblock)
|
2015-05-08 16:08:57 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
2017-03-21 14:47:21 +01:00
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
2015-05-08 16:08:57 +02:00
|
|
|
|
kbnode_t node;
|
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
*r_kdbhd = NULL;
|
|
|
|
|
*r_keyblock = NULL;
|
2015-05-08 16:08:57 +02:00
|
|
|
|
|
|
|
|
|
/* Search the key; we don't want the whole getkey stuff here. */
|
2019-09-09 14:34:09 +02:00
|
|
|
|
kdbhd = keydb_new (ctrl);
|
2015-12-03 12:18:32 +01:00
|
|
|
|
if (!kdbhd)
|
|
|
|
|
{
|
2016-01-06 08:45:01 +01:00
|
|
|
|
/* Note that keydb_new has already used log_error. */
|
2017-03-21 14:47:21 +01:00
|
|
|
|
err = gpg_error_from_syserror ();
|
2015-12-03 12:18:32 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-08 16:08:57 +02:00
|
|
|
|
err = classify_user_id (username, &desc, 1);
|
|
|
|
|
if (!err)
|
|
|
|
|
err = keydb_search (kdbhd, &desc, 1, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
err = keydb_get_keyblock (kdbhd, &keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
/* Now with the keyblock retrieved, search again to detect an
|
|
|
|
|
ambiguous specification. We need to save the found state so
|
|
|
|
|
that we can do an update later. */
|
|
|
|
|
keydb_push_found_state (kdbhd);
|
|
|
|
|
err = keydb_search (kdbhd, &desc, 1, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
|
|
|
|
|
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
|
|
|
|
err = 0;
|
|
|
|
|
keydb_pop_found_state (kdbhd);
|
|
|
|
|
|
2020-10-28 17:06:27 +01:00
|
|
|
|
if (!err && want_secret)
|
2015-05-08 16:08:57 +02:00
|
|
|
|
{
|
2017-03-21 14:47:21 +01:00
|
|
|
|
/* We require the secret primary key to set the primary UID. */
|
2015-05-08 16:08:57 +02:00
|
|
|
|
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
2017-03-21 14:47:21 +01:00
|
|
|
|
log_assert (node);
|
2020-01-17 07:11:02 +01:00
|
|
|
|
if (!agent_probe_secret_key (ctrl, node->pkt->pkt.public_key))
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
2015-05-08 16:08:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-21 14:47:21 +01:00
|
|
|
|
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
|
|
|
|
|
2015-05-08 16:08:57 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2017-03-21 14:47:21 +01:00
|
|
|
|
log_error (_("key \"%s\" not found: %s\n"),
|
2015-05-08 16:08:57 +02:00
|
|
|
|
username, gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
fix_keyblock (ctrl, &keyblock);
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2016-09-22 21:32:31 +02:00
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
*r_keyblock = keyblock;
|
|
|
|
|
keyblock = NULL;
|
|
|
|
|
*r_kdbhd = kdbhd;
|
|
|
|
|
kdbhd = NULL;
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Unattended adding of a new keyid. USERNAME specifies the
|
|
|
|
|
key. NEWUID is the new user id to add to the key. */
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
char *uidstring = NULL;
|
|
|
|
|
|
|
|
|
|
uidstring = xstrdup (newuid);
|
|
|
|
|
trim_spaces (uidstring);
|
|
|
|
|
if (!*uidstring)
|
|
|
|
|
{
|
|
|
|
|
log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#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. */
|
2020-10-28 17:06:27 +01:00
|
|
|
|
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
2017-03-21 14:47:21 +01:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
2016-05-21 11:41:49 +02:00
|
|
|
|
if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
|
2015-05-08 16:08:57 +02:00
|
|
|
|
{
|
g10: Cache the effective policy. Recompute it when required.
* g10/tofu.c (initdb): Add column effective_policy to the bindings
table.
(record_binding): New parameters effective_policy and set_conflict.
Save the effective policy. If SET_CONFLICT is set, then set conflict
according to CONFLICT. Otherwise, preserve the current value of
conflict. Update callers.
(get_trust): Don't compute the effective policy here...
(get_policy): ... do it here, if it was not cached. Take new
parameters, PK, the public key, and NOW, the time that the operation
started. Update callers.
(show_statistics): New parameter PK. Pass it to get_policy. Update
callers.
(tofu_notice_key_changed): New function.
* g10/gpgv.c (tofu_notice_key_changed): New stub.
* g10/import.c (import_revoke_cert): Take additional argument CTRL.
Pass it to keydb_update_keyblock.
* g10/keydb.c (keydb_update_keyblock): Take additional argument CTRL.
Update callers.
[USE_TOFU]: Call tofu_notice_key_changed.
* g10/test-stubs.c (tofu_notice_key_changed): New stub.
* tests/openpgp/tofu.scm: Assume that manually setting a binding's
policy to auto does not cause the tofu engine to forget about any
conflict.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
We now store the computed policy in the tofu DB (in the
effective_policy column of the bindings table) to avoid computing it
every time, which is expensive. Further, policy is never overridden
in case of a conflict. Instead, we detect a conflict if CONFLICT is
not empty.
This change is backwards compatible to existing DBs. The only minor
incompatibility is that unresolved conflicts won't be automatically
resolved in case we import a direct signature, or cross signatures.
2016-11-21 22:47:30 +01:00
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
2015-05-08 16:08:57 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (update_trust)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2015-05-08 16:08:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
xfree (uidstring);
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
|
2022-04-21 16:43:50 +02:00
|
|
|
|
/* Helper to find the UID node for namehash. On success, returns the UID node.
|
|
|
|
|
Otherwise, return NULL. */
|
|
|
|
|
kbnode_t
|
2022-08-08 12:29:00 +02:00
|
|
|
|
find_userid_by_namehash (kbnode_t keyblock, const char *namehash, int want_valid)
|
2022-04-21 16:43:50 +02:00
|
|
|
|
{
|
|
|
|
|
byte hash[NAMEHASH_LEN];
|
|
|
|
|
kbnode_t node = NULL;
|
|
|
|
|
|
|
|
|
|
if (!namehash)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
if (strlen (namehash) != NAMEHASH_LEN * 2)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
if (hex2bin (namehash, hash, NAMEHASH_LEN) < 0)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
2022-08-08 12:29:00 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& (!want_valid || (!node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& !node->pkt->pkt.user_id->flags.expired)))
|
2022-04-21 16:43:50 +02:00
|
|
|
|
{
|
|
|
|
|
namehash_from_uid (node->pkt->pkt.user_id);
|
|
|
|
|
if (!memcmp (node->pkt->pkt.user_id->namehash, hash, NAMEHASH_LEN))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to find the UID node for uid. On success, returns the UID node.
|
|
|
|
|
Otherwise, return NULL. */
|
|
|
|
|
kbnode_t
|
2022-08-08 12:29:00 +02:00
|
|
|
|
find_userid (kbnode_t keyblock, const char *uid, int want_valid)
|
2022-04-21 16:43:50 +02:00
|
|
|
|
{
|
|
|
|
|
kbnode_t node = NULL;
|
|
|
|
|
size_t uidlen;
|
|
|
|
|
|
|
|
|
|
if (!keyblock || !uid)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* First try to find UID by namehash. */
|
2022-08-08 12:29:00 +02:00
|
|
|
|
node = find_userid_by_namehash (keyblock, uid, want_valid);
|
2022-04-21 16:43:50 +02:00
|
|
|
|
if (node)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
uidlen = strlen (uid);
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
2022-08-08 12:29:00 +02:00
|
|
|
|
&& (!want_valid || (!node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& !node->pkt->pkt.user_id->flags.expired))
|
2022-04-21 16:43:50 +02:00
|
|
|
|
&& uidlen == node->pkt->pkt.user_id->len
|
|
|
|
|
&& !memcmp (node->pkt->pkt.user_id->name, uid, uidlen))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-11-17 10:46:43 +01:00
|
|
|
|
/* Unattended revocation of a keyid. USERNAME specifies the
|
2016-06-17 00:05:57 +02:00
|
|
|
|
key. UIDTOREV is the user id revoke from the key. */
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
int modified = 0;
|
2017-03-02 14:14:55 +01:00
|
|
|
|
size_t valid_uids;
|
2016-06-17 00:05:57 +02:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* See keyedit_menu for why we need this. */
|
2016-06-30 15:28:42 +02:00
|
|
|
|
check_trustdb_stale (ctrl);
|
2016-06-17 00:05:57 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Search the key; we don't want the whole getkey stuff here. */
|
2020-10-28 17:06:27 +01:00
|
|
|
|
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
2016-06-17 00:05:57 +02:00
|
|
|
|
if (err)
|
2017-03-21 14:47:21 +01:00
|
|
|
|
goto leave;
|
2017-03-02 14:14:55 +01:00
|
|
|
|
|
2022-04-21 16:43:50 +02:00
|
|
|
|
/* To make sure that we do not revoke the last valid UID, we first
|
2017-03-02 14:14:55 +01:00
|
|
|
|
count how many valid UIDs there are. */
|
|
|
|
|
valid_uids = 0;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2017-03-21 14:47:21 +01:00
|
|
|
|
valid_uids += (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& !node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& !node->pkt->pkt.user_id->flags.expired);
|
2016-06-17 00:05:57 +02:00
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
/* Find the right UID. */
|
2022-08-08 12:29:00 +02:00
|
|
|
|
node = find_userid (keyblock, uidtorev, 0);
|
2022-04-21 16:43:50 +02:00
|
|
|
|
if (node)
|
2016-06-17 00:05:57 +02:00
|
|
|
|
{
|
2022-04-21 16:43:50 +02:00
|
|
|
|
struct revocation_reason_info *reason;
|
|
|
|
|
|
|
|
|
|
/* Make sure that we do not revoke the last valid UID. */
|
|
|
|
|
if (valid_uids == 1
|
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.expired)
|
2016-06-17 00:05:57 +02:00
|
|
|
|
{
|
2022-04-21 16:43:50 +02:00
|
|
|
|
log_error (_("cannot revoke the last valid user ID.\n"));
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2016-06-17 00:05:57 +02:00
|
|
|
|
|
2022-04-21 16:43:50 +02:00
|
|
|
|
reason = get_default_uid_revocation_reason ();
|
|
|
|
|
err = core_revuid (ctrl, keyblock, node, reason, &modified);
|
|
|
|
|
release_revocation_reason_info (reason);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
2016-06-17 00:05:57 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2022-04-21 16:43:50 +02:00
|
|
|
|
|
|
|
|
|
revalidation_mark (ctrl);
|
|
|
|
|
goto leave;
|
2016-06-17 00:05:57 +02:00
|
|
|
|
}
|
2017-03-21 14:47:21 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_NO_USER_ID);
|
|
|
|
|
|
2016-06-17 00:05:57 +02:00
|
|
|
|
|
2017-03-21 14:47:21 +01:00
|
|
|
|
leave:
|
|
|
|
|
if (err)
|
2017-08-09 18:35:56 +02:00
|
|
|
|
{
|
|
|
|
|
log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
write_status_error ("keyedit.revoke.uid", err);
|
|
|
|
|
}
|
2017-03-21 14:47:21 +01:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Unattended setting of the primary uid. USERNAME specifies the key.
|
|
|
|
|
PRIMARYUID is the user id which shall be primary. */
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
|
|
|
|
|
const char *primaryuid)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
2022-08-08 12:29:00 +02:00
|
|
|
|
kbnode_t primarynode;
|
2017-03-21 14:47:21 +01:00
|
|
|
|
kbnode_t node;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* See keyedit_menu for why we need this. */
|
|
|
|
|
check_trustdb_stale (ctrl);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-10-28 17:06:27 +01:00
|
|
|
|
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
2017-03-21 14:47:21 +01:00
|
|
|
|
if (err)
|
2022-08-09 12:02:28 +02:00
|
|
|
|
{
|
|
|
|
|
write_status_error ("keyedit.primary", err);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2017-03-21 14:47:21 +01:00
|
|
|
|
|
2022-08-08 12:29:00 +02:00
|
|
|
|
/* Find the first matching UID that is valid */
|
|
|
|
|
primarynode = find_userid (keyblock, primaryuid, 1);
|
|
|
|
|
|
|
|
|
|
/* and mark it. */
|
|
|
|
|
if (primarynode)
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node == primarynode)
|
2017-03-21 14:47:21 +01:00
|
|
|
|
node->flag |= NODFLG_SELUID;
|
2022-08-08 12:29:00 +02:00
|
|
|
|
else
|
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
|
|
|
|
}
|
2017-03-21 14:47:21 +01:00
|
|
|
|
|
2022-08-08 12:29:00 +02:00
|
|
|
|
if (!primarynode)
|
2017-03-21 14:47:21 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_NO_USER_ID);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
else if (menu_set_primary_uid (ctrl, keyblock))
|
2017-03-21 14:47:21 +01:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2017-03-21 14:47:21 +01:00
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2017-03-21 14:47:21 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
|
|
|
|
|
if (err)
|
2022-08-09 12:02:28 +02:00
|
|
|
|
{
|
|
|
|
|
log_error (_("setting the primary user ID failed: %s\n"),
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
write_status_error ("keyedit.primary", err);
|
|
|
|
|
}
|
2017-03-02 11:39:00 +01:00
|
|
|
|
|
2016-06-17 00:05:57 +02:00
|
|
|
|
leave:
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-08 16:08:57 +02:00
|
|
|
|
|
2022-11-04 15:26:15 +01:00
|
|
|
|
/* Unattended updating of the preference tro the standard preferences.
|
|
|
|
|
* USERNAME specifies the key. This is basically the same as
|
|
|
|
|
* gpg --edit-key <<userif> updpref save
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_update_pref (ctrl_t ctrl, const char *username)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* See keyedit_menu for why we need this. */
|
|
|
|
|
check_trustdb_stale (ctrl);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
err = quick_find_keyblock (ctrl, username, 1, &kdbhd, &keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
if (menu_set_preferences (ctrl, keyblock, 1))
|
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (err)
|
|
|
|
|
write_status_error ("keyedit.updpref", err);
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-04-17 11:42:20 +02:00
|
|
|
|
/* Unattended updating of the ownertrust or disable/enable state of a key
|
|
|
|
|
* USERNAME specifies the key. This is somewhat similar to
|
|
|
|
|
* gpg --edit-key <userid> trust save
|
|
|
|
|
* gpg --edit-key <userid> disable save
|
|
|
|
|
*
|
|
|
|
|
* VALUE is the new trust value which is one of:
|
|
|
|
|
* "undefined" - Ownertrust is set to undefined
|
|
|
|
|
* "never" - Ownertrust is set to never trust
|
|
|
|
|
* "marginal" - Ownertrust is set to marginal trust
|
|
|
|
|
* "full" - Ownertrust is set to full trust
|
|
|
|
|
* "ultimate" - Ownertrust is set to ultimate trust
|
|
|
|
|
* "enable" - The key is re-enabled.
|
|
|
|
|
* "disable" - The key is disabled.
|
|
|
|
|
* Trust settings do not change the ebable/disable state.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_set_ownertrust (ctrl_t ctrl, const char *username,
|
|
|
|
|
const char *value)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
unsigned int trust, newtrust;
|
|
|
|
|
int x;
|
|
|
|
|
int maybe_update_trust = 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. Note
|
|
|
|
|
* 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);
|
|
|
|
|
pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
trust = newtrust = get_ownertrust (ctrl, pk);
|
|
|
|
|
|
|
|
|
|
if (!ascii_strcasecmp (value, "enable"))
|
|
|
|
|
newtrust &= ~TRUST_FLAG_DISABLED;
|
|
|
|
|
else if (!ascii_strcasecmp (value, "disable"))
|
|
|
|
|
newtrust |= TRUST_FLAG_DISABLED;
|
|
|
|
|
else if ((x = string_to_trust_value (value)) >= 0)
|
|
|
|
|
{
|
|
|
|
|
newtrust = x;
|
|
|
|
|
newtrust &= TRUST_MASK;
|
|
|
|
|
newtrust |= (trust & ~TRUST_MASK);
|
|
|
|
|
maybe_update_trust = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_ARG);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trust != newtrust)
|
|
|
|
|
{
|
|
|
|
|
update_ownertrust (ctrl, pk, newtrust);
|
|
|
|
|
if (maybe_update_trust)
|
|
|
|
|
revalidation_mark (ctrl);
|
|
|
|
|
}
|
|
|
|
|
else if (opt.verbose)
|
|
|
|
|
log_info (_("Key not changed so no update needed.\n"));
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("setting the ownertrust to '%s' failed: %s\n"),
|
|
|
|
|
value, gpg_strerror (err));
|
|
|
|
|
write_status_error ("keyedit.setownertrust", err);
|
|
|
|
|
}
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-02 15:54:48 +02:00
|
|
|
|
/* Find a keyblock by fingerprint because only this uniquely
|
|
|
|
|
* identifies a key and may thus be used to select a key for
|
|
|
|
|
* unattended subkey creation os key signing. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
|
|
|
|
|
kbnode_t *r_keyblock, KEYDB_HANDLE *r_kdbhd)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
byte fprbin[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
|
|
|
|
|
|
|
|
|
*r_keyblock = NULL;
|
|
|
|
|
*r_kdbhd = NULL;
|
|
|
|
|
|
|
|
|
|
if (classify_user_id (fpr, &desc, 1)
|
2019-03-14 14:55:06 +01:00
|
|
|
|
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
|
2016-06-02 15:54:48 +02:00
|
|
|
|
{
|
|
|
|
|
log_error (_("\"%s\" is not a fingerprint\n"), fpr);
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2019-07-04 10:42:48 +02:00
|
|
|
|
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
|
|
|
|
|
NULL, NULL, fpr, &keyblock, &kdbhd, 1);
|
2016-06-02 15:54:48 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check that the primary fingerprint has been given. */
|
|
|
|
|
fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
|
2019-03-14 14:55:06 +01:00
|
|
|
|
if (desc.mode == KEYDB_SEARCH_MODE_FPR
|
|
|
|
|
&& fprlen == desc.fprlen
|
|
|
|
|
&& !memcmp (fprbin, desc.u.fpr, fprlen))
|
2019-03-14 08:54:59 +01:00
|
|
|
|
;
|
2016-06-02 15:54:48 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*r_keyblock = keyblock;
|
|
|
|
|
keyblock = NULL;
|
|
|
|
|
*r_kdbhd = kdbhd;
|
|
|
|
|
kdbhd = NULL;
|
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-05-13 00:09:23 +02:00
|
|
|
|
/* Unattended key signing function. If the key specified by FPR is
|
2016-04-19 17:47:24 +02:00
|
|
|
|
available and FPR is the primary fingerprint all user ids of the
|
|
|
|
|
key are signed using the default signing key. If UIDS is an empty
|
|
|
|
|
list all usable UIDs are signed, if it is not empty, only those
|
|
|
|
|
user ids matching one of the entries of the list are signed. With
|
|
|
|
|
LOCAL being true the signatures are marked as non-exportable. */
|
2014-03-27 16:33:40 +01:00
|
|
|
|
void
|
|
|
|
|
keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
|
|
|
|
|
strlist_t locusr, int local)
|
|
|
|
|
{
|
2023-05-24 16:02:39 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
KEYDB_HANDLE kdbhd = NULL;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
strlist_t sl;
|
|
|
|
|
int any;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_W32_SYSTEM
|
|
|
|
|
/* See keyedit_menu for why we need this. */
|
2016-05-21 11:41:49 +02:00
|
|
|
|
check_trustdb_stale (ctrl);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* We require a fingerprint because only this uniquely identifies a
|
|
|
|
|
key and may thus be used to select a key for unattended key
|
|
|
|
|
signing. */
|
2016-06-02 15:54:48 +02:00
|
|
|
|
if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
|
|
|
|
|
goto leave;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (fix_keyblock (ctrl, &keyblock))
|
2015-05-08 12:05:52 +02:00
|
|
|
|
modified++;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
|
|
|
|
|
/* Give some info in verbose. */
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
{
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, es_stdout, keyblock, 0,
|
2014-03-27 16:33:40 +01:00
|
|
|
|
1/*with_revoker*/, 1/*with_fingerprint*/,
|
|
|
|
|
0, 0, 1);
|
|
|
|
|
es_fflush (es_stdout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
if (pk->flags.revoked)
|
|
|
|
|
{
|
|
|
|
|
if (!opt.verbose)
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
log_error ("%s%s", _("Key is revoked."), _(" Unable to sign.\n"));
|
2023-05-24 16:02:39 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the flags according to the UIDS list. Fixme: We may want to
|
|
|
|
|
use classify_user_id along with dedicated compare functions so
|
|
|
|
|
that we match the same way as in the key lookup. */
|
|
|
|
|
any = 0;
|
|
|
|
|
menu_select_uid (keyblock, 0); /* Better clear the flags first. */
|
|
|
|
|
for (sl=uids; sl; sl = sl->next)
|
|
|
|
|
{
|
2016-04-19 17:47:24 +02:00
|
|
|
|
const char *name = sl->d;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
sl->flags &= ~(1|2); /* Clear flags used for error reporting. */
|
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
|
2016-04-19 17:47:24 +02:00
|
|
|
|
if (uid->attrib_data)
|
|
|
|
|
;
|
|
|
|
|
else if (*name == '='
|
|
|
|
|
&& strlen (name+1) == uid->len
|
|
|
|
|
&& !memcmp (uid->name, name + 1, uid->len))
|
|
|
|
|
{ /* Exact match - we don't do a check for ambiguity
|
|
|
|
|
* in this case. */
|
|
|
|
|
node->flag |= NODFLG_SELUID;
|
|
|
|
|
if (any != -1)
|
|
|
|
|
{
|
|
|
|
|
sl->flags |= 1; /* Report as found. */
|
|
|
|
|
any = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (ascii_memistr (uid->name, uid->len,
|
|
|
|
|
*name == '*'? name+1:name))
|
2014-03-27 16:33:40 +01:00
|
|
|
|
{
|
|
|
|
|
node->flag |= NODFLG_SELUID;
|
2016-04-19 17:47:24 +02:00
|
|
|
|
if (any != -1)
|
|
|
|
|
{
|
|
|
|
|
sl->flags |= 1; /* Report as found. */
|
|
|
|
|
any = 1;
|
|
|
|
|
}
|
|
|
|
|
count++;
|
2014-03-27 16:33:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-19 17:47:24 +02:00
|
|
|
|
|
|
|
|
|
if (count > 1)
|
|
|
|
|
{
|
|
|
|
|
any = -1; /* Force failure at end. */
|
|
|
|
|
sl->flags |= 2; /* Report as ambiguous. */
|
|
|
|
|
}
|
2014-03-27 16:33:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-19 17:47:24 +02:00
|
|
|
|
/* Check whether all given user ids were found. */
|
|
|
|
|
for (sl=uids; sl; sl = sl->next)
|
|
|
|
|
if (!(sl->flags & 1))
|
|
|
|
|
any = -1; /* That user id was not found. */
|
|
|
|
|
|
|
|
|
|
/* Print an error if there was a problem with the user ids. */
|
|
|
|
|
if (uids && any < 1)
|
2014-03-27 16:33:40 +01:00
|
|
|
|
{
|
|
|
|
|
if (!opt.verbose)
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
es_fflush (es_stdout);
|
2016-04-19 17:47:24 +02:00
|
|
|
|
for (sl=uids; sl; sl = sl->next)
|
|
|
|
|
{
|
|
|
|
|
if ((sl->flags & 2))
|
|
|
|
|
log_info (_("Invalid user ID '%s': %s\n"),
|
|
|
|
|
sl->d, gpg_strerror (GPG_ERR_AMBIGUOUS_NAME));
|
|
|
|
|
else if (!(sl->flags & 1))
|
|
|
|
|
log_info (_("Invalid user ID '%s': %s\n"),
|
|
|
|
|
sl->d, gpg_strerror (GPG_ERR_NOT_FOUND));
|
|
|
|
|
}
|
2014-03-27 16:33:40 +01:00
|
|
|
|
log_error ("%s %s", _("No matching user IDs."), _("Nothing to sign.\n"));
|
2023-05-24 16:02:39 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_NO_USER_ID);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sign. */
|
2015-07-28 18:21:47 +02:00
|
|
|
|
sign_uids (ctrl, es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
es_fflush (es_stdout);
|
|
|
|
|
|
|
|
|
|
if (modified)
|
|
|
|
|
{
|
g10: Cache the effective policy. Recompute it when required.
* g10/tofu.c (initdb): Add column effective_policy to the bindings
table.
(record_binding): New parameters effective_policy and set_conflict.
Save the effective policy. If SET_CONFLICT is set, then set conflict
according to CONFLICT. Otherwise, preserve the current value of
conflict. Update callers.
(get_trust): Don't compute the effective policy here...
(get_policy): ... do it here, if it was not cached. Take new
parameters, PK, the public key, and NOW, the time that the operation
started. Update callers.
(show_statistics): New parameter PK. Pass it to get_policy. Update
callers.
(tofu_notice_key_changed): New function.
* g10/gpgv.c (tofu_notice_key_changed): New stub.
* g10/import.c (import_revoke_cert): Take additional argument CTRL.
Pass it to keydb_update_keyblock.
* g10/keydb.c (keydb_update_keyblock): Take additional argument CTRL.
Update callers.
[USE_TOFU]: Call tofu_notice_key_changed.
* g10/test-stubs.c (tofu_notice_key_changed): New stub.
* tests/openpgp/tofu.scm: Assume that manually setting a binding's
policy to auto does not cause the tofu engine to forget about any
conflict.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
We now store the computed policy in the tofu DB (in the
effective_policy column of the bindings table) to avoid computing it
every time, which is expensive. Further, policy is never overridden
in case of a conflict. Instead, we detect a conflict if CONFLICT is
not empty.
This change is backwards compatible to existing DBs. The only minor
incompatibility is that unresolved conflicts won't be automatically
resolved in case we import a direct signature, or cross signatures.
2016-11-21 22:47:30 +01:00
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
log_info (_("Key not changed so no update needed.\n"));
|
|
|
|
|
|
|
|
|
|
if (update_trust)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
|
|
|
|
|
leave:
|
2023-05-24 16:02:39 +02:00
|
|
|
|
if (err)
|
|
|
|
|
write_status_error ("keyedit.sign-key", err);
|
2014-03-27 16:33:40 +01:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-10-28 17:06:27 +01:00
|
|
|
|
/* 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)
|
|
|
|
|
{
|
2023-05-24 16:02:39 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2020-10-28 17:06:27 +01:00
|
|
|
|
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
|
|
|
|
|
|
2024-04-17 11:42:20 +02:00
|
|
|
|
/* Search the key; we don't want the whole getkey stuff here. Note
|
2020-10-28 17:06:27 +01:00
|
|
|
|
* 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;
|
|
|
|
|
|
2024-05-13 00:09:23 +02:00
|
|
|
|
/* Allocate an array large enough for all signatures. */
|
2020-10-28 17:06:27 +01:00
|
|
|
|
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)
|
|
|
|
|
{
|
2020-10-30 15:49:27 +01:00
|
|
|
|
sig = n->pkt->pkt.signature;
|
2020-10-28 17:06:27 +01:00
|
|
|
|
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 cm_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,
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-02 15:54:48 +02:00
|
|
|
|
/* Unattended subkey creation function.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
|
|
|
|
|
const char *usagestr, const char *expirestr)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t keyblock;
|
|
|
|
|
KEYDB_HANDLE kdbhd;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
|
|
|
|
|
#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 subkey
|
|
|
|
|
* creation. */
|
2024-01-05 11:33:51 +01:00
|
|
|
|
if ((err=find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)))
|
2016-06-02 15:54:48 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (fix_keyblock (ctrl, &keyblock))
|
2016-06-02 15:54:48 +02:00
|
|
|
|
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");
|
2024-01-05 11:33:51 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
2016-06-02 15:54:48 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-13 11:30:54 +02:00
|
|
|
|
/* Create the subkey. Note that the called function already prints
|
2016-06-02 15:54:48 +02:00
|
|
|
|
* an error message. */
|
|
|
|
|
if (!generate_subkeypair (ctrl, keyblock, algostr, usagestr, expirestr))
|
|
|
|
|
modified = 1;
|
|
|
|
|
es_fflush (es_stdout);
|
|
|
|
|
|
|
|
|
|
/* Store. */
|
|
|
|
|
if (modified)
|
|
|
|
|
{
|
g10: Cache the effective policy. Recompute it when required.
* g10/tofu.c (initdb): Add column effective_policy to the bindings
table.
(record_binding): New parameters effective_policy and set_conflict.
Save the effective policy. If SET_CONFLICT is set, then set conflict
according to CONFLICT. Otherwise, preserve the current value of
conflict. Update callers.
(get_trust): Don't compute the effective policy here...
(get_policy): ... do it here, if it was not cached. Take new
parameters, PK, the public key, and NOW, the time that the operation
started. Update callers.
(show_statistics): New parameter PK. Pass it to get_policy. Update
callers.
(tofu_notice_key_changed): New function.
* g10/gpgv.c (tofu_notice_key_changed): New stub.
* g10/import.c (import_revoke_cert): Take additional argument CTRL.
Pass it to keydb_update_keyblock.
* g10/keydb.c (keydb_update_keyblock): Take additional argument CTRL.
Update callers.
[USE_TOFU]: Call tofu_notice_key_changed.
* g10/test-stubs.c (tofu_notice_key_changed): New stub.
* tests/openpgp/tofu.scm: Assume that manually setting a binding's
policy to auto does not cause the tofu engine to forget about any
conflict.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
We now store the computed policy in the tofu DB (in the
effective_policy column of the bindings table) to avoid computing it
every time, which is expensive. Further, policy is never overridden
in case of a conflict. Instead, we detect a conflict if CONFLICT is
not empty.
This change is backwards compatible to existing DBs. The only minor
incompatibility is that unresolved conflicts won't be automatically
resolved in case we import a direct signature, or cross signatures.
2016-11-21 22:47:30 +01:00
|
|
|
|
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
|
2016-06-02 15:54:48 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
log_info (_("Key not changed so no update needed.\n"));
|
|
|
|
|
|
|
|
|
|
leave:
|
2024-01-05 11:33:51 +01:00
|
|
|
|
if (err)
|
|
|
|
|
write_status_error ("keyedit.addkey", err);
|
2016-06-02 15:54:48 +02:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-03-21 16:30:18 +01:00
|
|
|
|
/* Unattended ADSK setup function.
|
|
|
|
|
*
|
|
|
|
|
* FPR is the fingerprint of our key. ADSKFPR is the fingerprint of
|
|
|
|
|
* another subkey which we want to add as ADSK to our key.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t keyblock;
|
|
|
|
|
KEYDB_HANDLE kdbhd;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
|
|
|
|
|
#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 adsk
|
|
|
|
|
* adding. */
|
2024-01-05 11:33:51 +01:00
|
|
|
|
if ((err = find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)))
|
2023-03-21 16:30:18 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
if (fix_keyblock (ctrl, &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");
|
2024-01-05 11:33:51 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Locate and add the ADSK. Note that the called function already
|
|
|
|
|
* prints error messages. */
|
2024-06-05 17:04:33 +02:00
|
|
|
|
if (adskfpr && !ascii_strcasecmp (adskfpr, "default"))
|
|
|
|
|
{
|
|
|
|
|
err = append_all_default_adsks (ctrl, keyblock);
|
|
|
|
|
if (!err)
|
|
|
|
|
modified = 1;
|
|
|
|
|
else if (gpg_err_code (err) == GPG_ERR_FALSE)
|
|
|
|
|
err = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (menu_addadsk (ctrl, keyblock, adskfpr))
|
2023-03-21 16:30:18 +01:00
|
|
|
|
modified = 1;
|
|
|
|
|
else
|
|
|
|
|
log_inc_errorcount (); /* (We use log_info in menu_adsk) */
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
2024-01-05 11:33:51 +01:00
|
|
|
|
if (err)
|
|
|
|
|
write_status_error ("keyedit.addadsk", err);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keydb_release (kdbhd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-21 14:12:55 +02:00
|
|
|
|
/* 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
|
2024-01-23 14:19:40 +01:00
|
|
|
|
* may also be an array with only the item "*" to indicate that all
|
2017-07-21 14:12:55 +02:00
|
|
|
|
* keys shall be set to that expiration date.
|
2016-12-05 10:58:39 +01:00
|
|
|
|
*/
|
|
|
|
|
void
|
2017-07-21 14:12:55 +02:00
|
|
|
|
keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr,
|
|
|
|
|
char **subkeyfprs)
|
2016-12-05 10:58:39 +01:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2017-07-21 14:12:55 +02:00
|
|
|
|
kbnode_t keyblock, node;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
KEYDB_HANDLE kdbhd;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
u32 expire;
|
2017-07-21 14:12:55 +02:00
|
|
|
|
int primary_only = 0;
|
|
|
|
|
int idx;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (fix_keyblock (ctrl, &keyblock))
|
2016-12-05 10:58:39 +01:00
|
|
|
|
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 ();
|
|
|
|
|
|
2017-07-21 14:12:55 +02:00
|
|
|
|
/* 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)
|
2019-03-14 14:55:06 +01:00
|
|
|
|
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
|
2017-07-21 14:12:55 +02:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-05 10:58:39 +01:00
|
|
|
|
/* Set the new expiration date. */
|
2017-07-21 14:12:55 +02:00
|
|
|
|
err = menu_expire (ctrl, keyblock, primary_only? 1 : 2, expire);
|
2016-12-05 10:58:39 +01:00
|
|
|
|
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)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2016-12-05 10:58:39 +01:00
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_print_notations (int indent, PKT_signature * sig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int first = 1;
|
|
|
|
|
struct notation *notation, *nd;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (indent < 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
first = 0;
|
|
|
|
|
indent = -indent;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
notation = sig_to_notation (sig);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (nd = notation; nd; nd = nd->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!first)
|
|
|
|
|
tty_printf ("%*s", indent, "");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
first = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_print_utf8_string (nd->name, strlen (nd->name));
|
|
|
|
|
tty_printf ("=");
|
|
|
|
|
tty_print_utf8_string (nd->value, strlen (nd->value));
|
|
|
|
|
tty_printf ("\n");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_notation (notation);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Show preferences of a public keyblock.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!uid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (verbose)
|
|
|
|
|
{
|
2022-11-04 12:44:09 +01:00
|
|
|
|
show_preferences (uid, 4, -1, 1);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
{
|
|
|
|
|
const byte *pref_ks;
|
|
|
|
|
size_t pref_ks_len;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2019-09-05 20:36:38 +02:00
|
|
|
|
pref_ks = parse_sig_subpkt (selfsig, 1,
|
|
|
|
|
SIGSUBPKT_PREF_KS, &pref_ks_len);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pref_ks && pref_ks_len)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("Preferred keyserver: "));
|
|
|
|
|
tty_print_utf8_string (pref_ks, pref_ks_len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig->flags.notation)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("Notations: "));
|
|
|
|
|
tty_print_notations (5 + strlen (_("Notations: ")), selfsig);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2022-11-04 12:44:09 +01:00
|
|
|
|
show_preferences (uid, 4, -1, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* This is the version of show_key_with_all_names used when
|
|
|
|
|
opt.with_colons is used. It prints all available data in a easy to
|
|
|
|
|
parse format and does not translate utf8 */
|
|
|
|
|
static void
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int i, j, ulti_hack = 0;
|
|
|
|
|
byte pk_version = 0;
|
|
|
|
|
PKT_public_key *primary = NULL;
|
2015-07-28 18:21:47 +02:00
|
|
|
|
int have_seckey;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
if (!fp)
|
|
|
|
|
fp = es_stdout;
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* the keys */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|| (node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = node->pkt->pkt.public_key;
|
|
|
|
|
u32 keyid[2];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
pk_version = pk->version;
|
|
|
|
|
primary = pk;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (pk, keyid);
|
2020-01-17 07:11:02 +01:00
|
|
|
|
have_seckey = agent_probe_secret_key (ctrl, pk);
|
2015-07-28 18:21:47 +02:00
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
es_fputs (have_seckey? "sec:" : "pub:", fp);
|
|
|
|
|
else
|
|
|
|
|
es_fputs (have_seckey? "ssb:" : "sub:", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (!pk->flags.valid)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('i', fp);
|
2010-10-20 13:33:50 +02:00
|
|
|
|
else if (pk->flags.revoked)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('r', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (pk->has_expired)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('e', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2016-11-23 12:29:22 +01:00
|
|
|
|
int trust = get_validity_info (ctrl, keyblock, pk, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (trust == 'u')
|
|
|
|
|
ulti_hack = 1;
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (trust, fp);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fprintf (fp, ":%u:%d:%08lX%08lX:%lu:%lu::",
|
|
|
|
|
nbits_from_pk (pk),
|
|
|
|
|
pk->pubkey_algo,
|
|
|
|
|
(ulong) keyid[0], (ulong) keyid[1],
|
|
|
|
|
(ulong) pk->timestamp, (ulong) pk->expiredate);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
&& !(opt.fast_list_mode || opt.no_expensive_trust_checks))
|
2017-03-31 20:03:52 +02:00
|
|
|
|
es_putc (get_ownertrust_info (ctrl, pk, 0), fp);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (':', fp);
|
|
|
|
|
es_putc (':', fp);
|
|
|
|
|
es_putc (':', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Print capabilities. */
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('e', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_SIG))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('s', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_CERT))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('c', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('a', fp);
|
2022-09-07 10:34:05 +02:00
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_RENC))
|
|
|
|
|
es_putc ('r', fp);
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_TIME))
|
|
|
|
|
es_putc ('t', fp);
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_GROUP))
|
|
|
|
|
es_putc ('g', fp);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('\n', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, fp, pk, 0);
|
2024-06-05 09:10:47 +02:00
|
|
|
|
print_revokers (fp, 1, pk);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* the user ids */
|
|
|
|
|
i = 0;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
++i;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uid->attrib_data)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs ("uat:", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs ("uid:", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.revoked)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs ("r::::::::", fp);
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uid->flags.expired)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs ("e::::::::", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (opt.fast_list_mode || opt.no_expensive_trust_checks)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs ("::::::::", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int uid_validity;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (primary && !ulti_hack)
|
2016-11-23 12:29:22 +01:00
|
|
|
|
uid_validity = get_validity_info (ctrl, keyblock, primary, uid);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
uid_validity = 'u';
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fprintf (fp, "%c::::::::", uid_validity);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (uid->attrib_data)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fprintf (fp, "%u %lu", uid->numattribs, uid->attrib_len);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_write_sanitized (fp, uid->name, uid->len, ":", NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (':', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* signature class */
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (':', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* capabilities */
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (':', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* preferences */
|
|
|
|
|
if (pk_version > 3 || uid->selfsigversion > 3)
|
|
|
|
|
{
|
|
|
|
|
const prefitem_t *prefs = uid->prefs;
|
|
|
|
|
|
|
|
|
|
for (j = 0; prefs && prefs[j].type; j++)
|
|
|
|
|
{
|
|
|
|
|
if (j)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (' ', fp);
|
|
|
|
|
es_fprintf (fp,
|
|
|
|
|
"%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' :
|
|
|
|
|
prefs[j].type == PREFTYPE_HASH ? 'H' :
|
|
|
|
|
prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?',
|
|
|
|
|
prefs[j].value);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
if (uid->flags.mdc)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs (",mdc", fp);
|
2018-01-10 11:42:38 +01:00
|
|
|
|
if (uid->flags.aead)
|
|
|
|
|
es_fputs (",aead", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!uid->flags.ks_modify)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fputs (",no-ks-modify", fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc (':', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* flags */
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_fprintf (fp, "%d,", i);
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.primary)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('p', fp);
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.revoked)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('r', fp);
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.expired)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('e', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((node->flag & NODFLG_SELUID))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('s', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((node->flag & NODFLG_MARK_A))
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('m', fp);
|
|
|
|
|
es_putc (':', fp);
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
|
|
|
|
|
{
|
2015-10-20 17:32:23 +02:00
|
|
|
|
#ifdef USE_TOFU
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
enum tofu_policy policy;
|
2016-05-21 12:26:44 +02:00
|
|
|
|
if (! tofu_get_policy (ctrl, primary, uid, &policy)
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
&& policy != TOFU_POLICY_NONE)
|
|
|
|
|
es_fprintf (fp, "%s", tofu_policy_str (policy));
|
2015-10-20 17:32:23 +02:00
|
|
|
|
#endif /*USE_TOFU*/
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
}
|
|
|
|
|
es_putc (':', fp);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
es_putc ('\n', fp);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
2016-05-21 11:41:49 +02:00
|
|
|
|
show_names (ctrl_t ctrl, estream_t fp,
|
|
|
|
|
kbnode_t keyblock, PKT_public_key * pk, unsigned int flag,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int with_prefs)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int i = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID && !is_deleted_kbnode (node))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
++i;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!flag || (flag && (node->flag & flag)))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!(flag & NODFLG_MARK_A) && pk)
|
2016-05-21 11:41:49 +02:00
|
|
|
|
tty_fprintf (fp, "%s ", uid_trust_string_fixed (ctrl, pk, uid));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (flag & NODFLG_MARK_A)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, " ");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->flag & NODFLG_SELUID)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "(%d)* ", i);
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uid->flags.primary)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "(%d). ", i);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "(%d) ", i);
|
|
|
|
|
tty_print_utf8_string2 (fp, uid->name, uid->len, 0);
|
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (with_prefs && pk)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pk->version > 3 || uid->selfsigversion > 3)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *selfsig = NULL;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
KBNODE signode;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (signode = node->next;
|
|
|
|
|
signode && signode->pkt->pkttype == PKT_SIGNATURE;
|
|
|
|
|
signode = signode->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (signode->pkt->pkt.signature->
|
|
|
|
|
flags.chosen_selfsig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
selfsig = signode->pkt->pkt.signature;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
show_prefs (uid, selfsig, with_prefs == 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("There are no preferences on a"
|
|
|
|
|
" PGP 2.x-style user ID.\n"));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2014-03-27 12:59:55 +01:00
|
|
|
|
* Display the key a the user ids, if only_marked is true, do only so
|
|
|
|
|
* for user ids with mark A flag set and do not display the index
|
|
|
|
|
* number. If FP is not NULL print to the given stream and not to the
|
|
|
|
|
* tty (ignored in with-colons mode).
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names (ctrl_t ctrl, estream_t fp,
|
2014-03-27 12:59:55 +01:00
|
|
|
|
KBNODE keyblock, int only_marked, int with_revoker,
|
2014-03-27 16:33:40 +01:00
|
|
|
|
int with_fpr, int with_subkeys, int with_prefs,
|
|
|
|
|
int nowarn)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2015-07-28 18:21:47 +02:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int i;
|
|
|
|
|
int do_warn = 0;
|
2015-07-28 18:21:47 +02:00
|
|
|
|
int have_seckey = 0;
|
|
|
|
|
char *serialno = NULL;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *primary = NULL;
|
2014-02-05 10:37:59 +01:00
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.with_colons)
|
|
|
|
|
{
|
2015-07-28 18:21:47 +02:00
|
|
|
|
show_key_with_all_names_colon (ctrl, fp, keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* the keys */
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& !is_deleted_kbnode (node)))
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = node->pkt->pkt.public_key;
|
2014-03-27 12:59:55 +01:00
|
|
|
|
const char *otrust = "err";
|
|
|
|
|
const char *trust = "err";
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
/* do it here, so that debug messages don't clutter the
|
|
|
|
|
* output */
|
|
|
|
|
static int did_warn = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2016-05-21 11:41:49 +02:00
|
|
|
|
trust = get_validity_string (ctrl, pk, NULL);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
otrust = get_ownertrust_string (ctrl, pk, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* Show a warning once */
|
|
|
|
|
if (!did_warn
|
2016-11-23 12:29:22 +01:00
|
|
|
|
&& (get_validity (ctrl, keyblock, pk, NULL, NULL, 0)
|
g10: Add TOFU support.
* configure.ac: Check for sqlite3.
(SQLITE3_CFLAGS): AC_SUBST it.
(SQLITE3_LIBS): Likewise.
* g10/Makefile.am (AM_CFLAGS): Add $(SQLITE3_CFLAGS).
(gpg2_SOURCES): Add tofu.h and tofu.c.
(gpg2_LDADD): Add $(SQLITE3_LIBS).
* g10/tofu.c: New file.
* g10/tofu.h: New file.
* g10/options.h (trust_model): Define TM_TOFU and TM_TOFU_PGP.
(tofu_db_format): Define.
* g10/packet.h (PKT_signature): Add fields digest and digest_len.
* g10/gpg.c: Include "tofu.h".
(cmd_and_opt_values): Declare aTOFUPolicy, oTOFUDefaultPolicy,
oTOFUDBFormat.
(opts): Add them.
(parse_trust_model): Recognize the tofu and tofu+pgp trust models.
(parse_tofu_policy): New function.
(parse_tofu_db_format): New function.
(main): Initialize opt.tofu_default_policy and opt.tofu_db_format.
Handle aTOFUPolicy, oTOFUDefaultPolicy and oTOFUDBFormat.
* g10/mainproc.c (do_check_sig): If the signature is good, copy the
hash to SIG->DIGEST and set SIG->DIGEST_LEN appropriately.
* g10/trustdb.h (get_validity): Add arguments sig and may_ask. Update
callers.
(tdb_get_validity_core): Add arguments sig and may_ask. Update
callers.
* g10/trust.c (get_validity) Add arguments sig and may_ask. Pass them
to tdb_get_validity_core.
* g10/trustdb.c: Include "tofu.h".
(trust_model_string): Handle TM_TOFU and TM_TOFU_PGP.
(tdb_get_validity_core): Add arguments sig and may_ask. If
OPT.TRUST_MODEL is TM_TOFU or TM_TOFU_PGP, compute the TOFU trust
level. Combine it with the computed PGP trust level, if appropriate.
* g10/keyedit.c: Include "tofu.h".
(show_key_with_all_names_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/keylist.c: Include "tofu.h".
(public_key_list): Also show the PGP stats if the trust model is
TM_TOFU_PGP.
(list_keyblock_colon): If the trust mode is tofu or
tofu+pgp, then show the trust policy.
* g10/pkclist.c: Include "tofu.h".
* g10/gpgv.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* g10/test-stubs.c (get_validity): Add arguments sig and may_ask.
(enum tofu_policy): Define.
(tofu_get_policy): New stub.
(tofu_policy_str): Likewise.
* doc/DETAILS: Describe the TOFU Policy field.
* doc/gpg.texi: Document --tofu-set-policy, --trust-model=tofu,
--trust-model=tofu+pgp, --tofu-default-policy and --tofu-db-format.
* tests/openpgp/Makefile.am (TESTS): Add tofu.test.
(TEST_FILES): Add tofu-keys.asc, tofu-keys-secret.asc,
tofu-2183839A-1.txt, tofu-BC15C85A-1.txt and tofu-EE37CF96-1.txt.
(CLEANFILES): Add tofu.db.
(clean-local): Add tofu.d.
* tests/openpgp/tofu.test: New file.
* tests/openpgp/tofu-2183839A-1.txt: New file.
* tests/openpgp/tofu-BC15C85A-1.txt: New file.
* tests/openpgp/tofu-EE37CF96-1.txt: New file.
* tests/openpgp/tofu-keys.asc: New file.
* tests/openpgp/tofu-keys-secret.asc: New file.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>.
2015-10-18 18:44:05 +02:00
|
|
|
|
& TRUST_FLAG_PENDING_CHECK))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
did_warn = 1;
|
|
|
|
|
do_warn = 1;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
primary = pk;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (pk->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
char *user = get_user_id_string_native (ctrl, pk->revoked.keyid);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("The following key was revoked on"
|
2010-10-01 22:33:53 +02:00
|
|
|
|
" %s by %s key %s\n"),
|
|
|
|
|
revokestr_from_pk (pk),
|
|
|
|
|
gcry_pk_algo_name (pk->revoked.algo), user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (with_revoker)
|
|
|
|
|
{
|
|
|
|
|
if (!pk->revkey && pk->numrevkeys)
|
|
|
|
|
BUG ();
|
|
|
|
|
else
|
|
|
|
|
for (i = 0; i < pk->numrevkeys; i++)
|
|
|
|
|
{
|
|
|
|
|
u32 r_keyid[2];
|
|
|
|
|
char *user;
|
|
|
|
|
const char *algo;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
algo = gcry_pk_algo_name (pk->revkey[i].algid);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
keyid_from_fingerprint (ctrl, pk->revkey[i].fpr,
|
2018-12-04 15:43:19 +01:00
|
|
|
|
pk->revkey[i].fprlen, r_keyid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
user = get_user_id_string_native (ctrl, r_keyid);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp,
|
|
|
|
|
_("This key may be revoked by %s key %s"),
|
|
|
|
|
algo ? algo : "?", user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pk->revkey[i].class & 0x40)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, " ");
|
|
|
|
|
tty_fprintf (fp, _("(sensitive)"));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (pk, NULL);
|
2015-07-28 18:21:47 +02:00
|
|
|
|
|
|
|
|
|
xfree (serialno);
|
|
|
|
|
serialno = NULL;
|
|
|
|
|
{
|
|
|
|
|
char *hexgrip;
|
|
|
|
|
|
|
|
|
|
err = hexkeygrip_from_pk (pk, &hexgrip);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("error computing a keygrip: %s\n",
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
have_seckey = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-06-10 22:15:33 +02:00
|
|
|
|
have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
|
2015-07-28 18:21:47 +02:00
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tty_fprintf
|
|
|
|
|
(fp, "%s%c %s/%s",
|
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_KEY && have_seckey? "sec" :
|
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" :
|
|
|
|
|
have_seckey ? "ssb" :
|
|
|
|
|
"sub",
|
|
|
|
|
(node->flag & NODFLG_SELKEY) ? '*' : ' ',
|
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr (pk->keyid));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-02-05 10:37:59 +01:00
|
|
|
|
if (opt.legacy_list_mode)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, " ");
|
2014-02-05 10:37:59 +01:00
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "\n ");
|
2014-02-05 10:37:59 +01:00
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk));
|
|
|
|
|
tty_fprintf (fp, " ");
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (pk->flags.revoked)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (pk->has_expired)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk));
|
|
|
|
|
tty_fprintf (fp, " ");
|
2014-08-12 10:36:30 +02:00
|
|
|
|
tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk, 1));
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2015-07-28 18:21:47 +02:00
|
|
|
|
if (serialno)
|
|
|
|
|
{
|
|
|
|
|
/* The agent told us that a secret key is available and
|
|
|
|
|
that it has been stored on a card. */
|
|
|
|
|
tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "",
|
|
|
|
|
_("card-no: "));
|
|
|
|
|
if (strlen (serialno) == 32
|
|
|
|
|
&& !strncmp (serialno, "D27600012401", 12))
|
|
|
|
|
{
|
|
|
|
|
/* This is an OpenPGP card. Print the relevant part. */
|
|
|
|
|
/* Example: D2760001240101010001000003470000 */
|
|
|
|
|
/* xxxxyyyyyyyy */
|
|
|
|
|
tty_fprintf (fp, "%.*s %.*s\n",
|
|
|
|
|
4, serialno+16, 8, serialno+20);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
tty_fprintf (fp, "%s\n", serialno);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if (pk->seckey_info
|
2010-09-06 21:57:42 +02:00
|
|
|
|
&& pk->seckey_info->is_protected
|
|
|
|
|
&& pk->seckey_info->s2k.mode == 1002)
|
|
|
|
|
{
|
2017-04-28 03:06:33 +02:00
|
|
|
|
/* FIXME: Check whether this code path is still used. */
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "",
|
|
|
|
|
_("card-no: "));
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if (pk->seckey_info->ivlen == 16
|
|
|
|
|
&& !memcmp (pk->seckey_info->iv,
|
|
|
|
|
"\xD2\x76\x00\x01\x24\x01", 6))
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
|
/* This is an OpenPGP card. */
|
|
|
|
|
for (i = 8; i < 14; i++)
|
|
|
|
|
{
|
|
|
|
|
if (i == 10)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, " ");
|
|
|
|
|
tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]);
|
2010-09-06 21:57:42 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
|
/* Unknown card: Print all. */
|
|
|
|
|
for (i = 0; i < pk->seckey_info->ivlen; i++)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]);
|
2010-09-06 21:57:42 +02:00
|
|
|
|
}
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-09-06 21:57:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_KEY)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
if (opt.trust_model != TM_ALWAYS)
|
|
|
|
|
{
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "%*s",
|
|
|
|
|
opt.legacy_list_mode?
|
|
|
|
|
((int) keystrlen () + 13):5, "");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Ownertrust is only meaningful for the PGP or
|
2015-12-14 09:31:08 +01:00
|
|
|
|
classic trust models, or PGP combined with TOFU */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.trust_model == TM_PGP
|
2015-12-14 09:31:08 +01:00
|
|
|
|
|| opt.trust_model == TM_CLASSIC
|
|
|
|
|
|| opt.trust_model == TM_TOFU_PGP)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
int width = 14 - strlen (otrust);
|
|
|
|
|
if (width <= 0)
|
|
|
|
|
width = 1;
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("trust: %s"), otrust);
|
|
|
|
|
tty_fprintf (fp, "%*s", width, "");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("validity: %s"), trust);
|
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
2017-03-31 20:03:52 +02:00
|
|
|
|
&& (get_ownertrust (ctrl, pk) & TRUST_FLAG_DISABLED))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "*** ");
|
|
|
|
|
tty_fprintf (fp, _("This key has been disabled"));
|
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if ((node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_KEY) && with_fpr)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, fp, pk, 2);
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, "\n");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-21 11:41:49 +02:00
|
|
|
|
show_names (ctrl, fp,
|
2014-03-27 12:59:55 +01:00
|
|
|
|
keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-03-27 16:33:40 +01:00
|
|
|
|
if (do_warn && !nowarn)
|
2014-03-27 12:59:55 +01:00
|
|
|
|
tty_fprintf (fp, _("Please note that the shown key validity"
|
|
|
|
|
" is not necessarily correct\n"
|
|
|
|
|
"unless you restart the program.\n"));
|
2015-07-28 18:21:47 +02:00
|
|
|
|
|
|
|
|
|
xfree (serialno);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Display basic key information. This function is suitable to show
|
2019-03-15 19:11:32 +01:00
|
|
|
|
* information on the key without any dependencies on the trustdb or
|
|
|
|
|
* any other internal GnuPG stuff. KEYBLOCK may either be a public or
|
|
|
|
|
* a secret key. This function may be called with KEYBLOCK containing
|
|
|
|
|
* secret keys and thus the printing of "pub" vs. "sec" does only
|
|
|
|
|
* depend on the packet type and not by checking with gpg-agent. If
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 15:34:42 +01:00
|
|
|
|
* PRINT_SEC is set "sec" is printed instead of "pub". */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
void
|
2019-03-15 19:11:32 +01:00
|
|
|
|
show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
2014-02-05 10:37:59 +01:00
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* The primary key */
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_KEY)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = node->pkt->pkt.public_key;
|
2019-03-15 19:11:32 +01:00
|
|
|
|
const char *tag;
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype == PKT_SECRET_KEY || print_sec)
|
|
|
|
|
tag = "sec";
|
|
|
|
|
else
|
|
|
|
|
tag = "pub";
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* Note, we use the same format string as in other show
|
|
|
|
|
functions to make the translation job easier. */
|
2014-02-05 10:37:59 +01:00
|
|
|
|
tty_printf ("%s %s/%s ",
|
2019-03-15 19:11:32 +01:00
|
|
|
|
tag,
|
2014-02-05 10:37:59 +01:00
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr_from_pk (pk));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("created: %s"), datestr_from_pk (pk));
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("expires: %s"), expirestr_from_pk (pk));
|
|
|
|
|
tty_printf ("\n");
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, NULL, pk, 3);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The user IDs. */
|
2022-09-14 04:48:42 +02:00
|
|
|
|
(void)i; /* Counting User IDs */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0, node = keyblock; node; node = node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
++i;
|
|
|
|
|
|
|
|
|
|
tty_printf (" ");
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("[%s] ", _("revoked"));
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uid->flags.expired)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("[%s] ", _("expired"));
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-06 18:00:12 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static void
|
2017-03-31 20:03:52 +02:00
|
|
|
|
show_key_and_fingerprint (ctrl_t ctrl, kbnode_t keyblock, int with_subkeys)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2015-08-06 18:00:12 +02:00
|
|
|
|
kbnode_t node;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
PKT_public_key *pk = NULL;
|
2014-02-05 10:37:59 +01:00
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
2014-02-05 10:37:59 +01:00
|
|
|
|
tty_printf ("pub %s/%s %s ",
|
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr_from_pk(pk),
|
|
|
|
|
datestr_from_pk (pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
if (pk)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, NULL, pk, 2);
|
2015-08-06 18:00:12 +02:00
|
|
|
|
if (with_subkeys)
|
|
|
|
|
{
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
tty_printf ("sub %s/%s %s [%s]\n",
|
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr_from_pk(pk),
|
|
|
|
|
datestr_from_pk (pk),
|
|
|
|
|
usagestr_from_pk (pk, 0));
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, NULL, pk, 4);
|
2015-08-06 18:00:12 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Show a listing of the primary and its subkeys along with their
|
|
|
|
|
keygrips. */
|
|
|
|
|
static void
|
|
|
|
|
show_key_and_grip (kbnode_t keyblock)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
|
|
|
|
char *hexgrip;
|
|
|
|
|
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
tty_printf ("%s %s/%s %s [%s]\n",
|
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
|
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr_from_pk(pk),
|
|
|
|
|
datestr_from_pk (pk),
|
|
|
|
|
usagestr_from_pk (pk, 0));
|
|
|
|
|
|
|
|
|
|
if (!hexkeygrip_from_pk (pk, &hexgrip))
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" Keygrip: %s\n", hexgrip);
|
|
|
|
|
xfree (hexgrip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Show a warning if no uids on the key have the primary uid flag
|
|
|
|
|
set. */
|
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
no_primary_warning (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int have_primary = 0, uid_count = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* TODO: if we ever start behaving differently with a primary or
|
|
|
|
|
non-primary attribute ID, we will need to check for attributes
|
|
|
|
|
here as well. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& node->pkt->pkt.user_id->attrib_data == NULL)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
uid_count++;
|
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (node->pkt->pkt.user_id->flags.primary == 2)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
have_primary = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uid_count > 1 && !have_primary)
|
|
|
|
|
log_info (_
|
|
|
|
|
("WARNING: no user ID has been marked as primary. This command"
|
2006-04-19 13:26:11 +02:00
|
|
|
|
" may\n cause a different user ID to become"
|
|
|
|
|
" the assumed primary.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2014-09-17 16:27:37 +02:00
|
|
|
|
/* Print a warning if the latest encryption subkey expires soon. This
|
|
|
|
|
function is called after the expire data of the primary key has
|
|
|
|
|
been changed. */
|
|
|
|
|
static void
|
|
|
|
|
subkey_expire_warning (kbnode_t keyblock)
|
|
|
|
|
{
|
|
|
|
|
u32 curtime = make_timestamp ();
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
/* u32 mainexpire = 0; */
|
|
|
|
|
u32 subexpire = 0;
|
|
|
|
|
u32 latest_date = 0;
|
|
|
|
|
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
/* if (node->pkt->pkttype == PKT_PUBLIC_KEY) */
|
|
|
|
|
/* { */
|
|
|
|
|
/* pk = node->pkt->pkt.public_key; */
|
|
|
|
|
/* mainexpire = pk->expiredate; */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
|
|
|
|
|
continue;
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
if (!pk->flags.valid)
|
|
|
|
|
continue;
|
|
|
|
|
if (pk->flags.revoked)
|
|
|
|
|
continue;
|
|
|
|
|
if (pk->timestamp > curtime)
|
|
|
|
|
continue; /* Ignore future keys. */
|
|
|
|
|
if (!(pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
|
|
|
continue; /* Not an encryption key. */
|
|
|
|
|
|
|
|
|
|
if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date))
|
|
|
|
|
{
|
|
|
|
|
latest_date = pk->timestamp;
|
|
|
|
|
subexpire = pk->expiredate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subexpire)
|
|
|
|
|
return; /* No valid subkey with an expiration time. */
|
|
|
|
|
|
|
|
|
|
if (curtime + (10*86400) > subexpire)
|
|
|
|
|
{
|
|
|
|
|
log_info (_("WARNING: Your encryption subkey expires soon.\n"));
|
|
|
|
|
log_info (_("You may want to change its expiration date too.\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-05-08 13:10:47 +02:00
|
|
|
|
/* Print a warning if all encryption (sub|primary)keys are expired.
|
|
|
|
|
* The warning is not printed if there is no encryption
|
|
|
|
|
* (sub|primary)key at all. This function is called after the expire
|
|
|
|
|
* data of the primary key has been changed. */
|
|
|
|
|
void
|
|
|
|
|
no_usable_encr_subkeys_warning (kbnode_t keyblock)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
int any_encr_key = 0;
|
|
|
|
|
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
|
|
|
{
|
|
|
|
|
any_encr_key = 1;
|
|
|
|
|
if (pk->flags.valid && !pk->has_expired && !pk->flags.revoked
|
|
|
|
|
&& !pk->flags.disabled)
|
|
|
|
|
{
|
|
|
|
|
return; /* Key is usable for encryption */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (any_encr_key && !opt.quiet)
|
|
|
|
|
log_info (_("WARNING: No valid encryption subkey left over.\n"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2015-05-08 16:08:57 +02:00
|
|
|
|
* Ask for a new user id, add the self-signature, and update the
|
|
|
|
|
* keyblock. If UIDSTRING is not NULL the user ID is generated
|
|
|
|
|
* unattended using that string. UIDSTRING is expected to be utf-8
|
|
|
|
|
* encoded and white space trimmed. Returns true if there is a new
|
|
|
|
|
* user id.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2016-05-21 11:41:49 +02:00
|
|
|
|
menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock,
|
|
|
|
|
int photo, const char *photo_name, const char *uidstring)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
PKT_signature *sig = NULL;
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
KBNODE node;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
KBNODE pub_where = NULL;
|
|
|
|
|
gpg_error_t err;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2015-05-08 16:08:57 +02:00
|
|
|
|
if (photo && uidstring)
|
|
|
|
|
return 0; /* Not allowed. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; pub_where = node, node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (!node) /* No subkey. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pub_where = NULL;
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (pk);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (photo)
|
|
|
|
|
{
|
|
|
|
|
int hasattrib = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID &&
|
|
|
|
|
node->pkt->pkt.user_id->attrib_data != NULL)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
hasattrib = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* It is legal but bad for compatibility to add a photo ID to a
|
|
|
|
|
v3 key as it means that PGP2 will not be able to use that key
|
|
|
|
|
anymore. Also, PGP may not expect a photo on a v3 key.
|
|
|
|
|
Don't bother to ask this if the key already has a photo - any
|
|
|
|
|
damage has already been done at that point. -dms */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pk->version == 3 && !hasattrib)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("WARNING: This is a PGP2-style key. "
|
|
|
|
|
"Adding a photo ID may cause some versions\n"
|
|
|
|
|
" of PGP to reject this key.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!cpr_get_answer_is_yes ("keyedit.v3_photo.okay",
|
|
|
|
|
_("Are you sure you still want "
|
|
|
|
|
"to add it? (y/N) ")))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("You may not add a photo ID to "
|
|
|
|
|
"a PGP2-style key.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-21 11:41:49 +02:00
|
|
|
|
uid = generate_photo_id (ctrl, pk, photo_name);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-05-08 16:08:57 +02:00
|
|
|
|
uid = generate_user_id (pub_keyblock, uidstring);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!uid)
|
2015-05-08 16:08:57 +02:00
|
|
|
|
{
|
|
|
|
|
if (uidstring)
|
2016-09-14 10:59:18 +02:00
|
|
|
|
{
|
|
|
|
|
write_status_error ("adduid", gpg_error (304));
|
2022-04-22 09:57:38 +02:00
|
|
|
|
log_error ("%s\n", _("Such a user ID already exists on this key!"));
|
2016-09-14 10:59:18 +02:00
|
|
|
|
}
|
2015-05-08 16:08:57 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-05-13 12:38:32 +02:00
|
|
|
|
err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
keygen_add_std_prefs, pk, NULL);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (err)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", err);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("signing failed: %s\n", gpg_strerror (err));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_user_id (uid);
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Insert/append to public keyblock */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_USER_ID;
|
|
|
|
|
pkt->pkt.user_id = uid;
|
|
|
|
|
node = new_kbnode (pkt);
|
|
|
|
|
if (pub_where)
|
|
|
|
|
insert_kbnode (pub_where, node, 0);
|
|
|
|
|
else
|
|
|
|
|
add_kbnode (pub_keyblock, node);
|
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
2016-11-15 13:10:51 +01:00
|
|
|
|
pkt->pkt.signature = sig;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pub_where)
|
|
|
|
|
insert_kbnode (node, new_kbnode (pkt), 0);
|
|
|
|
|
else
|
|
|
|
|
add_kbnode (pub_keyblock, new_kbnode (pkt));
|
|
|
|
|
return 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/*
|
|
|
|
|
* Remove all selected userids from the keyring
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static void
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_deluid (KBNODE pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int selected = 0;
|
|
|
|
|
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
selected = node->flag & NODFLG_SELUID;
|
|
|
|
|
if (selected)
|
|
|
|
|
{
|
|
|
|
|
/* Only cause a trust update if we delete a
|
|
|
|
|
non-revoked user id */
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (!node->pkt->pkt.user_id->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
update_trust = 1;
|
|
|
|
|
delete_kbnode (node);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (selected && node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
selected = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
PKT_user_id *uid = NULL;
|
|
|
|
|
int changed = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
uid = (node->flag & NODFLG_SELUID) ? node->pkt->pkt.user_id : NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (uid && node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
int okay, valid, selfsig, inv_sig, no_key, other_err;
|
|
|
|
|
|
|
|
|
|
tty_printf ("uid ");
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
|
|
|
|
|
okay = inv_sig = no_key = other_err = 0;
|
|
|
|
|
if (opt.with_colons)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
valid = print_and_check_one_sig_colon (ctrl, pub_keyblock, node,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
&inv_sig, &no_key,
|
|
|
|
|
&other_err, &selfsig, 1);
|
|
|
|
|
else
|
2017-03-31 20:03:52 +02:00
|
|
|
|
valid = print_and_check_one_sig (ctrl, pub_keyblock, node,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
&inv_sig, &no_key, &other_err,
|
2015-10-01 16:22:29 +02:00
|
|
|
|
&selfsig, 1, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (valid)
|
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
okay = cpr_get_answer_yes_no_quit
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("keyedit.delsig.valid",
|
|
|
|
|
_("Delete this good signature? (y/N/q)"));
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Only update trust if we delete a good signature.
|
|
|
|
|
The other two cases do not affect trust. */
|
|
|
|
|
if (okay)
|
|
|
|
|
update_trust = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (inv_sig || other_err)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
okay = cpr_get_answer_yes_no_quit
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("keyedit.delsig.invalid",
|
|
|
|
|
_("Delete this invalid signature? (y/N/q)"));
|
|
|
|
|
else if (no_key)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
okay = cpr_get_answer_yes_no_quit
|
2010-04-20 20:19:19 +02:00
|
|
|
|
("keyedit.delsig.unknown",
|
|
|
|
|
_("Delete this unknown signature? (y/N/q)"));
|
|
|
|
|
|
|
|
|
|
if (okay == -1)
|
|
|
|
|
break;
|
|
|
|
|
if (okay && selfsig
|
|
|
|
|
&& !cpr_get_answer_is_yes
|
|
|
|
|
("keyedit.delsig.selfsig",
|
|
|
|
|
_("Really delete this self-signature? (y/N)")))
|
|
|
|
|
okay = 0;
|
|
|
|
|
if (okay)
|
|
|
|
|
{
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
changed++;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
uid = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (changed)
|
|
|
|
|
{
|
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2016-01-18 11:20:15 +01:00
|
|
|
|
tty_printf (ngettext("Deleted %d signature.\n",
|
|
|
|
|
"Deleted %d signatures.\n", changed), changed);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
tty_printf (_("Nothing deleted.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return changed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2024-03-04 14:22:42 +01:00
|
|
|
|
/* Note: OPTIONS are from the EXPORT_* set. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2024-03-04 14:22:42 +01:00
|
|
|
|
menu_clean (ctrl_t ctrl, kbnode_t keyblock, unsigned int options)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE uidnode;
|
2024-03-04 14:22:42 +01:00
|
|
|
|
int modified = 0;
|
|
|
|
|
int select_all = !count_selected_uids (keyblock);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (uidnode = keyblock->next;
|
|
|
|
|
uidnode && uidnode->pkt->pkttype != PKT_PUBLIC_SUBKEY;
|
|
|
|
|
uidnode = uidnode->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uidnode->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& (uidnode->flag & NODFLG_SELUID || select_all))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int uids = 0, sigs = 0;
|
|
|
|
|
char *user = utf8_to_native (uidnode->pkt->pkt.user_id->name,
|
|
|
|
|
uidnode->pkt->pkt.user_id->len,
|
|
|
|
|
0);
|
|
|
|
|
|
2024-03-04 14:22:42 +01:00
|
|
|
|
clean_one_uid (ctrl, keyblock, uidnode, opt.verbose, options,
|
|
|
|
|
&uids, &sigs);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uids)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
const char *reason;
|
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uidnode->pkt->pkt.user_id->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reason = _("revoked");
|
2017-03-08 11:01:22 +01:00
|
|
|
|
else if (uidnode->pkt->pkt.user_id->flags.expired)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reason = _("expired");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reason = _("invalid");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2006-12-06 11:16:50 +01:00
|
|
|
|
tty_printf (_("User ID \"%s\" compacted: %s\n"), user, reason);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (sigs)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2016-01-18 11:20:15 +01:00
|
|
|
|
tty_printf (ngettext("User ID \"%s\": %d signature removed\n",
|
|
|
|
|
"User ID \"%s\": %d signatures removed\n",
|
|
|
|
|
sigs), user, sigs);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2006-12-03 07:27:49 +01:00
|
|
|
|
{
|
2024-03-04 14:22:42 +01:00
|
|
|
|
tty_printf ((options & EXPORT_MINIMAL)?
|
2010-04-20 20:19:19 +02:00
|
|
|
|
_("User ID \"%s\": already minimized\n") :
|
|
|
|
|
_("User ID \"%s\": already clean\n"), user);
|
2006-12-03 07:27:49 +01:00
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return modified;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Remove some of the secondary keys
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_delkey (KBNODE pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int selected = 0;
|
|
|
|
|
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
selected = node->flag & NODFLG_SELKEY;
|
|
|
|
|
if (selected)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
delete_kbnode (node);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (selected && node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
else
|
|
|
|
|
selected = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* No need to set update_trust here since signing keys are no
|
|
|
|
|
longer used to certify other keys, so there is no change in
|
2010-04-21 18:26:17 +02:00
|
|
|
|
trust when revoking/removing them. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/*
|
|
|
|
|
* Ask for a new revoker, create the self-signature and put it into
|
|
|
|
|
* the keyblock. Returns true if there is a new revoker.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-10-01 22:33:53 +02:00
|
|
|
|
menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
PKT_public_key *revoker_pk = NULL;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *sig = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
PACKET *pkt;
|
|
|
|
|
struct revocation_key revkey;
|
|
|
|
|
size_t fprlen;
|
|
|
|
|
int rc;
|
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pk = pub_keyblock->pkt->pkt.public_key;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (pk->numrevkeys == 0 && pk->version == 3)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* It is legal but bad for compatibility to add a revoker to a
|
|
|
|
|
v3 key as it means that PGP2 will not be able to use that key
|
|
|
|
|
anymore. Also, PGP may not expect a revoker on a v3 key.
|
|
|
|
|
Don't bother to ask this if the key already has a revoker -
|
|
|
|
|
any damage has already been done at that point. -dms */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("WARNING: This is a PGP 2.x-style key. "
|
|
|
|
|
"Adding a designated revoker may cause\n"
|
|
|
|
|
" some versions of PGP to reject this key.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!cpr_get_answer_is_yes ("keyedit.v3_revoker.okay",
|
|
|
|
|
_("Are you sure you still want "
|
|
|
|
|
"to add it? (y/N) ")))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("You may not add a designated revoker to "
|
|
|
|
|
"a PGP 2.x-style key.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (;;)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
char *answer;
|
|
|
|
|
|
2011-09-20 19:24:52 +02:00
|
|
|
|
free_public_key (revoker_pk);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
revoker_pk = xmalloc_clear (sizeof (*revoker_pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
answer = cpr_get_utf8
|
2010-04-21 18:26:17 +02:00
|
|
|
|
("keyedit.add_revoker",
|
|
|
|
|
_("Enter the user ID of the designated revoker: "));
|
|
|
|
|
if (answer[0] == '\0' || answer[0] == CONTROL_D)
|
2003-09-23 19:48:33 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Note that I'm requesting CERT here, which usually implies
|
2010-04-20 20:19:19 +02:00
|
|
|
|
primary keys only, but some casual testing shows that PGP and
|
2010-04-21 18:26:17 +02:00
|
|
|
|
GnuPG both can handle a designated revocation from a subkey. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
revoker_pk->req_usage = PUBKEY_USAGE_CERT;
|
2019-07-04 10:42:48 +02:00
|
|
|
|
rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
|
|
|
|
|
NULL, revoker_pk, answer, NULL, NULL, 1);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error (_("key \"%s\" not found: %s\n"), answer,
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen);
|
2018-12-04 15:43:19 +01:00
|
|
|
|
if (fprlen != 20 && fprlen != 32)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error (_("cannot appoint a PGP 2.x style key as a "
|
|
|
|
|
"designated revoker\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-04 15:43:19 +01:00
|
|
|
|
revkey.fprlen = fprlen;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
revkey.class = 0x80;
|
|
|
|
|
if (sensitive)
|
|
|
|
|
revkey.class |= 0x40;
|
|
|
|
|
revkey.algid = revoker_pk->pubkey_algo;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (cmp_public_keys (revoker_pk, pk) == 0)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* This actually causes no harm (after all, a key that
|
|
|
|
|
designates itself as a revoker is the same as a
|
|
|
|
|
regular key), but it's easy enough to check. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error (_("you cannot appoint a key as its own "
|
|
|
|
|
"designated revoker\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (pk, NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Does this revkey already exist? */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!pk->revkey && pk->numrevkeys)
|
|
|
|
|
BUG ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0; i < pk->numrevkeys; i++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (memcmp (&pk->revkey[i], &revkey,
|
|
|
|
|
sizeof (struct revocation_key)) == 0)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
char buf[50];
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error (_("this key has already been designated "
|
|
|
|
|
"as a revoker\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-02-19 14:59:19 +01:00
|
|
|
|
format_keyid (pk_keyid (pk), KF_LONG, buf, sizeof (buf));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
write_status_text (STATUS_ALREADY_SIGNED, buf);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (i < pk->numrevkeys)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 12:54:47 +02:00
|
|
|
|
print_key_info (ctrl, NULL, 0, revoker_pk, 0);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_fingerprint (ctrl, NULL, revoker_pk, 2);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("WARNING: appointing a key as a designated revoker "
|
|
|
|
|
"cannot be undone!\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!cpr_get_answer_is_yes ("keyedit.add_revoker.okay",
|
|
|
|
|
_("Are you sure you want to appoint this "
|
|
|
|
|
"key as a designated revoker? (y/N) ")))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_public_key (revoker_pk);
|
|
|
|
|
revoker_pk = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:38:32 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
keygen_add_revkey, &revkey, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", rc);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("signing failed: %s\n", gpg_strerror (rc));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Insert into public keyblock. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
insert_kbnode (pub_keyblock, new_kbnode (pkt), PKT_SIGNATURE);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
fail:
|
|
|
|
|
if (sig)
|
|
|
|
|
free_seckey_enc (sig);
|
2011-09-20 19:24:52 +02:00
|
|
|
|
free_public_key (revoker_pk);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-06-03 18:52:06 +02:00
|
|
|
|
/* Core function to add an ADSK to the KEYBLOCK. Returns 0 on success
|
|
|
|
|
* or an error code. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
append_adsk_to_key (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *adsk)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
PKT_public_key *main_pk; /* The primary key. */
|
|
|
|
|
PKT_signature *sig = NULL;
|
|
|
|
|
kbnode_t adsknode = NULL;
|
|
|
|
|
PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
|
|
|
|
|
|
|
|
|
|
/* First get a copy. */
|
|
|
|
|
adsk = copy_public_key_basics (NULL, adsk);
|
|
|
|
|
|
|
|
|
|
/* Check compliance. */
|
|
|
|
|
if (!gnupg_pk_is_compliant (opt.compliance, adsk->pubkey_algo, 0,
|
|
|
|
|
adsk->pkey, nbits_from_pk (adsk), NULL))
|
|
|
|
|
{
|
|
|
|
|
char pkhex[MAX_FINGERPRINT_LEN*2+1];
|
|
|
|
|
|
|
|
|
|
hexfingerprint (adsk, pkhex, sizeof pkhex);
|
|
|
|
|
log_error (_("WARNING: key %s is not suitable for encryption"
|
|
|
|
|
" in %s mode\n"),
|
|
|
|
|
pkhex, gnupg_compliance_option_string (opt.compliance));
|
|
|
|
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the primary key. */
|
|
|
|
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
main_pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
/* Prepare and append the adsk. */
|
|
|
|
|
keyid_from_pk (main_pk, adsk->main_keyid); /* Fixup main keyid. */
|
|
|
|
|
log_assert ((adsk->pubkey_usage & PUBKEY_USAGE_ENC));
|
|
|
|
|
adsk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
|
|
|
|
|
pkt = xtrycalloc (1, sizeof *pkt);
|
|
|
|
|
if (!pkt)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
|
|
|
|
|
pkt->pkt.public_key = adsk;
|
|
|
|
|
adsknode = new_kbnode (pkt);
|
|
|
|
|
|
|
|
|
|
/* Make the signature. */
|
|
|
|
|
err = make_keysig_packet (ctrl, &sig, main_pk, NULL, adsk, main_pk, 0x18,
|
|
|
|
|
adsk->timestamp, 0,
|
|
|
|
|
keygen_add_key_flags_and_expire, adsk, NULL);
|
|
|
|
|
adsk = NULL; /* (owned by adsknode - avoid double free.) */
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
write_status_error ("keysig", err);
|
|
|
|
|
log_error ("creating key binding failed: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Append the subkey packet and the binding signature. */
|
|
|
|
|
add_kbnode (keyblock, adsknode);
|
|
|
|
|
adsknode = NULL;
|
|
|
|
|
pkt = xtrycalloc (1, sizeof *pkt);
|
|
|
|
|
if (!pkt)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
|
add_kbnode (keyblock, new_kbnode (pkt));
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
release_kbnode (adsknode);
|
|
|
|
|
free_public_key (adsk); /* Release our copy. */
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-03-01 17:22:20 +01:00
|
|
|
|
/*
|
|
|
|
|
* Ask for a new additional decryption subkey and add it to the key
|
2023-03-21 16:30:18 +01:00
|
|
|
|
* block. Returns true if the keyblock was changed and false
|
2023-11-08 16:08:25 +01:00
|
|
|
|
* otherwise. If ADSKFPR is not NULL, this function has been called
|
2023-03-21 16:30:18 +01:00
|
|
|
|
* by quick_addadsk and gives the fingerprint of the to be added key.
|
2023-03-01 17:22:20 +01:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2023-03-21 16:30:18 +01:00
|
|
|
|
menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock, const char *adskfpr)
|
2023-03-01 17:22:20 +01:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
PKT_public_key *adsk_pk = NULL;
|
|
|
|
|
kbnode_t adsk_keyblock = NULL;
|
|
|
|
|
char *answer = NULL;
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
KEYDB_SEARCH_DESC desc;
|
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
2024-06-05 17:04:33 +02:00
|
|
|
|
kbnode_t node;
|
2023-03-01 17:22:20 +01:00
|
|
|
|
|
|
|
|
|
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
xfree (answer);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if (adskfpr)
|
|
|
|
|
answer = xstrdup (adskfpr);
|
|
|
|
|
else
|
2023-03-01 17:22:20 +01:00
|
|
|
|
{
|
2023-03-21 16:30:18 +01:00
|
|
|
|
answer = cpr_get_utf8
|
|
|
|
|
("keyedit.addadsk",
|
|
|
|
|
_("Enter the fingerprint of the additional decryption subkey: "));
|
|
|
|
|
if (answer[0] == '\0' || answer[0] == CONTROL_D)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_CANCELED);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2023-03-01 17:22:20 +01:00
|
|
|
|
}
|
|
|
|
|
if (classify_user_id (answer, &desc, 1)
|
|
|
|
|
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
|
|
|
|
|
{
|
|
|
|
|
log_info (_("\"%s\" is not a fingerprint\n"), answer);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
|
|
|
|
if (adskfpr)
|
|
|
|
|
goto leave;
|
2023-03-01 17:22:20 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 11:57:04 +02:00
|
|
|
|
/* Force searching for that exact fingerprint and for any key
|
|
|
|
|
* which has a key with that fingerprint. */
|
|
|
|
|
if (!strchr (answer, '!'))
|
|
|
|
|
{
|
|
|
|
|
char *tmpstr = xstrconcat (answer, "!", NULL);
|
|
|
|
|
xfree (answer);
|
|
|
|
|
answer = tmpstr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 17:22:20 +01:00
|
|
|
|
free_public_key (adsk_pk);
|
|
|
|
|
adsk_pk = xcalloc (1, sizeof *adsk_pk);
|
|
|
|
|
adsk_pk->req_usage = PUBKEY_USAGE_ENC;
|
|
|
|
|
release_kbnode (adsk_keyblock);
|
|
|
|
|
adsk_keyblock = NULL;
|
|
|
|
|
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
|
|
|
|
|
NULL, adsk_pk, answer, &adsk_keyblock, NULL, 1);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_info (_("key \"%s\" not found: %s\n"), answer,
|
|
|
|
|
gpg_strerror (err));
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if ((!opt.batch || adskfpr) && !opt.quiet
|
|
|
|
|
&& gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
|
2023-03-01 17:22:20 +01:00
|
|
|
|
log_info (_("Did you specify the fingerprint of a subkey?\n"));
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if (adskfpr)
|
|
|
|
|
goto leave;
|
2023-03-01 17:22:20 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (node = adsk_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
fingerprint_from_pk (pk, fpr, &fprlen);
|
|
|
|
|
if (fprlen == desc.fprlen
|
|
|
|
|
&& !memcmp (fpr, desc.u.fpr, fprlen)
|
|
|
|
|
&& (pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!node)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
|
|
|
|
log_info (_("key \"%s\" not found: %s\n"), answer,
|
|
|
|
|
gpg_strerror (err));
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if ((!opt.batch || adskfpr) && !opt.quiet)
|
2023-03-01 17:22:20 +01:00
|
|
|
|
log_info (_("Did you specify the fingerprint of a subkey?\n"));
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if (adskfpr)
|
|
|
|
|
goto leave;
|
2023-03-01 17:22:20 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check that the selected subkey is not yet on our keyblock. */
|
2024-06-05 17:04:33 +02:00
|
|
|
|
err = has_key_with_fingerprint (pub_keyblock, desc.u.fpr, desc.fprlen);
|
|
|
|
|
if (err)
|
2023-03-01 17:22:20 +01:00
|
|
|
|
{
|
|
|
|
|
log_info (_("key \"%s\" is already on this keyblock\n"), answer);
|
2023-03-21 16:30:18 +01:00
|
|
|
|
if (adskfpr)
|
|
|
|
|
goto leave;
|
2023-03-01 17:22:20 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-03 18:52:06 +02:00
|
|
|
|
/* Append the subkey. */
|
2023-03-01 17:22:20 +01:00
|
|
|
|
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
|
2024-06-03 18:52:06 +02:00
|
|
|
|
err = append_adsk_to_key (ctrl, pub_keyblock, node->pkt->pkt.public_key);
|
2023-03-01 17:22:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
xfree (answer);
|
|
|
|
|
free_public_key (adsk_pk);
|
|
|
|
|
release_kbnode (adsk_keyblock);
|
|
|
|
|
if (!err)
|
|
|
|
|
return 1; /* The keyblock was modified. */
|
|
|
|
|
else
|
|
|
|
|
return 0; /* Not modified. */
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-12-05 10:58:39 +01:00
|
|
|
|
/* With FORCE_MAINKEY cleared this function handles the interactive
|
2017-07-21 14:12:55 +02:00
|
|
|
|
* menu option "expire". With UNATTENDED set to 1 this function only
|
2016-12-05 10:58:39 +01:00
|
|
|
|
* sets the expiration date of the primary key to NEWEXPIRATION and
|
2017-07-21 14:12:55 +02:00
|
|
|
|
* avoid all interactivity; with a value of 2 only the flagged subkeys
|
|
|
|
|
* are set to NEWEXPIRATION. Returns 0 if nothing was done,
|
2016-12-05 10:58:39 +01:00
|
|
|
|
* GPG_ERR_TRUE if the key was modified, or any other error code. */
|
|
|
|
|
static gpg_error_t
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
|
2017-07-21 14:12:55 +02:00
|
|
|
|
int unattended, u32 newexpiration)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2016-12-05 10:58:39 +01:00
|
|
|
|
int signumber, rc;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
u32 expiredate;
|
2017-07-21 14:12:55 +02:00
|
|
|
|
int only_mainkey; /* Set if only the mainkey is to be updated. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *main_pk, *sub_pk;
|
|
|
|
|
PKT_user_id *uid;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
kbnode_t node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
2022-09-14 04:48:42 +02:00
|
|
|
|
(void)signumber;
|
2017-07-21 14:12:55 +02:00
|
|
|
|
if (unattended)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-07-21 14:12:55 +02:00
|
|
|
|
only_mainkey = (unattended == 1);
|
2016-12-05 10:58:39 +01:00
|
|
|
|
expiredate = newexpiration;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-07-21 14:12:55 +02:00
|
|
|
|
int n1;
|
|
|
|
|
|
|
|
|
|
only_mainkey = 0;
|
|
|
|
|
n1 = count_selected_keys (pub_keyblock);
|
2016-12-05 10:58:39 +01:00
|
|
|
|
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"));
|
2017-07-21 14:12:55 +02:00
|
|
|
|
only_mainkey = 1;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
no_primary_warning (pub_keyblock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expiredate = ask_expiredate ();
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Now we can actually change the self-signature(s) */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
main_pk = sub_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
signumber = 0;
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
|
|
|
|
main_pk->expiredate = expiredate;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2015-11-23 12:16:33 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2017-07-21 14:12:55 +02:00
|
|
|
|
if ((node->flag & NODFLG_SELKEY) && unattended != 1)
|
2015-11-23 12:16:33 +01:00
|
|
|
|
{
|
2017-07-21 14:12:55 +02:00
|
|
|
|
/* The flag is set and we do not want to set the
|
|
|
|
|
* expiration date only for the main key. */
|
2015-11-23 12:16:33 +01:00
|
|
|
|
sub_pk = node->pkt->pkt.public_key;
|
|
|
|
|
sub_pk->expiredate = expiredate;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sub_pk = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
uid = node->pkt->pkt.user_id;
|
|
|
|
|
else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 14:12:55 +02:00
|
|
|
|
&& (only_mainkey || sub_pk))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
|
2017-07-21 14:12:55 +02:00
|
|
|
|
&& ((only_mainkey && uid
|
2010-04-20 20:19:19 +02:00
|
|
|
|
&& uid->created && (sig->sig_class & ~3) == 0x10)
|
2017-07-21 14:12:55 +02:00
|
|
|
|
|| (!only_mainkey && sig->sig_class == 0x18))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
&& sig->flags.chosen_selfsig)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* This is a self-signature which is to be replaced. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
|
|
|
|
|
signumber++;
|
|
|
|
|
|
2017-07-21 14:12:55 +02:00
|
|
|
|
if ((only_mainkey && main_pk->version < 4)
|
|
|
|
|
|| (!only_mainkey && sub_pk->version < 4))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
log_info
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(_("You can't change the expiration date of a v3 key\n"));
|
2016-12-05 10:58:39 +01:00
|
|
|
|
return gpg_error (GPG_ERR_LEGACY_KEY);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-21 14:12:55 +02:00
|
|
|
|
if (only_mainkey)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl,
|
|
|
|
|
&newsig, sig, main_pk, uid, NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk, keygen_add_key_expire,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
main_pk);
|
|
|
|
|
else
|
|
|
|
|
rc =
|
2017-03-31 20:03:52 +02:00
|
|
|
|
update_keysig_packet (ctrl,
|
|
|
|
|
&newsig, sig, main_pk, NULL, sub_pk,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk, keygen_add_key_expire, sub_pk);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("make_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2016-12-05 10:58:39 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_TRUE)
|
|
|
|
|
rc = GPG_ERR_GENERAL;
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/* Replace the packet. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (node->pkt);
|
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
sub_pk = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
update_trust = 1;
|
2016-12-05 10:58:39 +01:00
|
|
|
|
return gpg_error (GPG_ERR_TRUE);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2016-02-14 15:50:12 +01:00
|
|
|
|
/* Change the capability of a selected key. This command should only
|
|
|
|
|
* be used to rectify badly created keys and as such is not suggested
|
|
|
|
|
* for general use. */
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_changeusage (ctrl_t ctrl, kbnode_t keyblock)
|
2016-02-14 15:50:12 +01:00
|
|
|
|
{
|
|
|
|
|
int n1, rc;
|
|
|
|
|
int mainkey = 0;
|
|
|
|
|
PKT_public_key *main_pk, *sub_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
|
|
n1 = count_selected_keys (keyblock);
|
|
|
|
|
if (n1 > 1)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You must select exactly one key.\n"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (n1)
|
2018-04-09 10:36:02 +02:00
|
|
|
|
tty_printf (_("Changing usage of a subkey.\n"));
|
2016-02-14 15:50:12 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2018-04-09 10:36:02 +02:00
|
|
|
|
tty_printf (_("Changing usage of the primary key.\n"));
|
2016-02-14 15:50:12 +01:00
|
|
|
|
mainkey = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we can actually change the self-signature(s) */
|
|
|
|
|
main_pk = sub_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
|
|
|
|
}
|
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
if (node->flag & NODFLG_SELKEY)
|
|
|
|
|
sub_pk = node->pkt->pkt.public_key;
|
|
|
|
|
else
|
|
|
|
|
sub_pk = NULL;
|
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
|| (!mainkey && sig->sig_class == 0x18))
|
|
|
|
|
&& sig->flags.chosen_selfsig)
|
|
|
|
|
{
|
|
|
|
|
/* This is the self-signature which is to be replaced. */
|
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
|
|
|
|
|
if ((mainkey && main_pk->version < 4)
|
|
|
|
|
|| (!mainkey && sub_pk->version < 4))
|
|
|
|
|
{
|
2018-04-09 10:36:02 +02:00
|
|
|
|
/* Note: This won't happen because we don't support
|
|
|
|
|
* v3 keys anymore. */
|
2016-02-14 15:50:12 +01:00
|
|
|
|
log_info ("You can't change the capabilities of a v3 key\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mainkey)
|
|
|
|
|
main_pk->pubkey_usage = ask_key_flags (main_pk->pubkey_algo, 0,
|
|
|
|
|
main_pk->pubkey_usage);
|
|
|
|
|
else
|
|
|
|
|
sub_pk->pubkey_usage = ask_key_flags (sub_pk->pubkey_algo, 1,
|
|
|
|
|
sub_pk->pubkey_usage);
|
|
|
|
|
|
|
|
|
|
if (mainkey)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl,
|
|
|
|
|
&newsig, sig, main_pk, uid, NULL,
|
2016-02-14 15:50:12 +01:00
|
|
|
|
main_pk, keygen_add_key_flags,
|
|
|
|
|
main_pk);
|
|
|
|
|
else
|
|
|
|
|
rc =
|
2017-03-31 20:03:52 +02:00
|
|
|
|
update_keysig_packet (ctrl,
|
|
|
|
|
&newsig, sig, main_pk, NULL, sub_pk,
|
2016-02-14 15:50:12 +01:00
|
|
|
|
main_pk, keygen_add_key_flags, sub_pk);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("make_keysig_packet failed: %s\n",
|
2018-04-09 10:36:02 +02:00
|
|
|
|
gpg_strerror (rc));
|
2016-02-14 15:50:12 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Replace the packet. */
|
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2016-02-14 15:50:12 +01:00
|
|
|
|
xfree (node->pkt);
|
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
sub_pk = NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int rc, modified = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
PKT_public_key *main_pk;
|
|
|
|
|
KBNODE node;
|
2007-07-05 18:58:19 +02:00
|
|
|
|
u32 timestamp;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
main_pk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (main_pk, NULL);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2007-07-05 18:58:19 +02:00
|
|
|
|
/* We use the same timestamp for all backsigs so that we don't
|
|
|
|
|
reveal information about the used machine. */
|
|
|
|
|
timestamp = make_timestamp ();
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *sub_pk = NULL;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
KBNODE node2, sig_pk = NULL /*,sig_sk = NULL*/;
|
|
|
|
|
/* char *passphrase; */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
/* Find a signing subkey with no backsig */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2006-04-28 16:31:29 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkt.public_key->pubkey_usage & PUBKEY_USAGE_SIG)
|
2006-04-28 16:31:29 +02:00
|
|
|
|
{
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (node->pkt->pkt.public_key->flags.backsig)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_
|
|
|
|
|
("signing subkey %s is already cross-certified\n"),
|
|
|
|
|
keystr_from_pk (node->pkt->pkt.public_key));
|
2006-04-28 16:31:29 +02:00
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sub_pk = node->pkt->pkt.public_key;
|
2006-04-28 16:31:29 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("subkey %s does not sign and so does"
|
|
|
|
|
" not need to be cross-certified\n"),
|
|
|
|
|
keystr_from_pk (node->pkt->pkt.public_key));
|
2006-04-28 16:31:29 +02:00
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!sub_pk)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Find the selected selfsig on this subkey */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node2 = node->next;
|
|
|
|
|
node2 && node2->pkt->pkttype == PKT_SIGNATURE; node2 = node2->next)
|
|
|
|
|
if (node2->pkt->pkt.signature->version >= 4
|
|
|
|
|
&& node2->pkt->pkt.signature->flags.chosen_selfsig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sig_pk = node2;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!sig_pk)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Find the secret subkey that matches the public subkey */
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_debug ("FIXME: Check whether a secret subkey is available.\n");
|
|
|
|
|
/* if (!sub_sk) */
|
|
|
|
|
/* { */
|
|
|
|
|
/* tty_printf (_("no secret subkey for public subkey %s - ignoring\n"), */
|
|
|
|
|
/* keystr_from_pk (sub_pk)); */
|
|
|
|
|
/* continue; */
|
|
|
|
|
/* } */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Now we can get to work. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_backsig (ctrl,
|
|
|
|
|
sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_pk,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
timestamp, NULL);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (!rc)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl,
|
|
|
|
|
&newsig, sig_pk->pkt->pkt.signature,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk, NULL, sub_pk, main_pk,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
if (!rc)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* Put the new sig into place on the pubkey */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
newpkt = xmalloc_clear (sizeof (*newpkt));
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (sig_pk->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (sig_pk->pkt);
|
|
|
|
|
sig_pk->pkt = newpkt;
|
|
|
|
|
|
|
|
|
|
modified = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error ("update_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error ("make_backsig failed: %s\n", gpg_strerror (rc));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return modified;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
change_primary_uid_cb (PKT_signature * sig, void *opaque)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
byte buf[1];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* first clear all primary uid flags so that we are sure none are
|
|
|
|
|
* lingering around */
|
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID);
|
|
|
|
|
delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* if opaque is set,we want to set the primary id */
|
|
|
|
|
if (opaque)
|
|
|
|
|
{
|
|
|
|
|
buf[0] = 1;
|
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the primary uid flag for the selected UID. We will also reset
|
2017-03-21 14:47:21 +01:00
|
|
|
|
* all other primary uid flags. For this to work we have to update
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* all the signature timestamps. If we would do this with the current
|
2017-02-20 22:19:50 +01:00
|
|
|
|
* time, we lose quite a lot of information, so we use a kludge to
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* do this: Just increment the timestamp by one second which is
|
|
|
|
|
* sufficient to updated a signature during import.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *main_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int selected;
|
|
|
|
|
int attribute = 0;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
|
|
|
|
|
if (count_selected_uids (pub_keyblock) != 1)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Please select exactly one user ID.\n"));
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
main_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
selected = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Is our selected uid an attribute packet? */
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID)
|
|
|
|
|
attribute = (node->pkt->pkt.user_id->attrib_data != NULL);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
break; /* No more user ids expected - ready. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
uid = node->pkt->pkt.user_id;
|
|
|
|
|
selected = node->flag & NODFLG_SELUID;
|
|
|
|
|
}
|
|
|
|
|
else if (main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
|
|
|
|
|
&& (uid && (sig->sig_class & ~3) == 0x10)
|
|
|
|
|
&& attribute == (uid->attrib_data != NULL)
|
|
|
|
|
&& sig->flags.chosen_selfsig)
|
|
|
|
|
{
|
|
|
|
|
if (sig->version < 4)
|
|
|
|
|
{
|
|
|
|
|
char *user =
|
|
|
|
|
utf8_to_native (uid->name, strlen (uid->name), 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_info (_("skipping v3 self-signature on user ID \"%s\"\n"),
|
|
|
|
|
user);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is a selfsignature which is to be replaced.
|
|
|
|
|
We can just ignore v3 signatures because they are
|
|
|
|
|
not able to carry the primary ID flag. We also
|
|
|
|
|
ignore self-sigs on user IDs that are not of the
|
|
|
|
|
same type that we are making primary. That is, if
|
|
|
|
|
we are making a user ID primary, we alter user IDs.
|
|
|
|
|
If we are making an attribute packet primary, we
|
|
|
|
|
alter attribute packets. */
|
|
|
|
|
|
|
|
|
|
/* FIXME: We must make sure that we only have one
|
|
|
|
|
self-signature per user ID here (not counting
|
|
|
|
|
revocations) */
|
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
const byte *p;
|
|
|
|
|
int action;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* See whether this signature has the primary UID flag. */
|
2019-09-05 20:36:38 +02:00
|
|
|
|
p = parse_sig_subpkt (sig, 1,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
SIGSUBPKT_PRIMARY_UID, NULL);
|
|
|
|
|
if (!p)
|
2019-09-05 20:36:38 +02:00
|
|
|
|
p = parse_sig_subpkt (sig, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
SIGSUBPKT_PRIMARY_UID, NULL);
|
|
|
|
|
if (p && *p) /* yes */
|
|
|
|
|
action = selected ? 0 : -1;
|
|
|
|
|
else /* no */
|
|
|
|
|
action = selected ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
int rc = update_keysig_packet (ctrl, &newsig, sig,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
main_pk, uid, NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
change_primary_uid_cb,
|
|
|
|
|
action > 0 ? "x" : NULL);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("update_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* replace the packet */
|
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (node->pkt);
|
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return modified;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/*
|
2022-11-04 15:26:15 +01:00
|
|
|
|
* Set preferences to new values for the selected user IDs.
|
|
|
|
|
* --quick-update-pred calls this with UNATTENDED set.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2022-11-04 15:26:15 +01:00
|
|
|
|
menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock, int unattended)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *main_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int selected, select_all;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
|
2022-11-04 15:26:15 +01:00
|
|
|
|
if (!unattended)
|
|
|
|
|
no_primary_warning (pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2022-11-04 15:26:15 +01:00
|
|
|
|
select_all = unattended? 1 : !count_selected_uids (pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* Now we can actually change the self signature(s) */
|
|
|
|
|
main_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
selected = 0;
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
break; /* No more user-ids expected - ready. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
uid = node->pkt->pkt.user_id;
|
|
|
|
|
selected = select_all || (node->flag & NODFLG_SELUID);
|
|
|
|
|
}
|
|
|
|
|
else if (main_pk && uid && selected
|
|
|
|
|
&& node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
|
|
|
|
|
&& (uid && (sig->sig_class & ~3) == 0x10)
|
|
|
|
|
&& sig->flags.chosen_selfsig)
|
|
|
|
|
{
|
|
|
|
|
if (sig->version < 4)
|
|
|
|
|
{
|
|
|
|
|
char *user =
|
|
|
|
|
utf8_to_native (uid->name, strlen (uid->name), 0);
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_info (_("skipping v3 self-signature on user ID \"%s\"\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
user);
|
|
|
|
|
xfree (user);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
/* This is a selfsignature which is to be replaced
|
2010-04-20 20:19:19 +02:00
|
|
|
|
* We have to ignore v3 signatures because they are
|
2010-04-21 18:26:17 +02:00
|
|
|
|
* not able to carry the preferences. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
int rc;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl, &newsig, sig,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk, uid, NULL, main_pk,
|
|
|
|
|
keygen_upd_std_prefs, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("update_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* replace the packet */
|
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (node->pkt);
|
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
return modified;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-23 19:48:33 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock)
|
2003-09-23 19:48:33 +02:00
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
PKT_public_key *main_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int selected, select_all;
|
|
|
|
|
int modified = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *answer, *uri;
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
no_primary_warning (pub_keyblock);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (url)
|
|
|
|
|
answer = xstrdup (url);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
answer = cpr_get_utf8 ("keyedit.add_keyserver",
|
|
|
|
|
_("Enter your preferred keyserver URL: "));
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (answer[0] == '\0' || answer[0] == CONTROL_D)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2021-05-20 10:13:51 +02:00
|
|
|
|
if (!ascii_strcasecmp (answer, "none"))
|
|
|
|
|
{
|
|
|
|
|
xfree (answer);
|
|
|
|
|
uri = NULL;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
struct keyserver_spec *keyserver = NULL;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Sanity check the format */
|
2015-01-05 15:07:23 +01:00
|
|
|
|
keyserver = parse_keyserver_uri (answer, 1);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
|
|
|
|
if (!keyserver)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_info (_("could not parse keyserver URL\n"));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
uri = xstrdup (keyserver->uri);
|
|
|
|
|
free_keyserver_spec (keyserver);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
select_all = !count_selected_uids (pub_keyblock);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Now we can actually change the self signature(s) */
|
|
|
|
|
main_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
selected = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
break; /* ready */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
uid = node->pkt->pkt.user_id;
|
|
|
|
|
selected = select_all || (node->flag & NODFLG_SELUID);
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (main_pk && uid && selected
|
|
|
|
|
&& node->pkt->pkttype == PKT_SIGNATURE)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
|
|
|
|
|
&& (uid && (sig->sig_class & ~3) == 0x10)
|
|
|
|
|
&& sig->flags.chosen_selfsig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *user = utf8_to_native (uid->name, strlen (uid->name), 0);
|
|
|
|
|
if (sig->version < 4)
|
|
|
|
|
log_info (_("skipping v3 self-signature on user ID \"%s\"\n"),
|
|
|
|
|
user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is a selfsignature which is to be replaced
|
|
|
|
|
* We have to ignore v3 signatures because they are
|
|
|
|
|
* not able to carry the subpacket. */
|
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
|
|
|
|
int rc;
|
|
|
|
|
const byte *p;
|
|
|
|
|
size_t plen;
|
|
|
|
|
|
2019-09-05 20:36:38 +02:00
|
|
|
|
p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &plen);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (p && plen)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("Current preferred keyserver for user"
|
|
|
|
|
" ID \"%s\": ", user);
|
|
|
|
|
tty_print_utf8_string (p, plen);
|
|
|
|
|
tty_printf ("\n");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!cpr_get_answer_is_yes
|
2010-04-21 18:26:17 +02:00
|
|
|
|
("keyedit.confirm_keyserver",
|
|
|
|
|
uri
|
|
|
|
|
? _("Are you sure you want to replace it? (y/N) ")
|
|
|
|
|
: _("Are you sure you want to delete it? (y/N) ")))
|
2021-04-12 20:05:48 +02:00
|
|
|
|
{
|
|
|
|
|
xfree (user);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (uri == NULL)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* There is no current keyserver URL, so there
|
2010-04-20 20:19:19 +02:00
|
|
|
|
is no point in trying to un-set it. */
|
2021-04-12 20:05:48 +02:00
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl, &newsig, sig,
|
2006-04-19 13:26:11 +02:00
|
|
|
|
main_pk, uid, NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keygen_add_keyserver_url, uri);
|
|
|
|
|
if (rc)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
log_error ("update_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (uri);
|
2021-05-20 10:13:51 +02:00
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* replace the packet */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (node->pkt);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (uri);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return modified;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_set_notation (ctrl_t ctrl, const char *string, KBNODE pub_keyblock)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *main_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int selected, select_all;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
char *answer;
|
|
|
|
|
struct notation *notation;
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
no_primary_warning (pub_keyblock);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (string)
|
|
|
|
|
answer = xstrdup (string);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
answer = cpr_get_utf8 ("keyedit.add_notation",
|
|
|
|
|
_("Enter the notation: "));
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (answer[0] == '\0' || answer[0] == CONTROL_D)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (!ascii_strcasecmp (answer, "none")
|
|
|
|
|
|| !ascii_strcasecmp (answer, "-"))
|
|
|
|
|
notation = NULL; /* Delete them all. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
notation = string_to_notation (answer, 0);
|
|
|
|
|
if (!notation)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
select_all = !count_selected_uids (pub_keyblock);
|
|
|
|
|
|
|
|
|
|
/* Now we can actually change the self signature(s) */
|
|
|
|
|
main_pk = NULL;
|
|
|
|
|
uid = NULL;
|
|
|
|
|
selected = 0;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
break; /* ready */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
main_pk = node->pkt->pkt.public_key;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyid_from_pk (main_pk, keyid);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
uid = node->pkt->pkt.user_id;
|
|
|
|
|
selected = select_all || (node->flag & NODFLG_SELUID);
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (main_pk && uid && selected
|
|
|
|
|
&& node->pkt->pkttype == PKT_SIGNATURE)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
|
|
|
|
|
&& (uid && (sig->sig_class & ~3) == 0x10)
|
|
|
|
|
&& sig->flags.chosen_selfsig)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *user = utf8_to_native (uid->name, strlen (uid->name), 0);
|
|
|
|
|
if (sig->version < 4)
|
|
|
|
|
log_info (_("skipping v3 self-signature on user ID \"%s\"\n"),
|
|
|
|
|
user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *newsig;
|
|
|
|
|
PACKET *newpkt;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int rc, skip = 0, addonly = 1;
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->flags.notation)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("Current notations for user ID \"%s\":\n",
|
|
|
|
|
user);
|
|
|
|
|
tty_print_notations (-9, sig);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("No notations on user ID \"%s\"\n", user);
|
|
|
|
|
if (notation == NULL)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* There are no current notations, so there
|
|
|
|
|
is no point in trying to un-set them. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (notation)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
struct notation *n;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int deleting = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
notation->next = sig_to_notation (sig);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (n = notation->next; n; n = n->next)
|
|
|
|
|
if (strcmp (n->name, notation->name) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (notation->value)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (strcmp (n->value, notation->value) == 0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (notation->flags.ignore)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* Value match with a delete
|
|
|
|
|
flag. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
n->flags.ignore = 1;
|
|
|
|
|
deleting = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Adding the same notation
|
|
|
|
|
twice, so don't add it at
|
|
|
|
|
all. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
skip = 1;
|
|
|
|
|
tty_printf ("Skipping notation:"
|
|
|
|
|
" %s=%s\n",
|
|
|
|
|
notation->name,
|
|
|
|
|
notation->value);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* No value, so it means delete. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
n->flags.ignore = 1;
|
|
|
|
|
deleting = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (n->flags.ignore)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("Removing notation: %s=%s\n",
|
|
|
|
|
n->name, n->value);
|
|
|
|
|
addonly = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!notation->flags.ignore && !skip)
|
|
|
|
|
tty_printf ("Adding notation: %s=%s\n",
|
|
|
|
|
notation->name, notation->value);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* We tried to delete, but had no matches. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (notation->flags.ignore && !deleting)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("Removing all notations\n");
|
|
|
|
|
addonly = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (skip
|
|
|
|
|
|| (!addonly
|
|
|
|
|
&&
|
|
|
|
|
!cpr_get_answer_is_yes ("keyedit.confirm_notation",
|
|
|
|
|
_("Proceed? (y/N) "))))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = update_keysig_packet (ctrl, &newsig, sig,
|
2006-04-19 13:26:11 +02:00
|
|
|
|
main_pk, uid, NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
main_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keygen_add_notations, notation);
|
|
|
|
|
if (rc)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
log_error ("update_keysig_packet failed: %s\n",
|
2015-01-22 12:06:11 +01:00
|
|
|
|
gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_notation (notation);
|
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* replace the packet */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (node->pkt, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (node->pkt);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
node->pkt = newpkt;
|
|
|
|
|
modified = 1;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (notation)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
/* Snip off the notation list from the sig */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_notation (notation->next);
|
|
|
|
|
notation->next = NULL;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (user);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-09-23 19:48:33 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_notation (notation);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return modified;
|
2003-09-23 19:48:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-09-04 13:52:03 +02:00
|
|
|
|
/*
|
|
|
|
|
* Select one user id or remove all selection if IDX is 0 or select
|
|
|
|
|
* all if IDX is -1. Returns: True if the selection changed.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2009-09-04 13:52:03 +02:00
|
|
|
|
menu_select_uid (KBNODE keyblock, int idx)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2009-09-04 13:52:03 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (idx == -1) /* Select all. */
|
|
|
|
|
{
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
node->flag |= NODFLG_SELUID;
|
2009-09-04 13:52:03 +02:00
|
|
|
|
return 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (idx) /* Toggle. */
|
2009-09-04 13:52:03 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0, node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
if (++i == idx)
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2009-09-04 13:52:03 +02:00
|
|
|
|
if (!node)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("No user ID with index %d\n"), idx);
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0, node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
if (++i == idx)
|
|
|
|
|
{
|
|
|
|
|
if ((node->flag & NODFLG_SELUID))
|
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
|
|
|
|
else
|
|
|
|
|
node->flag |= NODFLG_SELUID;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-04 13:52:03 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else /* Unselect all */
|
2009-09-04 13:52:03 +02:00
|
|
|
|
{
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
2009-09-04 13:52:03 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
2009-09-04 13:52:03 +02:00
|
|
|
|
return 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-04 13:52:03 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Search in the keyblock for a uid that matches namehash */
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
menu_select_uid_namehash (KBNODE keyblock, const char *namehash)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
byte hash[NAMEHASH_LEN];
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (strlen (namehash) == NAMEHASH_LEN * 2);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0; i < NAMEHASH_LEN; i++)
|
|
|
|
|
hash[i] = hextobyte (&namehash[i * 2]);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock->next; node; node = node->next)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
namehash_from_uid (node->pkt->pkt.user_id);
|
|
|
|
|
if (memcmp (node->pkt->pkt.user_id->namehash, hash, NAMEHASH_LEN) ==
|
|
|
|
|
0)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->flag & NODFLG_SELUID)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
|
|
|
|
else
|
|
|
|
|
node->flag |= NODFLG_SELUID;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!node)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("No user ID with hash %s\n"), namehash);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Select secondary keys
|
2009-09-04 13:52:03 +02:00
|
|
|
|
* Returns: True if the selection changed.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2015-11-17 21:21:03 +01:00
|
|
|
|
menu_select_key (KBNODE keyblock, int idx, char *p)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2009-09-04 13:52:03 +02:00
|
|
|
|
KBNODE node;
|
2015-11-17 21:21:03 +01:00
|
|
|
|
int i, j;
|
2015-11-23 11:21:24 +01:00
|
|
|
|
int is_hex_digits;
|
2015-11-17 21:21:03 +01:00
|
|
|
|
|
2015-11-23 11:21:24 +01:00
|
|
|
|
is_hex_digits = p && strlen (p) >= 8;
|
2015-11-17 21:21:03 +01:00
|
|
|
|
if (is_hex_digits)
|
|
|
|
|
{
|
2015-11-24 13:03:24 +01:00
|
|
|
|
/* Skip initial spaces. */
|
|
|
|
|
while (spacep (p))
|
|
|
|
|
p ++;
|
|
|
|
|
/* If the id starts with 0x accept and ignore it. */
|
|
|
|
|
if (p[0] == '0' && p[1] == 'x')
|
|
|
|
|
p += 2;
|
|
|
|
|
|
2015-11-17 21:21:03 +01:00
|
|
|
|
for (i = 0, j = 0; p[i]; i ++)
|
2015-11-24 13:03:24 +01:00
|
|
|
|
if (hexdigitp (&p[i]))
|
2015-11-17 21:21:03 +01:00
|
|
|
|
{
|
|
|
|
|
p[j] = toupper (p[i]);
|
|
|
|
|
j ++;
|
|
|
|
|
}
|
2015-11-24 13:03:24 +01:00
|
|
|
|
else if (spacep (&p[i]))
|
2015-11-17 21:21:03 +01:00
|
|
|
|
/* Skip spaces. */
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
is_hex_digits = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (is_hex_digits)
|
|
|
|
|
/* In case we skipped some spaces, add a new NUL terminator. */
|
|
|
|
|
{
|
|
|
|
|
p[j] = 0;
|
|
|
|
|
/* If we skipped some spaces, make sure that we still have
|
|
|
|
|
at least 8 characters. */
|
2015-11-24 13:03:24 +01:00
|
|
|
|
is_hex_digits = (/* Short keyid. */
|
|
|
|
|
strlen (p) == 8
|
|
|
|
|
/* Long keyid. */
|
|
|
|
|
|| strlen (p) == 16
|
|
|
|
|
/* Fingerprints are (currently) 32 or 40
|
|
|
|
|
characters. */
|
|
|
|
|
|| strlen (p) >= 32);
|
2015-11-17 21:21:03 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_hex_digits)
|
|
|
|
|
{
|
|
|
|
|
int found_one = 0;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
{
|
2015-11-24 13:03:24 +01:00
|
|
|
|
int match = 0;
|
|
|
|
|
if (strlen (p) == 8 || strlen (p) == 16)
|
2015-11-17 21:21:03 +01:00
|
|
|
|
{
|
2015-11-24 13:03:24 +01:00
|
|
|
|
u32 kid[2];
|
|
|
|
|
char kid_str[17];
|
|
|
|
|
keyid_from_pk (node->pkt->pkt.public_key, kid);
|
|
|
|
|
format_keyid (kid, strlen (p) == 8 ? KF_SHORT : KF_LONG,
|
|
|
|
|
kid_str, sizeof (kid_str));
|
|
|
|
|
|
|
|
|
|
if (strcmp (p, kid_str) == 0)
|
|
|
|
|
match = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char fp[2*MAX_FINGERPRINT_LEN + 1];
|
|
|
|
|
hexfingerprint (node->pkt->pkt.public_key, fp, sizeof (fp));
|
|
|
|
|
if (strcmp (fp, p) == 0)
|
|
|
|
|
match = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (match)
|
|
|
|
|
{
|
|
|
|
|
if ((node->flag & NODFLG_SELKEY))
|
|
|
|
|
node->flag &= ~NODFLG_SELKEY;
|
|
|
|
|
else
|
|
|
|
|
node->flag |= NODFLG_SELKEY;
|
2015-11-17 21:21:03 +01:00
|
|
|
|
|
|
|
|
|
found_one = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found_one)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2015-12-03 10:39:29 +01:00
|
|
|
|
tty_printf (_("No subkey with key ID '%s'.\n"), p);
|
2015-11-17 21:21:03 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (idx == -1) /* Select all. */
|
2009-09-04 13:52:03 +02:00
|
|
|
|
{
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
node->flag |= NODFLG_SELKEY;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (idx) /* Toggle selection. */
|
2009-09-04 13:52:03 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0, node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
if (++i == idx)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-09-04 13:52:03 +02:00
|
|
|
|
if (!node)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("No subkey with index %d\n"), idx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0, node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
if (++i == idx)
|
|
|
|
|
{
|
|
|
|
|
if ((node->flag & NODFLG_SELKEY))
|
|
|
|
|
node->flag &= ~NODFLG_SELKEY;
|
|
|
|
|
else
|
|
|
|
|
node->flag |= NODFLG_SELKEY;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else /* Unselect all. */
|
2009-09-04 13:52:03 +02:00
|
|
|
|
{
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
node->flag &= ~NODFLG_SELKEY;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-04 13:52:03 +02:00
|
|
|
|
return 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count_uids_with_flag (KBNODE keyblock, unsigned flag)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID && (node->flag & flag))
|
|
|
|
|
i++;
|
|
|
|
|
return i;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count_keys_with_flag (KBNODE keyblock, unsigned flag)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY) && (node->flag & flag))
|
|
|
|
|
i++;
|
|
|
|
|
return i;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count_uids (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
i++;
|
|
|
|
|
return i;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Returns true if there is at least one selected user id
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count_selected_uids (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return count_uids_with_flag (keyblock, NODFLG_SELUID);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
count_selected_keys (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return count_keys_with_flag (keyblock, NODFLG_SELKEY);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/* Returns how many real (i.e. not attribute) uids are unmarked. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
real_uids_left (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int real = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & NODFLG_SELUID) &&
|
|
|
|
|
!node->pkt->pkt.user_id->attrib_data)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
real++;
|
|
|
|
|
|
|
|
|
|
return real;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/*
|
|
|
|
|
* Ask whether the signature should be revoked. If the user commits this,
|
|
|
|
|
* flag bit MARK_A is set on the signature and the user ID.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-03-31 20:03:52 +02:00
|
|
|
|
ask_revoke_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int doit = 0;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
KBNODE unode = find_prev_kbnode (keyblock, node, PKT_USER_ID);
|
|
|
|
|
|
|
|
|
|
if (!unode)
|
|
|
|
|
{
|
|
|
|
|
log_error ("Oops: no user ID for signature\n");
|
|
|
|
|
return;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
uid = unode->pkt->pkt.user_id;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.with_colons)
|
|
|
|
|
{
|
|
|
|
|
if (uid->attrib_data)
|
|
|
|
|
printf ("uat:::::::::%u %lu", uid->numattribs, uid->attrib_len);
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf ("uid:::::::::");
|
2010-04-20 20:19:19 +02:00
|
|
|
|
es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2015-02-19 17:22:27 +01:00
|
|
|
|
es_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
print_and_check_one_sig_colon (ctrl, keyblock, node,
|
|
|
|
|
NULL, NULL, NULL, NULL, 1);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *p = utf8_to_native (unode->pkt->pkt.user_id->name,
|
|
|
|
|
unode->pkt->pkt.user_id->len, 0);
|
|
|
|
|
tty_printf (_("user ID: \"%s\"\n"), p);
|
|
|
|
|
xfree (p);
|
|
|
|
|
|
|
|
|
|
tty_printf (_("signed by your key %s on %s%s%s\n"),
|
|
|
|
|
keystr (sig->keyid), datestr_from_sig (sig),
|
|
|
|
|
sig->flags.exportable ? "" : _(" (non-exportable)"), "");
|
|
|
|
|
}
|
|
|
|
|
if (sig->flags.expired)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("This signature expired on %s.\n"),
|
|
|
|
|
expirestr_from_sig (sig));
|
|
|
|
|
/* Use a different question so we can have different help text */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
doit = cpr_get_answer_is_yes
|
2010-04-21 18:26:17 +02:00
|
|
|
|
("ask_revoke_sig.expired",
|
|
|
|
|
_("Are you sure you still want to revoke it? (y/N) "));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
2011-02-04 12:57:53 +01:00
|
|
|
|
doit = cpr_get_answer_is_yes
|
2010-04-21 18:26:17 +02:00
|
|
|
|
("ask_revoke_sig.one",
|
|
|
|
|
_("Create a revocation certificate for this signature? (y/N) "));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (doit)
|
|
|
|
|
{
|
2003-06-05 09:14:21 +02:00
|
|
|
|
node->flag |= NODFLG_MARK_A;
|
|
|
|
|
unode->flag |= NODFLG_MARK_A;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Display all user ids of the current public key together with signatures
|
|
|
|
|
* done by one of our keys. Then walk over all this sigs and ask the user
|
|
|
|
|
* whether he wants to revoke this signature.
|
|
|
|
|
* Return: True when the keyblock has changed.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
PKT_public_key *primary_pk;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int changed = 0;
|
|
|
|
|
int rc, any, skip = 1, all = !count_selected_uids (keyblock);
|
|
|
|
|
struct revocation_reason_info *reason = NULL;
|
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
/* First check whether we have any signatures at all. */
|
|
|
|
|
any = 0;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
if (node->flag & NODFLG_SELUID || all)
|
|
|
|
|
skip = 0;
|
|
|
|
|
else
|
|
|
|
|
skip = 1;
|
2009-08-26 08:46:02 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& ((sig = node->pkt->pkt.signature),
|
2019-09-09 14:34:09 +02:00
|
|
|
|
have_secret_key_with_kid (ctrl, sig->keyid)))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
if ((sig->sig_class & ~3) == 0x10)
|
|
|
|
|
{
|
|
|
|
|
any = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-26 08:46:02 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!any)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Not signed by you.\n"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* FIXME: detect duplicates here */
|
|
|
|
|
tty_printf (_("You have signed these user IDs on key %s:\n"),
|
|
|
|
|
keystr_from_pk (keyblock->pkt->pkt.public_key));
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
if (node->flag & NODFLG_SELUID || all)
|
|
|
|
|
{
|
2003-06-05 09:14:21 +02:00
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
/* Hmmm: Should we show only UIDs with a signature? */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
skip = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
skip = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& ((sig = node->pkt->pkt.signature),
|
2019-09-09 14:34:09 +02:00
|
|
|
|
have_secret_key_with_kid (ctrl, sig->keyid)))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
if ((sig->sig_class & ~3) == 0x10)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("signed by your key %s on %s%s%s\n"),
|
|
|
|
|
keystr (sig->keyid), datestr_from_sig (sig),
|
|
|
|
|
sig->flags.exportable ? "" : _(" (non-exportable)"),
|
|
|
|
|
sig->flags.revocable ? "" : _(" (non-revocable)"));
|
|
|
|
|
if (sig->flags.revocable)
|
|
|
|
|
node->flag |= NODFLG_SELSIG;
|
|
|
|
|
}
|
|
|
|
|
else if (sig->sig_class == 0x30)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("revoked by your key %s on %s\n"),
|
|
|
|
|
keystr (sig->keyid), datestr_from_sig (sig));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* ask */
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (!(node->flag & NODFLG_SELSIG))
|
|
|
|
|
continue;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
ask_revoke_sig (ctrl, keyblock, node);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* present selected */
|
|
|
|
|
any = 0;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (!(node->flag & NODFLG_MARK_A))
|
|
|
|
|
continue;
|
|
|
|
|
if (!any)
|
|
|
|
|
{
|
|
|
|
|
any = 1;
|
|
|
|
|
tty_printf (_("You are about to revoke these signatures:\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("signed by your key %s on %s%s%s\n"),
|
|
|
|
|
keystr (sig->keyid), datestr_from_sig (sig), "",
|
|
|
|
|
sig->flags.exportable ? "" : _(" (non-exportable)"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!any)
|
|
|
|
|
return 0; /* none selected */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (!cpr_get_answer_is_yes
|
2010-04-21 18:26:17 +02:00
|
|
|
|
("ask_revoke_sig.okay",
|
|
|
|
|
_("Really create the revocation certificates? (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0; /* forget it */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reason = ask_revocation_reason (0, 1, 0);
|
|
|
|
|
if (!reason)
|
|
|
|
|
{ /* user decided to cancel */
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* now we can sign the user ids */
|
2017-04-28 03:06:33 +02:00
|
|
|
|
reloop: /* (must use this, because we are modifying the list) */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
primary_pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
KBNODE unode;
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
struct sign_attrib attrib;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
PKT_public_key *signerkey;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
if (!(node->flag & NODFLG_MARK_A)
|
|
|
|
|
|| node->pkt->pkttype != PKT_SIGNATURE)
|
|
|
|
|
continue;
|
|
|
|
|
unode = find_prev_kbnode (keyblock, node, PKT_USER_ID);
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (unode); /* we already checked this */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
memset (&attrib, 0, sizeof attrib);
|
|
|
|
|
attrib.reason = reason;
|
|
|
|
|
attrib.non_exportable = !node->pkt->pkt.signature->flags.exportable;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag &= ~NODFLG_MARK_A;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
signerkey = xmalloc_secure_clear (sizeof *signerkey);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (get_seckey (ctrl, signerkey, node->pkt->pkt.signature->keyid))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
log_info (_("no secret key\n"));
|
2010-04-21 18:26:17 +02:00
|
|
|
|
free_public_key (signerkey);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
continue;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, primary_pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
unode->pkt->pkt.user_id,
|
2019-05-13 12:38:32 +02:00
|
|
|
|
NULL, signerkey, 0x30, 0, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
sign_mk_attrib, &attrib, NULL);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
free_public_key (signerkey);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", rc);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_revocation_reason_info (reason);
|
|
|
|
|
return changed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
changed = 1; /* we changed the keyblock */
|
|
|
|
|
update_trust = 1;
|
|
|
|
|
/* Are we revoking our own uid? */
|
|
|
|
|
if (primary_pk->keyid[0] == sig->keyid[0] &&
|
|
|
|
|
primary_pk->keyid[1] == sig->keyid[1])
|
2017-03-08 11:01:22 +01:00
|
|
|
|
unode->pkt->pkt.user_id->flags.revoked = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
|
insert_kbnode (unode, new_kbnode (pkt), 0);
|
|
|
|
|
goto reloop;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_revocation_reason_info (reason);
|
|
|
|
|
return changed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2016-06-17 00:05:57 +02:00
|
|
|
|
/* return 0 if revocation of NODE (which must be a User ID) was
|
|
|
|
|
successful, non-zero if there was an error. *modified will be set
|
|
|
|
|
to 1 if a change was made. */
|
|
|
|
|
static int
|
|
|
|
|
core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
|
|
|
|
|
const struct revocation_reason_info *reason, int *modified)
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
gpg_error_t rc;
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype != PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
rc = gpg_error (GPG_ERR_NO_USER_ID);
|
|
|
|
|
write_status_error ("keysig", rc);
|
|
|
|
|
log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
|
if (uid->flags.revoked)
|
2016-06-17 00:05:57 +02:00
|
|
|
|
{
|
|
|
|
|
char *user = utf8_to_native (uid->name, uid->len, 0);
|
|
|
|
|
log_info (_("user ID \"%s\" is already revoked\n"), user);
|
|
|
|
|
xfree (user);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
struct sign_attrib attrib;
|
|
|
|
|
u32 timestamp = make_timestamp ();
|
|
|
|
|
|
|
|
|
|
if (uid->created >= timestamp)
|
|
|
|
|
{
|
|
|
|
|
/* Okay, this is a problem. The user ID selfsig was
|
|
|
|
|
created in the future, so we need to warn the user and
|
|
|
|
|
set our revocation timestamp one second after that so
|
|
|
|
|
everything comes out clean. */
|
|
|
|
|
|
|
|
|
|
log_info (_("WARNING: a user ID signature is dated %d"
|
|
|
|
|
" seconds in the future\n"),
|
|
|
|
|
uid->created - timestamp);
|
|
|
|
|
|
|
|
|
|
timestamp = uid->created + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset (&attrib, 0, sizeof attrib);
|
|
|
|
|
/* should not need to cast away const here; but
|
|
|
|
|
revocation_reason_build_cb needs to take a non-const
|
2020-10-28 17:06:27 +01:00
|
|
|
|
void* in order to meet the function signature for the
|
2016-06-17 00:05:57 +02:00
|
|
|
|
mksubpkt argument to make_keysig_packet */
|
|
|
|
|
attrib.reason = (struct revocation_reason_info *)reason;
|
|
|
|
|
|
2019-05-13 12:38:32 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30,
|
2016-06-17 00:05:57 +02:00
|
|
|
|
timestamp, 0,
|
|
|
|
|
sign_mk_attrib, &attrib, NULL);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
write_status_error ("keysig", rc);
|
|
|
|
|
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
|
insert_kbnode (node, new_kbnode (pkt), 0);
|
|
|
|
|
|
|
|
|
|
#ifndef NO_TRUST_MODELS
|
|
|
|
|
/* If the trustdb has an entry for this key+uid then the
|
|
|
|
|
trustdb needs an update. */
|
|
|
|
|
if (!update_trust
|
2016-11-23 12:29:22 +01:00
|
|
|
|
&& ((get_validity (ctrl, keyblock, pk, uid, NULL, 0)
|
|
|
|
|
& TRUST_MASK)
|
2016-06-17 00:05:57 +02:00
|
|
|
|
>= TRUST_UNDEFINED))
|
|
|
|
|
update_trust = 1;
|
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
|
node->pkt->pkt.user_id->flags.revoked = 1;
|
2016-06-17 00:05:57 +02:00
|
|
|
|
if (modified)
|
|
|
|
|
*modified = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* Revoke a user ID (i.e. revoke a user ID selfsig). Return true if
|
2010-04-21 18:26:17 +02:00
|
|
|
|
keyblock changed. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2016-05-21 11:41:49 +02:00
|
|
|
|
menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int changed = 0;
|
|
|
|
|
int rc;
|
|
|
|
|
struct revocation_reason_info *reason = NULL;
|
2017-03-02 14:14:55 +01:00
|
|
|
|
size_t valid_uids;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Note that this is correct as per the RFCs, but nevertheless
|
|
|
|
|
somewhat meaningless in the real world. 1991 did define the 0x30
|
|
|
|
|
sig class, but PGP 2.x did not actually implement it, so it would
|
|
|
|
|
probably be safe to use v4 revocations everywhere. -ds */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (pk->version > 3 || (node->pkt->pkttype == PKT_USER_ID &&
|
|
|
|
|
node->pkt->pkt.user_id->selfsigversion > 3))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((reason = ask_revocation_reason (0, 1, 4)))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-02 14:14:55 +01:00
|
|
|
|
/* Too make sure that we do not revoke the last valid UID, we first
|
|
|
|
|
count how many valid UIDs there are. */
|
|
|
|
|
valid_uids = 0;
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
valid_uids +=
|
|
|
|
|
node->pkt->pkttype == PKT_USER_ID
|
2017-03-08 11:01:22 +01:00
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.expired;
|
2017-03-02 14:14:55 +01:00
|
|
|
|
|
2016-06-17 00:05:57 +02:00
|
|
|
|
reloop: /* (better this way because we are modifying the keyring) */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2016-06-17 00:05:57 +02:00
|
|
|
|
int modified = 0;
|
2017-03-02 14:14:55 +01:00
|
|
|
|
|
|
|
|
|
/* Make sure that we do not revoke the last valid UID. */
|
|
|
|
|
if (valid_uids == 1
|
2017-03-08 11:01:22 +01:00
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.revoked
|
|
|
|
|
&& ! node->pkt->pkt.user_id->flags.expired)
|
2017-03-02 14:14:55 +01:00
|
|
|
|
{
|
|
|
|
|
log_error (_("Cannot revoke the last valid user ID.\n"));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-17 00:05:57 +02:00
|
|
|
|
rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto leave;
|
|
|
|
|
if (modified)
|
|
|
|
|
{
|
2003-06-05 09:14:21 +02:00
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
2016-06-17 00:05:57 +02:00
|
|
|
|
changed = 1;
|
|
|
|
|
goto reloop;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (changed)
|
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
leave:
|
|
|
|
|
release_revocation_reason_info (reason);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2006-04-19 13:26:11 +02:00
|
|
|
|
* Revoke the whole key.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
|
int rc, changed = 0;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
struct revocation_reason_info *reason;
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (pk->flags.revoked)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Key %s is already revoked.\n"), keystr_from_pk (pk));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reason = ask_revocation_reason (1, 0, 0);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* user decided to cancel */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!reason)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk,
|
2019-05-13 12:38:32 +02:00
|
|
|
|
0x20, 0, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
revocation_reason_build_cb, reason, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", rc);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
goto scram;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
changed = 1; /* we changed the keyblock */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
insert_kbnode (pub_keyblock, new_kbnode (pkt), 0);
|
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
update_trust = 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
scram:
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_revocation_reason_info (reason);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *mainpk;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int changed = 0;
|
|
|
|
|
int rc;
|
|
|
|
|
struct revocation_reason_info *reason = NULL;
|
|
|
|
|
|
|
|
|
|
reason = ask_revocation_reason (1, 0, 0);
|
|
|
|
|
if (!reason)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
return 0; /* User decided to cancel. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-04-28 03:06:33 +02:00
|
|
|
|
reloop: /* (better this way because we are modifying the keyring) */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
mainpk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
|
for (node = pub_keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& (node->flag & NODFLG_SELKEY))
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
PKT_public_key *subpk = node->pkt->pkt.public_key;
|
|
|
|
|
struct sign_attrib attrib;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (subpk->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Subkey %s is already revoked.\n"),
|
|
|
|
|
keystr_from_pk (subpk));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
memset (&attrib, 0, sizeof attrib);
|
|
|
|
|
attrib.reason = reason;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->flag &= ~NODFLG_SELKEY;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk,
|
2019-05-13 12:38:32 +02:00
|
|
|
|
0x28, 0, 0, sign_mk_attrib, &attrib,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
2015-08-25 15:06:40 +02:00
|
|
|
|
write_status_error ("keysig", rc);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_revocation_reason_info (reason);
|
|
|
|
|
return changed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
changed = 1; /* we changed the keyblock */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
|
insert_kbnode (node, new_kbnode (pkt), 0);
|
|
|
|
|
goto reloop;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
commit_kbnode (&pub_keyblock);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* No need to set update_trust here since signing keys no longer
|
|
|
|
|
are used to certify other keys, so there is no change in trust
|
|
|
|
|
when revoking/removing them */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
release_revocation_reason_info (reason);
|
|
|
|
|
return changed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* Note that update_ownertrust is going to mark the trustdb dirty when
|
|
|
|
|
enabling or disabling a key. This is arguably sub-optimal as
|
|
|
|
|
disabled keys are still counted in the web of trust, but perhaps
|
|
|
|
|
not worth adding extra complexity to change. -ds */
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#ifndef NO_TRUST_MODELS
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_public_key *pk =
|
|
|
|
|
find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
|
|
|
|
|
unsigned int trust, newtrust;
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
trust = newtrust = get_ownertrust (ctrl, pk);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
newtrust &= ~TRUST_FLAG_DISABLED;
|
|
|
|
|
if (disable)
|
|
|
|
|
newtrust |= TRUST_FLAG_DISABLED;
|
|
|
|
|
if (trust == newtrust)
|
|
|
|
|
return 0; /* already in that state */
|
2017-03-31 20:03:52 +02:00
|
|
|
|
update_ownertrust (ctrl, pk, newtrust);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
gpg: Allow building without any trust model support.
* configure.ac: Add option --disable-trust-models
(NO_TRUST_MODELS): New ac_define and am_conditional.
* g10/Makefile.am (trust_source): New.
(gpg2_SOURCES): Factor some files out to above. Add trust.c.
* g10/gpg.c [NO_TRUST_MODELS]: Disable options --export-ownertrust,
--import-ownertrust, --update-trustdb, --check-trustdb, --fix-trustdb,
--list-trustdb, --trustdb-name, --auto-check-trustdb,
--no-auto-check-trustdb, and --force-ownertrust.
(parse_trust_model) [NO_TRUST_MODELS]: Do not build.
(main) [NO_TRUST_MODELS]: Set trust_model to always and exclude all
trustdb related option code.
* g10/keyedit.c (cmds) [NO_TRUST_MODELS]: Remove menu items "trust",
"enable", and "disable".
* g10/keylist.c (public_key_list) [NO_TRUST_MODELS]: Do not print
"tru" record.
* g10/trust.c: New.
* g10/trustdb.c (struct key_item): Move to trustdb.h.
(register_trusted_keyid): Rename to tdb_register_trusted_keyid.
(register_trusted_key): Rename to tdb_register_trusted_key.
(trust_letter, uid_trust_string_fixed, trust_value_to_string)
(string_to_trust_value, get_ownertrust_with_min, get_ownertrust_info)
(get_ownertrust_string, get_validity_info, get_validity_string)
(clean_sigs_from_uid, clean_uid_from_key, clean_key): Move to trust.c.
(mark_usable_uid_certs): Move to trust.c and make global.
(is_in_klist): Move as inline to trustdb.h.
(trustdb_check_or_update): Rename to tdb_check_or_update
(revalidation_mark): Rename to tdb_revalidation_mark.
(get_ownertrust): Rename to tdb_get_ownertrust.
(get_min_ownertrust): Rename to tdb_get_min_ownertrust.
(update_ownertrust): Rename to tdb_update_ownertrust.
(clear_ownertrusts): Rename to tdb_clear_ownertrusts.
(cache_disabled_value): Rename to tdb_cache_disabled_value.
(check_trustdb_stale): Rename to tdb_check_trustdb_stale.
(get_validity): Rename to tdb_get_validity_core, add arg MAIN_PK and
factor some code out to ...
* trust.c (get_validity): ...new.
(check_or_update_trustdb): New wrapper.
(revalidation_mark): New wrapper.
(get_ownertrust): New wrapper.
(get_ownertrust_with_min): New wrapper.
(update_ownertrust): New wrapper.
(clear_ownertrusts): New wrapper.
(cache_disabled_value): New wrapper.
(check_trustdb_stale): New wrapper.
* tests/openpgp/defs.inc (opt_always): New. Use in all tests instead
of --always-trust.
2014-02-10 17:05:54 +01:00
|
|
|
|
#endif /*!NO_TRUST_MODELS*/
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2016-05-21 11:41:49 +02:00
|
|
|
|
menu_showphoto (ctrl_t ctrl, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int select_all = !count_selected_uids (keyblock);
|
|
|
|
|
int count = 0;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Look for the public key first. We have to be really, really,
|
|
|
|
|
explicit as to which photo this is, and what key it is a UID on
|
|
|
|
|
since people may want to sign it. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (node = keyblock; node; node = node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
pk = node->pkt->pkt.public_key;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
count++;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if ((select_all || (node->flag & NODFLG_SELUID)) &&
|
|
|
|
|
uid->attribs != NULL)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
for (i = 0; i < uid->numattribs; i++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
byte type;
|
|
|
|
|
u32 size;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uid->attribs[i].type == ATTRIB_IMAGE &&
|
|
|
|
|
parse_image_header (&uid->attribs[i], &type, &size))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Displaying %s photo ID of size %ld for "
|
|
|
|
|
"key %s (uid %d)\n"),
|
|
|
|
|
image_type_to_string (type, 1),
|
|
|
|
|
(ulong) size, keystr_from_pk (pk), count);
|
2016-05-21 11:41:49 +02:00
|
|
|
|
show_photos (ctrl, &uid->attribs[i], 1, pk, uid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|