PC/SC pinpad support (pinpad input for modify pass phrase with resetcode, by admin).

This commit is contained in:
NIIBE Yutaka 2011-11-29 17:56:22 +09:00
parent 57d4f7fae1
commit 5a62b0d6ee
6 changed files with 139 additions and 73 deletions

View File

@ -1,5 +1,27 @@
2011-11-29 Niibe Yutaka <gniibe@fsij.org> 2011-11-29 Niibe Yutaka <gniibe@fsij.org>
PC/SC pininput support for passphrase modification (2/2)
* apdu.h (apdu_send_simple_kp): Remove.
* apdu.c (pcsc_keypad_modify): Add bConfirmPIN handling.
(apdu_send_simple_kp): Remove.
* iso7816.h (iso7816_reset_retry_counter_kp): Remove arguments
of NEWCHV, and NEWCHVLEN.
(iso7816_reset_retry_counter_with_rc_kp, iso7816_put_data_kp): New.
* iso7816.c (iso7816_reset_retry_counter_with_rc_kp): New.
(iso7816_reset_retry_counter_kp): Call apdu_keypad_modify. Only
handle the case with PININFO.
(iso7816_reset_retry_counter): Don't call
iso7816_reset_retry_counter_kp.
(iso7816_put_data_kp): New.
* app-openpgp.c (do_change_pin): Add with_resetcode.
Handle keypad for unblocking pass phrase with resetcode,
setting up of resetcode, and unblocking by admin.
PC/SC pininput support for passphrase modification (1/2)
* iso7816.h (iso7816_change_reference_data_kp): Remove arguments * iso7816.h (iso7816_change_reference_data_kp): Remove arguments
of OLDCHV, OLDCHVLEN, NEWCHV, and NEWCHVLEN. of OLDCHV, OLDCHVLEN, NEWCHV, and NEWCHVLEN.
@ -23,7 +45,7 @@
* iso7816.h (iso7816_verify_kp): Remove arguments of CHV and CHVLEN. * iso7816.h (iso7816_verify_kp): Remove arguments of CHV and CHVLEN.
* iso7816.c (iso7816_verify_kp): Call apdu_keypad_verify. Only * iso7816.c (iso7816_verify_kp): Call apdu_keypad_verify. Only
handle thecase with PININFO. handle the case with PININFO.
(iso7816_verify): Call apdu_send_simple. (iso7816_verify): Call apdu_send_simple.
* app-openpgp.c (verify_a_chv, verify_chv3): Follow the change of * app-openpgp.c (verify_a_chv, verify_chv3): Follow the change of

View File

