merge Martin Paljak's ccid pinpad changes from the OPENSC_0_9 branch to the cvs head
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2095 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
f66913ca30
commit
3158fa3e05
|
@ -24,6 +24,7 @@ libopensc_la_SOURCES = \
|
|||
emv.c \
|
||||
\
|
||||
ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c \
|
||||
pinpad-ccid.c \
|
||||
\
|
||||
card-setcos.c card-miocos.c card-flex.c card-gpk.c \
|
||||
card-etoken.c card-tcos.c card-emv.c card-default.c \
|
||||
|
@ -40,7 +41,7 @@ include_HEADERS = \
|
|||
cardctl.h asn1.h log.h ui.h \
|
||||
errors.h types.h
|
||||
|
||||
noinst_HEADERS = ctbcs.h internal.h esteid.h card-oberthur.h
|
||||
noinst_HEADERS = ctbcs.h internal.h esteid.h card-oberthur.h pinpad-ccid.h
|
||||
|
||||
pkgconfigdir = @libdir@/pkgconfig
|
||||
pkgconfig_DATA = libopensc.pc libpkcs15init.pc \
|
||||
|
|
|
@ -384,7 +384,7 @@ struct sc_reader_operations {
|
|||
int (*transmit)(struct sc_reader *reader, struct sc_slot_info *slot,
|
||||
const u8 *sendbuf, size_t sendsize,
|
||||
u8 *recvbuf, size_t *recvsize,
|
||||
int control);
|
||||
unsigned long control);
|
||||
int (*lock)(struct sc_reader *reader, struct sc_slot_info *slot);
|
||||
int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot);
|
||||
int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot,
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* OpenSC pinpad support for CCID compatible readers.
|
||||
*
|
||||
* These functions build CCID PIN control blocks to be used with
|
||||
* CCID compatible pinpad readers.
|
||||
* Currently known to work only with libccid under unices via SCardControl().
|
||||
*
|
||||
* Tested with: SPR532 with firmware 5.04, ccid-0.9.2mp1, EstEID, opensc-0.9.4mp3 (CVS)
|
||||
*
|
||||
* (C) 2004 Martin Paljak <martin@paljak.pri.ee>
|
||||
*/
|
||||
#ifdef MP_CCID_PINPAD
|
||||
#include "internal.h"
|
||||
#include "pinpad-ccid.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Build a pin verification CCID block + APDU */
|
||||
int ccid_build_verify_pin_block(u8 * buf, size_t * size, struct sc_pin_cmd_data *data)
|
||||
{
|
||||
size_t buflen, count = 0;
|
||||
sc_apdu_t *apdu = data->apdu;
|
||||
u8 tmp;
|
||||
buflen = sizeof(buf);
|
||||
|
||||
/* CCID PIN verification control message */
|
||||
buf[count++] = SC_CCID_PIN_TIMEOUT; /* bTimeOut */
|
||||
|
||||
tmp = 0x00;
|
||||
if (data->pin1.encoding == SC_PIN_ENCODING_ASCII)
|
||||
tmp |= SC_CCID_PIN_ENCODING_ASCII;
|
||||
else if (data->pin1.encoding == SC_PIN_ENCODING_BCD)
|
||||
tmp |= SC_CCID_PIN_ENCODING_BCD;
|
||||
else
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
/* Only byte-aligend cards are cupported */
|
||||
tmp |= SC_CCID_PIN_UNITS_BYTES;
|
||||
tmp |= (data->pin1.length_offset - 5) << 3;
|
||||
buf[count++] = tmp; /* bmFormatString */
|
||||
|
||||
/* Ignored */
|
||||
buf[count++] = 0x00; /* bmPINBlockString */
|
||||
/* Ignored */
|
||||
buf[count++] = 0x00; /* bmPINLengthFormat */
|
||||
|
||||
if (!data->pin1.min_length || !data->pin1.max_length)
|
||||
return SC_ERROR_INVALID_PIN_LENGTH;
|
||||
buf[count++] = data->pin1.max_length; /* wPINMaxExtraDigit: max */
|
||||
buf[count++] = data->pin1.min_length; /* wPINMaxExtraDigit: min */
|
||||
|
||||
buf[count++] = 0x02; /* bEntryValidationCondition, keypress only */
|
||||
|
||||
/* ignore language and T=1 parameters. */
|
||||
buf[count++] = 0x00; /* bNumberMessage */
|
||||
buf[count++] = 0x00; /* wLangId */
|
||||
buf[count++] = 0x00; /* " */
|
||||
buf[count++] = 0x00; /* bMsgIndex */
|
||||
buf[count++] = 0x00; /* bTeoPrologue */
|
||||
buf[count++] = 0x00; /* " */
|
||||
buf[count++] = 0x00; /* " */
|
||||
|
||||
/* APDU itself */
|
||||
buf[count++] = apdu->cla;
|
||||
buf[count++] = apdu->ins;
|
||||
buf[count++] = apdu->p1;
|
||||
buf[count++] = apdu->p2;
|
||||
|
||||
/* If the effective PIN length offset == 4 (Lc) the condition is
|
||||
* not possible to handle with standard CCID capabilities, as
|
||||
* CCID defines all reader insertion offsets as relative to the first
|
||||
* byte _after_ Lc ... Too bad.
|
||||
* Do a special reader-dependant trick that is known to work with SPR532
|
||||
* reader and previously mentioned library versions (We omit the APDU
|
||||
* from the command block and send only APDU headers)
|
||||
*
|
||||
* Otherwise we assume a proper APDU and CCID compatible operations
|
||||
* and the APDU is copied verbatim.
|
||||
*/
|
||||
if (data->pin1.length_offset > 4) {
|
||||
memcpy(&buf[count], apdu->data, apdu->datalen);
|
||||
count += apdu->datalen;
|
||||
}
|
||||
|
||||
*size = count;
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Do the PIN command */
|
||||
int
|
||||
ccid_pin_cmd(struct sc_reader *reader, sc_slot_info_t * slot,
|
||||
struct sc_pin_cmd_data *data)
|
||||
{
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
size_t rcount = sizeof(rbuf), scount = 0;
|
||||
int r;
|
||||
unsigned long code;
|
||||
sc_apdu_t *apdu;
|
||||
|
||||
SC_FUNC_CALLED(reader->ctx, 3);
|
||||
|
||||
/* The APDU must be provided by the card driver */
|
||||
if (!data->apdu) {
|
||||
sc_error(reader->ctx, "No APDU provided for CCID PinPad verification!");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Only T=0 is currently supported */
|
||||
if (slot->active_protocol != SC_PROTO_T0) {
|
||||
sc_error(reader->ctx, "Only T=0 is currently supported!");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
apdu = data->apdu;
|
||||
switch (data->cmd) {
|
||||
case SC_PIN_CMD_VERIFY:
|
||||
r = ccid_build_verify_pin_block(sbuf, &scount, data);
|
||||
code = IOCTL_SMARTCARD_VENDOR_VERIFY_PIN;
|
||||
break;
|
||||
case SC_PIN_CMD_CHANGE:
|
||||
case SC_PIN_CMD_UNBLOCK:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
default:
|
||||
sc_error(reader->ctx, "Unknown PIN command %d", data->cmd);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* If CCID block building failed, we fail too */
|
||||
SC_TEST_RET(reader->ctx, r, "CCID PIN block building failed!");
|
||||
|
||||
/* The slot must be manually locked, as the control does not pass through card.c
|
||||
* wrappers that lock the card (card_transmit is not OK in this case, as it assumes
|
||||
* a proper APDU as a parameter, not a arbitary binary blob to be sent to the reader)
|
||||
*/
|
||||
r = reader->ops->lock(reader, slot);
|
||||
SC_TEST_RET(reader->ctx, r, "CCID PIN: Could not lock!");
|
||||
r = reader->ops->transmit(reader, slot, sbuf, scount, rbuf, &rcount, code);
|
||||
reader->ops->unlock(reader, slot);
|
||||
|
||||
SC_TEST_RET(reader->ctx, r, "CCID PIN block transmit failed!");
|
||||
|
||||
/* We expect only two bytes of result data (SW1 and SW2) */
|
||||
if (rcount != 2) {
|
||||
SC_FUNC_RETURN(reader->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
||||
}
|
||||
|
||||
/* Extract the SWs for the result APDU */
|
||||
apdu->sw1 = (unsigned int) rbuf[rcount - 2];
|
||||
apdu->sw2 = (unsigned int) rbuf[rcount - 1];
|
||||
|
||||
/* PIN command completed, all is good */
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
#endif /* MP_CCID_PINPAD */
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* pinpad-ccid.h: CCID ifdhandler control codes for pinpad support.
|
||||
*
|
||||
* Copy from pcsc-lite package created by Ludovic Rousseau
|
||||
*
|
||||
* Martin Paljak <martin@paljak.pri.ee>
|
||||
*/
|
||||
|
||||
#ifdef MP_CCID_PINPAD
|
||||
#ifndef _PINPAD_CCID_H
|
||||
#define _PINPAD_CCID_H
|
||||
|
||||
#define SCARD_CTL_CODE(code) (0x42000000 + (code))
|
||||
|
||||
#define IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE SCARD_CTL_CODE(1)
|
||||
#define IOCTL_SMARTCARD_VENDOR_VERIFY_PIN SCARD_CTL_CODE(2)
|
||||
#define IOCTL_SMARTCARD_VENDOR_MODIFY_PIN SCARD_CTL_CODE(3)
|
||||
#define IOCTL_SMARTCARD_VENDOR_TRANSFER_PIN SCARD_CTL_CODE(4)
|
||||
|
||||
#define SC_CCID_PIN_TIMEOUT 30
|
||||
|
||||
#define SC_CCID_PIN_ENCODING_BIN 0x00
|
||||
#define SC_CCID_PIN_ENCODING_BCD 0x01
|
||||
#define SC_CCID_PIN_ENCODING_ASCII 0x02
|
||||
|
||||
#define SC_CCID_PIN_UNITS_BYTES 0x80
|
||||
|
||||
/* CCID reader operation for pin commands */
|
||||
int ccid_pin_cmd(struct sc_reader *, sc_slot_info_t *, struct sc_pin_cmd_data *);
|
||||
|
||||
#endif /* _PINPAD_CCID_H */
|
||||
#endif /* MP_CCID_PINPAD */
|
|
@ -105,7 +105,7 @@ static int refresh_slot_attributes(struct sc_reader *reader,
|
|||
static int ctapi_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
|
||||
const u8 *sendbuf, size_t sendsize,
|
||||
u8 *recvbuf, size_t *recvsize,
|
||||
int control)
|
||||
unsigned long control)
|
||||
{
|
||||
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
||||
u8 dad, sad;
|
||||
|
|
|
@ -45,7 +45,7 @@ static int openct_reader_disconnect(struct sc_reader *reader,
|
|||
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);
|
||||
u8 *recvbuf, size_t *recvsize, unsigned long control);
|
||||
static int openct_reader_perform_verify(struct sc_reader *reader,
|
||||
struct sc_slot_info *slot,
|
||||
struct sc_pin_cmd_data *info);
|
||||
|
@ -274,7 +274,7 @@ 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)
|
||||
u8 *recvbuf, size_t *recvsize, unsigned long control)
|
||||
{
|
||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||
int rc;
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "internal.h"
|
||||
#ifdef HAVE_PCSC
|
||||
#include "ctbcs.h"
|
||||
#ifdef MP_CCID_PINPAD
|
||||
#include "pinpad-ccid.h"
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -125,7 +128,7 @@ static DWORD opensc_proto_to_pcsc(unsigned int proto)
|
|||
static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
|
||||
const u8 *sendbuf, size_t sendsize,
|
||||
u8 *recvbuf, size_t *recvsize,
|
||||
int control)
|
||||
unsigned long control)
|
||||
{
|
||||
SCARD_IO_REQUEST sSendPci, sRecvPci;
|
||||
DWORD dwSendLength, dwRecvLength;
|
||||
|
@ -155,7 +158,7 @@ static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
|
|||
rv = SCardControl(card, sendbuf, dwSendLength,
|
||||
recvbuf, &dwRecvLength);
|
||||
#else
|
||||
rv = SCardControl(card, 0, sendbuf, dwSendLength,
|
||||
rv = SCardControl(card, (DWORD) control, sendbuf, dwSendLength,
|
||||
recvbuf, dwRecvLength, &dwRecvLength);
|
||||
#endif
|
||||
}
|
||||
|
@ -436,6 +439,25 @@ static int pcsc_connect(struct sc_reader *reader, struct sc_slot_info *slot)
|
|||
slot->active_protocol = pcsc_proto_to_opensc(active_proto);
|
||||
pslot->pcsc_card = card_handle;
|
||||
|
||||
#ifdef MP_CCID_PINPAD
|
||||
/* check for PINPAD support, addon by -mp */
|
||||
{
|
||||
unsigned char attribute[1];
|
||||
DWORD attribute_length;
|
||||
sc_debug(reader->ctx, "Testing for CCID pinpad support ... ");
|
||||
/* See if this reader supports pinpad... */
|
||||
attribute_length = 1;
|
||||
rv = SCardGetAttrib(pslot->pcsc_card, IOCTL_SMARTCARD_VENDOR_VERIFY_PIN, attribute, &attribute_length);
|
||||
if (rv == SCARD_S_SUCCESS) {
|
||||
if (attribute[0] != 0) {
|
||||
sc_debug(reader->ctx, "Reader supports CCID pinpad");
|
||||
slot->capabilities |= SC_SLOT_CAP_PIN_PAD;
|
||||
}
|
||||
} else {
|
||||
PCSC_ERROR(reader->ctx, "SCardGetAttrib failed", rv)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -618,10 +640,13 @@ struct sc_reader_driver * sc_get_pcsc_driver(void)
|
|||
pcsc_ops.release = pcsc_release;
|
||||
pcsc_ops.connect = pcsc_connect;
|
||||
pcsc_ops.disconnect = pcsc_disconnect;
|
||||
#ifdef MP_CCID_PINPAD
|
||||
pcsc_ops.perform_verify = ccid_pin_cmd;
|
||||
#else
|
||||
pcsc_ops.perform_verify = ctbcs_pin_cmd;
|
||||
#endif
|
||||
pcsc_ops.wait_for_event = pcsc_wait_for_event;
|
||||
|
||||
return &pcsc_drv;
|
||||
}
|
||||
|
||||
#endif /* HAVE_PCSC */
|
||||
|
|
Loading…
Reference in New Issue