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>
This commit is contained in:
NIIBE Yutaka 2022-06-22 15:45:18 +09:00
parent fe535cf265
commit 30b54a0ebb
4 changed files with 139 additions and 7 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;