diff options
author | NIIBE Yutaka <[email protected]> | 2013-02-06 05:00:05 +0000 |
---|---|---|
committer | NIIBE Yutaka <[email protected]> | 2013-02-12 05:19:12 +0000 |
commit | 30f8a3c8736451d8c06ef72521a8da5eabf23016 (patch) | |
tree | d1e3a45a02a5b5c87be2f72d408ce88482b037a2 /agent/command.c | |
parent | Japanese: update po and doc. (diff) | |
download | gnupg-30f8a3c8736451d8c06ef72521a8da5eabf23016.tar.gz gnupg-30f8a3c8736451d8c06ef72521a8da5eabf23016.zip |
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.
Diffstat (limited to 'agent/command.c')
-rw-r--r-- | agent/command.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/agent/command.c b/agent/command.c index 715e70a94..2844398f6 100644 --- a/agent/command.c +++ b/agent/command.c @@ -2119,9 +2119,133 @@ cmd_export_key (assuan_context_t ctx, char *line) 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[] = "GETVAL <key>\n" @@ -2674,6 +2798,7 @@ register_commands (assuan_context_t ctx) { "KILLAGENT", cmd_killagent, hlp_killagent }, { "RELOADAGENT", cmd_reloadagent,hlp_reloadagent }, { "GETINFO", cmd_getinfo, hlp_getinfo }, + { "KEYTOCARD", cmd_keytocard, hlp_keytocard }, { NULL } }; int i, rc; |