summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2023-04-21 14:04:04 +0200
committerWerner Koch <wk@gnupg.org>2023-04-21 15:23:29 +0200
commitc03ba92576e34f791430ab1c68814ff16c81407b (patch)
tree196ae333ab0f0213f9164dc5585e5530c5c49d1c /agent
parentcommon: Incorporate upstream changes of regexp. (diff)
downloadgnupg2-c03ba92576e34f791430ab1c68814ff16c81407b.tar.xz
gnupg2-c03ba92576e34f791430ab1c68814ff16c81407b.zip
gpg: Fix writing ECDH keys to OpenPGP smartcards.
* agent/command.c (cmd_keytocard): Add new arg for ECDH params. * scd/app-openpgp.c (ecc_writekey): Use provided ECDH params to compute the fingerprint. * g10/call-agent.c (agent_keytocard): Add arg ecdh_param_str. * g10/keyid.c (ecdh_param_str_from_pk): New. * g10/card-util.c (card_store_subkey): Pass ECDH params to writekey. * g10/keygen.c (card_store_key_with_backup): Ditto. * scd/app-openpgp.c (store_fpr): Add arg update. (rsa_read_pubkey, ecc_read_pubkey): Add arg meta_update and avoid writing the fingerprint back to the card if not set. (read_public_key): Also add arg meta_update. (get_public_key): Do not pass it as true here... (do_genkey): ... but here. (rsa_write_key, ecc_writekey): Force string the fingerprint. -- The problem showed up because in 2.4 we changed the standard ECDH parameter some years ago. Now when trying to write an ECDH key created by 2.2 with 2.4 to an openpgp card, scdaemon computes a wrong fingerprint and thus gpg was not able to find the key again by fingerprint. The patch also avoids updating the stored fingerprint in certain situations. This fix is somewhat related to GnuPG-bug-id: 6378
Diffstat (limited to 'agent')
-rw-r--r--agent/command.c67
1 files changed, 59 insertions, 8 deletions
diff --git a/agent/command.c b/agent/command.c
index 9481f47c3..dd7cb5e57 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -3175,9 +3175,10 @@ cmd_delete_key (assuan_context_t ctx, char *line)
#endif
static const char hlp_keytocard[] =
- "KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp>]\n"
+ "KEYTOCARD [--force] <hexgrip> <serialno> <keyref> [<timestamp> [<ecdh>]]\n"
"\n"
- "TIMESTAMP is required for OpenPGP and defaults to the Epoch. The\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)
@@ -3194,6 +3195,9 @@ cmd_keytocard (assuan_context_t ctx, char *line)
size_t keydatalen;
unsigned char *shadow_info = NULL;
time_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));
@@ -3240,10 +3244,38 @@ cmd_keytocard (assuan_context_t ctx, char *line)
/* Default to the creation time as stored in the private key. The
* parameter is here so that gpg can make sure that the timestamp as
- * used for key creation (and thus the openPGP fingerprint) is
- * used. */
+ * 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 (argv[3]);
+ {
+ timestamp = isotime2epoch (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 == (time_t)(-1))
timestamp = isotime2epoch ("19700101T000000");
@@ -3254,9 +3286,12 @@ cmd_keytocard (assuan_context_t ctx, char *line)
}
/* Note: We can't use make_canon_sexp because we need to allocate a
- * few extra bytes for our hack below. */
+ * 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);
- keydata = xtrymalloc_secure (keydatalen + 30);
+ 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 ();
@@ -3265,15 +3300,31 @@ cmd_keytocard (assuan_context_t ctx, char *line)
gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
gcry_sexp_release (s_skey);
s_skey = NULL;
+
keydatalen--; /* Decrement for last '\0'. */
+
/* Hack to insert the timestamp "created-at" into the private key. */
- snprintf (keydata+keydatalen-1, 30, KEYTOCARD_TIMESTAMP_FORMAT, timestamp);
+ snprintf (keydata+keydatalen-1, extralen1, KEYTOCARD_TIMESTAMP_FORMAT,
+ timestamp);
keydatalen += 10 + 19 - 1;
+ /* 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);