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@gnupg.org>
This commit is contained in:
Werner Koch 2017-02-22 13:03:52 +01:00
parent 6488ffb767
commit e3944f34e3
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 220 additions and 53 deletions

View File

@ -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)

View File

@ -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 ();