1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-23 10:29:58 +01:00

scd: PC/SC pinpad support (pinpad input for modify pass phrase). (backport)

* iso7816.h (iso7816_change_reference_data_kp): Remove arguments
of OLDCHV, OLDCHVLEN, NEWCHV, and NEWCHVLEN.

* iso7816.c (iso7816_change_reference_data_kp): Call
apdu_keypad_modify.
(iso7816_change_reference_data): Don't call
iso7816_change_reference_data_kp.

* apdu.h (apdu_keypad_modify): New.

* apdu.c (pcsc_keypad_modify, apdu_keypad_modify): New.
(struct reader_table_s): New memeber function keypad_modify.
(new_reader_slot, open_ct_reader, open_ccid_reader)
(open_rapdu_reader): Initialize keypad_modify.

* app-openpgp.c (do_change_pin): Handle keypad and call
iso7816_change_reference_data_kp if it is the case.
This commit is contained in:
NIIBE Yutaka 2011-11-29 11:59:32 +09:00
parent c2525d507d
commit f98a5e8480
5 changed files with 177 additions and 52 deletions

View File

@ -111,6 +111,7 @@ struct reader_table_s {
void (*dump_status_reader)(int); void (*dump_status_reader)(int);
int (*set_progress_cb)(int, gcry_handler_progress_t, void*); int (*set_progress_cb)(int, gcry_handler_progress_t, void*);
int (*keypad_verify)(int, int, int, int, int, struct pininfo_s *); int (*keypad_verify)(int, int, int, int, int, struct pininfo_s *);
int (*keypad_modify)(int, int, int, int, int, struct pininfo_s *);
struct { struct {
ccid_driver_t handle; ccid_driver_t handle;
@ -317,6 +318,8 @@ static int check_pcsc_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen); int pinlen_min, int pinlen_max, int pin_padlen);
static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
struct pininfo_s *pininfo); struct pininfo_s *pininfo);
static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
struct pininfo_s *pininfo);
@ -364,6 +367,7 @@ new_reader_slot (void)
reader_table[reader].dump_status_reader = NULL; reader_table[reader].dump_status_reader = NULL;
reader_table[reader].set_progress_cb = NULL; reader_table[reader].set_progress_cb = NULL;
reader_table[reader].keypad_verify = pcsc_keypad_verify; reader_table[reader].keypad_verify = pcsc_keypad_verify;
reader_table[reader].keypad_modify = pcsc_keypad_modify;
reader_table[reader].used = 1; reader_table[reader].used = 1;
reader_table[reader].any_status = 0; reader_table[reader].any_status = 0;
@ -651,6 +655,7 @@ open_ct_reader (int port)
reader_table[reader].check_keypad = NULL; reader_table[reader].check_keypad = NULL;
reader_table[reader].dump_status_reader = ct_dump_reader_status; reader_table[reader].dump_status_reader = ct_dump_reader_status;
reader_table[reader].keypad_verify = NULL; reader_table[reader].keypad_verify = NULL;
reader_table[reader].keypad_modify = NULL;
dump_reader_status (reader); dump_reader_status (reader);
return reader; return reader;
@ -2093,6 +2098,88 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
sw = (result[resultlen-2] << 8) | result[resultlen-1]; sw = (result[resultlen-2] << 8) | result[resultlen-1];
return sw; return sw;
} }
#define PIN_MODIFY_STRUCTURE_SIZE 28
static int
pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
struct pininfo_s *pininfo)
{
int sw;
unsigned char *pin_modify;
unsigned long len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
if (!reader_table[slot].atrlen
&& (sw = reset_pcsc_reader (slot)))
return sw;
if (pininfo->mode != 1)
return SW_NOT_SUPPORTED;
if (pininfo->padlen != 0)
return SW_NOT_SUPPORTED;
if (!pininfo->minlen)
pininfo->minlen = 1;
if (!pininfo->maxlen)
pininfo->maxlen = 25;
/* Note that the 25 is the maximum value the SPR532 allows. */
if (pininfo->minlen < 1 || pininfo->minlen > 25
|| pininfo->maxlen < 1 || pininfo->maxlen > 25
|| pininfo->minlen > pininfo->maxlen)
return SW_HOST_INV_VALUE;
pin_modify = xtrymalloc (len);
if (!pin_modify)
return SW_HOST_OUT_OF_CORE;
pin_modify[0] = 0x00; /* bTimerOut */
pin_modify[1] = 0x00; /* bTimerOut2 */
pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
pin_modify[3] = 0x00; /* bmPINBlockString */
pin_modify[4] = 0x00; /* bmPINLengthFormat */
pin_modify[5] = 0x00; /* bInsertionOffsetOld */
pin_modify[6] = 0x00; /* bInsertionOffsetNew */
pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
pin_modify[9] = 0x03; /* bConfirmPIN
* 0x00: new PIN once
* 0x01: new PIN twice (confirmation)
* 0x02: old PIN and new PIN once
* 0x03: old PIN and new PIN twice (confirmation)
*/
pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */
if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
pin_modify[10] |= 0x01; /* Max size reached. */
pin_modify[11] = 0xff; /* bNumberMessage: Default */
pin_modify[12] = 0x09; /* wLangId: 0x0409: US English */
pin_modify[13] = 0x04; /* wLangId: 0x0409: US English */
pin_modify[14] = 0x00; /* bMsgIndex1 */
pin_modify[15] = 0x00; /* bMsgIndex2 */
pin_modify[16] = 0x00; /* bMsgIndex3 */
pin_modify[17] = 0x00; /* bTeoPrologue[0] */
pin_modify[18] = 0x00; /* bTeoPrologue[1] */
pin_modify[19] = 0x00; /* bTeoPrologue[2] */
pin_modify[20] = 0x04; /* ulDataLength */
pin_modify[21] = 0x00; /* ulDataLength */
pin_modify[22] = 0x00; /* ulDataLength */
pin_modify[23] = 0x00; /* ulDataLength */
pin_modify[24] = class; /* abData[0] */
pin_modify[25] = ins; /* abData[1] */
pin_modify[26] = p0; /* abData[2] */
pin_modify[27] = p1; /* abData[3] */
sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
pin_modify, len, result, &resultlen);
xfree (pin_modify);
if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
sw = (result[resultlen-2] << 8) | result[resultlen-1];
return sw;
}
#ifdef HAVE_LIBUSB #ifdef HAVE_LIBUSB
/* /*
@ -2304,6 +2391,7 @@ open_ccid_reader (const char *portstr)
reader_table[slot].dump_status_reader = dump_ccid_reader_status; reader_table[slot].dump_status_reader = dump_ccid_reader_status;
reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader; reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader;
reader_table[slot].keypad_verify = ccid_keypad_verify; reader_table[slot].keypad_verify = ccid_keypad_verify;
reader_table[slot].keypad_modify = NULL;
/* Our CCID reader code does not support T=0 at all, thus reset the /* Our CCID reader code does not support T=0 at all, thus reset the
flag. */ flag. */
reader_table[slot].is_t0 = 0; reader_table[slot].is_t0 = 0;
@ -2597,6 +2685,7 @@ open_rapdu_reader (int portno,
reader_table[slot].check_keypad = NULL; reader_table[slot].check_keypad = NULL;
reader_table[slot].dump_status_reader = NULL; reader_table[slot].dump_status_reader = NULL;
reader_table[slot].keypad_verify = NULL; reader_table[slot].keypad_verify = NULL;
reader_table[slot].keypad_modify = NULL;
dump_reader_status (slot); dump_reader_status (slot);
rapdu_msg_release (msg); rapdu_msg_release (msg);
@ -3233,6 +3322,28 @@ apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
} }
int
apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen)
{
struct pininfo_s pininfo;
pininfo.mode = pin_mode;
pininfo.minlen = pinlen_min;
pininfo.maxlen = pinlen_max;
pininfo.padlen = pin_padlen;
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
if (reader_table[slot].keypad_modify)
return reader_table[slot].keypad_modify (slot, class, ins, p0, p1,
&pininfo);
else
return SW_HOST_NOT_SUPPORTED;
}
/* Dispatcher for the actual send_apdu function. Note, that this /* Dispatcher for the actual send_apdu function. Note, that this
function should be called in locked state. */ function should be called in locked state. */
static int static int

