From 5a62b0d6ee7cecc2e41a429ccc586a1a129e1b04 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 29 Nov 2011 17:56:22 +0900 Subject: [PATCH] PC/SC pinpad support (pinpad input for modify pass phrase with resetcode, by admin). --- scd/ChangeLog | 24 ++++++++++++++- scd/apdu.c | 51 ++++++++++++++++--------------- scd/apdu.h | 4 --- scd/app-openpgp.c | 76 +++++++++++++++++++++++++++++++---------------- scd/iso7816.c | 52 +++++++++++++++++++++----------- scd/iso7816.h | 5 ++-- 6 files changed, 139 insertions(+), 73 deletions(-) diff --git a/scd/ChangeLog b/scd/ChangeLog index 9c11fb309..d0f779ebd 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,5 +1,27 @@ 2011-11-29 Niibe Yutaka + 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 of OLDCHV, OLDCHVLEN, NEWCHV, and NEWCHVLEN. @@ -23,7 +45,7 @@ * iso7816.h (iso7816_verify_kp): Remove arguments of CHV and CHVLEN. * 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. * app-openpgp.c (verify_a_chv, verify_chv3): Follow the change of diff --git a/scd/apdu.c b/scd/apdu.c index 380450df3..4d11157e3 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -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 char result[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 && (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[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[9] = confirm_pin; pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */ if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen) 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 takes an already formatted APDU in APDUDATA or length APDUDATALEN and returns with an APDU including the status word. With diff --git a/scd/apdu.h b/scd/apdu.h index e5b4c0878..ac1eeeb3b 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -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 class, int ins, int p0, int p1, 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 class, int ins, int p0, int p1, int lc, const char *data, unsigned char **retbuf, size_t *retbuflen); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index b3a3ae13a..08d641db6 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1915,6 +1915,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, char *pinvalue = NULL; int reset_mode = !!(flags & APP_CHANGE_FLAG_RESET); int set_resetcode = 0; + int with_resetcode = 0; iso7816_pininfo_t pininfo; int use_keypad = 0; int minlen = 6; @@ -2024,6 +2025,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, size_t valuelen; int remaining; + with_resetcode = 1; minlen = 8; relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); if (!relptr || valuelen < 7) @@ -2044,14 +2046,14 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, rc = pincb (pincb_arg, _("||Please enter the Reset Code for the card"), - &resetcode); + use_keypad ? NULL : &resetcode); if (rc) { log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc)); goto leave; } - if (strlen (resetcode) < minlen) + if (!use_keypad && strlen (resetcode) < minlen) { log_info (_("Reset Code is too short; minimum length is %d\n"), minlen); @@ -2088,40 +2090,65 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, } - if (resetcode) + if (with_resetcode) { - char *buffer; - - buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1); - if (!buffer) - rc = gpg_error_from_syserror (); + if (use_keypad) + { + rc = iso7816_reset_retry_counter_with_rc_kp (app->slot, 0x81, + &pininfo); + pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ + } 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); + char *buffer; + + buffer = xtrymalloc (strlen (resetcode) + strlen (pinvalue) + 1); + if (!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) { - if (strlen (pinvalue) < 8) + if (use_keypad) { - log_error (_("Reset Code is too short; minimum length is %d\n"), 8); - rc = gpg_error (GPG_ERR_BAD_PIN); + rc = pincb (pincb_arg, _("|RN|New Reset Code"), NULL); + rc = iso7816_put_data_kp (app->slot, 0xD3, &pininfo); + pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ } else - rc = iso7816_put_data (app->slot, 0, 0xD3, - pinvalue, strlen (pinvalue)); + if (strlen (pinvalue) < 8) + { + 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) { - 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)); + if (use_keypad) + { + rc = pincb (pincb_arg, _("|N|New PIN"), NULL); + rc = iso7816_reset_retry_counter_kp (app->slot, 0x81, &pininfo); + 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) { @@ -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, &pininfo); - /* Dismiss the prompt. */ - pincb (pincb_arg, NULL, NULL); + pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */ } else rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, diff --git a/scd/iso7816.c b/scd/iso7816.c index 8d0f10557..8876b931a 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -354,26 +354,14 @@ iso7816_change_reference_data (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_reset_retry_counter_with_rc_kp (int slot, int chvno, + iso7816_pininfo_t *pininfo) { int sw; - if (!newchv || !newchvlen ) - return gpg_error (GPG_ERR_INV_VALUE); - - /* 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, + sw = apdu_keypad_modify (slot, 0x00, CMD_RESET_RETRY_COUNTER, 0, chvno, + pininfo->mode, pininfo->minlen, pininfo->maxlen, pininfo->padlen); - else - sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER, - 2, chvno, newchvlen, newchv); 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 iso7816_reset_retry_counter (int slot, int chvno, 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 DATALEN to TAG. EXTENDED_MODE controls whether extended length headers or command chaining is used instead of single length diff --git a/scd/iso7816.h b/scd/iso7816.h index 5b99e869b..9ed7b219f 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -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, const char *newchv, size_t newchvlen); gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno, - const char *newchv, - size_t newchvlen, iso7816_pininfo_t *pininfo); gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno, const char *data, 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, 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, const void *data, size_t datalen); gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,