mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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:
parent
6488ffb767
commit
e3944f34e3
@ -39,22 +39,39 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
|
|||||||
char *serialno;
|
char *serialno;
|
||||||
int no_card = 0;
|
int no_card = 0;
|
||||||
char *desc;
|
char *desc;
|
||||||
char *want_sn, *want_kid;
|
char *want_sn, *want_kid, *want_sn_disp;
|
||||||
int want_sn_displen;
|
int len;
|
||||||
|
|
||||||
*r_kid = NULL;
|
*r_kid = NULL;
|
||||||
|
|
||||||
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
|
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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
|
len = strlen (want_sn_disp);
|
||||||
has the property to have a zero in the last nibble (Due to BCD
|
if (len == 32 && !strncmp (want_sn_disp, "D27600012401", 12))
|
||||||
representation). We don't display this '0' because it may
|
{
|
||||||
confuse the user. */
|
/* This is an OpenPGP card - reformat */
|
||||||
want_sn_displen = strlen (want_sn);
|
memmove (want_sn_disp, want_sn_disp+16, 4);
|
||||||
if (want_sn_displen == 20 && want_sn[19] == '0')
|
want_sn_disp[4] = ' ';
|
||||||
want_sn_displen--;
|
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 (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -93,12 +110,12 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
|
|||||||
{
|
{
|
||||||
if (asprintf (&desc,
|
if (asprintf (&desc,
|
||||||
"%s:%%0A%%0A"
|
"%s:%%0A%%0A"
|
||||||
" \"%.*s\"",
|
" %s",
|
||||||
no_card
|
no_card
|
||||||
? L_("Please insert the card with serial number")
|
? L_("Please insert the card with serial number")
|
||||||
: L_("Please remove the current card and "
|
: L_("Please remove the current card and "
|
||||||
"insert the one with serial number"),
|
"insert the one with serial number"),
|
||||||
want_sn_displen, want_sn) < 0)
|
want_sn_disp) < 0)
|
||||||
{
|
{
|
||||||
rc = out_of_core ();
|
rc = out_of_core ();
|
||||||
}
|
}
|
||||||
@ -114,6 +131,7 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
|
|||||||
}
|
}
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
xfree (want_sn_disp);
|
||||||
xfree (want_sn);
|
xfree (want_sn);
|
||||||
xfree (want_kid);
|
xfree (want_kid);
|
||||||
return rc;
|
return rc;
|
||||||
@ -312,7 +330,8 @@ getpin_cb (void *opaque, const char *desc_text, const char *info,
|
|||||||
info, NULL);
|
info, NULL);
|
||||||
else
|
else
|
||||||
desc2 = NULL;
|
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);
|
xfree (desc2);
|
||||||
}
|
}
|
||||||
again_text = NULL;
|
again_text = NULL;
|
||||||
@ -401,6 +420,8 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
|
|||||||
size_t siglen;
|
size_t siglen;
|
||||||
unsigned char *sigval = NULL;
|
unsigned char *sigval = NULL;
|
||||||
|
|
||||||
|
(void)desc_text;
|
||||||
|
|
||||||
rc = ask_for_card (ctrl, shadow_info, &kid);
|
rc = ask_for_card (ctrl, shadow_info, &kid);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
@ -409,7 +430,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
|
|||||||
{
|
{
|
||||||
int save = ctrl->use_auth_call;
|
int save = ctrl->use_auth_call;
|
||||||
ctrl->use_auth_call = 1;
|
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);
|
algo, digest, digestlen, &sigval, &siglen);
|
||||||
ctrl->use_auth_call = save;
|
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);
|
rc = encode_md_for_card (digest, digestlen, algo, &data, &ndata);
|
||||||
if (!rc)
|
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);
|
algo, data, ndata, &sigval, &siglen);
|
||||||
xfree (data);
|
xfree (data);
|
||||||
}
|
}
|
||||||
@ -458,6 +479,8 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
char *plaintext;
|
char *plaintext;
|
||||||
size_t plaintextlen;
|
size_t plaintextlen;
|
||||||
|
|
||||||
|
(void)desc_text;
|
||||||
|
|
||||||
*r_padding = -1;
|
*r_padding = -1;
|
||||||
|
|
||||||
s = cipher;
|
s = cipher;
|
||||||
@ -523,7 +546,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 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,
|
ciphertext, ciphertextlen,
|
||||||
&plaintext, &plaintextlen, r_padding);
|
&plaintext, &plaintextlen, r_padding);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
@ -1082,6 +1082,104 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
return rc;
|
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
|
/* Retrieve the fingerprint from the card inserted in SLOT and write
|
||||||
the according hex representation to FPR. Caller must have provide
|
the according hex representation to FPR. Caller must have provide
|
||||||
a buffer at FPR of least 41 bytes. Returns 0 on success or an
|
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
|
/* Verify a CHV either using the pinentry or if possible by
|
||||||
using a pinpad. PINCB and PINCB_ARG describe the usual callback
|
using a pinpad. PINCB and PINCB_ARG describe the usual callback
|
||||||
for the pinentry. CHVNO must be either 1 or 2. SIGCOUNT is only
|
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;
|
const char *prompt;
|
||||||
pininfo_t pininfo;
|
pininfo_t pininfo;
|
||||||
int minlen = 6;
|
int minlen = 6;
|
||||||
|
int remaining;
|
||||||
|
|
||||||
assert (chvno == 1 || chvno == 2);
|
log_assert (chvno == 1 || chvno == 2);
|
||||||
|
|
||||||
*pinvalue = NULL;
|
*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)
|
if (chvno == 2 && app->app_local->flags.def_chv2)
|
||||||
{
|
{
|
||||||
/* Special case for def_chv2 mechanism. */
|
/* Special case for def_chv2 mechanism. */
|
||||||
@ -1923,22 +2082,19 @@ verify_a_chv (app_t app,
|
|||||||
pininfo.fixedlen = -1;
|
pininfo.fixedlen = -1;
|
||||||
pininfo.minlen = minlen;
|
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)
|
prompt_buffer = strconcat (firstline, "%0A%0A", infoblock, NULL);
|
||||||
{
|
if (prompt_buffer)
|
||||||
#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 = prompt_buffer;
|
prompt = prompt_buffer;
|
||||||
#undef PROMPTSTRING
|
else
|
||||||
}
|
prompt = firstline; /* ENOMEM fallback. */
|
||||||
else
|
|
||||||
prompt = _("||Please enter the PIN");
|
|
||||||
|
|
||||||
|
xfree (infoblock);
|
||||||
|
}
|
||||||
|
|
||||||
if (!opt.disable_pinpad
|
if (!opt.disable_pinpad
|
||||||
&& !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
|
&& !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
|
||||||
@ -1961,7 +2117,7 @@ verify_a_chv (app_t app,
|
|||||||
/* Dismiss the prompt. */
|
/* Dismiss the prompt. */
|
||||||
pincb (pincb_arg, NULL, NULL);
|
pincb (pincb_arg, NULL, NULL);
|
||||||
|
|
||||||
assert (!*pinvalue);
|
log_assert (!*pinvalue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2049,29 +2205,20 @@ verify_chv2 (app_t app,
|
|||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
build_enter_admin_pin_prompt (app_t app, char **r_prompt)
|
build_enter_admin_pin_prompt (app_t app, char **r_prompt)
|
||||||
{
|
{
|
||||||
void *relptr;
|
|
||||||
unsigned char *value;
|
|
||||||
size_t valuelen;
|
|
||||||
int remaining;
|
int remaining;
|
||||||
char *prompt;
|
char *prompt;
|
||||||
|
char *infoblock;
|
||||||
|
|
||||||
*r_prompt = NULL;
|
*r_prompt = NULL;
|
||||||
|
|
||||||
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
|
remaining = get_remaining_tries (app, 1);
|
||||||
if (!relptr || valuelen < 7)
|
if (remaining == -1)
|
||||||
{
|
return gpg_error (GPG_ERR_CARD);
|
||||||
log_error (_("error retrieving CHV status from card\n"));
|
if (!remaining)
|
||||||
xfree (relptr);
|
|
||||||
return gpg_error (GPG_ERR_CARD);
|
|
||||||
}
|
|
||||||
if (value[6] == 0)
|
|
||||||
{
|
{
|
||||||
log_info (_("card is permanently locked!\n"));
|
log_info (_("card is permanently locked!\n"));
|
||||||
xfree (relptr);
|
|
||||||
return gpg_error (GPG_ERR_BAD_PIN);
|
return gpg_error (GPG_ERR_BAD_PIN);
|
||||||
}
|
}
|
||||||
remaining = value[6];
|
|
||||||
xfree (relptr);
|
|
||||||
|
|
||||||
log_info (ngettext("%d Admin PIN attempt remaining before card"
|
log_info (ngettext("%d Admin PIN attempt remaining before card"
|
||||||
" is permanently locked\n",
|
" is permanently locked\n",
|
||||||
@ -2079,16 +2226,13 @@ build_enter_admin_pin_prompt (app_t app, char **r_prompt)
|
|||||||
" is permanently locked\n",
|
" is permanently locked\n",
|
||||||
remaining), remaining);
|
remaining), remaining);
|
||||||
|
|
||||||
if (remaining < 3)
|
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 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"));
|
|
||||||
|
|
||||||
|
/* 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)
|
if (!prompt)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user