mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-17 14:07:03 +01:00
agent: Add KEYTOCARD command.
* agent/agent.h (divert_writekey, agent_card_writekey): New. * agent/call-scd.c (inq_writekey_parms, agent_card_writekey): New. * agent/command.c (cmd_keytocard, hlp_keytocard): New. (register_commands): Add cmd_keytocard. * agent/divert-scd.c (divert_writekey): New.
This commit is contained in:
parent
595ab0da66
commit
30f8a3c873
@ -412,6 +412,8 @@ int divert_pkdecrypt (ctrl_t ctrl,
|
|||||||
char **r_buf, size_t *r_len);
|
char **r_buf, size_t *r_len);
|
||||||
int divert_generic_cmd (ctrl_t ctrl,
|
int divert_generic_cmd (ctrl_t ctrl,
|
||||||
const char *cmdline, void *assuan_context);
|
const char *cmdline, void *assuan_context);
|
||||||
|
int divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
|
const char *id, const char *keydata, size_t keydatalen);
|
||||||
|
|
||||||
|
|
||||||
/*-- call-scd.c --*/
|
/*-- call-scd.c --*/
|
||||||
@ -445,6 +447,11 @@ int agent_card_pkdecrypt (ctrl_t ctrl,
|
|||||||
int agent_card_readcert (ctrl_t ctrl,
|
int agent_card_readcert (ctrl_t ctrl,
|
||||||
const char *id, char **r_buf, size_t *r_buflen);
|
const char *id, char **r_buf, size_t *r_buflen);
|
||||||
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
|
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
|
||||||
|
int agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
|
const char *id, const char *keydata,
|
||||||
|
size_t keydatalen,
|
||||||
|
int (*getpin_cb)(void *, const char *, char*, size_t),
|
||||||
|
void *getpin_cb_arg);
|
||||||
gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
|
gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
|
||||||
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
|
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
|
||||||
int (*getpin_cb)(void *, const char *, char*, size_t),
|
int (*getpin_cb)(void *, const char *, char*, size_t),
|
||||||
|
@ -1050,6 +1050,64 @@ agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct writekey_parm_s
|
||||||
|
{
|
||||||
|
assuan_context_t ctx;
|
||||||
|
int (*getpin_cb)(void *, const char *, char*, size_t);
|
||||||
|
void *getpin_cb_arg;
|
||||||
|
assuan_context_t passthru;
|
||||||
|
int any_inq_seen;
|
||||||
|
/**/
|
||||||
|
const unsigned char *keydata;
|
||||||
|
size_t keydatalen;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Handle a KEYDATA inquiry. Note, we only send the data,
|
||||||
|
assuan_transact takes care of flushing and writing the end */
|
||||||
|
static gpg_error_t
|
||||||
|
inq_writekey_parms (void *opaque, const char *line)
|
||||||
|
{
|
||||||
|
struct writekey_parm_s *parm = opaque;
|
||||||
|
|
||||||
|
if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
|
||||||
|
return assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
|
||||||
|
else
|
||||||
|
return inq_needpin (opaque, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
|
const char *id, const char *keydata, size_t keydatalen,
|
||||||
|
int (*getpin_cb)(void *, const char *, char*, size_t),
|
||||||
|
void *getpin_cb_arg)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
struct writekey_parm_s parms;
|
||||||
|
|
||||||
|
(void)serialno;
|
||||||
|
rc = start_scd (ctrl);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
snprintf (line, DIM(line)-1, "WRITEKEY %s%s", force ? "--force " : "", id);
|
||||||
|
line[DIM(line)-1] = 0;
|
||||||
|
parms.ctx = ctrl->scd_local->ctx;
|
||||||
|
parms.getpin_cb = getpin_cb;
|
||||||
|
parms.getpin_cb_arg = getpin_cb_arg;
|
||||||
|
parms.passthru = 0;
|
||||||
|
parms.any_inq_seen = 0;
|
||||||
|
parms.keydata = keydata;
|
||||||
|
parms.keydatalen = keydatalen;
|
||||||
|
|
||||||
|
rc = assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL,
|
||||||
|
inq_writekey_parms, &parms, NULL, NULL);
|
||||||
|
if (parms.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED ||
|
||||||
|
gpg_err_code(rc) == GPG_ERR_ASS_CANCELED))
|
||||||
|
rc = cancel_inquire (ctrl, rc);
|
||||||
|
return unlock_scd (ctrl, rc);
|
||||||
|
}
|
||||||
|
|
||||||
/* Type used with the card_getattr_cb. */
|
/* Type used with the card_getattr_cb. */
|
||||||
struct card_getattr_parm_s {
|
struct card_getattr_parm_s {
|
||||||
|
125
agent/command.c
125
agent/command.c
@ -2119,9 +2119,133 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
return leave_cmd (ctx, err);
|
return leave_cmd (ctx, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char hlp_keytocard[] =
|
||||||
|
"KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
|
||||||
|
"\n";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_keytocard (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
int force;
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
unsigned char grip[20];
|
||||||
|
gcry_sexp_t s_skey = NULL;
|
||||||
|
gcry_sexp_t s_pkey = NULL;
|
||||||
|
unsigned char *keydata;
|
||||||
|
size_t keydatalen, timestamplen;
|
||||||
|
const char *serialno, *timestamp_str, *id;
|
||||||
|
unsigned char *shadow_info;
|
||||||
|
unsigned char *shdkey;
|
||||||
|
time_t timestamp;
|
||||||
|
|
||||||
|
force = has_option (line, "--force");
|
||||||
|
line = skip_options (line);
|
||||||
|
|
||||||
|
err = parse_keygrip (ctx, line, grip);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (agent_key_available (grip))
|
||||||
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
|
||||||
|
line += 40;
|
||||||
|
while (*line && (*line == ' ' || *line == '\t'))
|
||||||
|
line++;
|
||||||
|
serialno = line;
|
||||||
|
while (*line && (*line != ' ' && *line != '\t'))
|
||||||
|
line++;
|
||||||
|
if (!*line)
|
||||||
|
return gpg_error (GPG_ERR_MISSING_VALUE);
|
||||||
|
*line = '\0';
|
||||||
|
line++;
|
||||||
|
while (*line && (*line == ' ' || *line == '\t'))
|
||||||
|
line++;
|
||||||
|
id = line;
|
||||||
|
while (*line && (*line != ' ' && *line != '\t'))
|
||||||
|
line++;
|
||||||
|
if (!*line)
|
||||||
|
return gpg_error (GPG_ERR_MISSING_VALUE);
|
||||||
|
*line = '\0';
|
||||||
|
line++;
|
||||||
|
while (*line && (*line == ' ' || *line == '\t'))
|
||||||
|
line++;
|
||||||
|
timestamp_str = line;
|
||||||
|
while (*line && (*line != ' ' && *line != '\t'))
|
||||||
|
line++;
|
||||||
|
if (*line)
|
||||||
|
*line = '\0';
|
||||||
|
timestamplen = line - timestamp_str;
|
||||||
|
if (timestamplen != 15)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
|
||||||
|
NULL, CACHE_MODE_IGNORE, NULL, &s_skey, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (!s_skey)
|
||||||
|
/* Key is on a smartcard already. */
|
||||||
|
return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
|
||||||
|
|
||||||
|
keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||||
|
keydata = xtrymalloc_secure (keydatalen + 30);
|
||||||
|
if (keydata == NULL)
|
||||||
|
{
|
||||||
|
gcry_sexp_release (s_skey);
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
|
||||||
|
gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
|
||||||
|
gcry_sexp_release (s_skey);
|
||||||
|
/* Add timestamp "created-at" in the private key */
|
||||||
|
timestamp = isotime2epoch (timestamp_str);
|
||||||
|
snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
|
||||||
|
keydatalen += 10 + 19 - 1;
|
||||||
|
err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (keydata);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
xfree (keydata);
|
||||||
|
|
||||||
|
err = agent_public_key_from_file (ctrl, grip, &s_pkey);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
shadow_info = make_shadow_info (serialno, id);
|
||||||
|
if (!shadow_info)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_ENOMEM);
|
||||||
|
gcry_sexp_release (s_pkey);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
keydatalen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||||
|
keydata = xtrymalloc (keydatalen);
|
||||||
|
if (keydata == NULL)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
gcry_sexp_release (s_pkey);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
|
||||||
|
gcry_sexp_release (s_pkey);
|
||||||
|
err = agent_shadow_key (keydata, shadow_info, &shdkey);
|
||||||
|
xfree (keydata);
|
||||||
|
xfree (shadow_info);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
keydatalen = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
||||||
|
err = agent_write_private_key (grip, shdkey, keydatalen, 1);
|
||||||
|
xfree (shdkey);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
return leave_cmd (ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
static const char hlp_getval[] =
|
static const char hlp_getval[] =
|
||||||
"GETVAL <key>\n"
|
"GETVAL <key>\n"
|
||||||
@ -2674,6 +2798,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "KILLAGENT", cmd_killagent, hlp_killagent },
|
{ "KILLAGENT", cmd_killagent, hlp_killagent },
|
||||||
{ "RELOADAGENT", cmd_reloadagent,hlp_reloadagent },
|
{ "RELOADAGENT", cmd_reloadagent,hlp_reloadagent },
|
||||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||||
|
{ "KEYTOCARD", cmd_keytocard, hlp_keytocard },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
@ -442,6 +442,13 @@ divert_pkdecrypt (ctrl_t ctrl,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
|
const char *id, const char *keydata, size_t keydatalen)
|
||||||
|
{
|
||||||
|
return agent_card_writekey (ctrl, force, serialno, id, keydata, keydatalen,
|
||||||
|
getpin_cb, ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
|
divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user