@ -2125,6 +2125,32 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
unsigned long len = PIN_MODIFY_STRUCTURE_SIZE; unsigned long len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2]; unsigned char result[2];
size_t resultlen = 2; size_t resultlen = 2;
unsigned char confirm_pin;
/* 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)
*/
switch (ins)
{
case ISO7816_CHANGE_REFERENCE_DATA:
confirm_pin = 0x03;
break;
case 0xDA: /* PUT_DATA */
confirm_pin = 0x01;
break;
case ISO7816_RESET_RETRY_COUNTER:
if (p0 == 0)
confirm_pin = 0x03;
else
confirm_pin = 0x01;
break;
default:
confirm_pin = 0x00;
break;
}
if (!reader_table[slot].atrlen if (!reader_table[slot].atrlen
&& (sw = reset_pcsc_reader (slot))) && (sw = reset_pcsc_reader (slot)))
@ -2160,12 +2186,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
pin_modify[6] = 0x00; /* bInsertionOffsetNew */ pin_modify[6] = 0x00; /* bInsertionOffsetNew */
pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */ pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */ pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
pin_modify[9] = 0x03; /* bConfirmPIN pin_modify[9] = confirm_pin;
* 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 */ pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */
if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen) if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
pin_modify[10] |= 0x01; /* Max size reached. */ pin_modify[10] |= 0x01; /* Max size reached. */
@ -3794,24 +3815,6 @@ apdu_send_simple (int slot, int extended_mode,
} }
/* Same as apdu_send_simple but uses the keypad of the reader. */
int
apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
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;
return send_le (slot, class, ins, p0, p1, lc, data, -1,
NULL, NULL, &pininfo, 0);
}
/* This is a more generic version of the apdu sending routine. It /* This is a more generic version of the apdu sending routine. It
takes an already formatted APDU in APDUDATA or length APDUDATALEN takes an already formatted APDU in APDUDATA or length APDUDATALEN
and returns with an APDU including the status word. With and returns with an APDU including the status word. With

View File

@ -123,10 +123,6 @@ int apdu_keypad_modify (int slot, int class, int ins, int p0, int p1,
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);
int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send (int slot, int extended_mode, int apdu_send (int slot, int extended_mode,
int class, int ins, int p0, int p1, int lc, const char *data, int class, int ins, int p0, int p1, int lc, const char *data,
unsigned char **retbuf, size_t *retbuflen); unsigned char **retbuf, size_t *retbuflen);

View File

@ -1915,6 +1915,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
char *pinvalue = NULL; 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;
int with_resetcode = 0;
iso7816_pininfo_t pininfo; iso7816_pininfo_t pininfo;
int use_keypad = 0; int use_keypad = 0;
int minlen = 6; int minlen = 6;
@ -2024,6 +2025,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
size_t valuelen; size_t valuelen;
int remaining; int remaining;
with_resetcode = 1;
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)
@ -2044,14 +2046,14 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
rc = pincb (pincb_arg, rc = pincb (pincb_arg,
_("||Please enter the Reset Code for the card"), _("||Please enter the Reset Code for the card"),
&resetcode); use_keypad ? NULL : &resetcode);
if (rc) if (rc)
{ {
log_info (_("PIN callback returned error: %s\n"), log_info (_("PIN callback returned error: %s\n"),
gpg_strerror (rc)); gpg_strerror (rc));
goto leave; goto leave;
} }
if (strlen (resetcode) < minlen) if (!use_keypad && strlen (resetcode) < minlen)
{ {
log_info (_("Reset Code is too short; minimum length is %d\n"), log_info (_("Reset Code is too short; minimum length is %d\n"),
minlen); minlen);
@ -2088,40 +2090,65 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
} }
if (resetcode) if (with_resetcode)
{ {
char *buffer; if (use_keypad)
{
buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1); rc = iso7816_reset_retry_counter_with_rc_kp (app->slot, 0x81,
if (!buffer) &pininfo);
rc = gpg_error_from_syserror (); pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
else else
{ {
strcpy (stpcpy (buffer, resetcode), pinvalue); char *buffer;
rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
buffer, strlen (buffer)); buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1);
wipememory (buffer, strlen (buffer)); if (!buffer)
xfree (buffer); rc = gpg_error_from_syserror ();
else
{
strcpy (stpcpy (buffer, resetcode), pinvalue);
rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
buffer, strlen (buffer));
wipememory (buffer, strlen (buffer));
xfree (buffer);
}
} }
} }
else if (set_resetcode) else if (set_resetcode)
{ {
if (strlen (pinvalue) < 8) if (use_keypad)
{ {
log_error (_("Reset Code is too short; minimum length is %d\n"), 8); rc = pincb (pincb_arg, _("|RN|New Reset Code"), NULL);
rc = gpg_error (GPG_ERR_BAD_PIN); rc = iso7816_put_data_kp (app->slot, 0xD3, &pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
} }
else else
rc = iso7816_put_data (app->slot, 0, 0xD3, if (strlen (pinvalue) < 8)
pinvalue, strlen (pinvalue)); {
log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
rc = gpg_error (GPG_ERR_BAD_PIN);
}
else
rc = iso7816_put_data (app->slot, 0, 0xD3,
pinvalue, strlen (pinvalue));
} }
else if (reset_mode) else if (reset_mode)
{ {
rc = iso7816_reset_retry_counter (app->slot, 0x81, if (use_keypad)
pinvalue, strlen (pinvalue)); {
if (!rc && !app->app_local->extcap.is_v2) rc = pincb (pincb_arg, _("|N|New PIN"), NULL);
rc = iso7816_reset_retry_counter (app->slot, 0x82, rc = iso7816_reset_retry_counter_kp (app->slot, 0x81, &pininfo);
pinvalue, strlen (pinvalue)); pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
else
{
rc = iso7816_reset_retry_counter (app->slot, 0x81,
pinvalue, strlen (pinvalue));
if (!rc && !app->app_local->extcap.is_v2)
rc = iso7816_reset_retry_counter (app->slot, 0x82,
pinvalue, strlen (pinvalue));
}
} }
else if (!app->app_local->extcap.is_v2) else if (!app->app_local->extcap.is_v2)
{ {
@ -2149,8 +2176,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
{ {
rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno, rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno,
&pininfo); &pininfo);
/* Dismiss the prompt. */ pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
} }
else else
rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,

