aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2021-04-23 06:47:06 +0000
committerWerner Koch <[email protected]>2021-04-23 06:50:39 +0000
commit50293ec2ebf2a997dbad9a47166d694efcc0709a (patch)
tree46e5a428c73cea0a3b44bd9dab06a74fb69bb458
parentagent: Require verbose level 2 for handler started/terminated notices. (diff)
downloadgnupg-50293ec2ebf2a997dbad9a47166d694efcc0709a.tar.gz
gnupg-50293ec2ebf2a997dbad9a47166d694efcc0709a.zip
gpg: Allow decryption w/o public key but with correct card inserted.
* agent/command.c (cmd_readkey): Add option --no-data and special handling for $SIGNKEYID and $AUTHKEYID. * g10/call-agent.c (agent_scd_getattr): Create shadow keys for KEY-FPR output. * g10/skclist.c (enum_secret_keys): Automagically get a missing public key for the current card. Signed-off-by: Werner Koch <[email protected]>
-rw-r--r--agent/command.c18
-rw-r--r--g10/call-agent.c10
-rw-r--r--g10/skclist.c41
3 files changed, 64 insertions, 5 deletions
diff --git a/agent/command.c b/agent/command.c
index 88580a754..21f4289b1 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1073,8 +1073,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.";
@@ -1087,12 +1087,14 @@ 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;
- int opt_card;
+ int opt_card, opt_no_data;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ opt_no_data = has_option (line, "--no-data");
opt_card = has_option (line, "--card");
line = skip_options (line);
@@ -1108,6 +1110,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, NULL))
+ keyid = keyidbuf;
+
rc = agent_card_readkey (ctrl, keyid, &pkbuf, NULL);
if (rc)
goto leave;
@@ -1133,7 +1140,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
{
@@ -1153,12 +1160,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 fb80489b2..83355454a 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1232,6 +1232,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->fpr1len)
+ assuan_transact (agent_ctx, "READKEY --card --no-data -- $SIGNKEYID",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (info->fpr2len)
+ 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 c9f7d126a..f9647cc1d 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"
@@ -322,11 +323,13 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
{
gpg_error_t err = 0;
const char *name;
+ int cardkey;
kbnode_t keyblock;
struct
{
int eof;
int state;
+ int cardkey_done;
strlist_t sl;
keypair_info_t card_keyinfo;
keypair_info_t card_keyinfo_list;
@@ -381,6 +384,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
do
{
name = NULL;
+ cardkey = 0;
keyblock = NULL;
switch (c->state)
{
@@ -431,6 +435,7 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
c->fpr2[i] = *s;
c->fpr2[i] = 0;
name = c->fpr2;
+ cardkey = 1;
c->card_keyinfo = c->card_keyinfo->next;
}
@@ -482,11 +487,47 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
if (err)
{
+ struct agent_card_info_s cinfo = { 0 };
+
/* getkey_byname might return a keyblock even in the
error case - I have not checked. Thus better release
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
+ && !agent_scd_getattr ("KEY-FPR", &cinfo)
+ && cinfo.fpr2len)
+ {
+ /* 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, cinfo.fpr2, cinfo.fpr2len, opt.keyserver,
+ KEYSERVER_IMPORT_FLAG_LDAP))
+ {
+ char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
+
+ bin2hex (cinfo.fpr2, cinfo.fpr2len, 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;