diff options
author | Werner Koch <wk@gnupg.org> | 2023-04-21 14:04:04 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2023-04-21 15:23:29 +0200 |
commit | c03ba92576e34f791430ab1c68814ff16c81407b (patch) | |
tree | 196ae333ab0f0213f9164dc5585e5530c5c49d1c /agent | |
parent | common: Incorporate upstream changes of regexp. (diff) | |
download | gnupg2-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.c | 67 |
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); |