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;
|
||||
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)
|
||||
|
@ -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 ();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user