View File

@ -117,6 +117,9 @@ int apdu_check_keypad (int slot, int command, int pin_mode,
int apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int apdu_keypad_verify (int slot, int class, int ins, int p0, int p1,
int pin_mode, int pinlen_min, int pinlen_max, int pin_mode, int pinlen_min, int pinlen_max,
int pin_padlen); int pin_padlen);
int apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
int pin_mode, int pinlen_min, int pinlen_max,
int pin_padlen);
int apdu_send_simple (int slot, int extended_mode, int apdu_send_simple (int slot, int extended_mode,
int class, int ins, int p0, int p1, int class, int ins, int p0, int p1,
int lc, const char *data); int lc, const char *data);

View File

@ -1912,11 +1912,17 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
int chvno = atoi (chvnostr); int chvno = atoi (chvnostr);
char *resetcode = NULL; char *resetcode = NULL;
char *oldpinvalue = NULL; char *oldpinvalue = NULL;
char *pinvalue; char *pinvalue = NULL;
int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET); int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET);
int set_resetcode = 0; int set_resetcode = 0;
iso7816_pininfo_t pininfo;
int use_keypad = 0;
int minlen = 6;
(void)ctrl; (void)ctrl;
memset (&pininfo, 0, sizeof pininfo);
pininfo.mode = 1;
pininfo.minlen = minlen;
if (reset_mode && chvno == 3) if (reset_mode && chvno == 3)
{ {
@ -1960,6 +1966,11 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
{ {
/* Version 2 cards. */ /* Version 2 cards. */
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot,
ISO7816_CHANGE_REFERENCE_DATA, &pininfo))
use_keypad = 1;
if (reset_mode) if (reset_mode)
{ {
/* To reset a PIN the Admin PIN is required. */ /* To reset a PIN the Admin PIN is required. */
@ -1973,12 +1984,12 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
} }
else if (chvno == 1 || chvno == 3) else if (chvno == 1 || chvno == 3)
{ {
int minlen = (chvno ==3)? 8 : 6;
char *promptbuf = NULL; char *promptbuf = NULL;
const char *prompt; const char *prompt;
if (chvno == 3) if (chvno == 3)
{ {
minlen = 8;
rc = build_enter_admin_pin_prompt (app, &promptbuf); rc = build_enter_admin_pin_prompt (app, &promptbuf);
if (rc) if (rc)
goto leave; goto leave;
@ -1986,7 +1997,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
} }
else else
prompt = _("||Please enter the PIN"); prompt = _("||Please enter the PIN");
rc = pincb (pincb_arg, prompt, &oldpinvalue); rc = pincb (pincb_arg, prompt, use_keypad ? NULL : &oldpinvalue);
xfree (promptbuf); xfree (promptbuf);
promptbuf = NULL; promptbuf = NULL;
if (rc) if (rc)
@ -1996,7 +2007,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
goto leave; goto leave;
} }
if (strlen (oldpinvalue) < minlen) if (!use_keypad && strlen (oldpinvalue) < minlen)
{ {
log_info (_("PIN for CHV%d is too short;" log_info (_("PIN for CHV%d is too short;"
" minimum length is %d\n"), chvno, minlen); " minimum length is %d\n"), chvno, minlen);
@ -2012,8 +2023,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
unsigned char *value; unsigned char *value;
size_t valuelen; size_t valuelen;
int remaining; int remaining;
int minlen = 8;
minlen = 8;
relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL);
if (!relptr || valuelen < 7) if (!relptr || valuelen < 7)
{ {
@ -2060,17 +2071,20 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
else else
app->did_chv1 = app->did_chv2 = 0; app->did_chv1 = app->did_chv2 = 0;
/* TRANSLATORS: Do not translate the "|*|" prefixes but if (!use_keypad)
keep it at the start of the string. We need this elsewhere
to get some infos on the string. */
rc = pincb (pincb_arg,
set_resetcode? _("|RN|New Reset Code") :
chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
&pinvalue);
if (rc)
{ {
log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc)); /* TRANSLATORS: Do not translate the "|*|" prefixes but
goto leave; keep it at the start of the string. We need this elsewhere
to get some infos on the string. */
rc = pincb (pincb_arg,
set_resetcode? _("|RN|New Reset Code") :
chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"),
&pinvalue);
if (rc)
{
log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc));
goto leave;
}
} }
@ -2131,9 +2145,17 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
/* Version 2 cards. */ /* Version 2 cards. */
assert (chvno == 1 || chvno == 3); assert (chvno == 1 || chvno == 3);
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, if (use_keypad)
oldpinvalue, strlen (oldpinvalue), {
pinvalue, strlen (pinvalue)); rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno,
&pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
}
else
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
oldpinvalue, strlen (oldpinvalue),
pinvalue, strlen (pinvalue));
} }
if (pinvalue) if (pinvalue)

