From 60415958954bedd81cd29090f3c401eafd77a1db Mon Sep 17 00:00:00 2001 From: martin Date: Wed, 8 Apr 2009 10:31:18 +0000 Subject: [PATCH] * Correctly set offsets for PINs for PIN modification operations with pinpads. Thanks to Robert Konklewski. * Only set messages if the reader has display capabilities. * Detect rejected pinpad commands * Whitespace fixes git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3679 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/libopensc/reader-pcsc.c | 110 ++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index caa08614..6207ef29 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -110,9 +110,9 @@ static int pcsc_ret_to_error(long rv) case SCARD_E_NO_READERS_AVAILABLE: return SC_ERROR_NO_READERS_FOUND; #endif - case SCARD_E_NO_SERVICE: - /* If the service is (auto)started, there could be readers later */ - return SC_ERROR_NO_READERS_FOUND; + case SCARD_E_NO_SERVICE: + /* If the service is (auto)started, there could be readers later */ + return SC_ERROR_NO_READERS_FOUND; default: return SC_ERROR_UNKNOWN; } @@ -505,7 +505,8 @@ static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) struct pcsc_private_data *priv = GET_PRIV_DATA(reader); struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); int r; - u8 feature_buf[256]; + u8 feature_buf[256], rbuf[SC_MAX_APDU_BUFFER_SIZE]; + size_t rcount; DWORD i, feature_len, display_ioctl; PCSC_TLV_STRUCTURE *pcsc_tlv; @@ -543,7 +544,7 @@ static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) } sc_debug(reader->ctx, "Proto after reconnect = %d", slot->active_protocol); } - } + } /* check for pinpad support */ if (priv->gpriv->SCardControl != NULL) { @@ -580,7 +581,7 @@ static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) } else if (pcsc_tlv[i].tag == FEATURE_IFD_PIN_PROPERTIES) { display_ioctl = ntohl(pcsc_tlv[i].value); } else { - sc_debug(reader->ctx, "Reader pinpad feature: %02x not supported", pcsc_tlv[i].tag); + sc_debug(reader->ctx, "Reader feature %02x is not supported", pcsc_tlv[i].tag); } } @@ -602,25 +603,24 @@ static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) slot->capabilities |= SC_SLOT_CAP_PIN_PAD; } else { sc_debug(reader->ctx, "%s %s", log_text, log_disabled); - } + } + } - if (display_ioctl) { - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - size_t rcount = sizeof(rbuf); - r = pcsc_internal_transmit(reader, slot, NULL, 0, rbuf, &rcount, display_ioctl); - if (r == SC_SUCCESS) { - if (rcount != sizeof(PIN_PROPERTIES_STRUCTURE)) { - PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)rbuf; - if (caps->wLcdLayout > 0) { - sc_debug(reader->ctx, "Reader has a display: %04X", caps->wLcdLayout); - slot->capabilities |= SC_SLOT_CAP_DISPLAY; - } else - sc_debug(reader->ctx, "Reader does not have a display."); - } else { - sc_debug(reader->ctx, "Returned PIN properties structure has bad length (%d)", rcount); - } - } - } + if (display_ioctl) { + rcount = sizeof(rbuf); + r = pcsc_internal_transmit(reader, slot, NULL, 0, rbuf, &rcount, display_ioctl); + if (r == SC_SUCCESS) { + if (rcount != sizeof(PIN_PROPERTIES_STRUCTURE)) { + PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)rbuf; + if (caps->wLcdLayout > 0) { + sc_debug(reader->ctx, "Reader has a display: %04X", caps->wLcdLayout); + slot->capabilities |= SC_SLOT_CAP_DISPLAY; + } else + sc_debug(reader->ctx, "Reader does not have a display."); + } else { + sc_debug(reader->ctx, "Returned PIN properties structure has bad length (%d)", rcount); + } + } } } } @@ -634,7 +634,7 @@ static int pcsc_disconnect(sc_reader_t * reader, sc_slot_info_t * slot) struct pcsc_private_data *priv = GET_PRIV_DATA(reader); priv->gpriv->SCardDisconnect(pslot->pcsc_card, priv->gpriv->transaction_reset ? - SCARD_RESET_CARD : SCARD_LEAVE_CARD); + SCARD_RESET_CARD : SCARD_LEAVE_CARD); memset(pslot, 0, sizeof(*pslot)); slot->flags = 0; return SC_SUCCESS; @@ -807,7 +807,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data) gpriv->SCardControl = (SCardControl_t)lt_dlsym(gpriv->dlhandle, "SCardControl132"); #endif if (gpriv->SCardControl == NULL) { - gpriv->SCardControl = (SCardControl_t)lt_dlsym(gpriv->dlhandle, "SCardControl"); + gpriv->SCardControl = (SCardControl_t)lt_dlsym(gpriv->dlhandle, "SCardControl"); } } else { @@ -1018,10 +1018,10 @@ out: static int pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t * slot, struct sc_pin_cmd_data *data) { - /* XXX: temporary */ if (slot->capabilities & SC_SLOT_CAP_PIN_PAD) { return part10_pin_cmd(reader, slot, data); } else { + /* XXX: probably dead code */ return ctbcs_pin_cmd(reader, slot, data); } } @@ -1051,7 +1051,7 @@ struct sc_reader_driver * sc_get_pcsc_driver(void) */ /* Local definitions */ -#define SC_CCID_PIN_TIMEOUT 30 +#define SC_CCID_PIN_TIMEOUT 30 /* CCID definitions */ #define SC_CCID_PIN_ENCODING_BIN 0x00 @@ -1061,13 +1061,13 @@ struct sc_reader_driver * sc_get_pcsc_driver(void) #define SC_CCID_PIN_UNITS_BYTES 0x80 /* Build a PIN verification block + APDU */ -static int part10_build_verify_pin_block(u8 * buf, size_t * size, struct sc_pin_cmd_data *data) +static int part10_build_verify_pin_block(u8 * buf, size_t * size, sc_slot_info_t *slot, struct sc_pin_cmd_data *data) { int offset = 0, count = 0; sc_apdu_t *apdu = data->apdu; u8 tmp; unsigned int tmp16; - PIN_VERIFY_STRUCTURE *pin_verify = (PIN_VERIFY_STRUCTURE *)buf; + PIN_VERIFY_STRUCTURE *pin_verify = (PIN_VERIFY_STRUCTURE *)buf; /* PIN verification control message */ pin_verify->bTimerOut = SC_CCID_PIN_TIMEOUT; @@ -1120,8 +1120,11 @@ static int part10_build_verify_pin_block(u8 * buf, size_t * size, struct sc_pin_ pin_verify->wPINMaxExtraDigit = HOST_TO_CCID_16(tmp16); /* Min Max */ pin_verify->bEntryValidationCondition = 0x02; /* Keypress only */ - - pin_verify->bNumberMessage = 0xFF; /* Default message */ + + if (slot->capabilities & SC_SLOT_CAP_DISPLAY) + pin_verify->bNumberMessage = 0xFF; /* Default message */ + else + pin_verify->bNumberMessage = 0x00; /* No messages */ /* Ignore language and T=1 parameters. */ pin_verify->wLangId = HOST_TO_CCID_16(0x0000); @@ -1129,7 +1132,7 @@ static int part10_build_verify_pin_block(u8 * buf, size_t * size, struct sc_pin_ pin_verify->bTeoPrologue[0] = 0x00; pin_verify->bTeoPrologue[1] = 0x00; pin_verify->bTeoPrologue[2] = 0x00; - + /* APDU itself */ pin_verify->abData[offset++] = apdu->cla; pin_verify->abData[offset++] = apdu->ins; @@ -1153,7 +1156,7 @@ static int part10_build_verify_pin_block(u8 * buf, size_t * size, struct sc_pin_ /* Build a PIN modification block + APDU */ -static int part10_build_modify_pin_block(u8 * buf, size_t * size, struct sc_pin_cmd_data *data) +static int part10_build_modify_pin_block(u8 * buf, size_t * size, sc_slot_info_t *slot, struct sc_pin_cmd_data *data) { int offset = 0, count = 0; sc_apdu_t *apdu = data->apdu; @@ -1205,14 +1208,14 @@ static int part10_build_modify_pin_block(u8 * buf, size_t * size, struct sc_pin_ } pin_modify->bmPINLengthFormat = tmp; /* bmPINLengthFormat */ - pin_modify->bInsertionOffsetOld = 0x00; /* bOffsetOld */ - - /* bInsertionOffsetNew */ - tmp = 0x00; - if (data->pin1.encoding == SC_PIN_ENCODING_GLP) { - tmp = 0x08; + /* Set offsets if not Case 1 APDU */ + if (data->pin1.length_offset != 4) { + pin_modify->bInsertionOffsetOld = data->pin1.offset - 5; + pin_modify->bInsertionOffsetNew = data->pin2.offset - 5; + } else { + pin_modify->bInsertionOffsetOld = 0x00; + pin_modify->bInsertionOffsetNew = 0x00; } - pin_modify->bInsertionOffsetNew = tmp; /* bOffsetNew */ if (!data->pin1.min_length || !data->pin1.max_length) return SC_ERROR_INVALID_ARGUMENTS; @@ -1222,17 +1225,21 @@ static int part10_build_modify_pin_block(u8 * buf, size_t * size, struct sc_pin_ pin_modify->bConfirmPIN = 0x03; /* bConfirmPIN, all */ pin_modify->bEntryValidationCondition = 0x02; /* bEntryValidationCondition, keypress only */ + + if (slot->capabilities & SC_SLOT_CAP_DISPLAY) + pin_modify->bNumberMessage = 0x03; /* 3 messages (because bConfirmPIN = 3), all default. Could be 0xFF too */ + else + pin_modify->bNumberMessage = 0x00; /* No messages */ /* Ignore language and T=1 parameters. */ - pin_modify->bNumberMessage = 0x00; /* XXX: Latest released CCID driver rejects 0xFF */ pin_modify->wLangId = HOST_TO_CCID_16(0x0000); - pin_modify->bMsgIndex1 = 0x00; - pin_modify->bMsgIndex2 = 0x00; - pin_modify->bMsgIndex3 = 0x00; + pin_modify->bMsgIndex1 = 0x00; /* Default message indexes */ + pin_modify->bMsgIndex2 = 0x01; + pin_modify->bMsgIndex3 = 0x02; pin_modify->bTeoPrologue[0] = 0x00; pin_modify->bTeoPrologue[1] = 0x00; pin_modify->bTeoPrologue[2] = 0x00; - + /* APDU itself */ pin_modify->abData[offset++] = apdu->cla; pin_modify->abData[offset++] = apdu->ins; @@ -1286,7 +1293,7 @@ part10_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, sc_error(reader->ctx, "Pinpad reader does not support verification!"); return SC_ERROR_NOT_SUPPORTED; } - r = part10_build_verify_pin_block(sbuf, &scount, data); + r = part10_build_verify_pin_block(sbuf, &scount, slot, data); ioctl = pslot->verify_ioctl ? pslot->verify_ioctl : pslot->verify_ioctl_start; break; case SC_PIN_CMD_CHANGE: @@ -1295,7 +1302,7 @@ part10_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, sc_error(reader->ctx, "Pinpad reader does not support modification!"); return SC_ERROR_NOT_SUPPORTED; } - r = part10_build_modify_pin_block(sbuf, &scount, data); + r = part10_build_modify_pin_block(sbuf, &scount, slot, data); ioctl = pslot->modify_ioctl ? pslot->modify_ioctl : pslot->modify_ioctl_start; break; default: @@ -1337,14 +1344,17 @@ part10_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, r = SC_SUCCESS; switch (((unsigned int) apdu->sw1 << 8) | apdu->sw2) { case 0x6400: /* Input timed out */ - r = SC_ERROR_KEYPAD_TIMEOUT; + r = SC_ERROR_KEYPAD_TIMEOUT; break; case 0x6401: /* Input cancelled */ - r = SC_ERROR_KEYPAD_CANCELLED; + r = SC_ERROR_KEYPAD_CANCELLED; break; case 0x6402: /* PINs don't match */ r = SC_ERROR_KEYPAD_PIN_MISMATCH; break; + case 0x6B80: /* Wrong data in the buffer, rejected by firmware */ + r = SC_ERROR_READER; + break; } SC_TEST_RET(reader->ctx, r, "PIN command failed");