summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2022-06-22 08:45:18 +0200
committerNIIBE Yutaka <gniibe@fsij.org>2022-06-22 08:45:18 +0200
commit30b54a0ebbaa8ac491710ad1b4f2fbd1b5814bce (patch)
treebcad2e6b65096f4eb6478519553d7d550002358e /agent
parentagent,gpg,tools: Fix use of log_get_fd. (diff)
downloadgnupg2-30b54a0ebbaa8ac491710ad1b4f2fbd1b5814bce.tar.xz
gnupg2-30b54a0ebbaa8ac491710ad1b4f2fbd1b5814bce.zip
agent: Add KEYATTR command.
* agent/agent.h (agent_raw_key_from_file): Add R_KEYMETA argument. (agent_update_private_key): New. * agent/command-ssh.c (data_sign): Follow the change of the function agent_raw_key_from_file. * agent/command.c (do_one_keyinfo): Likewise. (cmd_keyattr): New. (register_commands): Add an entry of cmd_keyattr. * agent/findkey.c (agent_update_private_key): New. (agent_raw_key_from_file): Add R_KEYMETA argument. -- GnuPG-bug-id: 5988 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'agent')
-rw-r--r--agent/agent.h4
-rw-r--r--agent/command-ssh.c2
-rw-r--r--agent/command.c82
-rw-r--r--agent/findkey.c58
4 files changed, 139 insertions, 7 deletions
diff --git a/agent/agent.h b/agent/agent.h
index d33b8cd34..30f30200d 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -37,6 +37,7 @@
#include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/session-env.h"
#include "../common/shareddefs.h"
+#include "../common/name-value.h"
/* To convey some special hash algorithms we use algorithm numbers
reserved for application use. */
@@ -471,7 +472,7 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
gcry_sexp_t *result,
char **r_passphrase, time_t *r_timestamp);
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
- gcry_sexp_t *result);
+ gcry_sexp_t *result, nvc_t *r_keymeta);
gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result);
@@ -488,6 +489,7 @@ gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
int force, int only_stubs);
+gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index b52604b70..2c18796bc 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -2760,7 +2760,7 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
char *fpr, *prompt;
char *comment = NULL;
- err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key);
+ err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key, NULL);
if (err)
goto out;
err = ssh_get_fingerprint_string (key, opt.ssh_fingerprint_digest, &fpr);
diff --git a/agent/command.c b/agent/command.c
index ead026341..50196f432 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1200,7 +1200,84 @@ cmd_genkey (assuan_context_t ctx, char *line)
}
+static const char hlp_keyattr[] =
+ "KEYATTR [--delete] <hexstring_with_keygrip> <ATTRNAME> [<VALUE>]\n"
+ "\n"
+ "For the secret key, show the attribute of ATTRNAME. With VALUE,\n"
+ "put the value to the attribute. Use --delete option to delete.";
+static gpg_error_t
+cmd_keyattr (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ const char *argv[3];
+ int argc;
+ unsigned char grip[20];
+ int opt_delete;
+
+ if (ctrl->restricted)
+ return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+
+ opt_delete = has_option (line, "--delete");
+
+ line = skip_options (line);
+
+ argc = split_fields (line, argv, DIM (argv));
+ if (argc < 2)
+ {
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ goto leave;
+ }
+
+ err = parse_keygrip (ctx, argv[0], grip);
+ if (err)
+ goto leave;
+
+ if (!err)
+ {
+ gcry_sexp_t s_key = NULL;
+ nvc_t keymeta = NULL;
+ const char *p;
+
+ err = agent_raw_key_from_file (ctrl, grip, &s_key, &keymeta);
+ if (keymeta == NULL) /* Not extended format? */
+ {
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+
+ if (argc == 2)
+ {
+ nve_t e = nvc_lookup (keymeta, argv[1]);
+
+ if (opt_delete)
+ {
+ if (e)
+ nvc_delete (keymeta, e);
+ }
+ else if (e)
+ {
+ p = nve_value (e);
+ if (p)
+ err = assuan_send_data (ctx, p, strlen (p));
+ }
+ }
+ else if (argc == 3)
+ {
+ err = nvc_set (keymeta, argv[1], argv[2]);
+ if (!err)
+ err = nvc_set_private_key (keymeta, s_key);
+ if (!err)
+ err = agent_update_private_key (grip, keymeta);
+ }
+
+ nvc_release (keymeta);
+ gcry_sexp_release (s_key);
+ }
+ leave:
+ return leave_cmd (ctx, err);
+}
static const char hlp_readkey[] =
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
@@ -1461,7 +1538,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
{
gcry_sexp_t key;
- if (!agent_raw_key_from_file (ctrl, grip, &key))
+ if (!agent_raw_key_from_file (ctrl, grip, &key, NULL))
{
ssh_get_fingerprint_string (key, with_ssh_fpr, &fpr);
gcry_sexp_release (key);
@@ -4044,7 +4121,8 @@ register_commands (assuan_context_t ctx)
{ "RELOADAGENT", cmd_reloadagent,hlp_reloadagent },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "KEYTOCARD", cmd_keytocard, hlp_keytocard },
- { "KEYTOTPM", cmd_keytotpm, hlp_keytotpm },
+ { "KEYTOTPM", cmd_keytotpm, hlp_keytotpm },
+ { "KEYATTR", cmd_keyattr, hlp_keyattr },
{ NULL }
};
int i, rc;
diff --git a/agent/findkey.c b/agent/findkey.c
index 22ce20a86..8c128ce00 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -33,7 +33,6 @@
#include "agent.h"
#include "../common/i18n.h"
#include "../common/ssh-utils.h"
-#include "../common/name-value.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -339,6 +338,59 @@ agent_write_private_key (const unsigned char *grip,
}
+gpg_error_t
+agent_update_private_key (const unsigned char *grip, nvc_t pk)
+{
+ char *fname, *fname0;
+ estream_t fp;
+ char hexgrip[40+8+1];
+ gpg_error_t err;
+
+ bin2hex (grip, 20, hexgrip);
+ strcpy (hexgrip+40, ".key.tmp");
+
+ fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
+ hexgrip, NULL);
+ fname0 = xstrdup (fname);
+ if (!fname0)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (fname);
+ return err;
+ }
+ fname0[strlen (fname)-4] = 0;
+
+ fp = es_fopen (fname, "wbx,mode=-rw");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+
+ log_error ("can't create '%s': %s\n", fname, gpg_strerror (err));
+ xfree (fname);
+ return err;
+ }
+
+ err = nvc_write (pk, fp);
+ if (err)
+ log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+
+ es_fclose (fp);
+
+#ifdef HAVE_W32_SYSTEM
+ /* No atomic mv on W32 systems. */
+ gnupg_remove (fname0);
+#endif
+ if (rename (fname, fname0))
+ {
+ err = gpg_error_from_errno (errno);
+ log_error (_("error renaming '%s' to '%s': %s\n"),
+ fname, fname0, strerror (errno));
+ }
+
+ xfree (fname);
+ return err;
+}
+
/* Callback function to try the unprotection from the passphrase query
code. */
static gpg_error_t
@@ -1349,7 +1401,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
failure an error code is returned and NULL stored at RESULT. */
gpg_error_t
agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
- gcry_sexp_t *result)
+ gcry_sexp_t *result, nvc_t *r_keymeta)
{
gpg_error_t err;
gcry_sexp_t s_skey;
@@ -1358,7 +1410,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL;
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, r_keymeta);
if (!err)
*result = s_skey;
return err;