summaryrefslogtreecommitdiffstats
path: root/agent/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/command.c')
-rw-r--r--agent/command.c211
1 files changed, 121 insertions, 90 deletions
diff --git a/agent/command.c b/agent/command.c
index b682c55..940e017 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -975,7 +975,6 @@ cmd_genkey (assuan_context_t ctx, char *line)
}
-
static const char hlp_readkey[] =
"READKEY [--no-data] <hexstring_with_keygrip>\n"
@@ -1040,20 +1039,11 @@ cmd_readkey (assuan_context_t ctx, char *line)
}
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno);
- if (agent_key_available (grip))
- {
- /* Shadow-key is not available in our key storage. */
- rc = agent_write_shadow_key (0, grip, serialno, keyid, pkbuf, 0,
- dispserialno);
- }
- else
- {
- /* Shadow-key is available in our key storage but ne check
- * whether we need to update it with a new display-s/n or
- * whatever. */
- rc = agent_write_shadow_key (1, grip, serialno, keyid, pkbuf, 0,
- dispserialno);
- }
+ /* Shadow-key is or is not available in our key storage. In
+ * any case we need to check whether we need to update with
+ * a new display-s/n or whatever. */
+ rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0, 0,
+ dispserialno);
if (rc)
goto leave;
@@ -1292,9 +1282,6 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
char hexgrip[41];
int disabled, ttl, confirm, is_ssh;
- if (ctrl->restricted)
- return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
-
if (has_option (line, "--ssh-list"))
list_mode = 2;
else
@@ -1343,6 +1330,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
char *dirname;
gnupg_dirent_t dir_entry;
+ if (ctrl->restricted)
+ return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+
dirname = make_filename_try (gnupg_homedir (),
GNUPG_PRIVATE_KEYS_DIR, NULL);
if (!dirname)
@@ -1865,16 +1855,18 @@ cmd_learn (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int send, sendinfo, force;
+ int send, sendinfo, force, reallyforce;
send = has_option (line, "--send");
sendinfo = send? 1 : has_option (line, "--sendinfo");
force = has_option (line, "--force");
+ reallyforce = has_option (line, "--reallyforce");
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
- err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
+ err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL,
+ force, reallyforce);
return leave_cmd (ctx, err);
}
@@ -1951,7 +1943,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
opt_verify? NULL : cache_nonce,
ctrl->server_local->keydesc,
grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, &passphrase);
+ &s_skey, &passphrase, NULL);
if (err)
;
else if (shadow_info)
@@ -2435,14 +2427,14 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (passphrase)
{
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
- ctrl->s2k_count, -1);
+ ctrl->s2k_count);
if (!err)
- err = agent_write_private_key (grip, finalkey, finalkeylen, force,
- opt_timestamp, NULL, NULL, NULL);
+ err = agent_write_private_key (grip, finalkey, finalkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
}
else
- err = agent_write_private_key (grip, key, realkeylen, force,
- opt_timestamp, NULL, NULL, NULL);
+ err = agent_write_private_key (grip, key, realkeylen, force, 0,
+ NULL, NULL, NULL, opt_timestamp);
leave:
gcry_sexp_release (openpgp_sexp);
@@ -2532,7 +2524,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
err = agent_key_from_file (ctrl, cache_nonce,
ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
- openpgp ? &passphrase : NULL);
+ openpgp ? &passphrase : NULL, NULL);
if (err)
goto leave;
if (shadow_info)
@@ -2677,28 +2669,30 @@ cmd_delete_key (assuan_context_t ctx, char *line)
-#if SIZEOF_TIME_T > SIZEOF_UNSIGNED_LONG
-#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010llu))"
-#else
-#define KEYTOCARD_TIMESTAMP_FORMAT "(10:created-at10:%010lu))"
-#endif
-
static const char hlp_keytocard[] =
- "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
- "\n";
+ "KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp> [<ecdh>]]\n"
+ "\n"
+ "TIMESTAMP is required for OpenPGP and defaults to the Epoch.\n"
+ "ECDH are the hexified ECDH parameters for OpenPGP.\n"
+ "SERIALNO is used for checking; use \"-\" to disable the check.";
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;
+ char *argv[5];
+ int argc;
unsigned char grip[20];
+ const char *serialno, *keyref;
gcry_sexp_t s_skey = NULL;
unsigned char *keydata;
size_t keydatalen;
- const char *serialno, *timestamp_str, *id;
unsigned char *shadow_info = NULL;
- time_t timestamp;
+ uint64_t timestamp;
+ char *ecdh_params = NULL;
+ unsigned int ecdh_params_len;
+ unsigned int extralen1, extralen2;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@@ -2706,7 +2700,14 @@ cmd_keytocard (assuan_context_t ctx, char *line)
force = has_option (line, "--force");
line = skip_options (line);
- err = parse_keygrip (ctx, line, grip);
+ argc = split_fields (line, argv, DIM (argv));
+ if (argc < 3)
+ {
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ goto leave;
+ }
+
+ err = parse_keygrip (ctx, argv[0], grip);
if (err)
goto leave;
@@ -2716,82 +2717,112 @@ cmd_keytocard (assuan_context_t ctx, char *line)
goto leave;
}
- /* Fixme: Replace the parsing code by split_fields(). */
- line += 40;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- serialno = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- {
- err = gpg_error (GPG_ERR_MISSING_VALUE);
- goto leave;
- }
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- id = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (!*line)
- {
- err = gpg_error (GPG_ERR_MISSING_VALUE);
- goto leave;
- }
- *line = '\0';
- line++;
- while (*line && (*line == ' ' || *line == '\t'))
- line++;
- timestamp_str = line;
- while (*line && (*line != ' ' && *line != '\t'))
- line++;
- if (*line)
- *line = '\0';
+ /* Note that checking of the s/n is currently not implemented but we
+ * want to provide a clean interface if we ever implement it. */
+ serialno = argv[1];
+ if (!strcmp (serialno, "-"))
+ serialno = NULL;
- if ((timestamp = isotime2epoch (timestamp_str)) == (time_t)(-1))
- {
- err = gpg_error (GPG_ERR_INV_TIME);
- goto leave;
- }
+ keyref = argv[2];
err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL,
- &s_skey, NULL);
+ &s_skey, NULL, &timestamp);
if (err)
+ goto leave;
+
+ if (shadow_info)
{
- xfree (shadow_info);
+ /* Key is already on a smartcard - wer can't extract it. */
+ err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
goto leave;
}
- if (shadow_info)
+
+ /* Default to the creation time as stored in the private key. The
+ * parameter is here so that gpg can make sure that the timestamp is
+ * used. It is also important for OpenPGP cards to allow computing
+ * of the fingerprint. Same goes for the ECDH params. */
+ if (argc > 3)
{
- /* Key is on a smartcard already. */
- xfree (shadow_info);
- gcry_sexp_release (s_skey);
- err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+ timestamp = isotime2epoch_u64 (argv[3]);
+ if (argc > 4)
+ {
+ size_t n;
+
+ err = parse_hexstring (ctx, argv[4], &n);
+ if (err)
+ goto leave; /* Badly formatted ecdh params. */
+ n /= 2;
+ if (n < 4)
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER, "ecdh param too short");
+ goto leave;
+ }
+ ecdh_params_len = n;
+ ecdh_params = xtrymalloc (ecdh_params_len);
+ if (!ecdh_params)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ if (hex2bin (argv[4], ecdh_params, ecdh_params_len) < 0)
+ {
+ err = set_error (GPG_ERR_BUG, "hex2bin");
+ goto leave;
+ }
+ }
+ }
+ else if (timestamp == (uint64_t)(-1))
+ timestamp = isotime2epoch_u64 ("19700101T000000");
+
+ if (timestamp == (uint64_t)(-1))
+ {
+ err = gpg_error (GPG_ERR_INV_TIME);
goto leave;
}
- keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
- keydata = xtrymalloc_secure (keydatalen + 30);
+ /* Note: We can't use make_canon_sexp because we need to allocate a
+ * few extra bytes for our hack below. The 20 for extralen2
+ * accounts for the sexp length of ecdh_params. */
+ keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
+ extralen1 = 30;
+ extralen2 = ecdh_params? (20+20+ecdh_params_len) : 0;
+ keydata = xtrymalloc_secure (keydatalen + extralen1 + extralen2);
if (keydata == NULL)
{
err = gpg_error_from_syserror ();
- gcry_sexp_release (s_skey);
goto leave;
}
-
gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
gcry_sexp_release (s_skey);
+ s_skey = NULL;
+
keydatalen--; /* Decrement for last '\0'. */
- /* Add timestamp "created-at" in the private key */
- snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp);
+
+ /* Hack to insert the timestamp "created-at" into the private key. */
+ snprintf (keydata+keydatalen-1, extralen1, "(10:created-at10:%010llu))",
+ (unsigned long long)timestamp);
keydatalen += 10 + 19 - 1;
- err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
+
+ /* Hack to insert the timestamp "ecdh-params" into the private key. */
+ if (ecdh_params)
+ {
+ snprintf (keydata+keydatalen-1, extralen2, "(11:ecdh-params%u:",
+ ecdh_params_len);
+ keydatalen += strlen (keydata+keydatalen-1) -1;
+ memcpy (keydata+keydatalen, ecdh_params, ecdh_params_len);
+ keydatalen += ecdh_params_len;
+ memcpy (keydata+keydatalen, "))", 3);
+ keydatalen += 2;
+ }
+
+ err = divert_writekey (ctrl, force, serialno, keyref, keydata, keydatalen);
xfree (keydata);
leave:
+ xfree (ecdh_params);
+ gcry_sexp_release (s_skey);
+ xfree (shadow_info);
return leave_cmd (ctx, err);
}