diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/apdu.c | 230 | ||||
-rw-r--r-- | scd/apdu.h | 15 | ||||
-rw-r--r-- | scd/app-dinsig.c | 12 | ||||
-rw-r--r-- | scd/app-nks.c | 10 | ||||
-rw-r--r-- | scd/app-openpgp.c | 160 | ||||
-rw-r--r-- | scd/app.c | 2 | ||||
-rw-r--r-- | scd/ccid-driver.c | 406 | ||||
-rw-r--r-- | scd/ccid-driver.h | 5 | ||||
-rw-r--r-- | scd/command.c | 11 | ||||
-rw-r--r-- | scd/iso7816.c | 28 | ||||
-rw-r--r-- | scd/iso7816.h | 25 | ||||
-rw-r--r-- | scd/sc-copykeys.c | 1 | ||||
-rw-r--r-- | scd/scdaemon.c | 17 | ||||
-rw-r--r-- | scd/scdaemon.h | 3 |
14 files changed, 644 insertions, 281 deletions
diff --git a/scd/apdu.c b/scd/apdu.c index 68d4e9970..6824ded55 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -60,10 +60,9 @@ #include "exechelp.h" #endif /* GNUPG_MAJOR_VERSION != 1 */ +#include "iso7816.h" #include "apdu.h" #include "ccid-driver.h" -#include "iso7816.h" - /* Due to conflicting use of threading libraries we usually can't link against libpcsclite. Instead we use a wrapper program. */ @@ -83,16 +82,6 @@ #define DLSTDCALL #endif - -/* Helper to pass parameters related to keypad based operations. */ -struct pininfo_s -{ - int mode; - int minlen; - int maxlen; - int padlen; -}; - /* A structure to collect information pertaining to one reader slot. */ struct reader_table_s { @@ -107,12 +96,12 @@ struct reader_table_s { int (*reset_reader)(int); int (*get_status_reader)(int, unsigned int *); int (*send_apdu_reader)(int,unsigned char *,size_t, - unsigned char *, size_t *, struct pininfo_s *); - int (*check_keypad)(int, int, int, int, int, int); + unsigned char *, size_t *, pininfo_t *); + int (*check_pinpad)(int, int, pininfo_t *); void (*dump_status_reader)(int); int (*set_progress_cb)(int, gcry_handler_progress_t, void*); - int (*keypad_verify)(int, int, int, int, int, struct pininfo_s *); - int (*keypad_modify)(int, int, int, int, int, struct pininfo_s *); + int (*pinpad_verify)(int, int, int, int, int, pininfo_t *); + int (*pinpad_modify)(int, int, int, int, int, pininfo_t *); struct { ccid_driver_t handle; @@ -330,12 +319,11 @@ static int reset_pcsc_reader (int slot); static int apdu_get_status_internal (int slot, int hang, int no_atr_reset, unsigned int *status, unsigned int *changed); -static int check_pcsc_keypad (int slot, int command, int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen); -static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, - struct pininfo_s *pininfo); -static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, - struct pininfo_s *pininfo); +static int check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo); +static int pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo); +static int pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo); @@ -381,11 +369,11 @@ new_reader_slot (void) reader_table[reader].reset_reader = NULL; reader_table[reader].get_status_reader = NULL; reader_table[reader].send_apdu_reader = NULL; - reader_table[reader].check_keypad = check_pcsc_keypad; + reader_table[reader].check_pinpad = check_pcsc_pinpad; reader_table[reader].dump_status_reader = NULL; reader_table[reader].set_progress_cb = NULL; - reader_table[reader].keypad_verify = pcsc_keypad_verify; - reader_table[reader].keypad_modify = pcsc_keypad_modify; + reader_table[reader].pinpad_verify = pcsc_pinpad_verify; + reader_table[reader].pinpad_modify = pcsc_pinpad_modify; reader_table[reader].used = 1; reader_table[reader].any_status = 0; @@ -440,7 +428,7 @@ host_sw_string (long err) case SW_HOST_GENERAL_ERROR: return "general error"; case SW_HOST_NO_READER: return "no reader"; case SW_HOST_ABORTED: return "aborted"; - case SW_HOST_NO_KEYPAD: return "no keypad"; + case SW_HOST_NO_PINPAD: return "no pinpad"; case SW_HOST_ALREADY_CONNECTED: return "already connected"; default: return "unknown host status error"; } @@ -608,7 +596,7 @@ ct_get_status (int slot, unsigned int *status) set to BUFLEN. Returns: CT API error code. */ static int ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo) + unsigned char *buffer, size_t *buflen, pininfo_t *pininfo) { int rc; unsigned char dad[1], sad[1]; @@ -673,10 +661,10 @@ open_ct_reader (int port) reader_table[reader].reset_reader = reset_ct_reader; reader_table[reader].get_status_reader = ct_get_status; reader_table[reader].send_apdu_reader = ct_send_apdu; - reader_table[reader].check_keypad = NULL; + reader_table[reader].check_pinpad = NULL; reader_table[reader].dump_status_reader = ct_dump_reader_status; - reader_table[reader].keypad_verify = NULL; - reader_table[reader].keypad_modify = NULL; + reader_table[reader].pinpad_verify = NULL; + reader_table[reader].pinpad_modify = NULL; dump_reader_status (reader); return reader; @@ -1039,7 +1027,7 @@ pcsc_get_status (int slot, unsigned int *status) static int pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen, - struct pininfo_s *pininfo) + pininfo_t *pininfo) { long err; struct pcsc_io_request_s send_pci; @@ -1075,7 +1063,7 @@ pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen, static int pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen, - struct pininfo_s *pininfo) + pininfo_t *pininfo) { long err; reader_table_t slotp; @@ -1195,7 +1183,7 @@ pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen, static int pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen, - struct pininfo_s *pininfo) + pininfo_t *pininfo) { #ifdef NEED_PCSC_WRAPPER return pcsc_send_apdu_wrapped (slot, apdu, apdulen, buffer, buflen, pininfo); @@ -1990,19 +1978,15 @@ open_pcsc_reader (const char *portstr) /* Check whether the reader supports the ISO command code COMMAND - on the keypad. Return 0 on success. */ + on the pinpad. Return 0 on success. */ static int -check_pcsc_keypad (int slot, int command, int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen) +check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo) { unsigned char buf[256]; size_t len = 256; int sw; - (void)pin_mode; - (void)pinlen_min; - (void)pinlen_max; - (void)pin_padlen; + (void)pininfo; /* XXX: Identify reader and set pininfo->fixedlen. */ check_again: if (command == ISO7816_VERIFY) @@ -2053,12 +2037,12 @@ check_pcsc_keypad (int slot, int command, int pin_mode, #define PIN_VERIFY_STRUCTURE_SIZE 24 static int -pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, - struct pininfo_s *pininfo) +pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo) { int sw; unsigned char *pin_verify; - int len = PIN_VERIFY_STRUCTURE_SIZE; + int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen; unsigned char result[2]; size_t resultlen = 2; @@ -2066,10 +2050,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, && (sw = reset_pcsc_reader (slot))) return sw; - if (pininfo->mode != 1) - return SW_NOT_SUPPORTED; - - if (pininfo->padlen != 0) + if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16) return SW_NOT_SUPPORTED; if (!pininfo->minlen) @@ -2090,7 +2071,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, pin_verify[0] = 0x00; /* bTimerOut */ pin_verify[1] = 0x00; /* bTimerOut2 */ pin_verify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */ - pin_verify[3] = 0x00; /* bmPINBlockString */ + pin_verify[3] = pininfo->fixedlen; /* bmPINBlockString */ pin_verify[4] = 0x00; /* bmPINLengthFormat */ pin_verify[5] = pininfo->maxlen; /* wPINMaxExtraDigit */ pin_verify[6] = pininfo->minlen; /* wPINMaxExtraDigit */ @@ -2103,8 +2084,8 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, pin_verify[11] = 0x00; /* bMsgIndex */ pin_verify[12] = 0x00; /* bTeoPrologue[0] */ pin_verify[13] = 0x00; /* bTeoPrologue[1] */ - pin_verify[14] = 0x00; /* bTeoPrologue[2] */ - pin_verify[15] = 0x05; /* ulDataLength */ + pin_verify[14] = pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */ + pin_verify[15] = pininfo->fixedlen + 0x05; /* ulDataLength */ pin_verify[16] = 0x00; /* ulDataLength */ pin_verify[17] = 0x00; /* ulDataLength */ pin_verify[18] = 0x00; /* ulDataLength */ @@ -2112,7 +2093,9 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, pin_verify[20] = ins; /* abData[1] */ pin_verify[21] = p0; /* abData[2] */ pin_verify[22] = p1; /* abData[3] */ - pin_verify[23] = 0x00; /* abData[4] */ + pin_verify[23] = pininfo->fixedlen; /* abData[4] */ + if (pininfo->fixedlen) + memset (&pin_verify[24], 0xff, pininfo->fixedlen); if (DBG_CARD_IO) log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n", @@ -2137,12 +2120,12 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, #define PIN_MODIFY_STRUCTURE_SIZE 29 static int -pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, - struct pininfo_s *pininfo) +pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo) { int sw; unsigned char *pin_modify; - int len = PIN_MODIFY_STRUCTURE_SIZE; + int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen; unsigned char result[2]; size_t resultlen = 2; @@ -2150,10 +2133,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, && (sw = reset_pcsc_reader (slot))) return sw; - if (pininfo->mode != 1) - return SW_NOT_SUPPORTED; - - if (pininfo->padlen != 0) + if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16) return SW_NOT_SUPPORTED; if (!pininfo->minlen) @@ -2174,10 +2154,10 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, 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[3] = pininfo->fixedlen; /* bmPINBlockString */ pin_modify[4] = 0x00; /* bmPINLengthFormat */ pin_modify[5] = 0x00; /* bInsertionOffsetOld */ - pin_modify[6] = 0x00; /* bInsertionOffsetNew */ + pin_modify[6] = pininfo->fixedlen; /* bInsertionOffsetNew */ pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */ pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */ pin_modify[9] = (p0 == 0 ? 0x03 : 0x01); @@ -2198,8 +2178,8 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, 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] = 0x05; /* ulDataLength */ + pin_modify[19] = 2 * pininfo->fixedlen + 0x05; /* bTeoPrologue[2] */ + pin_modify[20] = 2 * pininfo->fixedlen + 0x05; /* ulDataLength */ pin_modify[21] = 0x00; /* ulDataLength */ pin_modify[22] = 0x00; /* ulDataLength */ pin_modify[23] = 0x00; /* ulDataLength */ @@ -2207,7 +2187,9 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1, pin_modify[25] = ins; /* abData[1] */ pin_modify[26] = p0; /* abData[2] */ pin_modify[27] = p1; /* abData[3] */ - pin_modify[28] = 0x00; /* abData[4] */ + pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */ + if (pininfo->fixedlen) + memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen); if (DBG_CARD_IO) log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n", @@ -2312,7 +2294,7 @@ get_status_ccid (int slot, unsigned int *status) static int send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen, - struct pininfo_s *pininfo) + pininfo_t *pininfo) { long err; size_t maxbuflen; @@ -2328,11 +2310,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, maxbuflen = *buflen; if (pininfo) err = ccid_transceive_secure (reader_table[slot].ccid.handle, - apdu, apdulen, - pininfo->mode, - pininfo->minlen, - pininfo->maxlen, - pininfo->padlen, + apdu, apdulen, pininfo, buffer, maxbuflen, buflen); else err = ccid_transceive (reader_table[slot].ccid.handle, @@ -2347,25 +2325,22 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, /* Check whether the CCID reader supports the ISO command code COMMAND - on the keypad. Return 0 on success. For a description of the pin + on the pinpad. Return 0 on success. For a description of the pin parameters, see ccid-driver.c */ static int -check_ccid_keypad (int slot, int command, int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen) +check_ccid_pinpad (int slot, int command, pininfo_t *pininfo) { unsigned char apdu[] = { 0, 0, 0, 0x81 }; apdu[1] = command; - return ccid_transceive_secure (reader_table[slot].ccid.handle, - apdu, sizeof apdu, - pin_mode, pinlen_min, pinlen_max, pin_padlen, - NULL, 0, NULL); + return ccid_transceive_secure (reader_table[slot].ccid.handle, apdu, + sizeof apdu, pininfo, NULL, 0, NULL); } static int -ccid_keypad_operation (int slot, int class, int ins, int p0, int p1, - struct pininfo_s *pininfo) +ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo) { unsigned char apdu[4]; int err, sw; @@ -2377,9 +2352,7 @@ ccid_keypad_operation (int slot, int class, int ins, int p0, int p1, apdu[2] = p0; apdu[3] = p1; err = ccid_transceive_secure (reader_table[slot].ccid.handle, - apdu, sizeof apdu, - pininfo->mode, pininfo->minlen, pininfo->maxlen, - pininfo->padlen, + apdu, sizeof apdu, pininfo, result, 2, &resultlen); if (err) return err; @@ -2433,11 +2406,11 @@ open_ccid_reader (const char *portstr) reader_table[slot].reset_reader = reset_ccid_reader; reader_table[slot].get_status_reader = get_status_ccid; reader_table[slot].send_apdu_reader = send_apdu_ccid; - reader_table[slot].check_keypad = check_ccid_keypad; + reader_table[slot].check_pinpad = check_ccid_pinpad; reader_table[slot].dump_status_reader = dump_ccid_reader_status; reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader; - reader_table[slot].keypad_verify = ccid_keypad_operation; - reader_table[slot].keypad_modify = ccid_keypad_operation; + reader_table[slot].pinpad_verify = ccid_pinpad_operation; + reader_table[slot].pinpad_modify = ccid_pinpad_operation; /* Our CCID reader code does not support T=0 at all, thus reset the flag. */ reader_table[slot].is_t0 = 0; @@ -2597,7 +2570,7 @@ my_rapdu_get_status (int slot, unsigned int *status) static int my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen, - struct pininfo_s *pininfo) + pininfo_t *pininfo) { int err; reader_table_t slotp; @@ -2728,10 +2701,10 @@ open_rapdu_reader (int portno, reader_table[slot].reset_reader = reset_rapdu_reader; reader_table[slot].get_status_reader = my_rapdu_get_status; reader_table[slot].send_apdu_reader = my_rapdu_send_apdu; - reader_table[slot].check_keypad = NULL; + reader_table[slot].check_pinpad = NULL; reader_table[slot].dump_status_reader = NULL; - reader_table[slot].keypad_verify = NULL; - reader_table[slot].keypad_modify = NULL; + reader_table[slot].pinpad_verify = NULL; + reader_table[slot].pinpad_modify = NULL; dump_reader_status (slot); rapdu_msg_release (msg); @@ -3419,63 +3392,76 @@ apdu_get_status (int slot, int hang, /* Check whether the reader supports the ISO command code COMMAND on - the keypad. Return 0 on success. For a description of the pin + the pinpad. Return 0 on success. For a description of the pin parameters, see ccid-driver.c */ int -apdu_check_keypad (int slot, int command, int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen) +apdu_check_pinpad (int slot, int command, pininfo_t *pininfo) { if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return SW_HOST_NO_DRIVER; - if (reader_table[slot].check_keypad) - return reader_table[slot].check_keypad (slot, command, - pin_mode, pinlen_min, pinlen_max, - pin_padlen); + if (opt.enable_pinpad_varlen) + pininfo->fixedlen = 0; + + if (reader_table[slot].check_pinpad) + { + int sw; + + if ((sw = lock_slot (slot))) + return sw; + + sw = reader_table[slot].check_pinpad (slot, command, pininfo); + unlock_slot (slot); + return sw; + } else return SW_HOST_NOT_SUPPORTED; } 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_padlen) +apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo) { - 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_verify) - return reader_table[slot].keypad_verify (slot, class, ins, p0, p1, - &pininfo); + if (reader_table[slot].pinpad_verify) + { + int sw; + + if ((sw = lock_slot (slot))) + return sw; + + sw = reader_table[slot].pinpad_verify (slot, class, ins, p0, p1, + pininfo); + unlock_slot (slot); + return sw; + } else return SW_HOST_NOT_SUPPORTED; } 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) +apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo) { - 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); + if (reader_table[slot].pinpad_modify) + { + int sw; + + if ((sw = lock_slot (slot))) + return sw; + + sw = reader_table[slot].pinpad_modify (slot, class, ins, p0, p1, + pininfo); + unlock_slot (slot); + return sw; + } else return SW_HOST_NOT_SUPPORTED; } @@ -3485,7 +3471,7 @@ apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode, function should be called in locked state. */ static int send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo) + unsigned char *buffer, size_t *buflen, pininfo_t *pininfo) { if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return SW_HOST_NO_DRIVER; @@ -3501,7 +3487,7 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen, /* Core APDU tranceiver function. Parameters are described at - apdu_send_le with the exception of PININFO which indicates keypad + apdu_send_le with the exception of PININFO which indicates pinpad related operations if not NULL. If EXTENDED_MODE is not 0 command chaining or extended length will be used according to these values: @@ -3517,7 +3503,7 @@ static int send_le (int slot, int class, int ins, int p0, int p1, int lc, const char *data, int le, unsigned char **retbuf, size_t *retbuflen, - struct pininfo_s *pininfo, int extended_mode) + pininfo_t *pininfo, int extended_mode) { #define SHORT_RESULT_BUFFER_SIZE 258 /* We allocate 8 extra bytes as a safety margin towards a driver bug. */ diff --git a/scd/apdu.h b/scd/apdu.h index bf5534634..37f9f433c 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -69,7 +69,7 @@ enum { SW_HOST_GENERAL_ERROR = 0x1000b, SW_HOST_NO_READER = 0x1000c, SW_HOST_ABORTED = 0x1000d, - SW_HOST_NO_KEYPAD = 0x1000e, + SW_HOST_NO_PINPAD = 0x1000e, SW_HOST_ALREADY_CONNECTED = 0x1000f }; @@ -114,14 +114,11 @@ int apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg); int apdu_reset (int slot); int apdu_get_status (int slot, int hang, unsigned int *status, unsigned int *changed); -int apdu_check_keypad (int slot, int command, int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen); -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_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_check_pinpad (int slot, int command, pininfo_t *pininfo); +int apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo); +int apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1, + pininfo_t *pininfo); int apdu_send_simple (int slot, int extended_mode, int class, int ins, int p0, int p1, int lc, const char *data); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 50db78e1f..7dad6b14f 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -282,21 +282,21 @@ verify_pin (app_t app, { const char *s; int rc; - iso7816_pininfo_t pininfo; + pininfo_t pininfo; if ( app->did_chv1 && !app->force_chv1 ) return 0; /* No need to verify it again. */ memset (&pininfo, 0, sizeof pininfo); - pininfo.mode = 1; + pininfo.fixedlen = -1; pininfo.minlen = 6; pininfo.maxlen = 8; - if (!opt.disable_keypad - && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + if (!opt.disable_pinpad + && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) ) { rc = pincb (pincb_arg, - _("||Please enter your PIN at the reader's keypad"), + _("||Please enter your PIN at the reader's pinpad"), NULL); if (rc) { @@ -308,7 +308,7 @@ verify_pin (app_t app, /* Dismiss the prompt. */ pincb (pincb_arg, NULL, NULL); } - else /* No Keypad. */ + else /* No Pinpad. */ { char *pinvalue; diff --git a/scd/app-nks.c b/scd/app-nks.c index 28ccb9af7..72e726d39 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -781,19 +781,19 @@ verify_pin (app_t app, int pwid, const char *desc, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - iso7816_pininfo_t pininfo; + pininfo_t pininfo; int rc; if (!desc) desc = "PIN"; memset (&pininfo, 0, sizeof pininfo); - pininfo.mode = 1; + pininfo.fixedlen = -1; pininfo.minlen = 6; pininfo.maxlen = 16; - if (!opt.disable_keypad - && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + if (!opt.disable_pinpad + && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) ) { rc = pincb (pincb_arg, desc, NULL); if (rc) @@ -1144,7 +1144,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr, int is_sigg; const char *newdesc; int pwid; - iso7816_pininfo_t pininfo; + pininfo_t pininfo; (void)ctrl; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 5928ec620..23b28c3f5 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -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,14 @@ struct app_local_s { unsigned int def_chv2:1; /* Use 123456 for CHV2. */ } flags; + /* Pinpad request specified on card. */ + struct + { + unsigned int specified:1; + int fixedlen_user; + int fixedlen_admin; + } pinpad; + struct { unsigned int n_bits; /* Size of the modulus in bits. The rest @@ -581,17 +589,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=<pinpad-request> + + Where PINPAD_REQUEST is in the format of: <n> or <n>,<m>. + N for user PIN, M for admin PIN. If M is missing it means M=N. + 0 means to force not to use pinpad. + */ static void parse_login_data (app_t app) @@ -603,6 +617,9 @@ 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->pinpad.specified = 0; + app->app_local->pinpad.fixedlen_user = -1; + app->app_local->pinpad.fixedlen_admin = -1; /* Read the DO. */ relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL); @@ -628,11 +645,54 @@ 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] == '=') + { + /* Pinpad request control sequence found. */ + buffer += 2; + buflen -= 2; + + if (buflen) + { + if (digitp (buffer)) + { + char *q; + int n, m; + + n = strtol (buffer, &q, 10); + if (q >= (char *)buffer + buflen + || *q == '\x18' || *q == '\n') + m = n; + else + { + 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->pinpad.specified = 1; + app->app_local->pinpad.fixedlen_user = n; + app->app_local->pinpad.fixedlen_admin = m; + } + } + } next: for (; buflen && *buffer != '\x18'; buflen--, buffer++) if (*buffer == '\n') @@ -1470,15 +1530,50 @@ do_readcert (app_t app, const char *certid, } +/* Decide if we use the pinpad of the reader for PIN input according + to the user preference on the card, and the capability of the + reader. This routine is only called when the reader has pinpad. + Returns 0 if we use pinpad, 1 otherwise. */ +static int +check_pinpad_request (app_t app, pininfo_t *pininfo, int admin_pin) +{ + if (app->app_local->pinpad.specified == 0) /* No preference on card. */ + { + if (pininfo->fixedlen == 0) /* Reader has varlen capability. */ + return 0; /* Then, use pinpad. */ + else + /* + * Reader has limited capability, and it may not match PIN of + * the card. + */ + return 1; + } + + if (admin_pin) + pininfo->fixedlen = app->app_local->pinpad.fixedlen_admin; + else + pininfo->fixedlen = app->app_local->pinpad.fixedlen_user; + + if (pininfo->fixedlen == 0 /* User requests disable pinpad. */ + || pininfo->fixedlen < pininfo->minlen + || pininfo->fixedlen > pininfo->maxlen + /* Reader doesn't have the capability to input a PIN which + * length is FIXEDLEN. */) + 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 + using a pinpad. PINCB and PINCB_ARG describe the usual callback for the pinentry. CHVNO must be either 1 or 2. SIGCOUNT is only used with CHV1. PINVALUE is the address of a pointer which will receive a newly allocated block with the actual PIN (this is useful in case that PIN shall be used for another verify operation). The caller needs to free this value. If the function returns with success and NULL is stored at PINVALUE, the caller should take this - as an indication that the keypad has been used. + as an indication that the pinpad has been used. */ static gpg_error_t verify_a_chv (app_t app, @@ -1489,7 +1584,7 @@ verify_a_chv (app_t app, int rc = 0; char *prompt_buffer = NULL; const char *prompt; - iso7816_pininfo_t pininfo; + pininfo_t pininfo; int minlen = 6; assert (chvno == 1 || chvno == 2); @@ -1516,7 +1611,7 @@ verify_a_chv (app_t app, } memset (&pininfo, 0, sizeof pininfo); - pininfo.mode = 1; + pininfo.fixedlen = -1; pininfo.minlen = minlen; @@ -1536,12 +1631,13 @@ verify_a_chv (app_t app, prompt = _("||Please enter the PIN"); - if (!opt.disable_keypad - && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + if (!opt.disable_pinpad + && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) + && !check_pinpad_request (app, &pininfo, 0)) { - /* The reader supports the verify command through the keypad. + /* The reader supports the verify command through the pinpad. Note that the pincb appends a text to the prompt telling the - user to use the keypad. */ + user to use the pinpad. */ rc = pincb (pincb_arg, prompt, NULL); prompt = NULL; xfree (prompt_buffer); @@ -1560,7 +1656,7 @@ verify_a_chv (app_t app, } else { - /* The reader has no keypad or we don't want to use it. */ + /* The reader has no pinpad or we don't want to use it. */ rc = pincb (pincb_arg, prompt, pinvalue); prompt = NULL; xfree (prompt_buffer); @@ -1620,7 +1716,7 @@ verify_chv2 (app_t app, /* For convenience we verify CHV1 here too. We do this only if the card is not configured to require a verification before each CHV1 controlled operation (force_chv1) and if we are not - using the keypad (PINVALUE == NULL). */ + using the pinpad (PINVALUE == NULL). */ rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); @@ -1707,22 +1803,23 @@ verify_chv3 (app_t app, if (!app->did_chv3) { - iso7816_pininfo_t pininfo; + pininfo_t pininfo; int minlen = 8; char *prompt; memset (&pininfo, 0, sizeof pininfo); - pininfo.mode = 1; + pininfo.fixedlen = -1; pininfo.minlen = minlen; rc = build_enter_admin_pin_prompt (app, &prompt); if (rc) return rc; - if (!opt.disable_keypad - && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) ) + if (!opt.disable_pinpad + && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) + && !check_pinpad_request (app, &pininfo, 1)) { - /* The reader supports the verify command through the keypad. */ + /* The reader supports the verify command through the pinpad. */ rc = pincb (pincb_arg, prompt, NULL); xfree (prompt); prompt = NULL; @@ -1917,13 +2014,13 @@ 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; - iso7816_pininfo_t pininfo; - int use_keypad = 0; + pininfo_t pininfo; + int use_pinpad = 0; int minlen = 6; (void)ctrl; memset (&pininfo, 0, sizeof pininfo); - pininfo.mode = 1; + pininfo.fixedlen = -1; pininfo.minlen = minlen; if (reset_mode && chvno == 3) @@ -1968,15 +2065,16 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, { /* Version 2 cards. */ - if (!opt.disable_keypad - && !iso7816_check_keypad (app->slot, - ISO7816_CHANGE_REFERENCE_DATA, &pininfo)) - use_keypad = 1; + if (!opt.disable_pinpad + && !iso7816_check_pinpad (app->slot, + ISO7816_CHANGE_REFERENCE_DATA, &pininfo) + && !check_pinpad_request (app, &pininfo, chvno == 3)) + use_pinpad = 1; if (reset_mode) { /* To reset a PIN the Admin PIN is required. */ - use_keypad = 0; + use_pinpad = 0; app->did_chv3 = 0; rc = verify_chv3 (app, pincb, pincb_arg); if (rc) @@ -1987,7 +2085,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, } else if (chvno == 1 || chvno == 3) { - if (!use_keypad) + if (!use_pinpad) { char *promptbuf = NULL; const char *prompt; @@ -2030,7 +2128,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, size_t valuelen; int remaining; - use_keypad = 0; + use_pinpad = 0; minlen = 8; relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); if (!relptr || valuelen < 7) @@ -2078,7 +2176,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, else app->did_chv1 = app->did_chv2 = 0; - if (!use_keypad) + if (!use_pinpad) { /* TRANSLATORS: Do not translate the "|*|" prefixes but keep it at the start of the string. We need this elsewhere @@ -2151,7 +2249,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, /* Version 2 cards. */ assert (chvno == 1 || chvno == 3); - if (use_keypad) + if (use_pinpad) { rc = pincb (pincb_arg, chvno == 3 ? @@ -3226,7 +3324,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, sync, thus we verify CHV2 here using the given PIN. Cards with version2 to not have the need for a separate CHV2 and internally use just one. Obviously we can't do that if the - keypad has been used. */ + pinpad has been used. */ if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2) { rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); @@ -26,8 +26,8 @@ #include "scdaemon.h" #include "app-common.h" -#include "apdu.h" #include "iso7816.h" +#include "apdu.h" #include "tlv.h" /* This table is used to keep track of locks on a per reader base. diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 3fe932ca6..2d1ef8d46 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1,6 +1,6 @@ /* ccid-driver.c - USB ChipCardInterfaceDevices driver * Copyright (C) 2003, 2004, 2005, 2006, 2007 - * 2008, 2009 Free Software Foundation, Inc. + * 2008, 2009, 2013 Free Software Foundation, Inc. * Written by Werner Koch. * * This file is part of GnuPG. @@ -89,6 +89,8 @@ #include <usb.h> +#include "scdaemon.h" +#include "iso7816.h" #include "ccid-driver.h" #define DRVNAME "ccid-driver: " @@ -207,6 +209,7 @@ enum { VENDOR_SCM = 0x04e6, VENDOR_OMNIKEY= 0x076b, VENDOR_GEMPC = 0x08e6, + VENDOR_VEGA = 0x0982, VENDOR_KAAN = 0x0d46, VENDOR_FSIJ = 0x234b, VENDOR_VASCO = 0x1a44 @@ -220,6 +223,8 @@ enum { #define SCM_SPR532 0xe003 #define CHERRY_ST2000 0x003e #define VASCO_920 0x0920 +#define GEMPC_PINPAD 0x3478 +#define VEGA_ALPHA 0x0008 /* A list and a table with special transport descriptions. */ enum { @@ -264,6 +269,9 @@ struct ccid_driver_s unsigned char apdu_level:2; /* Reader supports short APDU level exchange. With a value of 2 short and extended level is supported.*/ + unsigned int auto_voltage:1; + unsigned int auto_param:1; + unsigned int auto_pps:1; unsigned int auto_ifsd:1; unsigned int powered_off:1; unsigned int has_pinpad:2; @@ -295,6 +303,9 @@ static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, size_t *nread, int expected_type, int seqno, int timeout, int no_debug); static int abort_cmd (ccid_driver_t handle, int seqno); +static int send_escape_cmd (ccid_driver_t handle, const unsigned char *data, + size_t datalen, unsigned char *result, + size_t resultmax, size_t *resultlen); /* Convert a little endian stored 4 byte value into an unsigned integer. */ @@ -758,7 +769,7 @@ parse_ccid_descriptor (ccid_driver_t handle, { unsigned int i; unsigned int us; - int have_t1 = 0, have_tpdu=0, have_auto_conf = 0; + int have_t1 = 0, have_tpdu=0; handle->nonnull_nad = 0; @@ -767,6 +778,9 @@ parse_ccid_descriptor (ccid_driver_t handle, handle->ifsd = 0; handle->has_pinpad = 0; handle->apdu_level = 0; + handle->auto_voltage = 0; + handle->auto_param = 0; + handle->auto_pps = 0; DEBUGOUT_3 ("idVendor: %04X idProduct: %04X bcdDevice: %04X\n", handle->id_vendor, handle->id_product, handle->bcd_device); if (buflen < 54 || buf[0] < 54) @@ -842,22 +856,31 @@ parse_ccid_descriptor (ccid_driver_t handle, DEBUGOUT_1 (" dwFeatures %08X\n", us); if ((us & 0x0002)) { - DEBUGOUT (" Auto configuration based on ATR\n"); - have_auto_conf = 1; + DEBUGOUT (" Auto configuration based on ATR (assumes auto voltage)\n"); + handle->auto_voltage = 1; } if ((us & 0x0004)) DEBUGOUT (" Auto activation on insert\n"); if ((us & 0x0008)) - DEBUGOUT (" Auto voltage selection\n"); + { + DEBUGOUT (" Auto voltage selection\n"); + handle->auto_voltage = 1; + } if ((us & 0x0010)) DEBUGOUT (" Auto clock change\n"); if ((us & 0x0020)) DEBUGOUT (" Auto baud rate change\n"); if ((us & 0x0040)) - DEBUGOUT (" Auto parameter negotiation made by CCID\n"); + { + DEBUGOUT (" Auto parameter negotiation made by CCID\n"); + handle->auto_param = 1; + } else if ((us & 0x0080)) - DEBUGOUT (" Auto PPS made by CCID\n"); - else if ((us & (0x0040 | 0x0080))) + { + DEBUGOUT (" Auto PPS made by CCID\n"); + handle->auto_pps = 1; + } + if ((us & (0x0040 | 0x0080)) == (0x0040 | 0x0080)) DEBUGOUT (" WARNING: conflicting negotiation features\n"); if ((us & 0x0100)) @@ -935,11 +958,10 @@ parse_ccid_descriptor (ccid_driver_t handle, DEBUGOUT_LF (); } - if (!have_t1 || !(have_tpdu || handle->apdu_level) || !have_auto_conf) + if (!have_t1 || !(have_tpdu || handle->apdu_level)) { DEBUGOUT ("this drivers requires that the reader supports T=1, " - "TPDU or APDU level exchange and auto configuration - " - "this is not available\n"); + "TPDU or APDU level exchange - this is not available\n"); return -1; } @@ -1506,6 +1528,29 @@ ccid_get_reader_list (void) } +/* Vendor specific custom initialization. */ +static int +ccid_vendor_specific_init (ccid_driver_t handle) +{ + if (handle->id_vendor == VENDOR_VEGA && handle->id_product == VEGA_ALPHA) + { + /* + * Vega alpha has a feature to show retry counter on the pinpad + * display. But it assumes that the card returns the value of + * retry counter by VERIFY with empty data (return code of + * 63Cx). Unfortunately, existing OpenPGP cards don't support + * VERIFY command with empty data. This vendor specific command + * sequence is to disable the feature. + */ + const unsigned char cmd[] = "\xb5\x01\x00\x03\x00"; + + return send_escape_cmd (handle, cmd, sizeof (cmd), NULL, 0, NULL); + } + + return 0; +} + + /* Open the reader with the internal number READERNO and return a pointer to be used as handle in HANDLE. Returns 0 on success. */ int @@ -1614,6 +1659,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) } } + rc = ccid_vendor_specific_init (*handle); + leave: free (ifcdesc_extra); if (rc) @@ -2338,6 +2385,151 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) } +/* Parse ATR string (of ATRLEN) and update parameters at PARAM. + Calling this routine, it should prepare default values at PARAM + beforehand. This routine assumes that card is accessed by T=1 + protocol. It doesn't analyze historical bytes at all. + + Returns < 0 value on error: + -1 for parse error or integrity check error + -2 for card doesn't support T=1 protocol + -3 for parameters are nod explicitly defined by ATR + -4 for this driver doesn't support CRC + + Returns >= 0 on success: + 0 for card is negotiable mode + 1 for card is specific mode (and not negotiable) + */ +static int +update_param_by_atr (unsigned char *param, unsigned char *atr, size_t atrlen) +{ + int i = -1; + int t, y, chk; + int historical_bytes_num, negotiable = 1; + +#define NEXTBYTE() do { i++; if (atrlen <= i) return -1; } while (0) + + NEXTBYTE (); + + if (atr[i] == 0x3F) + param[1] |= 0x02; /* Convention is inverse. */ + NEXTBYTE (); + + y = (atr[i] >> 4); + historical_bytes_num = atr[i] & 0x0f; + NEXTBYTE (); + + if ((y & 1)) + { + param[0] = atr[i]; /* TA1 - Fi & Di */ + NEXTBYTE (); + } + + if ((y & 2)) + NEXTBYTE (); /* TB1 - ignore */ + + if ((y & 4)) + { + param[2] = atr[i]; /* TC1 - Guard Time */ + NEXTBYTE (); + } + + if ((y & 8)) + { + y = (atr[i] >> 4); /* TD1 */ + t = atr[i] & 0x0f; + NEXTBYTE (); + + if ((y & 1)) + { /* TA2 - PPS mode */ + if ((atr[i] & 0x0f) != 1) + return -2; /* Wrong card protocol (!= 1). */ + + if ((atr[i] & 0x10) != 0x10) + return -3; /* Transmission parameters are implicitly defined. */ + + negotiable = 0; /* TA2 means specific mode. */ + NEXTBYTE (); + } + + if ((y & 2)) + NEXTBYTE (); /* TB2 - ignore */ + + if ((y & 4)) + NEXTBYTE (); /* TC2 - ignore */ + + if ((y & 8)) + { + y = (atr[i] >> 4); /* TD2 */ + t = atr[i] & 0x0f; + NEXTBYTE (); + } + else + y = 0; + + while (y) + { + if ((y & 1)) + { /* TAx */ + if (t == 1) + param[5] = atr[i]; /* IFSC */ + else if (t == 15) + /* XXX: check voltage? */ + param[4] = (atr[i] >> 6); /* ClockStop */ + + NEXTBYTE (); + } + + if ((y & 2)) + { + if (t == 1) + param[3] = atr[i]; /* TBx - BWI & CWI */ + NEXTBYTE (); + } + + if ((y & 4)) + { + if (t == 1) + param[1] |= (atr[i] & 0x01); /* TCx - LRC/CRC */ + NEXTBYTE (); + + if (param[1] & 0x01) + return -4; /* CRC not supported yet. */ + } + + if ((y & 8)) + { + y = (atr[i] >> 4); /* TDx */ + t = atr[i] & 0x0f; + NEXTBYTE (); + } + else + y = 0; + } + } + + i += historical_bytes_num - 1; + NEXTBYTE (); + if (atrlen != i+1) + return -1; + +#undef NEXTBYTE + + chk = 0; + do + { + chk ^= atr[i]; + i--; + } + while (i > 0); + + if (chk != 0) + return -1; + + return negotiable; +} + + /* Return the ATR of the card. This is not a cached value and thus an actual reset is done. */ int @@ -2354,6 +2546,15 @@ ccid_get_atr (ccid_driver_t handle, unsigned int edc; int tried_iso = 0; int got_param; + unsigned char param[7] = { /* For Protocol T=1 */ + 0x11, /* bmFindexDindex */ + 0x10, /* bmTCCKST1 */ + 0x00, /* bGuardTimeT1 */ + 0x4d, /* bmWaitingIntegersT1 */ + 0x00, /* bClockStop */ + 0x20, /* bIFSC */ + 0x00 /* bNadValue */ + }; /* First check whether a card is available. */ rc = ccid_slot_status (handle, &statusbits); @@ -2368,7 +2569,8 @@ ccid_get_atr (ccid_driver_t handle, msg[0] = PC_to_RDR_IccPowerOn; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; - msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */ + /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */ + msg[7] = handle->auto_voltage ? 0 : 1; msg[8] = 0; /* RFU */ msg[9] = 0; /* RFU */ set_msg_len (msg, 0); @@ -2410,23 +2612,73 @@ ccid_get_atr (ccid_driver_t handle, *atrlen = n; } + param[6] = handle->nonnull_nad? ((1 << 4) | 0): 0; + rc = update_param_by_atr (param, msg+10, msglen - 10); + if (rc < 0) + { + DEBUGOUT_1 ("update_param_by_atr failed: %d\n", rc); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + got_param = 0; - msg[0] = PC_to_RDR_GetParameters; - msg[5] = 0; /* slot */ - msg[6] = seqno = handle->seqno++; - msg[7] = 0; /* RFU */ - msg[8] = 0; /* RFU */ - msg[9] = 0; /* RFU */ - set_msg_len (msg, 0); - msglen = 10; - rc = bulk_out (handle, msg, msglen, 0); - if (!rc) - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, - seqno, 2000, 0); - if (rc) - DEBUGOUT ("GetParameters failed\n"); - else if (msglen == 17 && msg[9] == 1) - got_param = 1; + + if (handle->auto_param) + { + msg[0] = PC_to_RDR_GetParameters; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; + rc = bulk_out (handle, msg, msglen, 0); + if (!rc) + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 2000, 0); + if (rc) + DEBUGOUT ("GetParameters failed\n"); + else if (msglen == 17 && msg[9] == 1) + got_param = 1; + } + else if (handle->auto_pps) + ; + else if (rc == 1) /* It's negotiable, send PPS. */ + { + msg[0] = PC_to_RDR_XfrBlock; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; + msg[8] = 0; + msg[9] = 0; + msg[10] = 0xff; /* PPSS */ + msg[11] = 0x11; /* PPS0: PPS1, Protocol T=1 */ + msg[12] = param[0]; /* PPS1: Fi / Di */ + msg[13] = 0xff ^ 0x11 ^ param[0]; /* PCK */ + set_msg_len (msg, 4); + msglen = 10 + 4; + + rc = bulk_out (handle, msg, msglen, 0); + if (rc) + return rc; + + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, + seqno, 5000, 0); + if (rc) + return rc; + + if (msglen != 10 + 4) + { + DEBUGOUT_1 ("Setting PPS failed: %d\n", msglen); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + + if (msg[10] != 0xff || msg[11] != 0x11 || msg[12] != param[0]) + { + DEBUGOUT_1 ("Setting PPS failed: 0x%02x\n", param[0]); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + } /* Setup parameters to select T=1. */ msg[0] = PC_to_RDR_SetParameters; @@ -2437,16 +2689,7 @@ ccid_get_atr (ccid_driver_t handle, msg[9] = 0; /* RFU */ if (!got_param) - { - /* FIXME: Get those values from the ATR. */ - msg[10]= 0x01; /* Fi/Di */ - msg[11]= 0x10; /* LRC, direct convention. */ - msg[12]= 0; /* Extra guardtime. */ - msg[13]= 0x41; /* BWI/CWI */ - msg[14]= 0; /* No clock stoppping. */ - msg[15]= 254; /* IFSC */ - msg[16]= 0; /* Does not support non default NAD values. */ - } + memcpy (&msg[10], param, 7); set_msg_len (msg, 7); msglen = 10 + 7; @@ -2463,6 +2706,12 @@ ccid_get_atr (ccid_driver_t handle, else handle->ifsc = 128; /* Something went wrong, assume 128 bytes. */ + if (handle->nonnull_nad && msglen > 16 && msg[16] == 0) + { + DEBUGOUT ("Use Null-NAD, clearing handle->nonnull_nad.\n"); + handle->nonnull_nad = 0; + } + handle->t1_ns = 0; handle->t1_nr = 0; @@ -3071,7 +3320,7 @@ ccid_transceive (ccid_driver_t handle, The APDU should me made up of 4 bytes without Lc. PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0 - may be used t enable reasonable defaults. PIN_PADLEN should be 0. + may be used t enable reasonable defaults. When called with RESP and NRESP set to NULL, the function will merely check whether the reader supports the secure command for the @@ -3079,8 +3328,7 @@ ccid_transceive (ccid_driver_t handle, int ccid_transceive_secure (ccid_driver_t handle, const unsigned char *apdu_buf, size_t apdu_buflen, - int pin_mode, int pinlen_min, int pinlen_max, - int pin_padlen, + pininfo_t *pininfo, unsigned char *resp, size_t maxresplen, size_t *nresp) { int rc; @@ -3091,6 +3339,7 @@ ccid_transceive_secure (ccid_driver_t handle, size_t dummy_nresp; int testmode; int cherry_mode = 0; + int enable_varlen = 0; testmode = !resp && !nresp; @@ -3103,23 +3352,17 @@ ccid_transceive_secure (ccid_driver_t handle, else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2)) ; else - return CCID_DRIVER_ERR_NO_KEYPAD; + return CCID_DRIVER_ERR_NO_PINPAD; - if (pin_mode != 1) - return CCID_DRIVER_ERR_NOT_SUPPORTED; - - if (pin_padlen != 0) - return CCID_DRIVER_ERR_NOT_SUPPORTED; - - if (!pinlen_min) - pinlen_min = 1; - if (!pinlen_max) - pinlen_max = 25; + if (!pininfo->minlen) + pininfo->minlen = 1; + if (!pininfo->maxlen) + pininfo->maxlen = 25; /* Note that the 25 is the maximum value the SPR532 allows. */ - if (pinlen_min < 1 || pinlen_min > 25 - || pinlen_max < 1 || pinlen_max > 25 - || pinlen_min > pinlen_max) + if (pininfo->minlen < 1 || pininfo->minlen > 25 + || pininfo->maxlen < 1 || pininfo->maxlen > 25 + || pininfo->minlen > pininfo->maxlen) return CCID_DRIVER_ERR_INV_VALUE; /* We have only tested a few readers so better don't risk anything @@ -3129,11 +3372,14 @@ ccid_transceive_secure (ccid_driver_t handle, case VENDOR_SCM: /* Tested with SPR 532. */ case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */ case VENDOR_FSIJ: /* Tested with the gnuk code (2011-01-05). */ + enable_varlen = 1; break; case VENDOR_VASCO: /* Tested with DIGIPASS 920 */ - pinlen_max = 15; + enable_varlen = 1; + pininfo->maxlen = 15; break; case VENDOR_CHERRY: + enable_varlen = 1; /* The CHERRY XX44 keyboard echos an asterisk for each entered character on the keyboard channel. We use a special variant of PC_to_RDR_Secure which directs these characters to the @@ -3145,12 +3391,28 @@ ccid_transceive_secure (ccid_driver_t handle, cherry_mode = 1; break; default: + if ((handle->id_vendor == VENDOR_GEMPC && + handle->id_product == GEMPC_PINPAD) + || (handle->id_vendor == VENDOR_VEGA && + handle->id_product == VEGA_ALPHA)) + { + enable_varlen = 0; + pininfo->minlen = 4; + pininfo->maxlen = 8; + break; + } return CCID_DRIVER_ERR_NOT_SUPPORTED; } + if (enable_varlen) + pininfo->fixedlen = 0; + if (testmode) return 0; /* Success */ + if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16) + return CCID_DRIVER_ERR_NOT_SUPPORTED; + msg = send_buffer; if (handle->id_vendor == VENDOR_SCM) { @@ -3180,9 +3442,9 @@ ccid_transceive_secure (ccid_driver_t handle, } else { - msg[13] = 0x00; /* bmPINBlockString: - 0 bits of pin length to insert. - 0 bytes of PIN block size. */ + msg[13] = pininfo->fixedlen; /* bmPINBlockString: + 0 bits of pin length to insert. + PIN block size by fixedlen. */ msg[14] = 0x00; /* bmPINLengthFormat: Units are bytes, position is 0. */ } @@ -3191,12 +3453,12 @@ ccid_transceive_secure (ccid_driver_t handle, if (apdu_buf[1] == 0x24) { msg[msglen++] = 0; /* bInsertionOffsetOld */ - msg[msglen++] = 0; /* bInsertionOffsetNew */ + msg[msglen++] = pininfo->fixedlen; /* bInsertionOffsetNew */ } /* The following is a little endian word. */ - msg[msglen++] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */ - msg[msglen++] = pinlen_min; /* wPINMaxExtraDigit-Minimum. */ + msg[msglen++] = pininfo->maxlen; /* wPINMaxExtraDigit-Maximum. */ + msg[msglen++] = pininfo->minlen; /* wPINMaxExtraDigit-Minimum. */ if (apdu_buf[1] == 0x24) msg[msglen++] = apdu_buf[2] == 0 ? 0x03 : 0x01; @@ -3209,12 +3471,12 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen] = 0x02; /* bEntryValidationCondition: Validation key pressed */ - if (pinlen_min && pinlen_max && pinlen_min == pinlen_max) + if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen) msg[msglen] |= 0x01; /* Max size reached. */ msglen++; if (apdu_buf[1] == 0x20) - msg[msglen++] = 0xff; /* bNumberMessage: Default. */ + msg[msglen++] = 0x01; /* bNumberMessage. */ else msg[msglen++] = 0x03; /* bNumberMessage. */ @@ -3230,10 +3492,18 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen++] = 2; /* bMsgIndex3. */ } + /* Calculate Lc. */ + n = pininfo->fixedlen; + if (apdu_buf[1] == 0x24) + n += pininfo->fixedlen; + /* bTeoProlog follows: */ msg[msglen++] = handle->nonnull_nad? ((1 << 4) | 0): 0; msg[msglen++] = ((handle->t1_ns & 1) << 6); /* I-block */ - msg[msglen++] = 0; /* The apdulen will be filled in by the reader. */ + if (n) + msg[msglen++] = n + 5; /* apdulen should be filled for fixed length. */ + else + msg[msglen++] = 0; /* The apdulen will be filled in by the reader. */ /* APDU follows: */ msg[msglen++] = apdu_buf[0]; /* CLA */ msg[msglen++] = apdu_buf[1]; /* INS */ @@ -3241,6 +3511,12 @@ ccid_transceive_secure (ccid_driver_t handle, msg[msglen++] = apdu_buf[3]; /* P2 */ if (cherry_mode) msg[msglen++] = 0; + else if (pininfo->fixedlen != 0) + { + msg[msglen++] = n; + memset (&msg[msglen], 0xff, n); + msglen += n; + } /* An EDC is not required. */ set_msg_len (msg, msglen - 10); diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 121cb945b..1fd7ffa63 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -72,7 +72,7 @@ #define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b #define CCID_DRIVER_ERR_NO_READER 0x1000c #define CCID_DRIVER_ERR_ABORTED 0x1000d -#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e +#define CCID_DRIVER_ERR_NO_PINPAD 0x1000e struct ccid_driver_s; typedef struct ccid_driver_s *ccid_driver_t; @@ -93,8 +93,7 @@ int ccid_transceive (ccid_driver_t handle, unsigned char *resp, size_t maxresplen, size_t *nresp); int ccid_transceive_secure (ccid_driver_t handle, const unsigned char *apdu, size_t apdulen, - int pin_mode, - int pinlen_min, int pinlen_max, int pin_padlen, + pininfo_t *pininfo, unsigned char *resp, size_t maxresplen, size_t *nresp); int ccid_transceive_escape (ccid_driver_t handle, const unsigned char *data, size_t datalen, diff --git a/scd/command.c b/scd/command.c index 40e61a48b..6267bb0cd 100644 --- a/scd/command.c +++ b/scd/command.c @@ -34,6 +34,7 @@ #include <assuan.h> #include <ksba.h> #include "app-common.h" +#include "iso7816.h" #include "apdu.h" /* Required for apdu_*_reader (). */ #include "atr.h" #include "exechelp.h" @@ -908,13 +909,13 @@ pin_cb (void *opaque, const char *info, char **retstr) if (!retstr) { - /* We prompt for keypad entry. To make sure that the popup has + /* We prompt for pinpad entry. To make sure that the popup has been show we use an inquire and not just a status message. We ignore any value returned. */ if (info) { - log_debug ("prompting for keypad entry '%s'\n", info); - rc = estream_asprintf (&command, "POPUPKEYPADPROMPT %s", info); + log_debug ("prompting for pinpad entry '%s'\n", info); + rc = estream_asprintf (&command, "POPUPPINPADPROMPT %s", info); if (rc < 0) return gpg_error (gpg_err_code_from_errno (errno)); rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); @@ -922,8 +923,8 @@ pin_cb (void *opaque, const char *info, char **retstr) } else { - log_debug ("dismiss keypad entry prompt\n"); - rc = assuan_inquire (ctx, "DISMISSKEYPADPROMPT", + log_debug ("dismiss pinpad entry prompt\n"); + rc = assuan_inquire (ctx, "DISMISSPINPADPROMPT", &value, &valuelen, MAXLEN_PIN); } if (!rc) diff --git a/scd/iso7816.c b/scd/iso7816.c index 45f5e08bf..f1dbcffe4 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -94,7 +94,7 @@ map_sw (int sw) case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break; case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break; case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break; - case SW_HOST_NO_KEYPAD: ec = GPG_ERR_NOT_SUPPORTED; break; + case SW_HOST_NO_PINPAD: ec = GPG_ERR_NOT_SUPPORTED; break; default: if ((sw & 0x010000)) @@ -267,30 +267,26 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen, /* Check whether the reader supports the ISO command code COMMAND on - the keypad. Returns 0 on success. */ + the pinpad. Returns 0 on success. */ gpg_error_t -iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo) +iso7816_check_pinpad (int slot, int command, pininfo_t *pininfo) { int sw; - sw = apdu_check_keypad (slot, command, - pininfo->mode, pininfo->minlen, pininfo->maxlen, - pininfo->padlen); + sw = apdu_check_pinpad (slot, command, pininfo); return iso7816_map_sw (sw); } /* Perform a VERIFY command on SLOT using the card holder verification - vector CHVNO. With PININFO non-NULL the keypad of the reader will + vector CHVNO. With PININFO non-NULL the pinpad of the reader will be used. Returns 0 on success. */ gpg_error_t -iso7816_verify_kp (int slot, int chvno, iso7816_pininfo_t *pininfo) +iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo) { int sw; - sw = apdu_keypad_verify (slot, 0x00, CMD_VERIFY, 0, chvno, - pininfo->mode, pininfo->minlen, pininfo->maxlen, - pininfo->padlen); + sw = apdu_pinpad_verify (slot, 0x00, CMD_VERIFY, 0, chvno, pininfo); return map_sw (sw); } @@ -306,19 +302,17 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen) } /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder - verification vector CHVNO. With PININFO non-NULL the keypad of the + verification vector CHVNO. With PININFO non-NULL the pinpad of the reader will be used. If IS_EXCHANGE is 0, a "change reference data" is done, otherwise an "exchange reference data". */ gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno, int is_exchange, - iso7816_pininfo_t *pininfo) + pininfo_t *pininfo) { int sw; - sw = apdu_keypad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, - is_exchange ? 1 : 0, - chvno, pininfo->mode, pininfo->minlen, - pininfo->maxlen, pininfo->padlen); + sw = apdu_pinpad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, + is_exchange ? 1 : 0, chvno, pininfo); return map_sw (sw); } diff --git a/scd/iso7816.h b/scd/iso7816.h index 336208aba..6dd1052fe 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -24,23 +24,26 @@ #include "cardglue.h" #endif -/* Command codes used by iso7816_check_keypad. */ +/* Command codes used by iso7816_check_pinpad. */ #define ISO7816_VERIFY 0x20 #define ISO7816_CHANGE_REFERENCE_DATA 0x24 #define ISO7816_RESET_RETRY_COUNTER 0x2C -/* Information to be passed to keypad equipped readers. See +/* Information to be passed to pinpad equipped readers. See ccid-driver.c for details. */ -struct iso7816_pininfo_s +struct pininfo_s { - int mode; /* A mode of 0 means: Do not use the keypad. */ + int fixedlen; /* + * -1: Variable length input is not supported, + * no information of fixed length yet. + * 0: Use variable length input. + * >0: Fixed length of PIN. + */ int minlen; int maxlen; - int padlen; - int padchar; }; -typedef struct iso7816_pininfo_s iso7816_pininfo_t; +typedef struct pininfo_s pininfo_t; gpg_error_t iso7816_map_sw (int sw); @@ -59,17 +62,17 @@ gpg_error_t iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen, int handle_more, unsigned char **result, size_t *resultlen); -gpg_error_t iso7816_check_keypad (int slot, int command, - iso7816_pininfo_t *pininfo); +gpg_error_t iso7816_check_pinpad (int slot, int command, + pininfo_t *pininfo); gpg_error_t iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen); -gpg_error_t iso7816_verify_kp (int slot, int chvno, iso7816_pininfo_t *pininfo); +gpg_error_t iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo); gpg_error_t iso7816_change_reference_data (int slot, int chvno, const char *oldchv, size_t oldchvlen, const char *newchv, size_t newchvlen); gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno, int is_exchange, - iso7816_pininfo_t *pininfo); + pininfo_t *pininfo); gpg_error_t iso7816_reset_retry_counter (int slot, int chvno, const char *newchv, size_t newchvlen); gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno, diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 3f34d6983..e503d3665 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -33,6 +33,7 @@ #include "../common/ttyio.h" #include "../common/simple-pwquery.h" +#include "iso7816.h" #include "apdu.h" /* for open_reader */ #include "atr.h" #include "app-common.h" diff --git a/scd/scdaemon.c b/scd/scdaemon.c index af4c9c1ce..4f9b3695d 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -48,6 +48,7 @@ #include "i18n.h" #include "sysutils.h" #include "app-common.h" +#include "iso7816.h" #include "apdu.h" #include "ccid-driver.h" #include "mkdtemp.h" @@ -91,10 +92,11 @@ enum cmd_and_opt_values opcscDriver, oDisableCCID, oDisableOpenSC, - oDisableKeypad, + oDisablePinpad, oAllowAdmin, oDenyAdmin, oDisableApplication, + oEnablePinpadVarlen, oDebugDisableTicker }; @@ -142,12 +144,14 @@ static ARGPARSE_OPTS opts[] = { /* end --disable-ccid */), ARGPARSE_s_u (oCardTimeout, "card-timeout", N_("|N|disconnect the card after N seconds of inactivity")), - ARGPARSE_s_n (oDisableKeypad, "disable-keypad", - N_("do not use a reader's keypad")), + ARGPARSE_s_n (oDisablePinpad, "disable-pinpad", + N_("do not use a reader's pinpad")), ARGPARSE_s_n (oAllowAdmin, "allow-admin", "@"), ARGPARSE_s_n (oDenyAdmin, "deny-admin", N_("deny the use of admin card commands")), ARGPARSE_s_s (oDisableApplication, "disable-application", "@"), + ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen", + N_("use variable length input for pinpad")), ARGPARSE_end () }; @@ -575,7 +579,7 @@ main (int argc, char **argv ) case oDisableCCID: opt.disable_ccid = 1; break; case oDisableOpenSC: break; - case oDisableKeypad: opt.disable_keypad = 1; break; + case oDisablePinpad: opt.disable_pinpad = 1; break; case oAllowAdmin: /* Dummy because allow is now the default. */ break; @@ -587,6 +591,8 @@ main (int argc, char **argv ) add_to_strlist (&opt.disabled_applications, pargs.r.ret_str); break; + case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break; + default: pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR; break; @@ -675,8 +681,9 @@ main (int argc, char **argv ) es_printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE ); #endif es_printf ("deny-admin:%lu:\n", GC_OPT_FLAG_NONE ); - es_printf ("disable-keypad:%lu:\n", GC_OPT_FLAG_NONE ); + es_printf ("disable-pinpad:%lu:\n", GC_OPT_FLAG_NONE ); es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0); + es_printf ("enable-pinpad-varlen:%lu:\n", GC_OPT_FLAG_NONE ); scd_exit (0); } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 74e8b7d44..ab63425d8 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -56,7 +56,8 @@ struct const char *pcsc_driver; /* Library to access the PC/SC system. */ const char *reader_port; /* NULL or reder port to use. */ int disable_ccid; /* Disable the use of the internal CCID driver. */ - int disable_keypad; /* Do not use a keypad. */ + int disable_pinpad; /* Do not use a pinpad. */ + int enable_pinpad_varlen; /* Use variable length input for pinpad. */ int allow_admin; /* Allow the use of admin commands for certain cards. */ strlist_t disabled_applications; /* Card applications we do not |