diff --git a/src/libopensc/card-flex.c b/src/libopensc/card-flex.c index 0dafe7fc..4d230caf 100644 --- a/src/libopensc/card-flex.c +++ b/src/libopensc/card-flex.c @@ -932,6 +932,15 @@ static int flex_build_verify_apdu(struct sc_card *card, struct sc_apdu *apdu, return 0; } +static void flex_init_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num) +{ + pin->encoding = SC_PIN_ENCODING_ASCII; + pin->max_length = 8; + pin->pad_length = 8; + pin->pad_char = 0; + pin->offset = 5 + num * 8; +} + static int flex_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left) { @@ -940,10 +949,9 @@ static int flex_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int old_cla = -1; /* Fix pin data */ - data->pin1.encoding = SC_PIN_ENCODING_ASCII; - data->pin1.max_length = 8; - data->pin2.encoding = SC_PIN_ENCODING_ASCII; - data->pin2.max_length = 8; + data->flags |= SC_PIN_CMD_NEED_PADDING; + flex_init_pin_info(&data->pin1, 0); + flex_init_pin_info(&data->pin2, 1); if (data->cmd == SC_PIN_CMD_VERIFY) { r = flex_build_verify_apdu(card, &apdu, data); diff --git a/src/libopensc/card-gpk.c b/src/libopensc/card-gpk.c index 9c1afaaa..4fbdb933 100644 --- a/src/libopensc/card-gpk.c +++ b/src/libopensc/card-gpk.c @@ -1704,9 +1704,18 @@ gpk_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, struct sc_pin_cmd_data *dat memset(apdu, 0, sizeof(*apdu)); apdu->cse = SC_APDU_CASE_3_SHORT; + data->flags |= SC_PIN_CMD_NEED_PADDING; + data->pin1.encoding = SC_PIN_ENCODING_BCD; + data->pin1.pad_length = 8; + data->pin1.pad_char = 0x00; + data->pin2.encoding = SC_PIN_ENCODING_BCD; + data->pin2.pad_length = 8; + data->pin2.pad_char = 0x00; + switch (data->cmd) { case SC_PIN_CMD_VERIFY: /* Copy PIN to buffer and pad */ + data->pin1.offset = 5; r = sc_build_pin(sbuf, 8, &data->pin1, 1); if (r < 0) return r; @@ -1718,11 +1727,7 @@ gpk_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, struct sc_pin_cmd_data *dat case SC_PIN_CMD_CHANGE: case SC_PIN_CMD_UNBLOCK: /* Copy PINs to buffer, BCD-encoded, and pad */ - data->pin1.encoding = SC_PIN_ENCODING_BCD; - data->pin1.max_length = 8; - data->pin2.encoding = SC_PIN_ENCODING_BCD; - data->pin2.max_length = 8; - data->pin2.offset = 4; + data->pin2.offset = 5 + 4; if ((r = sc_build_pin(sbuf, 4, &data->pin1, 1)) < 0 || (r = sc_build_pin(sbuf + 4, 4, &data->pin2, 1)) < 0) return r; diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 2f4cc6e2..79111220 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -848,14 +848,18 @@ static int iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, } else { /* Call the reader driver to collect * the PIN and pass on the APDU to the card */ + if (data->pin1.offset == 0) { + error(card->ctx, + "Card driver didn't set PIN offset"); + return SC_ERROR_INVALID_ARGUMENTS; + } if (card->reader && card->reader->ops - && card->reader->ops->enter_pin) { - r = card->reader->ops->enter_pin(card->reader, + && card->reader->ops->perform_verify) { + r = card->reader->ops->perform_verify(card->reader, card->slot, data); - apdu->sw1 = 0x90; - apdu->sw2 = 0x00; + /* sw1/sw2 filled in by reader driver */ } else { error(card->ctx, "Card reader driver does not support " diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 81d4d9b0..9a902cb3 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -380,7 +380,7 @@ struct sc_reader_operations { /* Pin pad functions */ int (*display_message)(struct sc_reader *, struct sc_slot_info *, const char *); - int (*enter_pin)(struct sc_reader *, struct sc_slot_info *, + int (*perform_verify)(struct sc_reader *, struct sc_slot_info *, struct sc_pin_cmd_data *); /* Wait for an event */ diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index 881c7abd..04a648c9 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -374,7 +374,7 @@ const struct sc_reader_driver * sc_get_ctapi_driver() ctapi_ops.release = ctapi_release; ctapi_ops.connect = ctapi_connect; ctapi_ops.disconnect = ctapi_disconnect; - ctapi_ops.enter_pin = ctbcs_pin_cmd; + ctapi_ops.perform_verify = ctbcs_pin_cmd; return &ctapi_drv; } diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index 7740802c..dbbf93aa 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -47,6 +47,9 @@ static int openct_reader_transmit(struct sc_reader *reader, struct sc_slot_info *slot, const u8 *sendbuf, size_t sendsize, u8 *recvbuf, size_t *recvsize, int control); +static int openct_reader_perform_verify(struct sc_reader *reader, + struct sc_slot_info *slot, + struct sc_pin_cmd_data *info); static int openct_reader_lock(struct sc_reader *reader, struct sc_slot_info *slot); static int openct_reader_unlock(struct sc_reader *reader, @@ -62,6 +65,7 @@ static struct sc_reader_operations openct_reader_operations = { .connect = openct_reader_connect, .disconnect = openct_reader_disconnect, .transmit = openct_reader_transmit, + .perform_verify = openct_reader_perform_verify, .lock = openct_reader_lock, .unlock = openct_reader_unlock, }; @@ -153,6 +157,10 @@ openct_add_reader(struct sc_context *ctx, unsigned int num, ct_info_t *info) for (i = 0; i < SC_MAX_SLOTS; i++) { reader->slot[i].drv_data = calloc(1, sizeof(struct slot_data)); reader->slot[i].id = i; + if (data->info.ct_display) + reader->slot[i].capabilities |= SC_SLOT_CAP_DISPLAY; + if (data->info.ct_keypad) + reader->slot[i].capabilities |= SC_SLOT_CAP_PIN_PAD; } return 0; @@ -310,13 +318,76 @@ openct_reader_transmit(struct sc_reader *reader, return openct_error(reader, rc); } +int +openct_reader_perform_verify(struct sc_reader *reader, + struct sc_slot_info *slot, + struct sc_pin_cmd_data *info) +{ + struct driver_data *data = (struct driver_data *) reader->drv_data; + unsigned int pin_length = 0, pin_encoding; + size_t j = 0; + u8 buf[254]; + int rc; + + /* Hotplug check */ + if ((rc = openct_reader_reconnect(reader, slot)) < 0) + return rc; + + if (info->apdu == NULL) { + // complain + return SC_ERROR_INVALID_ARGUMENTS; + } + + buf[j++] = info->apdu->cla; + buf[j++] = info->apdu->ins; + buf[j++] = info->apdu->p1; + buf[j++] = info->apdu->p2; + + if (info->apdu->lc) { + size_t len = info->apdu->lc; + + if (j + 1 + len > sizeof(buf)) + return SC_ERROR_BUFFER_TOO_SMALL; + buf[j++] = len; + memcpy(buf+j, info->apdu->data, len); + j += len; + } + + if (info->pin1.min_length == info->pin1.max_length) + pin_length = info->pin1.min_length; + + if (info->pin1.encoding == SC_PIN_ENCODING_ASCII) + pin_encoding = IFD_PIN_ENCODING_ASCII; + else if (info->pin1.encoding == SC_PIN_ENCODING_BCD) + pin_encoding = IFD_PIN_ENCODING_BCD; + else + return SC_ERROR_INVALID_ARGUMENTS; + + rc = ct_card_verify(data->h, slot->id, + 0, /* no timeout?! */ + info->pin1.prompt, + pin_encoding, + pin_length, + info->pin1.offset, + buf, j, + buf, sizeof(buf)); + if (rc < 0) + return openct_error(reader, rc); + if (rc != 2) + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + info->apdu->sw1 = buf[0]; + info->apdu->sw2 = buf[1]; + return 0; +} + + int openct_reader_lock(struct sc_reader *reader, struct sc_slot_info *slot) { struct driver_data *data = (struct driver_data *) reader->drv_data; struct slot_data *slot_data = (struct slot_data *) slot->drv_data; - int rc, retry = 1; + int rc; SC_FUNC_CALLED(reader->ctx, 1); @@ -366,5 +437,11 @@ openct_error(struct sc_reader *reader, int code) return code; /* Fixme: translate error code */ + switch (code) { + case IFD_ERROR_USER_TIMEOUT: + return SC_ERROR_KEYPAD_TIMEOUT; + case IFD_ERROR_USER_ABORT: + return SC_ERROR_KEYPAD_CANCELLED; + } return SC_ERROR_READER; } diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index d5013bbf..14692d8a 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -601,7 +601,7 @@ const struct sc_reader_driver * sc_get_pcsc_driver() pcsc_ops.release = pcsc_release; pcsc_ops.connect = pcsc_connect; pcsc_ops.disconnect = pcsc_disconnect; - pcsc_ops.enter_pin = ctbcs_pin_cmd; + pcsc_ops.perform_verify = ctbcs_pin_cmd; pcsc_ops.wait_for_event = pcsc_wait_for_event; return &pcsc_drv;