aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2023-10-27 10:19:50 +0000
committerWerner Koch <[email protected]>2023-10-27 10:21:26 +0000
commitd03d0add1289847585942d2b99969f75e642cf04 (patch)
tree20d494883033abc5df7882d362f7d232cfed3bcd
parentgpg: Allow expiration time after 2013-01-19 on 32 bit Windows. (diff)
downloadgnupg-d03d0add1289847585942d2b99969f75e642cf04.tar.gz
gnupg-d03d0add1289847585942d2b99969f75e642cf04.zip
agent: Add optional ecdh parameter arg to KEYTOCARD.
* agent/command.c (KEYTOCARD_TIMESTAMP_FORMAT): Remove and use format string direct. (cmd_keytocard): Change timestamp to an u64 and use the new u64 parser functions. Use split_fields. Add ecdh parameter stuff. Take the default timestamp from the keyfile. * agent/findkey.c (agent_key_from_file): Add arg timestamp and set it. Adjust all callers. -- This is backport from 2.4 but only the agent part. We consider it more relibale if we also pass the ECDH parameters along in 2.2. Adding the timestamp stuff should not harm either. Because we now have the u64 time string parser, we use them here. See-commit: c03ba92576e34f791430ab1c68814ff16c81407b See-commit: c795be79c14fac01b984bdc2e2041d2141f27612 This patch is somewhat related to: GnuPG-bug-id: 6378, 5538
-rw-r--r--agent/agent.h3
-rw-r--r--agent/command.c169
-rw-r--r--agent/findkey.c22
-rw-r--r--agent/pkdecrypt.c2
-rw-r--r--agent/pksign.c2
5 files changed, 127 insertions, 71 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 8f68b2619..e72a75068 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -433,7 +433,8 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
cache_mode_t cache_mode,
lookup_ttl_t lookup_ttl,
gcry_sexp_t *result,
- char **r_passphrase);
+ char **r_passphrase,
+ uint64_t *r_timestamp);
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result);
gpg_error_t agent_keymeta_from_file (ctrl_t ctrl, const unsigned char *grip,
diff --git a/agent/command.c b/agent/command.c
index cd3ab18f7..4a4d6e81a 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1941,7 +1941,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)
@@ -2522,7 +2522,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)
@@ -2667,28 +2667,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));
@@ -2696,7 +2698,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;
@@ -2706,82 +2715,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);
}
diff --git a/agent/findkey.c b/agent/findkey.c
index 7917d2981..a359c7e1b 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -889,20 +889,24 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
const char *desc_text,
const unsigned char *grip, unsigned char **shadow_info,
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
- gcry_sexp_t *result, char **r_passphrase)
+ gcry_sexp_t *result, char **r_passphrase,
+ uint64_t *r_timestamp)
{
gpg_error_t err;
unsigned char *buf;
size_t len, buflen, erroff;
gcry_sexp_t s_skey;
+ nvc_t keymeta = NULL;
*result = NULL;
if (shadow_info)
*shadow_info = NULL;
if (r_passphrase)
*r_passphrase = NULL;
+ if (r_timestamp)
+ *r_timestamp = (uint64_t)(-1);
- err = read_key_file (grip, &s_skey, NULL);
+ err = read_key_file (grip, &s_skey, &keymeta);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@@ -915,7 +919,19 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
now. */
err = make_canon_sexp (s_skey, &buf, &len);
if (err)
- return err;
+ {
+ nvc_release (keymeta);
+ return err;
+ }
+
+ if (r_timestamp && keymeta)
+ {
+ const char *created = nvc_get_string (keymeta, "Created:");
+
+ if (created)
+ *r_timestamp = isotime2epoch_u64 (created);
+ }
+ nvc_release (keymeta);
switch (agent_private_key_type (buf))
{
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index 6aed96b4f..ccd395dc6 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -69,7 +69,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
}
rc = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip, &shadow_info,
- CACHE_MODE_NORMAL, NULL, &s_skey, NULL);
+ CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NO_SECKEY)
diff --git a/agent/pksign.c b/agent/pksign.c
index 09d61b8c7..571541dc8 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -311,7 +311,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
err = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
&shadow_info, cache_mode, lookup_ttl,
- &s_skey, NULL);
+ &s_skey, NULL, NULL);
if (err)
{
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)