[Pkg-gnupg-commit] [gnupg2] 122/166: scd: Improve the prompts for OpenPGP cards.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Thu Mar 16 22:33:12 UTC 2017
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch experimental
in repository gnupg2.
commit e3944f34e3220f96fb1be449eb6f3d7360bc2d0b
Author: Werner Koch <wk at gnupg.org>
Date: Wed Feb 22 13:03:52 2017 +0100
scd: Improve the prompts for OpenPGP cards.
* scd/app-openpgp.c (get_disp_name): New.
(get_disp_serialno): New.
(get_prompt_info): New.
(build_enter_admin_pin_prompt): Rework the prompt texts. Factor some
code out to ...
(get_remaining_tries): New.
(verify_a_chv): Print a remaining counter also for the standard PIN.
Rework the prompt texts.
* agent/divert-scd.c (ask_for_card): Pretty format an OpenPGP serial
no.
Signed-off-by: Werner Koch <wk at gnupg.org>
---
agent/divert-scd.c | 53 +++++++++----
scd/app-openpgp.c | 220 ++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 220 insertions(+), 53 deletions(-)
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index 3164404..d9d734c 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -39,22 +39,39 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
char *serialno;
int no_card = 0;
char *desc;
- char *want_sn, *want_kid;
- int want_sn_displen;
+ char *want_sn, *want_kid, *want_sn_disp;
+ int len;
*r_kid = NULL;
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
if (rc)
return rc;
+ want_sn_disp = xtrystrdup (want_sn);
+ if (!want_sn_disp)
+ {
+ rc = gpg_error_from_syserror ();
+ xfree (want_sn);
+ return rc;
+ }
- /* We assume that a 20 byte serial number is a standard one which
- has the property to have a zero in the last nibble (Due to BCD
- representation). We don't display this '0' because it may
- confuse the user. */
- want_sn_displen = strlen (want_sn);
- if (want_sn_displen == 20 && want_sn[19] == '0')
- want_sn_displen--;
+ len = strlen (want_sn_disp);
+ if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12))
+ {
+ /* This is an OpenPGP card - reformat */
+ memmove (want_sn_disp, want_sn_disp+16, 4);
+ want_sn_disp[4] = ' ';
+ memmove (want_sn_disp+5, want_sn_disp+20, 8);
+ want_sn_disp[13] = 0;
+ }
+ else if (len == 20 && want_sn_disp[19] == '0')
+ {
+ /* We assume that a 20 byte serial number is a standard one
+ * which has the property to have a zero in the last nibble (Due
+ * to BCD representation). We don't display this '0' because it
+ * may confuse the user. */
+ want_sn_disp[19] = 0;
+ }
for (;;)
{
@@ -93,12 +110,12 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
{
if (asprintf (&desc,
"%s:%%0A%%0A"
- " \"%.*s\"",
+ " %s",
no_card
? L_("Please insert the card with serial number")
: L_("Please remove the current card and "
"insert the one with serial number"),
- want_sn_displen, want_sn) < 0)
+ want_sn_disp) < 0)
{
rc = out_of_core ();
}
@@ -114,6 +131,7 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
}
if (rc)
{
+ xfree (want_sn_disp);
xfree (want_sn);
xfree (want_kid);
return rc;
@@ -312,7 +330,8 @@ getpin_cb (void *opaque, const char *desc_text, const char *info,
info, NULL);
else
desc2 = NULL;
- rc = agent_askpin (ctrl, desc2, prompt, again_text, pi, NULL, 0);
+ rc = agent_askpin (ctrl, desc2? desc2 : info,
+ prompt, again_text, pi, NULL, 0);
xfree (desc2);
}
again_text = NULL;
@@ -401,6 +420,8 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
size_t siglen;
unsigned char *sigval = NULL;
+ (void)desc_text;
+
rc = ask_for_card (ctrl, shadow_info, &kid);
if (rc)
return rc;
@@ -409,7 +430,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
{
int save = ctrl->use_auth_call;
ctrl->use_auth_call = 1;
- rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, desc_text,
+ rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL,
algo, digest, digestlen, &sigval, &siglen);
ctrl->use_auth_call = save;
}
@@ -421,7 +442,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
rc = encode_md_for_card (digest, digestlen, algo, &data, &ndata);
if (!rc)
{
- rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, desc_text,
+ rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL,
algo, data, ndata, &sigval, &siglen);
xfree (data);
}
@@ -458,6 +479,8 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
char *plaintext;
size_t plaintextlen;
+ (void)desc_text;
+
*r_padding = -1;
s = cipher;
@@ -523,7 +546,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
if (rc)
return rc;
- rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, desc_text,
+ rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, NULL,
ciphertext, ciphertextlen,
&plaintext, &plaintextlen, r_padding);
if (!rc)
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 608e3cc..90c2661 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1082,6 +1082,104 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
return rc;
}
+
+/* Return the DISP-NAME without any padding characters. Caller must
+ * free the result. If not found or empty NULL is returned. */
+static char *
+get_disp_name (app_t app)
+{
+ int rc;
+ void *relptr;
+ unsigned char *value;
+ size_t valuelen;
+ char *string;
+ char *p, *given;
+ char *result;
+
+ relptr = get_one_do (app, 0x005B, &value, &valuelen, &rc);
+ if (!relptr)
+ return NULL;
+
+ string = xtrymalloc (valuelen + 1);
+ if (!string)
+ {
+ xfree (relptr);
+ return NULL;
+ }
+ memcpy (string, value, valuelen);
+ string[valuelen] = 0;
+ xfree (relptr);
+
+ /* Swap surname and given name. */
+ given = strstr (string, "<<");
+ for (p = string; *p; p++)
+ if (*p == '<')
+ *p = ' ';
+
+ if (given && given[2])
+ {
+ *given = 0;
+ given += 2;
+ result = strconcat (given, " ", string, NULL);
+ }
+ else
+ {
+ result = string;
+ string = NULL;
+ }
+
+ xfree (string);
+ return result;
+}
+
+
+/* Return the pretty formatted serialnumber. On error NULL is
+ * returned. */
+static char *
+get_disp_serialno (app_t app)
+{
+ char *serial = app_get_serialno (app);
+
+ /* For our OpenPGP cards we do not want to show the entire serial
+ * number but a nicely reformatted actual serial number. */
+ if (serial && strlen (serial) > 16+12)
+ {
+ memmove (serial, serial+16, 4);
+ serial[4] = ' ';
+ /* memmove (serial+5, serial+20, 4); */
+ /* serial[9] = ' '; */
+ /* memmove (serial+10, serial+24, 4); */
+ /* serial[14] = 0; */
+ memmove (serial+5, serial+20, 8);
+ serial[13] = 0;
+ }
+ return serial;
+}
+
+
+/* Return the number of remaining tries for the standard or the admin
+ * pw. Returns -1 on card error. */
+static int
+get_remaining_tries (app_t app, int adminpw)
+{
+ void *relptr;
+ unsigned char *value;
+ size_t valuelen;
+ int remaining;
+
+ relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
+ if (!relptr || valuelen < 7)
+ {
+ log_error (_("error retrieving CHV status from card\n"));
+ xfree (relptr);
+ return -1;
+ }
+ remaining = value[adminpw? 6 : 4];
+ xfree (relptr);
+ return remaining;
+}
+
+
/* Retrieve the fingerprint from the card inserted in SLOT and write
the according hex representation to FPR. Caller must have provide
a buffer at FPR of least 41 bytes. Returns 0 on success or an
@@ -1874,6 +1972,62 @@ check_pinpad_request (app_t app, pininfo_t *pininfo, int admin_pin)
}
+/* Return a string with information about the card for use in a
+ * prompt. Returns NULL on memory failure. */
+static char *
+get_prompt_info (app_t app, int chvno, unsigned long sigcount, int remaining)
+{
+ char *serial, *disp_name, *rembuf, *tmpbuf, *result;
+
+ serial = get_disp_serialno (app);
+ if (!serial)
+ return NULL;
+
+ disp_name = get_disp_name (app);
+ if (chvno == 1)
+ {
+ result = xtryasprintf (_("Card number:\t%s%%0A"
+ "Signatures:\t%lu%%0A"
+ "Cardholder:\t%s"),
+ serial,
+ sigcount,
+ disp_name? disp_name:"");
+ }
+ else
+ {
+ result = xtryasprintf (_("Card number:\t%s%%0A"
+ "Cardholder:\t%s"),
+ serial,
+ disp_name? disp_name:"");
+ }
+ xfree (disp_name);
+ xfree (serial);
+
+ if (remaining != -1)
+ {
+ /* TRANSLATORS: This is the number of remaining attempts to
+ * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. */
+ rembuf = xtryasprintf (_("Remaining attempts: %d"), remaining);
+ if (!rembuf)
+ {
+ xfree (result);
+ return NULL;
+ }
+ tmpbuf = strconcat (result, "%0A%0A", rembuf, NULL);
+ xfree (rembuf);
+ if (!tmpbuf)
+ {
+ xfree (result);
+ return NULL;
+ }
+ xfree (result);
+ result = tmpbuf;
+ }
+
+ return result;
+}
+
+
/* Verify a CHV either using the pinentry or if possible by
using a pinpad. PINCB and PINCB_ARG describe the usual callback
for the pinentry. CHVNO must be either 1 or 2. SIGCOUNT is only
@@ -1895,11 +2049,16 @@ verify_a_chv (app_t app,
const char *prompt;
pininfo_t pininfo;
int minlen = 6;
+ int remaining;
- assert (chvno == 1 || chvno == 2);
+ log_assert (chvno == 1 || chvno == 2);
*pinvalue = NULL;
+ remaining = get_remaining_tries (app, 0);
+ if (remaining == -1)
+ return gpg_error (GPG_ERR_CARD);
+
if (chvno == 2 && app->app_local->flags.def_chv2)
{
/* Special case for def_chv2 mechanism. */
@@ -1923,22 +2082,19 @@ verify_a_chv (app_t app,
pininfo.fixedlen = -1;
pininfo.minlen = minlen;
+ {
+ const char *firstline = _("||Please unlock the card");
+ char *infoblock = get_prompt_info (app, chvno, sigcount,
+ remaining < 3? remaining : -1);
- if (chvno == 1)
- {
-#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]")
- size_t promptsize = strlen (PROMPTSTRING) + 50;
-
- prompt_buffer = xtrymalloc (promptsize);
- if (!prompt_buffer)
- return gpg_error_from_syserror ();
- snprintf (prompt_buffer, promptsize, PROMPTSTRING, sigcount);
+ prompt_buffer = strconcat (firstline, "%0A%0A", infoblock, NULL);
+ if (prompt_buffer)
prompt = prompt_buffer;
-#undef PROMPTSTRING
- }
- else
- prompt = _("||Please enter the PIN");
+ else
+ prompt = firstline; /* ENOMEM fallback. */
+ xfree (infoblock);
+ }
if (!opt.disable_pinpad
&& !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
@@ -1961,7 +2117,7 @@ verify_a_chv (app_t app,
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
- assert (!*pinvalue);
+ log_assert (!*pinvalue);
}
else
{
@@ -2049,29 +2205,20 @@ verify_chv2 (app_t app,
static gpg_error_t
build_enter_admin_pin_prompt (app_t app, char **r_prompt)
{
- void *relptr;
- unsigned char *value;
- size_t valuelen;
int remaining;
char *prompt;
+ char *infoblock;
*r_prompt = NULL;
- relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
- if (!relptr || valuelen < 7)
- {
- log_error (_("error retrieving CHV status from card\n"));
- xfree (relptr);
- return gpg_error (GPG_ERR_CARD);
- }
- if (value[6] == 0)
+ remaining = get_remaining_tries (app, 1);
+ if (remaining == -1)
+ return gpg_error (GPG_ERR_CARD);
+ if (!remaining)
{
log_info (_("card is permanently locked!\n"));
- xfree (relptr);
return gpg_error (GPG_ERR_BAD_PIN);
}
- remaining = value[6];
- xfree (relptr);
log_info (ngettext("%d Admin PIN attempt remaining before card"
" is permanently locked\n",
@@ -2079,16 +2226,13 @@ build_enter_admin_pin_prompt (app_t app, char **r_prompt)
" is permanently locked\n",
remaining), remaining);
- if (remaining < 3)
- {
- /* TRANSLATORS: Do not translate the "|A|" prefix but keep it at
- the start of the string. Use %%0A to force a linefeed. */
- prompt = xtryasprintf (_("|A|Please enter the Admin PIN%%0A"
- "[remaining attempts: %d]"), remaining);
- }
- else
- prompt = xtrystrdup (_("|A|Please enter the Admin PIN"));
+ infoblock = get_prompt_info (app, 3, 0, remaining < 3? remaining : -1);
+ /* TRANSLATORS: Do not translate the "|A|" prefix but keep it at
+ the start of the string. Use %0A (single percent) for a linefeed. */
+ prompt = strconcat (_("|A|Please enter the Admin PIN"),
+ "%0A%0A", infoblock, NULL);
+ xfree (infoblock);
if (!prompt)
return gpg_error_from_syserror ();
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git
More information about the Pkg-gnupg-commit
mailing list