View File

@ -354,26 +354,14 @@ iso7816_change_reference_data (int slot, int chvno,
gpg_error_t gpg_error_t
iso7816_reset_retry_counter_kp (int slot, int chvno, iso7816_reset_retry_counter_with_rc_kp (int slot, int chvno,
const char *newchv, size_t newchvlen, iso7816_pininfo_t *pininfo)
iso7816_pininfo_t *pininfo)
{ {
int sw; int sw;
if (!newchv || !newchvlen ) sw = apdu_keypad_modify (slot, 0x00, CMD_RESET_RETRY_COUNTER, 0, chvno,
return gpg_error (GPG_ERR_INV_VALUE); pininfo->mode, pininfo->minlen, pininfo->maxlen,
/* FIXME: The keypad mode has not yet been tested. */
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen); pininfo->padlen);
else
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
return map_sw (sw); return map_sw (sw);
} }
@ -393,11 +381,28 @@ iso7816_reset_retry_counter_with_rc (int slot, int chvno,
} }
gpg_error_t
iso7816_reset_retry_counter_kp (int slot, int chvno,
iso7816_pininfo_t *pininfo)
{
int sw;
sw = apdu_keypad_modify (slot, 0x00, CMD_RESET_RETRY_COUNTER, 2, chvno,
pininfo->mode, pininfo->minlen, pininfo->maxlen,
pininfo->padlen);
return map_sw (sw);
}
gpg_error_t gpg_error_t
iso7816_reset_retry_counter (int slot, int chvno, iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen) const char *newchv, size_t newchvlen)
{ {
return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL); int sw;
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
return map_sw (sw);
} }
@ -440,6 +445,19 @@ iso7816_get_data (int slot, int extended_mode, int tag,
} }
gpg_error_t
iso7816_put_data_kp (int slot, int tag, iso7816_pininfo_t *pininfo)
{
int sw;
sw = apdu_keypad_modify (slot, 0x00, CMD_PUT_DATA,
((tag >> 8) & 0xff), (tag & 0xff),
pininfo->mode, pininfo->minlen, pininfo->maxlen,
pininfo->padlen);
return map_sw (sw);
}
/* Perform a PUT DATA command on card in SLOT. Write DATA of length /* Perform a PUT DATA command on card in SLOT. Write DATA of length
DATALEN to TAG. EXTENDED_MODE controls whether extended length DATALEN to TAG. EXTENDED_MODE controls whether extended length
headers or command chaining is used instead of single length headers or command chaining is used instead of single length

View File

@ -72,14 +72,15 @@ gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
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,
const char *newchv,
size_t newchvlen,
iso7816_pininfo_t *pininfo); iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno, gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno,
const char *data, const char *data,
size_t datalen); size_t datalen);
gpg_error_t iso7816_reset_retry_counter_with_rc_kp (int slot, int chvno,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_get_data (int slot, int extended_mode, int tag, gpg_error_t iso7816_get_data (int slot, int extended_mode, int tag,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_put_data_kp (int slot, int tag, iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag, gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
const void *data, size_t datalen); const void *data, size_t datalen);
gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag, gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,