aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/command.c22
-rw-r--r--g10/call-agent.c10
-rw-r--r--g10/skclist.c39
3 files changed, 64 insertions, 7 deletions
diff --git a/agent/command.c b/agent/command.c
index 145c9595a..b1f89e0c8 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -978,8 +978,8 @@ cmd_genkey (assuan_context_t ctx, char *line)
static const char hlp_readkey[] =
- "READKEY <hexstring_with_keygrip>\n"
- " --card <keyid>\n"
+ "READKEY [--no-data] <hexstring_with_keygrip>\n"
+ " --card <keyid>\n"
"\n"
"Return the public key for the given keygrip or keyid.\n"
"With --card, private key file with card information will be created.";
@@ -992,18 +992,20 @@ cmd_readkey (assuan_context_t ctx, char *line)
gcry_sexp_t s_pkey = NULL;
unsigned char *pkbuf = NULL;
char *serialno = NULL;
+ char *keyidbuf = NULL;
size_t pkbuflen;
- const char *opt_card;
+ int opt_card, opt_no_data;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
- opt_card = has_option_name (line, "--card");
+ opt_no_data = has_option (line, "--no-data");
+ opt_card = has_option (line, "--card");
line = skip_options (line);
if (opt_card)
{
- const char *keyid = opt_card;
+ const char *keyid = line;
rc = agent_card_getattr (ctrl, "SERIALNO", &serialno);
if (rc)
@@ -1013,6 +1015,11 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
+ /* Hack to create the shadow key for the OpenPGP standard keys. */
+ if ((!strcmp (keyid, "$SIGNKEYID") || !strcmp (keyid, "$ENCRKEYID"))
+ && !agent_card_getattr (ctrl, keyid, &keyidbuf))
+ keyid = keyidbuf;
+
rc = agent_card_readkey (ctrl, keyid, &pkbuf);
if (rc)
goto leave;
@@ -1038,7 +1045,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
- rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+ rc = opt_no_data? 0 : assuan_send_data (ctx, pkbuf, pkbuflen);
}
else
{
@@ -1058,12 +1065,13 @@ cmd_readkey (assuan_context_t ctx, char *line)
{
pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON,
pkbuf, pkbuflen);
- rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+ rc = opt_no_data? 0 : assuan_send_data (ctx, pkbuf, pkbuflen);
}
}
}
leave:
+ xfree (keyidbuf);
xfree (serialno);
xfree (pkbuf);
gcry_sexp_release (s_pkey);
diff --git a/g10/call-agent.c b/g10/call-agent.c
index c7f1c296a..a9d72719f 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1097,6 +1097,16 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm,
learn_status_cb, info);
+ if (!rc && !strcmp (name, "KEY-FPR"))
+ {
+ /* Let the agent create the shadow keys if not yet done. */
+ if (info->fpr1valid)
+ assuan_transact (agent_ctx, "READKEY --card --no-data -- $SIGNKEYID",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (info->fpr2valid)
+ assuan_transact (agent_ctx, "READKEY --card --no-data -- $ENCRKEYID",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
return rc;
}
diff --git a/g10/skclist.c b/g10/skclist.c
index 5a32b6a17..d0511adea 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -31,6 +31,7 @@
#include "keydb.h"
#include "../common/util.h"
#include "../common/i18n.h"
+#include "keyserver-internal.h"
#include "call-agent.h"
@@ -326,11 +327,14 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
{
gpg_error_t err = 0;
const char *name;
+ int cardkey; /* We got an encryption fingerprint from the card */
+ /* in c->info.fpr2. */
kbnode_t keyblock;
struct
{
int eof;
int state;
+ int cardkey_done;
strlist_t sl;
strlist_t card_list;
char *serialno;
@@ -389,6 +393,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
char *serialno;
name = NULL;
+ cardkey = 0;
keyblock = NULL;
switch (c->state)
{
@@ -444,6 +449,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
bin2hex (c->info.fpr2, sizeof c->info.fpr2,
c->fpr2 + 2);
name = c->fpr2;
+ cardkey = 1;
}
}
else if (gpg_err_code (err) == GPG_ERR_INV_NAME)
@@ -551,6 +557,39 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
it. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
+ /* If this was a card key we might not yet have the
+ * public key for it. Thus check whether the card
+ * can return the fingerprint of the encryption key
+ * and we can then find the public key via LDAP. */
+ if (cardkey && !c->cardkey_done
+ && gpg_err_code (err) == GPG_ERR_NO_SECKEY)
+ {
+ /* Note that this code does not handle the case
+ * for two readers having both openpgp
+ * encryption keys. Only one will be tried. */
+ c->cardkey_done = 1;
+ if (opt.debug)
+ log_debug ("using LDAP to find public key"
+ " for current card\n");
+ if (!keyserver_import_fprint
+ (ctrl, c->info.fpr2, sizeof c->info.fpr2,
+ opt.keyserver, KEYSERVER_IMPORT_FLAG_LDAP))
+ {
+ char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
+
+ bin2hex (c->info.fpr2, sizeof c->info.fpr2,
+ fpr_string);
+ err = getkey_byname (ctrl, NULL, NULL, fpr_string, 1,
+ &c->keyblock);
+ if (err)
+ {
+ release_kbnode (c->keyblock);
+ c->keyblock = NULL;
+ }
+ else
+ c->node = c->keyblock;
+ }
+ }
}
else
c->node = c->keyblock;