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:
nils 2005-01-24 11:31:11 +00:00
parent f66913ca30
commit 3158fa3e05
7 changed files with 221 additions and 8 deletions

View File

@ -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 \

View File

@ -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,

155
src/libopensc/pinpad-ccid.c Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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 */