summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-08-11 12:56:44 +0200
committerWerner Koch <wk@gnupg.org>2009-08-11 12:56:44 +0200
commit25659d66f1bacd9c737766fd5db8c5eaa21ef796 (patch)
tree9737e8b97f2ba14132a9e9d80e3bf26e78ec2a71
parentImproved detection of bad/invalid signer keys. (diff)
downloadgnupg2-25659d66f1bacd9c737766fd5db8c5eaa21ef796.tar.xz
gnupg2-25659d66f1bacd9c737766fd5db8c5eaa21ef796.zip
Ask to insert the right OpenPGP card.
-rw-r--r--NEWS3
-rw-r--r--agent/ChangeLog4
-rw-r--r--agent/divert-scd.c7
-rw-r--r--g10/ChangeLog7
-rw-r--r--g10/call-agent.c180
-rw-r--r--g10/call-agent.h3
6 files changed, 186 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index f0a24879d..cfc99c89f 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,9 @@ Noteworthy changes in version 2.0.13
* Add hack to the internal CCID driver to allow the use of some
Omnikey based card readers with 2048 bit keys.
+ * GPG now repeatly asks the user to insert the requested OpenPGP
+ card. This can be disabled with --limit-card-insert-tries=1.
+
* Minor bug fixes.
diff --git a/agent/ChangeLog b/agent/ChangeLog
index d0c1a7f45..0fdcd92d1 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,7 @@
+2009-08-11 Werner Koch <wk@g10code.com>
+
+ * divert-scd.c (ask_for_card): I18n a prompt string.
+
2009-07-06 Werner Koch <wk@g10code.com>
* agent.h: Include session-env.h.
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index 4c3db9678..6f23e98ca 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -88,9 +88,10 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
if (asprintf (&desc,
"%s:%%0A%%0A"
" \"%.*s\"",
- no_card? "Please insert the card with serial number"
- : "Please remove the current card and "
- "insert the one with serial number",
+ no_card
+ ? _("Please insert the card with serial number")
+ : _("Please remove the current card and "
+ "insert the one with serial number"),
want_sn_displen, want_sn) < 0)
{
rc = out_of_core ();
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 7e6a6f758..f4cfe361f 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,10 @@
+2009-08-11 Werner Koch <wk@g10code.com>
+
+ * call-agent.c (get_serialno_cb): New. From ../agent/call-scd.c.
+ (gpg_agent_get_confirmation): New.
+ (select_openpgp): New.
+ (agent_scd_pkdecrypt, agent_scd_pksign): Use it here.
+
2009-08-06 Werner Koch <wk@g10code.com>
* skclist.c (build_sk_list): Print INV_SGNR status line.
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 64b5cd857..12ecd9d57 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1,6 +1,6 @@
/* call-agent.c - Divert GPG operations to the agent.
* Copyright (C) 2001, 2002, 2003, 2006, 2007,
- * 2008 Free Software Foundation, Inc.
+ * 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -239,6 +239,38 @@ dummy_data_cb (void *opaque, const void *buffer, size_t length)
return 0;
}
+/* A simple callback used to return the serialnumber of a card. */
+static int
+get_serialno_cb (void *opaque, const char *line)
+{
+ char **serialno = opaque;
+ const char *keyword = line;
+ const char *s;
+ int keywordlen, n;
+
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+ {
+ if (*serialno)
+ return gpg_error (GPG_ERR_CONFLICT); /* Unexpected status line. */
+ for (n=0,s=line; hexdigitp (s); s++, n++)
+ ;
+ if (!n || (n&1)|| !(spacep (s) || !*s) )
+ return gpg_error (GPG_ERR_ASS_PARAMETER);
+ *serialno = xtrymalloc (n+1);
+ if (!*serialno)
+ return out_of_core ();
+ memcpy (*serialno, line, n);
+ (*serialno)[n] = 0;
+ }
+
+ return 0;
+}
+
/* This is the default inquiry callback. It mainly handles the
Pinentry notifications. */
@@ -755,6 +787,100 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
return rc;
}
+
+
+
+/* Issue an SCD SERIALNO openpgp command and if SERIALNO is not NULL
+ ask the user to insert the requested card. */
+gpg_error_t
+select_openpgp (const char *serialno)
+{
+ gpg_error_t err;
+
+ /* Send the serialno command to initialize the connection. Without
+ a given S/N we don't care about the data returned. If the card
+ has already been initialized, this is a very fast command. We
+ request the openpgp card because that is what we expect.
+
+ Note that an opt.limit_card_insert_tries of 1 means: No tries at
+ all whereas 0 means do not limit the number of tries. Due to the
+ sue of a pinentry prompt with a cancel option we use it here in a
+ boolean sense. */
+ if (!serialno || opt.limit_card_insert_tries == 1)
+ err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else
+ {
+ char *this_sn = NULL;
+ char *desc;
+ int ask;
+ char *want_sn;
+ char *p;
+
+ want_sn = xtrystrdup (serialno);
+ if (!want_sn)
+ return gpg_error_from_syserror ();
+ p = strchr (want_sn, '/');
+ if (p)
+ *p = 0;
+
+ do
+ {
+ ask = 0;
+ err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
+ NULL, NULL, NULL, NULL,
+ get_serialno_cb, &this_sn);
+ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
+ ask = 1;
+ else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
+ ask = 2;
+ else if (err)
+ ;
+ else if (this_sn)
+ {
+ if (strcmp (want_sn, this_sn))
+ ask = 2;
+ }
+
+ xfree (this_sn);
+ this_sn = NULL;
+
+ if (ask)
+ {
+ char *formatted = NULL;
+ char *ocodeset = i18n_switchto_utf8 ();
+
+ if (!strncmp (want_sn, "D27600012401", 12)
+ && strlen (want_sn) == 32 )
+ formatted = xtryasprintf ("(%.4s) %.8s",
+ want_sn + 16, want_sn + 20);
+
+ err = 0;
+ desc = xtryasprintf
+ ("%s:\n\n"
+ " \"%s\"",
+ ask == 1
+ ? _("Please insert the card with serial number")
+ : _("Please remove the current card and "
+ "insert the one with serial number"),
+ formatted? formatted : want_sn);
+ if (!desc)
+ err = gpg_error_from_syserror ();
+ xfree (formatted);
+ i18n_switchback (ocodeset);
+ if (!err)
+ err = gpg_agent_get_confirmation (desc);
+ xfree (desc);
+ }
+ }
+ while (ask && !err);
+ xfree (want_sn);
+ }
+
+ return err;
+}
+
+
static int
membuf_data_cb (void *opaque, const void *buffer, size_t length)
@@ -784,18 +910,16 @@ agent_scd_pksign (const char *serialno, int hashalgo,
*r_buflen = 0;
rc = start_agent (1);
+ if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
+ || gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
+ rc = 0; /* We check later. */
if (rc)
return rc;
if (indatalen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
- /* Send the serialno command to initialize the connection. We don't
- care about the data returned. If the card has already been
- initialized, this is a very fast command. We request the openpgp
- card because that is what we expect. */
- rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL, NULL, NULL);
+ rc = select_openpgp (serialno);
if (rc)
return rc;
@@ -833,7 +957,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
/* Decrypt INDATA of length INDATALEN using the card identified by
SERIALNO. Return the plaintext in a nwly allocated buffer stored
- at the address of R_BUF.
+ at the address of R_BUF.
Note, we currently support only RSA or more exactly algorithms
taking one input data element. */
@@ -849,6 +973,9 @@ agent_scd_pkdecrypt (const char *serialno,
*r_buf = NULL;
rc = start_agent (1);
+ if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
+ || gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
+ rc = 0; /* We check later. */
if (rc)
return rc;
@@ -856,15 +983,10 @@ agent_scd_pkdecrypt (const char *serialno,
if (indatalen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
- /* Send the serialno command to initialize the connection. We don't
- care about the data returned. If the card has already been
- initialized, this is a very fast command. We request the openpgp
- card because that is what we expect. */
- rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL, NULL, NULL);
+ rc = select_openpgp (serialno);
if (rc)
return rc;
-
+
sprintf (line, "SCD SETDATA ");
p = line + strlen (line);
for (i=0; i < indatalen ; i++, p += 2 )
@@ -1104,3 +1226,31 @@ agent_clear_passphrase (const char *cache_id)
return assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, NULL, NULL, NULL);
}
+
+
+/* Ask the agent to pop up a confirmation dialog with the text DESC
+ and an okay and cancel button. */
+gpg_error_t
+gpg_agent_get_confirmation (const char *desc)
+{
+ int rc;
+ char *tmp;
+ char line[ASSUAN_LINELENGTH];
+
+ rc = start_agent (0);
+ if (rc)
+ return rc;
+
+ tmp = percent_plus_escape (desc);
+ if (!tmp)
+ return gpg_error_from_syserror ();
+ snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", tmp);
+ line[DIM(line)-1] = 0;
+ xfree (tmp);
+
+ rc = assuan_transact (agent_ctx, line, NULL, NULL,
+ default_inq_cb, NULL, NULL, NULL);
+ return rc;
+}
+
+
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 31985d6ee..a89f483de 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -134,6 +134,9 @@ gpg_error_t agent_get_passphrase (const char *cache_id,
/* Send the CLEAR_PASSPHRASE command to the agent. */
gpg_error_t agent_clear_passphrase (const char *cache_id);
+/* Present the prompt DESC and ask the user to confirm. */
+gpg_error_t gpg_agent_get_confirmation (const char *desc);
+
#endif /*GNUPG_G10_CALL_AGENT_H*/