summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2014-04-15 16:40:48 +0200
committerWerner Koch <wk@gnupg.org>2014-04-15 17:03:54 +0200
commite3a4ff89a0b106e678bf9d0a4d47917123071140 (patch)
tree16ce4dca4a890a8d79a41c3a76d74a2ca4771221 /agent
parentscd: EdDSA support. (diff)
downloadgnupg2-e3a4ff89a0b106e678bf9d0a4d47917123071140.tar.xz
gnupg2-e3a4ff89a0b106e678bf9d0a4d47917123071140.zip
agent: Add command DELETE_KEY.
* agent/command.c (cmd_delete_key): New. * agent/findkey.c (modify_description): Add '%C' feature. (remove_key_file): New. (agent_delete_key): New. * agent/command-ssh.c (search_control_file): Make arg R_DISABLE optional. * configure.ac: Require libgpg-error 1.13.
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h2
-rw-r--r--agent/command-ssh.c6
-rw-r--r--agent/command.c36
-rw-r--r--agent/findkey.c143
4 files changed, 184 insertions, 3 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 58e584132..4ed8c7fe6 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -334,6 +334,8 @@ int agent_key_available (const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
unsigned char **r_shadow_info);
+gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
+ const unsigned char *grip);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 364a8ccb4..a81468125 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -1031,7 +1031,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
assert (strlen (hexgrip) == 40 );
- *r_disabled = 0;
+ if (r_disabled)
+ *r_disabled = 0;
if (r_ttl)
*r_ttl = 0;
if (r_confirm)
@@ -1047,7 +1048,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
}
if (!err)
{
- *r_disabled = cf->item.disabled;
+ if (r_disabled)
+ *r_disabled = cf->item.disabled;
if (r_ttl)
*r_ttl = cf->item.ttl;
if (r_confirm)
diff --git a/agent/command.c b/agent/command.c
index fab27f09d..52876a9a9 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -695,7 +695,7 @@ static const char hlp_setkeydesc[] =
"blanks unless they are percent or '+' escaped.\n"
"\n"
"The description is only valid for the next PKSIGN, PKDECRYPT,\n"
- "IMPORT_KEY or EXPORT_KEY operation.";
+ "IMPORT_KEY, EXPORT_KEY, or DELETE_KEY operation.";
static gpg_error_t
cmd_setkeydesc (assuan_context_t ctx, char *line)
{
@@ -2244,6 +2244,39 @@ cmd_export_key (assuan_context_t ctx, char *line)
return leave_cmd (ctx, err);
}
+
+
+
+static const char hlp_delete_key[] =
+ "DELETE_KEY <hexstring_with_keygrip>\n"
+ "\n"
+ "Delete a secret key from the key store.\n"
+ "As safeguard the agent asks the user for confirmation.\n";
+static gpg_error_t
+cmd_delete_key (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ unsigned char grip[20];
+
+ line = skip_options (line);
+
+ err = parse_keygrip (ctx, line, grip);
+ if (err)
+ goto leave;
+
+ err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip);
+ if (err)
+ goto leave;
+
+ leave:
+ xfree (ctrl->server_local->keydesc);
+ ctrl->server_local->keydesc = NULL;
+
+ return leave_cmd (ctx, err);
+}
+
+
static const char hlp_keytocard[] =
"KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
@@ -2926,6 +2959,7 @@ register_commands (assuan_context_t ctx)
{ "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key },
{ "IMPORT_KEY", cmd_import_key, hlp_import_key },
{ "EXPORT_KEY", cmd_export_key, hlp_export_key },
+ { "DELETE_KEY", cmd_delete_key, hlp_delete_key },
{ "GETVAL", cmd_getval, hlp_getval },
{ "PUTVAL", cmd_putval, hlp_putval },
{ "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty },
diff --git a/agent/findkey.c b/agent/findkey.c
index 84d2cfdc6..e01c5c195 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -1,6 +1,7 @@
/* findkey.c - Locate the secret key
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
*
@@ -189,6 +190,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
%% - Replaced by a single %
%c - Replaced by the content of COMMENT.
+ %C - Same as %c but put into parentheses.
%F - Replaced by an ssh style fingerprint computed from KEY.
The functions returns 0 on success or an error code. On success a
@@ -240,6 +242,20 @@ modify_description (const char *in, const char *comment, const gcry_sexp_t key,
out_len += comment_length;
break;
+ case 'C': /* Comment. */
+ if (!comment_length)
+ ;
+ else if (out)
+ {
+ *out++ = '(';
+ memcpy (out, comment, comment_length);
+ out += comment_length;
+ *out++ = ')';
+ }
+ else
+ out_len += comment_length + 2;
+ break;
+
case 'F': /* SSH style fingerprint. */
if (!ssh_fpr && key)
ssh_get_fingerprint_string (key, &ssh_fpr);
@@ -536,6 +552,24 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
}
+/* Remove the key identified by GRIP from the private key directory. */
+static gpg_error_t
+remove_key_file (const unsigned char *grip)
+{
+ gpg_error_t err = 0;
+ char *fname;
+ char hexgrip[40+4+1];
+
+ bin2hex (grip, 20, hexgrip);
+ strcpy (hexgrip+40, ".key");
+ fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+ if (gnupg_remove (fname))
+ err = gpg_error_from_syserror ();
+ xfree (fname);
+ return err;
+}
+
+
/* Return the secret key as an S-Exp in RESULT after locating it using
the GRIP. If the operation shall be diverted to a token, an
allocated S-expression with the shadow_info part from the file is
@@ -1145,3 +1179,112 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
xfree (buf);
return err;
}
+
+
+
+/* Delete the key with GRIP from the disk after having asked for
+ confirmation using DESC_TEXT. Common error codes are:
+ GPG_ERR_NO_SECKEY
+ GPG_ERR_KEY_ON_CARD
+ GPG_ERR_NOT_CONFIRMED
+*/
+gpg_error_t
+agent_delete_key (ctrl_t ctrl, const char *desc_text,
+ const unsigned char *grip)
+{
+ gpg_error_t err;
+ gcry_sexp_t s_skey = NULL;
+ unsigned char *buf = NULL;
+ size_t len;
+ char *desc_text_final = NULL;
+ char *comment = NULL;
+ ssh_control_file_t cf = NULL;
+ char hexgrip[40+4+1];
+ char *default_desc = NULL;
+
+ err = read_key_file (grip, &s_skey);
+ if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ err = gpg_error (GPG_ERR_NO_SECKEY);
+ if (err)
+ goto leave;
+
+ err = make_canon_sexp (s_skey, &buf, &len);
+ if (err)
+ goto leave;
+
+ switch (agent_private_key_type (buf))
+ {
+ case PRIVATE_KEY_CLEAR:
+ case PRIVATE_KEY_PROTECTED:
+ {
+ bin2hex (grip, 20, hexgrip);
+ if (!desc_text)
+ {
+ default_desc = xtryasprintf
+ ("Do you really want to delete the key identified by keygrip%%0A"
+ " %s%%0A %%C%%0A?", hexgrip);
+ desc_text = default_desc;
+ }
+
+ /* Note, that we will take the comment as a C string for
+ display purposes; i.e. all stuff beyond a Nul character is
+ ignored. */
+ {
+ gcry_sexp_t comment_sexp;
+
+ comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
+ if (comment_sexp)
+ comment = gcry_sexp_nth_string (comment_sexp, 1);
+ gcry_sexp_release (comment_sexp);
+ }
+
+ if (desc_text)
+ err = modify_description (desc_text, comment? comment:"", s_skey,
+ &desc_text_final);
+ if (err)
+ goto leave;
+
+ err = agent_get_confirmation (ctrl, desc_text_final,
+ _("Delete key"), _("No"), 0);
+ if (err)
+ goto leave;
+
+ cf = ssh_open_control_file ();
+ if (cf)
+ {
+ if (!ssh_search_control_file (cf, hexgrip, NULL, NULL, NULL))
+ {
+ err = agent_get_confirmation
+ (ctrl,
+ _("Warning: This key is also listed for use with SSH!\n"
+ "Deleting the key will may remove your ability to"
+ "access remote machines."),
+ _("Delete key"), _("No"), 0);
+ if (err)
+ goto leave;
+ }
+ }
+
+ err = remove_key_file (grip);
+ }
+ break;
+
+ case PRIVATE_KEY_SHADOWED:
+ err = gpg_error (GPG_ERR_KEY_ON_CARD);
+ break;
+
+ default:
+ log_error ("invalid private key format\n");
+ err = gpg_error (GPG_ERR_BAD_SECKEY);
+ break;
+ }
+
+ leave:
+ ssh_close_control_file (cf);
+ gcry_free (comment);
+ xfree (desc_text_final);
+ xfree (default_desc);
+ xfree (buf);
+ gcry_sexp_release (s_skey);
+ return err;
+}