1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-27 21:41:23 +02:00

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: c03ba92576
See-commit: c795be79c1
This patch is somewhat related to:
GnuPG-bug-id: 6378, 5538
This commit is contained in:
Werner Koch 2023-10-27 12:19:50 +02:00
parent 5da8fe1c40
commit d03d0add12
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 133 additions and 77 deletions

View File

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

View File

@ -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))
keyref = argv[2];
err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL,
&s_skey, NULL, &timestamp);
if (err)
goto leave;
if (shadow_info)
{
/* Key is already on a smartcard - wer can't extract it. */
err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
goto leave;
}
/* 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)
{
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;
}
err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL,
&s_skey, NULL);
if (err)
{
xfree (shadow_info);
goto leave;
}
if (shadow_info)
{
/* Key is on a smartcard already. */
xfree (shadow_info);
gcry_sexp_release (s_skey);
err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
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);
}

View File

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

View File

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

View File

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