aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/call-agent.c32
-rw-r--r--g10/call-agent.h6
-rw-r--r--g10/card-util.c36
-rw-r--r--g10/import.c12
-rw-r--r--g10/keydb.h1
-rw-r--r--g10/keygen.c12
-rw-r--r--g10/keyid.c22
7 files changed, 111 insertions, 10 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 66812e998..b0bccc0a5 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1096,7 +1096,8 @@ agent_keytotpm (ctrl_t ctrl, const char *hexgrip)
*/
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];
@@ -1104,8 +1105,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)
@@ -1700,6 +1702,30 @@ agent_scd_cardlist (strlist_t *result)
}
+/* Make the app APPNAME the one on the card. This is sometimes
+ * required to make sure no other process has switched a card to
+ * another application. The only useful APPNAME is "openpgp". */
+gpg_error_t
+agent_scd_switchapp (const char *appname)
+{
+ int err;
+ char line[ASSUAN_LINELENGTH];
+
+ if (appname && !*appname)
+ appname = NULL;
+
+ err = start_agent (NULL, (1 | FLAG_FOR_CARD_SUPPRESS_ERRORS));
+ if (err)
+ return err;
+
+ snprintf (line, DIM(line), "SCD SWITCHAPP --%s%s",
+ appname? " ":"", appname? appname:"");
+ return assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+}
+
+
struct card_keyinfo_parm_s {
int error;
diff --git a/g10/call-agent.h b/g10/call-agent.h
index a3f234ade..45af95422 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -108,6 +108,9 @@ gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref,
/* Return list of cards. */
int agent_scd_cardlist (strlist_t *result);
+/* Switch/assure a certain application. */
+gpg_error_t agent_scd_switchapp (const char *appname);
+
/* Free a keypair info list. */
void free_keypair_info (keypair_info_t l);
@@ -132,7 +135,8 @@ int agent_keytotpm (ctrl_t ctrl, const char *hexgrip);
/* 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 6451b31e7..d680c4d0a 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -705,6 +705,14 @@ current_card_status (ctrl_t ctrl, estream_t fp,
}
else
tty_fprintf (fp, "[none]\n");
+
+ if (!info.manufacturer_name)
+ {
+ tty_fprintf (fp, "\n");
+ tty_fprintf (fp, _("Please try command \"%s\""
+ " if the listing does not look correct\n"),
+ "openpgp");
+ }
}
release_kbnode (keyblock);
@@ -1289,6 +1297,7 @@ get_info_for_key_operation (struct agent_card_info_s *info)
int rc;
memset (info, 0, sizeof *info);
+ agent_scd_switchapp ("openpgp");
rc = agent_scd_getattr ("SERIALNO", info);
if (rc || !info->serialno || strncmp (info->serialno, "D27600012401", 12)
|| strlen (info->serialno) != 32 )
@@ -1796,8 +1805,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
@@ -1871,8 +1881,19 @@ 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
@@ -1881,9 +1902,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;
}
@@ -2242,7 +2264,7 @@ enum cmdids
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
- cmdKEYATTR, cmdUIF,
+ cmdKEYATTR, cmdUIF, cmdOPENPGP,
cmdINVCMD
};
@@ -2280,6 +2302,7 @@ static struct
N_("setup KDF for PIN authentication (on/single/off)")},
{ "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
{ "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
+ { "openpgp", cmdOPENPGP, 0, N_("switch to the OpenPGP app")},
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL },
@@ -2579,6 +2602,11 @@ card_edit (ctrl_t ctrl, strlist_t commands)
uif (arg_number, arg_rest);
break;
+ case cmdOPENPGP:
+ agent_scd_switchapp ("openpgp");
+ redisplay = 1;
+ break;
+
case cmdQUIT:
goto leave;
diff --git a/g10/import.c b/g10/import.c
index 1ed40a63c..5e44942e7 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -2955,9 +2955,19 @@ do_transfer (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *pk,
{
gpg_error_t err;
struct import_stats_s subkey_stats = {0};
+ int force = 0;
+ int already_exist = agent_probe_secret_key (ctrl, pk);
+
+ if (already_exist == 2 || already_exist == 4)
+ {
+ if (!opt.quiet)
+ log_info (_("key %s: card reference is overridden by key material\n"),
+ keystr_from_pk (pk));
+ force = 1;
+ }
err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
- batch, 0, only_marked);
+ batch, force, only_marked);
if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
{
/* TRANSLATORS: For a smartcard, each private key on host has a
diff --git a/g10/keydb.h b/g10/keydb.h
index 9323e3137..1a66d664e 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -576,6 +576,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 c97783124..7f54f7da0 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -5327,12 +5327,20 @@ 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)
+ return gpg_error_from_syserror ();
+ }
+
err = hexkeygrip_from_pk (sk, &hexgrip);
if (err)
goto leave;
@@ -5345,7 +5353,8 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
goto leave;
}
- 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)
{
@@ -5388,6 +5397,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 ca6564c5c..9191fec92 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -1141,3 +1141,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);
+}