2003-06-05 09:14:21 +02:00
|
|
|
|
/* keyedit.c - keyedit stuff
|
2008-10-03 22:00:46 +02:00
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
2010-01-08 20:18:49 +01:00
|
|
|
|
* 2008, 2009, 2010 Free Software Foundation, Inc.
|
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
|
2007-07-04 21:49:40 +02:00
|
|
|
|
* along with this program; if not, see <http://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 <assert.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
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
#define JNLIB_NEED_LOG_LOGV
|
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"
|
2007-11-19 17:03:50 +01:00
|
|
|
|
#include "status.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "iobuf.h"
|
|
|
|
|
#include "keydb.h"
|
|
|
|
|
#include "photoid.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "trustdb.h"
|
|
|
|
|
#include "filter.h"
|
|
|
|
|
#include "ttyio.h"
|
|
|
|
|
#include "status.h"
|
|
|
|
|
#include "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"
|
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);
|
|
|
|
|
static void show_names (KBNODE keyblock, PKT_public_key * pk,
|
|
|
|
|
unsigned int flag, int with_prefs);
|
|
|
|
|
static void show_key_with_all_names (KBNODE keyblock, int only_marked,
|
|
|
|
|
int with_revoker, int with_fpr,
|
|
|
|
|
int with_subkeys, int with_prefs);
|
|
|
|
|
static void show_key_and_fingerprint (KBNODE keyblock);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name);
|
|
|
|
|
static void menu_deluid (KBNODE pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static int menu_delsig (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_clean (KBNODE keyblock, int self_only);
|
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);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
static int menu_expire (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_backsign (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_set_primary_uid (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_set_preferences (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_set_keyserver_url (const char *url, KBNODE pub_keyblock);
|
|
|
|
|
static int menu_set_notation (const char *string, KBNODE 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);
|
|
|
|
|
static int menu_select_key (KBNODE keyblock, int idx);
|
|
|
|
|
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);
|
|
|
|
|
static int menu_revsig (KBNODE keyblock);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
static int menu_revuid (KBNODE keyblock);
|
|
|
|
|
static int menu_revkey (KBNODE pub_keyblock);
|
|
|
|
|
static int menu_revsubkey (KBNODE pub_keyblock);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
static int enable_disable_key (KBNODE keyblock, int disable);
|
|
|
|
|
static void menu_showphoto (KBNODE keyblock);
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
#define NODFLG_BADSIG (1<<0) /* Bad signature. */
|
|
|
|
|
#define NODFLG_NOKEY (1<<1) /* No public key. */
|
|
|
|
|
#define NODFLG_SIGERR (1<<2) /* Other sig error. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
#define NODFLG_MARK_A (1<<4) /* Temporary mark. */
|
|
|
|
|
#define NODFLG_DELSIG (1<<5) /* To be deleted. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
#define NODFLG_SELUID (1<<8) /* Indicate the selected userid. */
|
|
|
|
|
#define NODFLG_SELKEY (1<<9) /* Indicate the selected key. */
|
|
|
|
|
#define NODFLG_SELSIG (1<<10) /* Indicate a selected signature. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
print_and_check_one_sig_colon (KBNODE keyblock, KBNODE 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 */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
switch ((rc = check_key_signature (keyblock, node, is_selfsig)))
|
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;
|
|
|
|
|
case G10ERR_BAD_SIGN:
|
|
|
|
|
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;
|
|
|
|
|
case G10ERR_NO_PUBKEY:
|
|
|
|
|
case G10ERR_UNU_PUBKEY:
|
|
|
|
|
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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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)
|
|
|
|
|
printf ("%d %d", sig->trust_depth, sig->trust_value);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Print information about a signature, check it and return true
|
|
|
|
|
* if the signature is okay. NODE must be a signature packet.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
print_and_check_one_sig (KBNODE keyblock, KBNODE node,
|
2003-06-05 09:14:21 +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)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
int rc, sigrc;
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
switch ((rc = check_key_signature (keyblock, node, is_selfsig)))
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR);
|
|
|
|
|
sigrc = '!';
|
|
|
|
|
break;
|
|
|
|
|
case G10ERR_BAD_SIGN:
|
|
|
|
|
node->flag = NODFLG_BADSIG;
|
|
|
|
|
sigrc = '-';
|
|
|
|
|
if (inv_sigs)
|
|
|
|
|
++ * inv_sigs;
|
|
|
|
|
break;
|
|
|
|
|
case G10ERR_NO_PUBKEY:
|
|
|
|
|
case G10ERR_UNU_PUBKEY:
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("%s%c%c %c%c%c%c%c%c %s %s",
|
|
|
|
|
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' +
|
|
|
|
|
sig->trust_depth : ' ', keystr (sig->keyid),
|
|
|
|
|
datestr_from_sig (sig));
|
|
|
|
|
if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
|
|
|
|
|
tty_printf (" %s", expirestr_from_sig (sig));
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
if (sigrc == '%')
|
|
|
|
|
tty_printf ("[%s] ", g10_errstr (rc));
|
|
|
|
|
else if (sigrc == '?')
|
|
|
|
|
;
|
|
|
|
|
else if (*is_selfsig)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (is_rev ? _("[revocation]") : _("[self-signature]"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t n;
|
|
|
|
|
char *p = get_user_id (sig->keyid, &n);
|
|
|
|
|
tty_print_utf8_string2 (p, n,
|
|
|
|
|
opt.screen_columns - keystrlen () - 26 -
|
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_SIG_EXPIRE) ? 11
|
|
|
|
|
: 0));
|
|
|
|
|
xfree (p);
|
|
|
|
|
}
|
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->flags.policy_url && (opt.list_options & LIST_SHOW_POLICY_URLS))
|
|
|
|
|
show_policy_url (sig, 3, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
|
|
|
|
show_notation (sig, 3, 0,
|
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
|
|
|
|
|
((opt.
|
|
|
|
|
list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
|
|
|
|
show_keyserver_url (sig, 3, 0);
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Check the keysigs and set the flags to indicate errors.
|
|
|
|
|
* Returns true if error found.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
check_all_keysigs (KBNODE keyblock, int only_selected)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE kbctx;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int inv_sigs = 0;
|
|
|
|
|
int no_key = 0;
|
|
|
|
|
int oth_err = 0;
|
|
|
|
|
int has_selfsig = 0;
|
|
|
|
|
int mis_selfsig = 0;
|
|
|
|
|
int selected = !only_selected;
|
|
|
|
|
int anyuid = 0;
|
|
|
|
|
|
|
|
|
|
for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
|
|
|
|
|
if (only_selected)
|
|
|
|
|
selected = (node->flag & NODFLG_SELUID);
|
|
|
|
|
if (selected)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("uid ");
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
if (anyuid && !has_selfsig)
|
|
|
|
|
mis_selfsig++;
|
|
|
|
|
has_selfsig = 0;
|
|
|
|
|
anyuid = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (selected && node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& ((node->pkt->pkt.signature->sig_class & ~3) == 0x10
|
|
|
|
|
|| node->pkt->pkt.signature->sig_class == 0x30))
|
|
|
|
|
{
|
|
|
|
|
int selfsig;
|
|
|
|
|
|
|
|
|
|
if (print_and_check_one_sig (keyblock, node, &inv_sigs,
|
|
|
|
|
&no_key, &oth_err, &selfsig, 0))
|
|
|
|
|
{
|
|
|
|
|
if (selfsig)
|
|
|
|
|
has_selfsig = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Hmmm: should we update the trustdb here? */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!has_selfsig)
|
|
|
|
|
mis_selfsig++;
|
|
|
|
|
if (inv_sigs == 1)
|
|
|
|
|
tty_printf (_("1 bad signature\n"));
|
|
|
|
|
else if (inv_sigs)
|
|
|
|
|
tty_printf (_("%d bad signatures\n"), inv_sigs);
|
|
|
|
|
if (no_key == 1)
|
|
|
|
|
tty_printf (_("1 signature not checked due to a missing key\n"));
|
|
|
|
|
else if (no_key)
|
|
|
|
|
tty_printf (_("%d signatures not checked due to missing keys\n"), no_key);
|
|
|
|
|
if (oth_err == 1)
|
|
|
|
|
tty_printf (_("1 signature not checked due to an error\n"));
|
|
|
|
|
else if (oth_err)
|
|
|
|
|
tty_printf (_("%d signatures not checked due to errors\n"), oth_err);
|
|
|
|
|
if (mis_selfsig == 1)
|
|
|
|
|
tty_printf (_("1 user ID without valid self-signature detected\n"));
|
|
|
|
|
else if (mis_selfsig)
|
|
|
|
|
tty_printf (_("%d user IDs without valid self-signatures detected\n"),
|
|
|
|
|
mis_selfsig);
|
|
|
|
|
|
|
|
|
|
return inv_sigs || no_key || oth_err || mis_selfsig;
|
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"
|
|
|
|
|
"A depth greater than 1 allows the key you are signing to make\n"
|
|
|
|
|
"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
|
|
|
|
|
|
|
|
|
/*
|
2010-04-21 18:26:17 +02:00
|
|
|
|
* Loop over all LOCUSR and and sign the uids after asking.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* If no user id is marked, all user ids will be signed;
|
|
|
|
|
* if some user_ids are marked those will be signed.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
|
|
|
|
|
int local, int nonrevocable, int trust, int interactive)
|
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;
|
|
|
|
|
int all_v3 = 1;
|
|
|
|
|
|
|
|
|
|
/* Are there any non-v3 sigs on this key already? */
|
|
|
|
|
if (PGP2)
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE &&
|
|
|
|
|
node->pkt->pkt.signature->version > 3)
|
|
|
|
|
{
|
|
|
|
|
all_v3 = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
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. */
|
2010-04-23 13:36:59 +02:00
|
|
|
|
rc = build_sk_list (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;
|
|
|
|
|
int force_v4 = 0, class = 0, selfsig = 0;
|
|
|
|
|
u32 duration = 0, timestamp = 0;
|
|
|
|
|
byte trust_depth = 0, trust_value = 0;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (local || nonrevocable || trust
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|| opt.cert_policy_url || opt.cert_notations)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
force_v4 = 1;
|
|
|
|
|
|
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])
|
|
|
|
|
{
|
|
|
|
|
selfsig = 1;
|
|
|
|
|
/* Do not force a v4 sig here, otherwise it would
|
|
|
|
|
be difficult to remake a v3 selfsig. If this
|
|
|
|
|
is a v3->v4 promotion case, then we set
|
|
|
|
|
force_v4 later anyway. */
|
|
|
|
|
force_v4 = 0;
|
|
|
|
|
}
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uidnode->pkt->pkt.user_id->is_revoked)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("User ID \"%s\" is revoked."), user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
else if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
/* 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;
|
|
|
|
|
tty_printf (_(" Unable to sign.\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (uidnode->pkt->pkt.user_id->is_expired)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("User ID \"%s\" is expired."), user);
|
2003-09-23 19:48:33 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
else if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
/* 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;
|
|
|
|
|
tty_printf (_(" Unable to sign.\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!uidnode->pkt->pkt.user_id->created && !selfsig)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("User ID \"%s\" is not self-signed."),
|
|
|
|
|
user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
/* 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;
|
|
|
|
|
tty_printf (_(" Unable to sign.\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uidnode && interactive && !yesreally)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("User ID \"%s\" is signable. "), user);
|
|
|
|
|
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? */
|
|
|
|
|
if (node->pkt->pkt.signature->version < 4 && selfsig)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("The self-signature on \"%s\"\n"
|
|
|
|
|
"is a PGP 2.x-style signature.\n"), user);
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
force_v4 = 1;
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Your current signature on \"%s\"\n"
|
|
|
|
|
"has expired.\n"), user);
|
|
|
|
|
|
|
|
|
|
if (cpr_get_answer_is_yes
|
|
|
|
|
("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. */
|
|
|
|
|
tty_printf (_("Your current signature on \"%s\"\n"
|
|
|
|
|
"is a local signature.\n"), user);
|
|
|
|
|
|
|
|
|
|
if (cpr_get_answer_is_yes
|
|
|
|
|
("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
|
|
|
|
|
* case we should allow to sign it again. */
|
|
|
|
|
if (!node->pkt->pkt.signature->flags.exportable && local)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
tty_printf
|
|
|
|
|
(_("\"%s\" was already locally signed by key %s\n"),
|
|
|
|
|
user, keystr_from_pk (pk));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
tty_printf (_("\"%s\" was already signed by key %s\n"),
|
|
|
|
|
user, keystr_from_pk (pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert
|
|
|
|
|
&& cpr_get_answer_is_yes ("sign_uid.dupe_okay",
|
2003-06-05 09:14:21 +02:00
|
|
|
|
_("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))
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Nothing to sign with key %s\n"),
|
|
|
|
|
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). */
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
show_key_with_all_names (keyblock, 1, 0, 1, 0, 0);
|
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (primary_pk->expiredate && !selfsig)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("This key has expired!"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_(" Unable to sign.\n"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("This key is due to expire on %s.\n"),
|
|
|
|
|
expirestr_from_pk (primary_pk));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.ask_cert_expire)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
force_v4 = 1;
|
|
|
|
|
}
|
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)
|
|
|
|
|
{
|
|
|
|
|
if (opt.ask_cert_expire)
|
|
|
|
|
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 (duration)
|
|
|
|
|
force_v4 = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Is --pgp2 on, it's a v3 key, all the sigs on the key are
|
|
|
|
|
currently v3 and we're about to sign it with a v4 sig? If
|
|
|
|
|
so, danger! */
|
|
|
|
|
if (PGP2 && all_v3 &&
|
|
|
|
|
(pk->version > 3 || force_v4) && primary_pk->version <= 3)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("You may not make an OpenPGP signature on a "
|
|
|
|
|
"PGP 2.x key while in --pgp2 mode.\n"));
|
|
|
|
|
tty_printf (_("This would make the key unusable in PGP 2.x.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.expert)
|
|
|
|
|
{
|
|
|
|
|
if (!cpr_get_answer_is_yes ("sign_uid.v4_on_v3_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
|
|
|
|
continue;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
all_v3 = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (selfsig)
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (opt.batch || !opt.ask_cert_level)
|
|
|
|
|
class = 0x10 + opt.def_cert_level;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *answer;
|
|
|
|
|
|
|
|
|
|
tty_printf (_("How carefully have you verified the key you are "
|
|
|
|
|
"about to sign actually belongs\nto the person "
|
|
|
|
|
"named above? If you don't know what to "
|
|
|
|
|
"answer, enter \"0\".\n"));
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_(" (0) I will not answer.%s\n"),
|
|
|
|
|
opt.def_cert_level == 0 ? " (default)" : "");
|
|
|
|
|
tty_printf (_(" (1) I have not checked at all.%s\n"),
|
|
|
|
|
opt.def_cert_level == 1 ? " (default)" : "");
|
|
|
|
|
tty_printf (_(" (2) I have done casual checking.%s\n"),
|
|
|
|
|
opt.def_cert_level == 2 ? " (default)" : "");
|
|
|
|
|
tty_printf (_(" (3) I have done very careful checking.%s\n"),
|
|
|
|
|
opt.def_cert_level == 3 ? " (default)" : "");
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
|
|
|
|
|
while (class == 0)
|
|
|
|
|
{
|
|
|
|
|
answer = cpr_get ("sign_uid.class",
|
|
|
|
|
_("Your selection? "
|
|
|
|
|
"(enter `?' for more information): "));
|
|
|
|
|
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
|
|
|
|
|
tty_printf (_("Invalid selection.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
xfree (answer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trust)
|
|
|
|
|
trustsig_prompt (&trust_value, &trust_depth, &trust_regexp);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
p = get_user_id_native (sk_keyid);
|
|
|
|
|
tty_printf (_("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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("WARNING: the signature will not be marked "
|
|
|
|
|
"as non-exportable.\n"));
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (nonrevocable)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("WARNING: the signature will not be marked "
|
|
|
|
|
"as non-revocable.\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (local)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
tty_printf
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(_("The signature will be marked as non-exportable.\n"));
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (nonrevocable)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n");
|
2011-02-04 12:57:53 +01:00
|
|
|
|
tty_printf
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(_("The signature will be marked as non-revocable.\n"));
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
switch (class)
|
|
|
|
|
{
|
|
|
|
|
case 0x11:
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("I have not checked this key at all.\n"));
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case 0x12:
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("I have checked this key casually.\n"));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x13:
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
tty_printf (_("I have checked this key very carefully.\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
|
|
|
|
|
if (opt.batch && opt.answer_yes)
|
|
|
|
|
;
|
|
|
|
|
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. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
reloop: /* (Must use this, because we are modifing the list.) */
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
assert (primary_pk);
|
|
|
|
|
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)
|
|
|
|
|
rc = make_keysig_packet (&sig, primary_pk,
|
|
|
|
|
node->pkt->pkt.user_id,
|
|
|
|
|
NULL,
|
|
|
|
|
pk,
|
|
|
|
|
0x13, 0, force_v4 ? 4 : 0, 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
|
|
|
|
|
rc = make_keysig_packet (&sig, primary_pk,
|
|
|
|
|
node->pkt->pkt.user_id,
|
|
|
|
|
NULL,
|
|
|
|
|
pk,
|
|
|
|
|
class, 0, force_v4 ? 4 : 0,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("signing failed: %s\n"), g10_errstr (rc));
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
leave:
|
|
|
|
|
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;
|
|
|
|
|
err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
|
|
|
|
|
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. */
|
|
|
|
|
for (any = 0, 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
|
|
|
|
|
2010-10-26 11:10:29 +02:00
|
|
|
|
desc = gpg_format_keydesc (pk, 0, 1);
|
|
|
|
|
err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce);
|
|
|
|
|
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)
|
|
|
|
|
? JNLIB_LOG_INFO : JNLIB_LOG_ERROR,
|
|
|
|
|
_("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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* There are some keys out (due to a bug in gnupg), where the sequence
|
|
|
|
|
* of the packets is wrong. This function fixes that.
|
|
|
|
|
* Returns: true if the keyblock has been fixed.
|
|
|
|
|
*
|
|
|
|
|
* Note: This function does not work if there is more than one user ID.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
fix_keyblock (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node, last, subkey;
|
|
|
|
|
int fixed = 0;
|
|
|
|
|
|
|
|
|
|
/* Locate key signatures of class 0x10..0x13 behind sub key packets. */
|
|
|
|
|
for (subkey = last = NULL, node = keyblock; node;
|
|
|
|
|
last = node, node = node->next)
|
|
|
|
|
{
|
|
|
|
|
switch (node->pkt->pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
|
case PKT_SECRET_SUBKEY:
|
|
|
|
|
if (!subkey)
|
|
|
|
|
subkey = last; /* Actually it is the one before the subkey. */
|
|
|
|
|
break;
|
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
|
if (subkey)
|
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
if (sig->sig_class >= 0x10 && sig->sig_class <= 0x13)
|
|
|
|
|
{
|
|
|
|
|
log_info (_("moving a key signature to the correct place\n"));
|
|
|
|
|
last->next = node->next;
|
|
|
|
|
node->next = subkey->next;
|
|
|
|
|
subkey->next = node;
|
|
|
|
|
node = last;
|
|
|
|
|
fixed = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
return fixed;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
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
|
|
|
|
|
/* Cannot be viewing the SK for this command */
|
|
|
|
|
#define KEYEDIT_NOT_SK 2
|
|
|
|
|
/* Must be viewing the SK for this command */
|
|
|
|
|
#define KEYEDIT_ONLY_SK 4
|
|
|
|
|
/* 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,
|
|
|
|
|
cmdEXPIRE, cmdBACKSIGN, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF,
|
|
|
|
|
cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
|
|
|
|
|
cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCHECKBKUPKEY,
|
|
|
|
|
cmdCLEAN, cmdMINIMIZE, cmdNOP
|
|
|
|
|
};
|
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")},
|
|
|
|
|
{ "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},
|
|
|
|
|
{ "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH,
|
|
|
|
|
N_("sign selected user IDs [* see below for related commands]")},
|
|
|
|
|
{ "s", cmdSIGN, KEYEDIT_NOT_SK, 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},
|
|
|
|
|
{ "adduid", cmdADDUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a user ID")},
|
|
|
|
|
{ "addphoto", cmdADDPHOTO, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("add a photo ID")},
|
|
|
|
|
{ "deluid", cmdDELUID, KEYEDIT_NOT_SK, N_("delete selected user IDs")},
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* delphoto is really deluid in disguise */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "delphoto", cmdDELUID, KEYEDIT_NOT_SK, NULL},
|
|
|
|
|
{ "addkey", cmdADDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a subkey")},
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef ENABLE_CARD_SUPPORT
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{ "addcardkey", cmdADDCARDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("add a key to a smartcard")},
|
|
|
|
|
{ "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
|
|
|
|
|
N_("move a key to a smartcard")},
|
|
|
|
|
{ "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
|
|
|
|
|
N_("move a backup key to a smartcard")},
|
|
|
|
|
{ "checkbkupkey", cmdCHECKBKUPKEY, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK, NULL},
|
|
|
|
|
#endif /*ENABLE_CARD_SUPPORT */
|
|
|
|
|
{ "delkey", cmdDELKEY, KEYEDIT_NOT_SK, N_("delete selected subkeys")},
|
|
|
|
|
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("add a revocation key")},
|
|
|
|
|
{ "delsig", cmdDELSIG, KEYEDIT_NOT_SK,
|
|
|
|
|
N_("delete signatures from the selected user IDs")},
|
|
|
|
|
{ "expire", cmdEXPIRE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("change the expiration date for the key or selected subkeys")},
|
|
|
|
|
{ "primary", cmdPRIMARY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("flag the selected user ID as primary")},
|
|
|
|
|
{ "toggle", cmdTOGGLE, KEYEDIT_NEED_SK,
|
|
|
|
|
N_("toggle between the secret and public key listings")},
|
|
|
|
|
{ "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "pref", cmdPREF, KEYEDIT_NOT_SK, N_("list preferences (expert)")},
|
|
|
|
|
{ "showpref", cmdSHOWPREF, KEYEDIT_NOT_SK, N_("list preferences (verbose)")},
|
|
|
|
|
{ "setpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("set preference list for the selected user IDs")},
|
|
|
|
|
{ "updpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "keyserver", cmdPREFKS, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("set the preferred keyserver URL for the selected user IDs")},
|
|
|
|
|
{ "notation", cmdNOTATION, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("set a notation for the selected user IDs")},
|
|
|
|
|
{ "passwd", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("change the passphrase")},
|
|
|
|
|
{ "password", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "trust", cmdTRUST, KEYEDIT_NOT_SK, N_("change the ownertrust")},
|
|
|
|
|
{ "revsig", cmdREVSIG, KEYEDIT_NOT_SK,
|
|
|
|
|
N_("revoke signatures on the selected user IDs")},
|
|
|
|
|
{ "revuid", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("revoke selected user IDs")},
|
|
|
|
|
{ "revphoto", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
|
|
|
|
|
{ "revkey", cmdREVKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
|
|
|
|
|
N_("revoke key or selected subkeys")},
|
|
|
|
|
{ "enable", cmdENABLEKEY, KEYEDIT_NOT_SK, N_("enable key")},
|
|
|
|
|
{ "disable", cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable key")},
|
|
|
|
|
{ "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")},
|
|
|
|
|
{ "clean", cmdCLEAN, KEYEDIT_NOT_SK,
|
|
|
|
|
N_("compact unusable user IDs and remove unusable signatures from key")},
|
|
|
|
|
{ "minimize", cmdMINIMIZE, KEYEDIT_NOT_SK,
|
|
|
|
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *answer = NULL;
|
|
|
|
|
int redisplay = 1;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
int toggle;
|
|
|
|
|
int have_commands = !!commands;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
non- W32 platforms it is run indirectly trough a call to
|
|
|
|
|
get_validity (). */
|
|
|
|
|
check_trustdb_stale ();
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* Get the public key */
|
2010-10-01 22:33:53 +02:00
|
|
|
|
err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (err)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
if (fix_keyblock (keyblock))
|
|
|
|
|
modified++;
|
|
|
|
|
if (collapse_uids (&keyblock))
|
|
|
|
|
modified++;
|
|
|
|
|
reorder_keyblock (keyblock);
|
|
|
|
|
/* We modified the keyblock, so let's make sure the flags are
|
|
|
|
|
right. */
|
|
|
|
|
if (modified)
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
|
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
|
|
|
|
{
|
2010-10-13 17:57:08 +02:00
|
|
|
|
have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (have_seckey && !quiet)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("Secret key is available.\n"));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
toggle = 0;
|
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)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
show_key_with_all_names (keyblock, 0, 1, 0, 1, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
redisplay = 0;
|
|
|
|
|
}
|
|
|
|
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
answer = cpr_get_no_help ("keyedit.prompt", "gpg> ");
|
|
|
|
|
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;
|
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Need the secret key to do this.\n"));
|
|
|
|
|
cmd = cmdNOP;
|
|
|
|
|
}
|
2010-04-21 18:26:17 +02:00
|
|
|
|
else if (((cmds[i].flags & KEYEDIT_NOT_SK) && have_seckey && toggle)
|
|
|
|
|
|| ((cmds[i].flags & KEYEDIT_ONLY_SK) && have_seckey
|
2006-04-19 13:26:11 +02:00
|
|
|
|
&& !toggle))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Please use the command \"toggle\" first.\n"));
|
|
|
|
|
cmd = cmdNOP;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
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++)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
|
|
|
|
|
; /* 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
|
|
|
|
|
(_("* The `sign' command may be prefixed with an `l' for local "
|
|
|
|
|
"signatures (lsign),\n"
|
|
|
|
|
" a `t' for trust signatures (tsign), an `nr' for "
|
|
|
|
|
"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:
|
|
|
|
|
show_key_and_fingerprint (keyblock);
|
|
|
|
|
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. */
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_select_key (keyblock, arg_number))
|
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:
|
|
|
|
|
check_all_keysigs (keyblock, count_selected_uids (keyblock));
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock)
|
|
|
|
|
&& !cpr_get_answer_is_yes ("keyedit.sign_all.okay",
|
2006-04-19 13:26:11 +02:00
|
|
|
|
_("Really sign all user IDs?"
|
|
|
|
|
" (y/N) ")))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
if (opt.interactive)
|
|
|
|
|
interactive = 1;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Hint: Select the user IDs to sign\n"));
|
|
|
|
|
have_commands = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
/* What sort of signing are we doing? */
|
|
|
|
|
if (!parse_sign_type
|
|
|
|
|
(answer, &localsig, &nonrevokesig, &trustsig))
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Unknown signature type `%s'\n"), answer);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sign_uids (keyblock, locusr, &modified,
|
|
|
|
|
localsig, nonrevokesig, trustsig, interactive);
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
toggle = !toggle;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdADDPHOTO:
|
|
|
|
|
if (RFC2440 || RFC1991 || PGP2)
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
tty_printf (_("This command is not allowed while in %s mode.\n"),
|
2010-04-20 20:19:19 +02:00
|
|
|
|
compliance_option_string ());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
photo = 1;
|
|
|
|
|
/* fall through */
|
|
|
|
|
case cmdADDUID:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_adduid (keyblock, photo, arg_string))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
update_trust = 1;
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
}
|
|
|
|
|
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)))
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
|
|
|
|
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)))
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
|
|
|
|
else if (menu_delsig (keyblock))
|
|
|
|
|
{
|
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:
|
2011-11-06 17:01:31 +01:00
|
|
|
|
if (!generate_subkeypair (ctrl, keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
merge_keys_and_selfsig (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:
|
2010-11-17 14:21:24 +01:00
|
|
|
|
if (!card_generate_subkey (keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
modified = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
merge_keys_and_selfsig (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
|
|
|
|
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* Only the secret key has been modified; thus
|
|
|
|
|
there is no need to set the modified flag. */
|
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:
|
|
|
|
|
case cmdCHECKBKUPKEY:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_debug ("FIXME: This needs to be changed\n");
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
const char *fname;
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
IOBUF a;
|
|
|
|
|
|
|
|
|
|
fname = arg_string;
|
|
|
|
|
if (!*fname)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Command expects a filename argument\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
if (!a)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Can't open `%s': %s\n"),
|
|
|
|
|
fname, strerror (errno));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse and check that file. */
|
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
|
|
|
|
init_packet (pkt);
|
2010-04-21 18:26:17 +02:00
|
|
|
|
err = parse_packet (a, pkt);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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)
|
2010-04-21 18:26:17 +02:00
|
|
|
|
err = G10ERR_NO_SECKEY;
|
|
|
|
|
if (err)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Error reading backup key from `%s': %s\n"),
|
2010-04-21 18:26:17 +02:00
|
|
|
|
fname, g10_errstr (err));
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_packet (pkt);
|
|
|
|
|
xfree (pkt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
node = new_kbnode (pkt);
|
|
|
|
|
|
|
|
|
|
if (cmd == cmdCHECKBKUPKEY)
|
|
|
|
|
{
|
2010-11-17 14:21:24 +01:00
|
|
|
|
/* PKT_public_key *sk = node->pkt->pkt.secret_key; */
|
|
|
|
|
/* switch (is_secret_key_protected (sk)) */
|
|
|
|
|
/* { */
|
|
|
|
|
/* case 0: /\* Not protected. *\/ */
|
|
|
|
|
/* tty_printf (_("This key is not protected.\n")); */
|
|
|
|
|
/* break; */
|
|
|
|
|
/* case -1: */
|
|
|
|
|
/* log_error (_("unknown key protection algorithm\n")); */
|
|
|
|
|
/* break; */
|
|
|
|
|
/* default: */
|
|
|
|
|
/* if (sk->protect.s2k.mode == 1001) */
|
|
|
|
|
/* tty_printf (_("Secret parts of key" */
|
|
|
|
|
/* " are not available.\n")); */
|
|
|
|
|
/* if (sk->protect.s2k.mode == 1002) */
|
|
|
|
|
/* tty_printf (_("Secret parts of key" */
|
|
|
|
|
/* " are stored on-card.\n")); */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* else */
|
|
|
|
|
/* check_secret_key (sk, 0); */
|
2010-11-17 14:21:24 +01:00
|
|
|
|
/* } */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
else /* Store it. */
|
|
|
|
|
{
|
|
|
|
|
if (card_store_subkey (node, 0))
|
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
/* FIXME:sec_modified = 1;*/
|
2010-04-20 20:19:19 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
release_kbnode (node);
|
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
|
|
|
|
|
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)))
|
|
|
|
|
tty_printf (_("You must select at least one key.\n"));
|
|
|
|
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
merge_keys_and_selfsig (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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdREVUID:
|
|
|
|
|
{
|
|
|
|
|
int n1;
|
|
|
|
|
|
|
|
|
|
if (!(n1 = count_selected_uids (keyblock)))
|
|
|
|
|
tty_printf (_("You must select at least one user ID.\n"));
|
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) ")))
|
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_revuid (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
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_revkey (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
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_revsubkey (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)
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdEXPIRE:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_expire (keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
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 cmdBACKSIGN:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_backsign (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:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_set_primary_uid (keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_key_with_all_names (keyblock, 0, 0, 0, 1, 0);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
if (edit_ownertrust (find_kbnode (keyblock,
|
|
|
|
|
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;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdPREF:
|
|
|
|
|
{
|
|
|
|
|
int count = count_selected_uids (keyblock);
|
|
|
|
|
assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
show_names (keyblock, keyblock->pkt->pkt.public_key,
|
|
|
|
|
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);
|
|
|
|
|
assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
show_names (keyblock, keyblock->pkt->pkt.public_key,
|
|
|
|
|
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
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (menu_set_preferences (keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
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:
|
|
|
|
|
if (menu_set_keyserver_url (*arg_string ? arg_string : NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
modified = 1;
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdNOTATION:
|
|
|
|
|
if (menu_set_notation (*arg_string ? arg_string : NULL,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
keyblock))
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (keyblock);
|
|
|
|
|
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:
|
|
|
|
|
if (menu_revsig (keyblock))
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdENABLEKEY:
|
|
|
|
|
case cmdDISABLEKEY:
|
|
|
|
|
if (enable_disable_key (keyblock, cmd == cmdDISABLEKEY))
|
|
|
|
|
{
|
|
|
|
|
redisplay = 1;
|
|
|
|
|
modified = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdSHOWPHOTO:
|
|
|
|
|
menu_showphoto (keyblock);
|
|
|
|
|
break;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdCLEAN:
|
|
|
|
|
if (menu_clean (keyblock, 0))
|
|
|
|
|
redisplay = modified = 1;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
case cmdMINIMIZE:
|
|
|
|
|
if (menu_clean (keyblock, 1))
|
|
|
|
|
redisplay = modified = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case cmdQUIT:
|
|
|
|
|
if (have_commands)
|
|
|
|
|
goto leave;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (!modified)
|
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
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
/* fall thru */
|
|
|
|
|
case cmdSAVE:
|
2010-04-21 18:26:17 +02:00
|
|
|
|
if (modified)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
err = keydb_update_keyblock (kdbhd, keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("update failed: %s\n"), g10_errstr (err));
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
revalidation_mark ();
|
|
|
|
|
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:
|
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;
|
|
|
|
|
}
|
2010-10-26 11:10:29 +02:00
|
|
|
|
err = getkey_byname (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)
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_info ("error changing the passphrase for `%s': %s\n",
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
const prefitem_t fake = { 0, 0 };
|
|
|
|
|
const prefitem_t *prefs;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!uid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (uid->prefs)
|
|
|
|
|
prefs = uid->prefs;
|
|
|
|
|
else if (verbose)
|
|
|
|
|
prefs = &fake;
|
|
|
|
|
else
|
|
|
|
|
return;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (verbose)
|
|
|
|
|
{
|
|
|
|
|
int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0;
|
|
|
|
|
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("Cipher: "));
|
|
|
|
|
for (i = any = 0; prefs[i].type; i++)
|
|
|
|
|
{
|
|
|
|
|
if (prefs[i].type == PREFTYPE_SYM)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
any = 1;
|
|
|
|
|
/* We don't want to display strings for experimental algos */
|
|
|
|
|
if (!openpgp_cipher_test_algo (prefs[i].value)
|
|
|
|
|
&& prefs[i].value < 100)
|
|
|
|
|
tty_printf ("%s", openpgp_cipher_algo_name (prefs[i].value));
|
|
|
|
|
else
|
|
|
|
|
tty_printf ("[%d]", prefs[i].value);
|
|
|
|
|
if (prefs[i].value == CIPHER_ALGO_3DES)
|
|
|
|
|
des_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!des_seen)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
|
|
|
|
|
}
|
|
|
|
|
tty_printf ("\n ");
|
|
|
|
|
tty_printf (_("Digest: "));
|
|
|
|
|
for (i = any = 0; prefs[i].type; i++)
|
|
|
|
|
{
|
|
|
|
|
if (prefs[i].type == PREFTYPE_HASH)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
any = 1;
|
|
|
|
|
/* We don't want to display strings for experimental algos */
|
|
|
|
|
if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100)
|
|
|
|
|
tty_printf ("%s", gcry_md_algo_name (prefs[i].value));
|
|
|
|
|
else
|
|
|
|
|
tty_printf ("[%d]", prefs[i].value);
|
|
|
|
|
if (prefs[i].value == DIGEST_ALGO_SHA1)
|
|
|
|
|
sha1_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!sha1_seen)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1));
|
|
|
|
|
}
|
|
|
|
|
tty_printf ("\n ");
|
|
|
|
|
tty_printf (_("Compression: "));
|
|
|
|
|
for (i = any = 0; prefs[i].type; i++)
|
|
|
|
|
{
|
|
|
|
|
if (prefs[i].type == PREFTYPE_ZIP)
|
|
|
|
|
{
|
|
|
|
|
const char *s = compress_algo_to_string (prefs[i].value);
|
|
|
|
|
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
any = 1;
|
|
|
|
|
/* We don't want to display strings for experimental algos */
|
|
|
|
|
if (s && prefs[i].value < 100)
|
|
|
|
|
tty_printf ("%s", s);
|
|
|
|
|
else
|
|
|
|
|
tty_printf ("[%d]", prefs[i].value);
|
|
|
|
|
if (prefs[i].value == COMPRESS_ALGO_NONE)
|
|
|
|
|
uncomp_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!uncomp_seen)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_ZIP));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
tty_printf (", ");
|
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
|
|
|
|
|
}
|
|
|
|
|
if (uid->flags.mdc || !uid->flags.ks_modify)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("\n ");
|
|
|
|
|
tty_printf (_("Features: "));
|
|
|
|
|
any = 0;
|
|
|
|
|
if (uid->flags.mdc)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("MDC");
|
|
|
|
|
any = 1;
|
|
|
|
|
}
|
|
|
|
|
if (!uid->flags.ks_modify)
|
|
|
|
|
{
|
|
|
|
|
if (any)
|
|
|
|
|
tty_printf (", ");
|
|
|
|
|
tty_printf (_("Keyserver no-modify"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tty_printf ("\n");
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
pref_ks = parse_sig_subpkt (selfsig->hashed,
|
|
|
|
|
SIGSUBPKT_PREF_KS, &pref_ks_len);
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
for (i = 0; prefs[i].type; i++)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
|
|
|
|
|
prefs[i].type == PREFTYPE_HASH ? 'H' :
|
|
|
|
|
prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
|
|
|
|
|
prefs[i].value);
|
|
|
|
|
}
|
|
|
|
|
if (uid->flags.mdc)
|
|
|
|
|
tty_printf (" [mdc]");
|
|
|
|
|
if (!uid->flags.ks_modify)
|
|
|
|
|
tty_printf (" [no-ks-modify]");
|
|
|
|
|
tty_printf ("\n");
|
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
|
|
|
|
|
show_key_with_all_names_colon (KBNODE keyblock)
|
|
|
|
|
{
|
|
|
|
|
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;
|
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);
|
|
|
|
|
|
|
|
|
|
fputs (node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub:" : "sub:",
|
|
|
|
|
stdout);
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (!pk->flags.valid)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
putchar ('i');
|
2010-10-20 13:33:50 +02:00
|
|
|
|
else if (pk->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
putchar ('r');
|
|
|
|
|
else if (pk->has_expired)
|
|
|
|
|
putchar ('e');
|
|
|
|
|
else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
int trust = get_validity_info (pk, NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (trust == 'u')
|
|
|
|
|
ulti_hack = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
putchar (trust);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
printf (":%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);
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
&& !(opt.fast_list_mode || opt.no_expensive_trust_checks))
|
|
|
|
|
putchar (get_ownertrust_info (pk));
|
|
|
|
|
putchar (':');
|
|
|
|
|
putchar (':');
|
|
|
|
|
putchar (':');
|
|
|
|
|
/* Print capabilities. */
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
|
|
|
putchar ('e');
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_SIG))
|
|
|
|
|
putchar ('s');
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_CERT))
|
|
|
|
|
putchar ('c');
|
|
|
|
|
if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH))
|
|
|
|
|
putchar ('a');
|
|
|
|
|
putchar ('\n');
|
|
|
|
|
|
2010-04-23 13:36:59 +02:00
|
|
|
|
print_fingerprint (pk, 0);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
print_revokers (pk);
|
|
|
|
|
}
|
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)
|
|
|
|
|
printf ("uat:");
|
|
|
|
|
else
|
|
|
|
|
printf ("uid:");
|
|
|
|
|
|
|
|
|
|
if (uid->is_revoked)
|
|
|
|
|
printf ("r::::::::");
|
|
|
|
|
else if (uid->is_expired)
|
|
|
|
|
printf ("e::::::::");
|
|
|
|
|
else if (opt.fast_list_mode || opt.no_expensive_trust_checks)
|
|
|
|
|
printf ("::::::::");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int uid_validity;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (primary && !ulti_hack)
|
|
|
|
|
uid_validity = get_validity_info (primary, uid);
|
|
|
|
|
else
|
|
|
|
|
uid_validity = 'u';
|
|
|
|
|
printf ("%c::::::::", uid_validity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (uid->attrib_data)
|
|
|
|
|
printf ("%u %lu", uid->numattribs, uid->attrib_len);
|
|
|
|
|
else
|
|
|
|
|
es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
|
|
|
|
|
|
|
|
|
|
putchar (':');
|
|
|
|
|
/* signature class */
|
|
|
|
|
putchar (':');
|
|
|
|
|
/* capabilities */
|
|
|
|
|
putchar (':');
|
|
|
|
|
/* preferences */
|
|
|
|
|
if (pk_version > 3 || uid->selfsigversion > 3)
|
|
|
|
|
{
|
|
|
|
|
const prefitem_t *prefs = uid->prefs;
|
|
|
|
|
|
|
|
|
|
for (j = 0; prefs && prefs[j].type; j++)
|
|
|
|
|
{
|
|
|
|
|
if (j)
|
|
|
|
|
putchar (' ');
|
|
|
|
|
printf ("%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' :
|
|
|
|
|
prefs[j].type == PREFTYPE_HASH ? 'H' :
|
|
|
|
|
prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?',
|
|
|
|
|
prefs[j].value);
|
|
|
|
|
}
|
|
|
|
|
if (uid->flags.mdc)
|
|
|
|
|
printf (",mdc");
|
|
|
|
|
if (!uid->flags.ks_modify)
|
|
|
|
|
printf (",no-ks-modify");
|
|
|
|
|
}
|
|
|
|
|
putchar (':');
|
|
|
|
|
/* flags */
|
|
|
|
|
printf ("%d,", i);
|
|
|
|
|
if (uid->is_primary)
|
|
|
|
|
putchar ('p');
|
|
|
|
|
if (uid->is_revoked)
|
|
|
|
|
putchar ('r');
|
|
|
|
|
if (uid->is_expired)
|
|
|
|
|
putchar ('e');
|
|
|
|
|
if ((node->flag & NODFLG_SELUID))
|
|
|
|
|
putchar ('s');
|
|
|
|
|
if ((node->flag & NODFLG_MARK_A))
|
|
|
|
|
putchar ('m');
|
|
|
|
|
putchar (':');
|
|
|
|
|
putchar ('\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_names (KBNODE keyblock, PKT_public_key * pk, unsigned int flag,
|
|
|
|
|
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)
|
|
|
|
|
tty_printf ("%s ", uid_trust_string_fixed (pk, uid));
|
|
|
|
|
|
|
|
|
|
if (flag & NODFLG_MARK_A)
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
else if (node->flag & NODFLG_SELUID)
|
|
|
|
|
tty_printf ("(%d)* ", i);
|
|
|
|
|
else if (uid->is_primary)
|
|
|
|
|
tty_printf ("(%d). ", i);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("(%d) ", i);
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("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
|
|
|
|
|
|
|
|
|
/*
|
2003-06-05 09:14:21 +02: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 dont display the index number
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker,
|
|
|
|
|
int with_fpr, int with_subkeys, int with_prefs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
|
|
|
|
int do_warn = 0;
|
|
|
|
|
PKT_public_key *primary = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (opt.with_colons)
|
|
|
|
|
{
|
|
|
|
|
show_key_with_all_names_colon (keyblock);
|
|
|
|
|
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;
|
|
|
|
|
const char *otrust = "err", *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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
trust = get_validity_string (pk, NULL);
|
|
|
|
|
otrust = get_ownertrust_string (pk);
|
|
|
|
|
|
|
|
|
|
/* Show a warning once */
|
|
|
|
|
if (!did_warn
|
|
|
|
|
&& (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK))
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
char *user = get_user_id_string_native (pk->revoked.keyid);
|
2010-10-01 22:33:53 +02:00
|
|
|
|
tty_printf (_("The following key was revoked on"
|
|
|
|
|
" %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);
|
|
|
|
|
keyid_from_fingerprint (pk->revkey[i].fpr,
|
|
|
|
|
MAX_FINGERPRINT_LEN, r_keyid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
user = get_user_id_string_native (r_keyid);
|
|
|
|
|
tty_printf (_("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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("(sensitive)"));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
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);
|
|
|
|
|
tty_printf ("%s%c %4u%c/%s ",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" :
|
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" :
|
|
|
|
|
node->pkt->pkttype == PKT_SECRET_KEY ? "sec" : "ssb",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(node->flag & NODFLG_SELKEY) ? '*' : ' ',
|
|
|
|
|
nbits_from_pk (pk),
|
|
|
|
|
pubkey_letter (pk->pubkey_algo), keystr (pk->keyid));
|
|
|
|
|
|
|
|
|
|
tty_printf (_("created: %s"), datestr_from_pk (pk));
|
|
|
|
|
tty_printf (" ");
|
2010-10-20 13:33:50 +02:00
|
|
|
|
if (pk->flags.revoked)
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (_("revoked: %s"), revokestr_from_pk (pk));
|
|
|
|
|
else if (pk->has_expired)
|
|
|
|
|
tty_printf (_("expired: %s"), expirestr_from_pk (pk));
|
|
|
|
|
else
|
|
|
|
|
tty_printf (_("expires: %s"), expirestr_from_pk (pk));
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("usage: %s"), usagestr_from_pk (pk));
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if (pk->seckey_info
|
|
|
|
|
&& pk->seckey_info->is_protected
|
|
|
|
|
&& pk->seckey_info->s2k.mode == 1002)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("card-no: "));
|
|
|
|
|
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)
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf ("%02X", pk->seckey_info->iv[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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++)
|
|
|
|
|
tty_printf ("%02X", pk->seckey_info->iv[i]);
|
|
|
|
|
}
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("%*s", (int) keystrlen () + 13, "");
|
|
|
|
|
/* Ownertrust is only meaningful for the PGP or
|
|
|
|
|
classic trust models */
|
|
|
|
|
if (opt.trust_model == TM_PGP
|
|
|
|
|
|| opt.trust_model == TM_CLASSIC)
|
|
|
|
|
{
|
|
|
|
|
int width = 14 - strlen (otrust);
|
|
|
|
|
if (width <= 0)
|
|
|
|
|
width = 1;
|
|
|
|
|
tty_printf (_("trust: %s"), otrust);
|
|
|
|
|
tty_printf ("%*s", width, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tty_printf (_("validity: %s"), trust);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
&& (get_ownertrust (pk) & TRUST_FLAG_DISABLED))
|
|
|
|
|
{
|
|
|
|
|
tty_printf ("*** ");
|
|
|
|
|
tty_printf (_("This key has been disabled"));
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
{
|
2010-04-23 13:36:59 +02:00
|
|
|
|
print_fingerprint (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
|
|
|
|
show_names (keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (do_warn)
|
|
|
|
|
tty_printf (_("Please note that the shown key validity"
|
|
|
|
|
" is not necessarily correct\n"
|
|
|
|
|
"unless you restart the program.\n"));
|
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
|
2003-06-05 09:14:21 +02: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.*/
|
|
|
|
|
void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_basic_key_info (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
/* Note, we use the same format string as in other show
|
|
|
|
|
functions to make the translation job easier. */
|
|
|
|
|
tty_printf ("%s %4u%c/%s ",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" :
|
|
|
|
|
node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" :
|
|
|
|
|
node->pkt->pkttype == PKT_SECRET_KEY ? "sec" :"ssb",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
nbits_from_pk (pk),
|
|
|
|
|
pubkey_letter (pk->pubkey_algo), keystr_from_pk (pk));
|
|
|
|
|
tty_printf (_("created: %s"), datestr_from_pk (pk));
|
|
|
|
|
tty_printf (" ");
|
|
|
|
|
tty_printf (_("expires: %s"), expirestr_from_pk (pk));
|
|
|
|
|
tty_printf ("\n");
|
2010-04-23 13:36:59 +02:00
|
|
|
|
print_fingerprint (pk, 3);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The 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 (" ");
|
|
|
|
|
if (uid->is_revoked)
|
|
|
|
|
tty_printf ("[%s] ", _("revoked"));
|
|
|
|
|
else if (uid->is_expired)
|
|
|
|
|
tty_printf ("[%s] ", _("expired"));
|
|
|
|
|
tty_print_utf8_string (uid->name, uid->len);
|
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
show_key_and_fingerprint (KBNODE keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
PKT_public_key *pk = NULL;
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf ("pub %4u%c/%s %s ",
|
|
|
|
|
nbits_from_pk (pk),
|
|
|
|
|
pubkey_letter (pk->pubkey_algo),
|
|
|
|
|
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)
|
2010-04-23 13:36:59 +02:00
|
|
|
|
print_fingerprint (pk, 2);
|
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++;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (node->pkt->pkt.user_id->is_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
|
|
|
|
|
|
|
|
|
/*
|
2010-04-21 18:26:17 +02:00
|
|
|
|
* Ask for a new user id, add the self-signature and update the keyblock.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Return true if there is a new user id
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_adduid (KBNODE pub_keyblock, int photo, const char *photo_name)
|
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
|
|
|
|
|
|
|
|
|
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;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
uid = generate_photo_id (pk, photo_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
uid = generate_user_id (pub_keyblock);
|
|
|
|
|
if (!uid)
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
err = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x13, 0, 0, 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
|
|
|
|
{
|
2010-04-21 18:26:17 +02:00
|
|
|
|
log_error ("signing failed: %s\n", g10_errstr (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;
|
|
|
|
|
pkt->pkt.signature = copy_signature (NULL, sig);
|
|
|
|
|
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 */
|
|
|
|
|
if (!node->pkt->pkt.user_id->is_revoked)
|
|
|
|
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
menu_delsig (KBNODE 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)
|
|
|
|
|
valid = print_and_check_one_sig_colon (pub_keyblock, node,
|
|
|
|
|
&inv_sig, &no_key,
|
|
|
|
|
&other_err, &selfsig, 1);
|
|
|
|
|
else
|
|
|
|
|
valid = print_and_check_one_sig (pub_keyblock, node,
|
|
|
|
|
&inv_sig, &no_key, &other_err,
|
|
|
|
|
&selfsig, 1);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
tty_printf (changed == 1 ? _("Deleted %d signature.\n")
|
|
|
|
|
: _("Deleted %d signatures.\n"), 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
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
menu_clean (KBNODE keyblock, int self_only)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
KBNODE uidnode;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int modified = 0, 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);
|
|
|
|
|
|
|
|
|
|
clean_one_uid (keyblock, uidnode, opt.verbose, self_only, &uids,
|
|
|
|
|
&sigs);
|
|
|
|
|
if (uids)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
const char *reason;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uidnode->pkt->pkt.user_id->is_revoked)
|
|
|
|
|
reason = _("revoked");
|
|
|
|
|
else if (uidnode->pkt->pkt.user_id->is_expired)
|
|
|
|
|
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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (sigs == 1 ?
|
|
|
|
|
_("User ID \"%s\": %d signature removed\n") :
|
|
|
|
|
_("User ID \"%s\": %d signatures removed\n"),
|
|
|
|
|
user, sigs);
|
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
|
|
|
|
}
|
|
|
|
|
else
|
2006-12-03 07:27:49 +01:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
tty_printf (self_only == 1 ?
|
|
|
|
|
_("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;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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;
|
2010-10-01 22:33:53 +02:00
|
|
|
|
rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 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,
|
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
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);
|
|
|
|
|
if (fprlen != 20)
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
sprintf (buf, "%08lX%08lX",
|
|
|
|
|
(ulong) pk->keyid[0], (ulong) pk->keyid[1]);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
print_pubkey_info (NULL, revoker_pk);
|
2010-04-23 13:36:59 +02:00
|
|
|
|
print_fingerprint (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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The 1F signature must be at least v4 to carry the revocation key
|
|
|
|
|
subpacket. */
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x1F, 0, 4, 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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error ("signing failed: %s\n", g10_errstr (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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_expire (KBNODE pub_keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
int n1, signumber, rc;
|
|
|
|
|
u32 expiredate;
|
|
|
|
|
int mainkey = 0;
|
|
|
|
|
PKT_public_key *main_pk, *sub_pk;
|
|
|
|
|
PKT_user_id *uid;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
|
|
n1 = count_selected_keys (pub_keyblock);
|
|
|
|
|
if (n1 > 1)
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Please select at most one subkey.\n"));
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (n1)
|
|
|
|
|
tty_printf (_("Changing expiration time for a subkey.\n"));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tty_printf (_("Changing expiration time for the primary key.\n"));
|
|
|
|
|
mainkey = 1;
|
|
|
|
|
no_primary_warning (pub_keyblock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
expiredate = ask_expiredate ();
|
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
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& (node->flag & NODFLG_SELKEY))
|
|
|
|
|
{
|
|
|
|
|
sub_pk = node->pkt->pkt.public_key;
|
|
|
|
|
sub_pk->expiredate = expiredate;
|
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
|
|
|
|
|
&& (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)
|
|
|
|
|
{
|
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++;
|
|
|
|
|
|
|
|
|
|
if ((mainkey && main_pk->version < 4)
|
|
|
|
|
|| (!mainkey && sub_pk->version < 4))
|
|
|
|
|
{
|
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"));
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (mainkey)
|
|
|
|
|
rc = update_keysig_packet (&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 =
|
|
|
|
|
update_keysig_packet (&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",
|
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
return 0;
|
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;
|
|
|
|
|
free_packet (node->pkt);
|
|
|
|
|
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;
|
|
|
|
|
return 1;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_backsign (KBNODE 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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
merge_keys_and_selfsig (pub_keyblock);
|
|
|
|
|
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
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = make_backsig (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;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = update_keysig_packet (&newsig, sig_pk->pkt->pkt.signature,
|
|
|
|
|
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;
|
|
|
|
|
free_packet (sig_pk->pkt);
|
|
|
|
|
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",
|
|
|
|
|
g10_errstr (rc));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error ("make_backsig failed: %s\n", g10_errstr (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
|
|
|
|
|
* all other primary uid flags. For this to work with have to update
|
|
|
|
|
* all the signature timestamps. If we would do this with the current
|
|
|
|
|
* time, we lose quite a lot of information, so we use a a kludge to
|
|
|
|
|
* do this: Just increment the timestamp by one second which is
|
|
|
|
|
* sufficient to updated a signature during import.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_set_primary_uid (KBNODE 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. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
p = parse_sig_subpkt (sig->hashed,
|
|
|
|
|
SIGSUBPKT_PRIMARY_UID, NULL);
|
|
|
|
|
if (!p)
|
|
|
|
|
p = parse_sig_subpkt (sig->unhashed,
|
|
|
|
|
SIGSUBPKT_PRIMARY_UID, NULL);
|
|
|
|
|
if (p && *p) /* yes */
|
|
|
|
|
action = selected ? 0 : -1;
|
|
|
|
|
else /* no */
|
|
|
|
|
action = selected ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
|
{
|
|
|
|
|
int rc = update_keysig_packet (&newsig, sig,
|
|
|
|
|
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",
|
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* replace the packet */
|
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
|
|
|
|
free_packet (node->pkt);
|
|
|
|
|
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
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Set preferences to new values for the selected user IDs
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_set_preferences (KBNODE 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, select_all;
|
|
|
|
|
int modified = 0;
|
|
|
|
|
|
|
|
|
|
no_primary_warning (pub_keyblock);
|
|
|
|
|
|
|
|
|
|
select_all = !count_selected_uids (pub_keyblock);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
rc = update_keysig_packet (&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",
|
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* replace the packet */
|
|
|
|
|
newpkt = xmalloc_clear (sizeof *newpkt);
|
|
|
|
|
newpkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
newpkt->pkt.signature = newsig;
|
|
|
|
|
free_packet (node->pkt);
|
|
|
|
|
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
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_set_keyserver_url (const char *url, KBNODE 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
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (ascii_strcasecmp (answer, "none") == 0)
|
|
|
|
|
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 */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
keyserver = parse_keyserver_uri (answer, 1, NULL, 0);
|
|
|
|
|
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;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
p = parse_sig_subpkt (sig->hashed, 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) ")))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
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. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = update_keysig_packet (&newsig, sig,
|
|
|
|
|
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",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
xfree (uri);
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_packet (node->pkt);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_set_notation (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;
|
|
|
|
|
|
|
|
|
|
rc = update_keysig_packet (&newsig, sig,
|
|
|
|
|
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",
|
2010-04-20 20:19:19 +02:00
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
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;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
free_packet (node->pkt);
|
|
|
|
|
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;
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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
|
2009-09-04 13:52:03 +02:00
|
|
|
|
menu_select_key (KBNODE keyblock, int idx)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2009-09-04 13:52:03 +02:00
|
|
|
|
KBNODE node;
|
|
|
|
|
int i;
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
ask_revoke_sig (KBNODE keyblock, KBNODE 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
|
|
|
|
|
{
|
|
|
|
|
printf ("uid:::::::::");
|
|
|
|
|
es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
printf ("\n");
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
print_and_check_one_sig_colon (keyblock, node, NULL, NULL, NULL, NULL,
|
|
|
|
|
1);
|
|
|
|
|
}
|
|
|
|
|
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
|
2010-04-20 20:19:19 +02:00
|
|
|
|
menu_revsig (KBNODE 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;
|
|
|
|
|
|
|
|
|
|
assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
|
|
|
|
|
/* 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),
|
2010-04-21 18:26:17 +02:00
|
|
|
|
have_secret_key_with_kid (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),
|
2010-04-21 18:26:17 +02:00
|
|
|
|
have_secret_key_with_kid (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;
|
|
|
|
|
ask_revoke_sig (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 */
|
|
|
|
|
reloop: /* (must use this, because we are modifing the list) */
|
|
|
|
|
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);
|
|
|
|
|
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);
|
|
|
|
|
if (get_seckey (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
|
|
|
|
}
|
2010-04-20 20:19:19 +02:00
|
|
|
|
rc = make_keysig_packet (&sig, primary_pk,
|
|
|
|
|
unode->pkt->pkt.user_id,
|
2010-04-21 18:26:17 +02:00
|
|
|
|
NULL, signerkey, 0x30, 0, 0, 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)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("signing failed: %s\n"), g10_errstr (rc));
|
|
|
|
|
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])
|
|
|
|
|
unode->pkt->pkt.user_id->is_revoked = 1;
|
|
|
|
|
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
|
|
|
|
|
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
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_revuid (KBNODE 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;
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
reloop: /* (better this way because we are modifing 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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
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
|
|
|
|
if (uid->is_revoked)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
char *user = utf8_to_native (uid->name, uid->len, 0);
|
|
|
|
|
log_info (_("user ID \"%s\" is already revoked\n"), user);
|
|
|
|
|
xfree (user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
struct sign_attrib attrib;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
u32 timestamp = make_timestamp ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (uid->created >= timestamp)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_info (_("WARNING: a user ID signature is dated %d"
|
|
|
|
|
" seconds in the future\n"),
|
|
|
|
|
uid->created - timestamp);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
timestamp = uid->created + 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-20 20:19:19 +02:00
|
|
|
|
memset (&attrib, 0, sizeof attrib);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
attrib.reason = reason;
|
|
|
|
|
|
|
|
|
|
node->flag &= ~NODFLG_SELUID;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
(reason == NULL) ? 3 : 0, timestamp, 0,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
sign_mk_attrib, &attrib, NULL);
|
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 (_("signing failed: %s\n"), g10_errstr (rc));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
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 (node, new_kbnode (pkt), 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* If the trustdb has an entry for this key+uid then the
|
|
|
|
|
trustdb needs an update. */
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (!update_trust
|
|
|
|
|
&& (get_validity (pk, uid) & TRUST_MASK) >=
|
|
|
|
|
TRUST_UNDEFINED)
|
|
|
|
|
update_trust = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
changed = 1;
|
2010-04-20 20:19:19 +02:00
|
|
|
|
node->pkt->pkt.user_id->is_revoked = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
goto reloop;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_revkey (KBNODE 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;
|
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = make_keysig_packet (&sig, pk, NULL, NULL, pk,
|
2010-04-20 20:19:19 +02:00
|
|
|
|
0x20, 0, opt.force_v4_certs ? 4 : 0, 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
|
|
|
|
{
|
2010-04-20 20:19:19 +02:00
|
|
|
|
log_error (_("signing failed: %s\n"), g10_errstr (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
|
2010-04-21 18:26:17 +02:00
|
|
|
|
menu_revsubkey (KBNODE 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
|
|
|
|
|
2010-04-21 18:26:17 +02:00
|
|
|
|
reloop: /* (better this way because we are modifing 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;
|
2010-04-21 18:26:17 +02:00
|
|
|
|
rc = make_keysig_packet (&sig, mainpk, NULL, subpk, mainpk,
|
2010-09-01 14:49:05 +02:00
|
|
|
|
0x28, 0, 0, 0, 0, sign_mk_attrib, &attrib,
|
|
|
|
|
NULL);
|
2010-04-20 20:19:19 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("signing failed: %s\n"), g10_errstr (rc));
|
|
|
|
|
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 */
|
|
|
|
|
static int
|
2010-04-20 20:19:19 +02:00
|
|
|
|
enable_disable_key (KBNODE 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;
|
|
|
|
|
|
|
|
|
|
trust = newtrust = get_ownertrust (pk);
|
|
|
|
|
newtrust &= ~TRUST_FLAG_DISABLED;
|
|
|
|
|
if (disable)
|
|
|
|
|
newtrust |= TRUST_FLAG_DISABLED;
|
|
|
|
|
if (trust == newtrust)
|
|
|
|
|
return 0; /* already in that state */
|
|
|
|
|
update_ownertrust (pk, newtrust);
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2010-04-20 20:19:19 +02:00
|
|
|
|
menu_showphoto (KBNODE 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);
|
2010-04-23 13:36:59 +02:00
|
|
|
|
show_photos (&uid->attribs[i], 1, pk, uid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|