diff --git a/g10/call-agent.c b/g10/call-agent.c index 3211649e1..eea0014c8 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -957,7 +957,8 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw) */ int agent_keytocard (const char *hexgrip, int keyno, int force, - const char *serialno, const char *timestamp) + const char *serialno, const char *timestamp, + const char *ecdh_param_str) { int rc; char line[ASSUAN_LINELENGTH]; @@ -965,8 +966,9 @@ agent_keytocard (const char *hexgrip, int keyno, int force, memset (&parm, 0, sizeof parm); - snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s", - force?"--force ": "", hexgrip, serialno, keyno, timestamp); + snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s%s%s", + force?"--force ": "", hexgrip, serialno, keyno, timestamp, + ecdh_param_str? " ":"", ecdh_param_str? ecdh_param_str:""); rc = start_agent (NULL, 1); if (rc) diff --git a/g10/call-agent.h b/g10/call-agent.h index 3728c5ff1..4b23287c3 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -104,7 +104,8 @@ int agent_scd_getattr (const char *name, struct agent_card_info_s *info); /* Send the KEYTOCARD command. */ int agent_keytocard (const char *hexgrip, int keyno, int force, - const char *serialno, const char *timestamp); + const char *serialno, const char *timestamp, + const char *ecdh_param_str); /* Send a SETATTR command to the SCdaemon. */ gpg_error_t agent_scd_setattr (const char *name, diff --git a/g10/card-util.c b/g10/card-util.c index d83f94ec8..2c977c2b1 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1749,8 +1749,9 @@ card_store_subkey (KBNODE node, int use, strlist_t *processed_keys) int keyno; PKT_public_key *pk; gpg_error_t err; - char *hexgrip; + char *hexgrip = NULL; int rc; + char *ecdh_param_str = NULL; gnupg_isotime_t timebuf; log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY @@ -1824,8 +1825,17 @@ card_store_subkey (KBNODE node, int use, strlist_t *processed_keys) goto leave; epoch2isotime (timebuf, (time_t)pk->timestamp); - rc = agent_keytocard (hexgrip, keyno, rc, info.serialno, timebuf); - + if (pk->pubkey_algo == PUBKEY_ALGO_ECDH) + { + ecdh_param_str = ecdh_param_str_from_pk (pk); + if (!ecdh_param_str) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + rc = agent_keytocard (hexgrip, keyno, rc, info.serialno, + timebuf, ecdh_param_str); if (rc) log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc)); else @@ -1834,9 +1844,10 @@ card_store_subkey (KBNODE node, int use, strlist_t *processed_keys) if (processed_keys) add_to_strlist (processed_keys, hexgrip); } - xfree (hexgrip); leave: + xfree (hexgrip); + xfree (ecdh_param_str); agent_release_card_info (&info); return okay; } diff --git a/g10/keydb.h b/g10/keydb.h index 074027690..9c35ccfee 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -552,6 +552,7 @@ char *format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen); gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array); gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip); +char *ecdh_param_str_from_pk (PKT_public_key *pk); /*-- kbnode.c --*/ diff --git a/g10/keygen.c b/g10/keygen.c index 95d71baa4..08e546954 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -5128,22 +5128,41 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, char *cache_nonce = NULL; void *kek = NULL; size_t keklen; + char *ecdh_param_str = NULL; sk = copy_public_key (NULL, sub_psk); if (!sk) return gpg_error_from_syserror (); epoch2isotime (timestamp, (time_t)sk->timestamp); + if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) + { + ecdh_param_str = ecdh_param_str_from_pk (sk); + if (!ecdh_param_str) + { + free_public_key (sk); + return gpg_error_from_syserror (); + } + } err = hexkeygrip_from_pk (sk, &hexgrip); if (err) - return err; + { + xfree (ecdh_param_str); + free_public_key (sk); + return err; + } memset(&info, 0, sizeof (info)); rc = agent_scd_getattr ("SERIALNO", &info); if (rc) - return (gpg_error_t)rc; + { + xfree (ecdh_param_str); + free_public_key (sk); + return (gpg_error_t)rc; + } - rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp); + rc = agent_keytocard (hexgrip, 2, 1, info.serialno, + timestamp, ecdh_param_str); xfree (info.serialno); if (rc) { @@ -5186,6 +5205,7 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, agent_scd_learn (NULL, 1); leave: + xfree (ecdh_param_str); xfree (cache_nonce); gcry_cipher_close (cipherhd); xfree (kek); diff --git a/g10/keyid.c b/g10/keyid.c index 4fc1622c1..7823f0d74 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -994,3 +994,25 @@ hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) } return err; } + + +/* Return a hexfied malloced string of the ECDH parameters for an ECDH + * key from the public key PK. Returns NULL on error. */ +char * +ecdh_param_str_from_pk (PKT_public_key *pk) +{ + const unsigned char *s; + unsigned int n; + + if (!pk + || pk->pubkey_algo != PUBKEY_ALGO_ECDH + || !gcry_mpi_get_flag (pk->pkey[2], GCRYMPI_FLAG_OPAQUE) + || !(s = gcry_mpi_get_opaque (pk->pkey[2], &n)) || !n) + { + gpg_err_set_errno (EINVAL); + return NULL; /* Invalid parameter */ + } + + n = (n+7)/8; + return bin2hex (s, n, NULL); +}