View File

@ -305,17 +305,30 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
return map_sw (sw); return map_sw (sw);
} }
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. With PININFO non-NULL the keypad of the
reader will be used. */
gpg_error_t
iso7816_change_reference_data_kp (int slot, int chvno,
iso7816_pininfo_t *pininfo)
{
int sw;
sw = apdu_keypad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, 0, chvno,
pininfo->mode, pininfo->minlen, pininfo->maxlen,
pininfo->padlen);
return map_sw (sw);
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange 0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. With PININFO non-NULL the keypad of the reader length NEWCHVLEN. */
will be used. */
gpg_error_t gpg_error_t
iso7816_change_reference_data_kp (int slot, int chvno, iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen, const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen, const char *newchv, size_t newchvlen)
iso7816_pininfo_t *pininfo)
{ {
int sw; int sw;
char *buf; char *buf;
@ -332,35 +345,13 @@ iso7816_change_reference_data_kp (int slot, int chvno,
memcpy (buf, oldchv, oldchvlen); memcpy (buf, oldchv, oldchvlen);
memcpy (buf+oldchvlen, newchv, newchvlen); memcpy (buf+oldchvlen, newchv, newchvlen);
if (pininfo && pininfo->mode) sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
xfree (buf); xfree (buf);
return map_sw (sw); return map_sw (sw);
} }
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. */
gpg_error_t
iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen)
{
return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen,
newchv, newchvlen, NULL);
}
gpg_error_t gpg_error_t
iso7816_reset_retry_counter_kp (int slot, int chvno, iso7816_reset_retry_counter_kp (int slot, int chvno,

View File

@ -68,9 +68,7 @@ gpg_error_t iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen, const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen); const char *newchv, size_t newchvlen);
gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno, gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
const char *oldchv, size_t oldchvlen, iso7816_pininfo_t *pininfo);
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_reset_retry_counter (int slot, int chvno, gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen); const char *newchv, size_t newchvlen);
gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno, gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,