SCD: handle keypad request on the card.

* scd/app-openpgp.c: Add 2013.
(struct app_local_s): Add keypad structure.
(parse_login_data): Add parsing keypad request on the card.
(check_keypad_request): New.
(verify_a_chv, verify_chv3, do_change_pin): Call check_keypad_request
to determine use of keypad.
This commit is contained in:
NIIBE Yutaka 2013-01-10 15:58:43 +09:00
parent d5bf83a24c
commit 334ba6efa5
1 changed files with 104 additions and 6 deletions

View File

@ -1,6 +1,6 @@
/* app-openpgp.c - The OpenPGP card application.
* Copyright (C) 2003, 2004, 2005, 2007, 2008,
* 2009 Free Software Foundation, Inc.
* 2009, 2013 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -191,6 +191,15 @@ struct app_local_s {
unsigned int def_chv2:1; /* Use 123456 for CHV2. */
} flags;
/* Keypad request specified on card. */
struct
{
unsigned int specified:1;
unsigned int varlen:1;
int fixedlen_user;
int fixedlen_admin;
} keypad;
struct
{
unsigned int n_bits; /* Size of the modulus in bits. The rest
@ -581,17 +590,23 @@ count_bits (const unsigned char *a, size_t len)
Everything up to a LF is considered a mailbox or account name. If
the first LF is followed by DC4 (0x14) control sequence are
expected up to the next LF. Control sequences are separated by FS
(0x18) and consist of key=value pairs. There is one key defined:
(0x18) and consist of key=value pairs. There are two keys defined:
F=<flags>
Were FLAGS is a plain hexadecimal number representing flag values.
Where FLAGS is a plain hexadecimal number representing flag values.
The lsb is here the rightmost bit. Defined flags bits are:
Bit 0 = CHV1 and CHV2 are not syncronized
Bit 1 = CHV2 has been been set to the default PIN of "123456"
(this implies that bit 0 is also set).
P=<keypad-request>
Where KEYPAD_REQUEST is 0 or a pair of two integers: <n>,<m>.
0 means use keypad with variable length input. <n>,<m> means use
keypad with fixed length input. N for user PIN, M for admin PIN.
*/
static void
parse_login_data (app_t app)
@ -603,6 +618,10 @@ parse_login_data (app_t app)
/* Set defaults. */
app->app_local->flags.no_sync = 0;
app->app_local->flags.def_chv2 = 0;
app->app_local->keypad.specified = 0;
app->app_local->keypad.varlen = 0;
app->app_local->keypad.fixedlen_user = 6;
app->app_local->keypad.fixedlen_admin = 8;
/* Read the DO. */
relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL);
@ -628,11 +647,56 @@ parse_login_data (app_t app)
any leading digits but bail out on invalid characters. */
for (p=buffer+2, len = buflen-2; len && hexdigitp (p); p++, len--)
lastdig = xtoi_1 (p);
buffer = p;
buflen = len;
if (len && !(*p == '\n' || *p == '\x18'))
goto next; /* Invalid characters in field. */
app->app_local->flags.no_sync = !!(lastdig & 1);
app->app_local->flags.def_chv2 = (lastdig & 3) == 3;
}
else if (buflen > 1 && *buffer == 'P' && buffer[1] == '=')
{
/* Keypad request control sequence found. */
buffer += 2;
buflen -= 2;
if (buflen)
{
if (*buffer == '0')
{
buffer++;
buflen--;
if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
goto next;
app->app_local->keypad.specified = 1;
app->app_local->keypad.varlen = 1;
}
else if (digitp (buffer))
{
char *q;
int n, m;
n = strtol (buffer, &q, 10);
if (*q++ != ',' || !digitp (q))
goto next;
m = strtol (q, &q, 10);
buffer = q;
if (buflen < ((unsigned char *)q - buffer))
{
buflen = 0;
break;
}
else
buflen -= ((unsigned char *)q - buffer);
if (buflen && !(*buffer == '\n' || *buffer == '\x18'))
goto next;
app->app_local->keypad.specified = 1;
app->app_local->keypad.fixedlen_user = n;
app->app_local->keypad.fixedlen_admin = m;
}
}
}
next:
for (; buflen && *buffer != '\x18'; buflen--, buffer++)
if (*buffer == '\n')
@ -1470,6 +1534,37 @@ do_readcert (app_t app, const char *certid,
}
/* Decide if we use keypad of reader for PIN input according to the
user preference on the card. Returns 0 if we use keypad, 1 otherwise. */
static int
check_keypad_request (app_t app, pininfo_t *pininfo, int admin_pin)
{
/* User specifies no preference on card, then, use pinentry. */
if (app->app_local->keypad.specified == 0)
return 1;
if (app->app_local->keypad.varlen)
if (pininfo->fixedlen == 0)
return 0;
else
/* On card, user specifies varlen but reader doesn't have the feature. */
return 1;
else
{
if (admin_pin)
pininfo->fixedlen = app->app_local->keypad.fixedlen_admin;
else
pininfo->fixedlen = app->app_local->keypad.fixedlen_user;
if (pininfo->fixedlen < pininfo->minlen
|| pininfo->fixedlen > pininfo->maxlen)
return 1;
return 0;
}
}
/* Verify a CHV either using using the pinentry or if possibile by
using a keypad. PINCB and PINCB_ARG describe the usual callback
for the pinentry. CHVNO must be either 1 or 2. SIGCOUNT is only
@ -1537,7 +1632,8 @@ verify_a_chv (app_t app,
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo)
&& !check_keypad_request (app, &pininfo, 0))
{
/* The reader supports the verify command through the keypad.
Note that the pincb appends a text to the prompt telling the
@ -1720,7 +1816,8 @@ verify_chv3 (app_t app,
return rc;
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo)
&& !check_keypad_request (app, &pininfo, 1))
{
/* The reader supports the verify command through the keypad. */
rc = pincb (pincb_arg, prompt, NULL);
@ -1970,7 +2067,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot,
ISO7816_CHANGE_REFERENCE_DATA, &pininfo))
ISO7816_CHANGE_REFERENCE_DATA, &pininfo)
&& !check_keypad_request (app, &pininfo, chvno == 3))
use_keypad = 1;
if (reset_mode)