- switched from libpcsc to libopensc. This brings some new features:
- Support for 4 slots per reader - abstraction of user interface - interactive pin verification - BCD encoding of PIN - Support for new readers (OpenCT) - automatically skip to a reader with a card - added defines - changed interface of ccid_initialize git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@23 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -9,7 +9,9 @@ bindir = $(exec_prefix)/bin
|
||||
# Compiler
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g
|
||||
LIBPCSCLITE_CFLAGS = `pkg-config --cflags --libs libpcsclite`
|
||||
#LIBPCSCLITE_CFLAGS = `pkg-config --cflags --libs libpcsclite`
|
||||
#OPENSSL_CFLAGS = `pkg-config --cflags --libs libssl`
|
||||
OPENSC_CFLAGS = `pkg-config --cflags --libs libopensc`
|
||||
PTHREAD_CFLAGS = -pthread
|
||||
|
||||
INSTALL = install
|
||||
@@ -23,7 +25,7 @@ all: $(TARGETS)
|
||||
|
||||
|
||||
ccid: ccid.h ccid.c usbstring.c usbstring.h usb.c
|
||||
$(CC) $(LIBPCSCLITE_CFLAGS) $(PTHREAD_CFLAGS) $(CFLAGS) usbstring.c ccid.c usb.c -o $@
|
||||
$(CC) $(LIBPCSCLITE_CFLAGS) $(OPENSC_CFLAGS) $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS) $(CFLAGS) usbstring.c ccid.c usb.c -o $@
|
||||
|
||||
|
||||
install: $(TARGETS) installdirs
|
||||
|
||||
1053
ccid/ccid.c
1053
ccid/ccid.c
File diff suppressed because it is too large
Load Diff
101
ccid/ccid.h
101
ccid/ccid.h
@@ -16,21 +16,69 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ccid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _VPCD_H_
|
||||
#define _VPCD_H_
|
||||
#ifndef _VPCD_H
|
||||
#define _VPCD_H
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <winscard.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef USB_REQ_CCID
|
||||
#define USB_REQ_CCID 0xA1
|
||||
|
||||
#define CCID_CONTROL_ABORT 0x01
|
||||
#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02
|
||||
#define CCID_CONTROL_GET_DATA_RATES 0x03
|
||||
|
||||
#define CCID_BERROR_CMD_ABORTED 0xff /* Host aborted the current activity */
|
||||
#define CCID_BERROR_ICC_MUTE 0xfe /* CCID timed out while talking to the ICC */
|
||||
#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /* Parity error while talking to the ICC */
|
||||
#define CCID_BERROR_XFR_OVERRUN 0xfc /* Overrun error while talking to the ICC */
|
||||
#define CCID_BERROR_HW_ERROR 0xfb /* An all inclusive hardware error occurred */
|
||||
#define CCID_BERROR_BAD_ATR_TS 0xf
|
||||
#define CCID_BERROR_BAD_ATR_TCK 0xf
|
||||
#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6
|
||||
#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5
|
||||
#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4
|
||||
#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3
|
||||
#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /* Automatic Sequence Ongoing */
|
||||
#define CCID_BERROR_PIN_TIMEOUT 0xf0
|
||||
#define CCID_BERROR_PIN_CANCELLED 0xef
|
||||
#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /* A second command was sent to a slot which was already processing a command. */
|
||||
#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00
|
||||
#define CCID_BERROR_OK 0x00
|
||||
|
||||
#define CCID_BSTATUS_OK_ACTIVE 0x00 /* No error. An ICC is present and active */
|
||||
#define CCID_BSTATUS_OK_INACTIVE 0x01 /* No error. ICC is present and inactive */
|
||||
#define CCID_BSTATUS_OK_NOICC 0x02 /* No error. No ICC is present */
|
||||
#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /* Failed. An ICC is present and active */
|
||||
#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /* Failed. ICC is present and inactive */
|
||||
#define CCID_BSTATUS_ERROR_NOICC 0x42 /* Failed. No ICC is present */
|
||||
|
||||
#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /* APDU begins and ends with this command */
|
||||
#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /* APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */
|
||||
#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /* abData field continues a command APDU and ends the APDU command */
|
||||
#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /* abData field continues a command APDU and another block is to follow */
|
||||
#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /* empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */
|
||||
|
||||
#define CCID_PIN_ENCODING_BIN 0x00
|
||||
#define CCID_PIN_ENCODING_BCD 0x01
|
||||
#define CCID_PIN_ENCODING_ASCII 0x02
|
||||
|
||||
#define CCID_PIN_UNITS_BYTES 0x80
|
||||
#define CCID_PIN_JUSTIFY_RIGHT 0x04
|
||||
|
||||
#define CCID_SLOTS_UNCHANGED 0x00
|
||||
#define CCID_SLOT1_CARD_PRESENT 0x01
|
||||
#define CCID_SLOT1_CHANGED 0x02
|
||||
#define CCID_SLOT2_CARD_PRESENT 0x04
|
||||
#define CCID_SLOT2_CHANGED 0x08
|
||||
#define CCID_SLOT3_CARD_PRESENT 0x10
|
||||
#define CCID_SLOT3_CHANGED 0x20
|
||||
#define CCID_SLOT4_CARD_PRESENT 0x40
|
||||
#define CCID_SLOT4_CHANGED 0x80
|
||||
|
||||
struct ccid_class_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
@@ -199,9 +247,8 @@ typedef struct {
|
||||
} __attribute__ ((packed)) RDR_to_PC_Parameters_t;
|
||||
typedef struct {
|
||||
__u8 bMessageType;
|
||||
__u8 bmSlotICCState;
|
||||
__u8 bmSlotICCState; /* we support 4 slots, so we need 2*4 bits = 1 byte */
|
||||
} __attribute__ ((packed)) RDR_to_PC_NotifySlotChange_t;
|
||||
#endif
|
||||
|
||||
struct hid_class_descriptor {
|
||||
__u8 bLength;
|
||||
@@ -211,47 +258,7 @@ struct hid_class_descriptor {
|
||||
__u8 bNumDescriptors;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
static struct ccid_class_descriptor
|
||||
ccid_desc = {
|
||||
.bLength = sizeof ccid_desc,
|
||||
.bDescriptorType = 0x21,
|
||||
.bcdCCID = __constant_cpu_to_le16(0x0110),
|
||||
.bMaxSlotIndex = 0,
|
||||
.bVoltageSupport = 0x01,
|
||||
.dwProtocols = __constant_cpu_to_le32(0x01| // T=0
|
||||
0x02), // T=1
|
||||
.dwDefaultClock = __constant_cpu_to_le32(0xDFC),
|
||||
.dwMaximumClock = __constant_cpu_to_le32(0xDFC),
|
||||
.bNumClockSupport = 1,
|
||||
.dwDataRate = __constant_cpu_to_le32(0x2580),
|
||||
.dwMaxDataRate = __constant_cpu_to_le32(0x2580),
|
||||
.bNumDataRatesSupported = 1,
|
||||
.dwMaxIFSD = __constant_cpu_to_le32(0xFF), // FIXME
|
||||
.dwSynchProtocols = __constant_cpu_to_le32(0),
|
||||
.dwMechanical = __constant_cpu_to_le32(0),
|
||||
.dwFeatures = __constant_cpu_to_le32(
|
||||
0x2| // Automatic parameter configuration based on ATR data
|
||||
0x8| // Automatic ICC voltage selection
|
||||
0x10| // Automatic ICC clock frequency change
|
||||
0x20| // Automatic baud rate change
|
||||
0x40| // Automatic parameters negotiation
|
||||
0x80| // Automatic PPS
|
||||
0x20000| // Short APDU level exchange
|
||||
0x100000),// USB Wake up signaling supported
|
||||
.dwMaxCCIDMessageLength = __constant_cpu_to_le32(261+10),
|
||||
.bClassGetResponse = 0xFF,
|
||||
.bclassEnvelope = 0xFF,
|
||||
.wLcdLayout = __constant_cpu_to_le16(
|
||||
//0),
|
||||
0xFF00| // Number of lines for the LCD display
|
||||
0x00FF), // Number of characters per line
|
||||
//.bPINSupport = 0,
|
||||
.bPINSupport = 0x1| // PIN Verification supported
|
||||
0x2, // PIN Modification supported
|
||||
.bMaxCCIDBusySlots = 0x01,
|
||||
};
|
||||
const char* ccid_initialize(int num);
|
||||
int ccid_initialize(int reader_id, int verbose);
|
||||
int ccid_shutdown();
|
||||
|
||||
int ccid_parse_bulkin(const __u8* inbuf, __u8** outbuf);
|
||||
|
||||
124
ccid/usb.c
124
ccid/usb.c
@@ -35,7 +35,11 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb/gadgetfs.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <opensc/ui.h>
|
||||
//#include <usb.h>
|
||||
//
|
||||
#include <getopt.h>
|
||||
|
||||
#ifdef AIO
|
||||
/* this aio code works with libaio-0.3.106 */
|
||||
@@ -50,13 +54,32 @@
|
||||
#define DRIVER_PRODUCT_NUM 0x3010 /* KOBIL Class 3 Reader */
|
||||
static int vendorid = DRIVER_VENDOR_NUM;
|
||||
static int productid = DRIVER_PRODUCT_NUM;
|
||||
static int verbose = 0;
|
||||
static int debug = 0;
|
||||
static int verbose = 1;
|
||||
static int debug = 1;
|
||||
static int dohid = 0;
|
||||
static int doint = 0;
|
||||
const char *usb_reader_name = NULL;
|
||||
int usb_reader_num = 0;
|
||||
|
||||
/*static const struct option options[] = {*/
|
||||
/*{ "hid", no_argument, &dohid, 1 },*/
|
||||
/*{ "interrupt", no_argument, &doint, 1 },*/
|
||||
/*{ "product", required_argument, NULL, 'p' },*/
|
||||
/*{ "reader", required_argument, NULL, 'r' },*/
|
||||
/*{ "serial", required_argument, NULL, 's' },*/
|
||||
/*{ "vendor", required_argument, NULL, 'v' },*/
|
||||
/*{ "verbose", no_argument, NULL, 'b' },*/
|
||||
/*{ NULL, 0, NULL, 0 }*/
|
||||
/*};*/
|
||||
/*static const char *option_help[] = {*/
|
||||
/*"Emulate HID device",*/
|
||||
/*"Uses reader number <arg> [auto-detect]",*/
|
||||
/*"Serial number of gadget [random]",*/
|
||||
/*"Add interrupt pipe for CCID",*/
|
||||
/*"Verbose operation. Use several times to enable debug output.",*/
|
||||
/*"USB vendor ID [0x0D46]",*/
|
||||
/*"USB product ID [0x3010]",*/
|
||||
/*};*/
|
||||
|
||||
/* NOTE: these IDs don't imply endpoint numbering; host side drivers
|
||||
* should use endpoint descriptors, or perhaps bcdDevice, to configure
|
||||
* such things. Other product IDs could have different policies.
|
||||
@@ -66,6 +89,8 @@ int usb_reader_num = 0;
|
||||
|
||||
/* these descriptors are modified based on what controller we find */
|
||||
|
||||
extern struct ccid_class_descriptor ccid_desc;
|
||||
|
||||
#define STRINGID_MFGR 1
|
||||
#define STRINGID_PRODUCT 2
|
||||
#define STRINGID_SERIAL 3
|
||||
@@ -899,9 +924,7 @@ ep_config (char *name, const char *label,
|
||||
|
||||
/* ccid thread, forwards ccid requests to pcsc and returns results */
|
||||
static void *ccid (void *param)
|
||||
{
|
||||
|
||||
//int tmp;
|
||||
{
|
||||
pthread_t interrupt_thread;
|
||||
|
||||
void *interrupt (void *param)
|
||||
@@ -958,11 +981,10 @@ static void *ccid (void *param)
|
||||
|
||||
void close_pcsc()
|
||||
{
|
||||
int result = ccid_shutdown();
|
||||
if (result != SCARD_S_SUCCESS)
|
||||
fprintf(stderr, "pc/sc error: %s\n", pcsc_stringify_error(result));
|
||||
if (!ccid_shutdown())
|
||||
fprintf(stderr, "pc/sc error\n");
|
||||
else if (verbose)
|
||||
fprintf(stderr, "closed connection to %s\n", usb_reader_name);
|
||||
fprintf(stderr, "closed connection\n");
|
||||
}
|
||||
|
||||
char **names = (char **) param;
|
||||
@@ -987,15 +1009,7 @@ static void *ccid (void *param)
|
||||
}
|
||||
pthread_cleanup_push (close_fd, &sink_fd);
|
||||
|
||||
usb_reader_name = ccid_initialize(usb_reader_num);
|
||||
if (usb_reader_name == NULL) {
|
||||
if (debug)
|
||||
perror("ccid_initialize");
|
||||
goto error;
|
||||
}
|
||||
pthread_cleanup_push (close_pcsc, NULL);
|
||||
if (verbose)
|
||||
fprintf (stderr, "connected to %s\n", usb_reader_name);
|
||||
|
||||
if (doint) {
|
||||
static char * interruptnames[1];
|
||||
@@ -1071,7 +1085,7 @@ error:
|
||||
|
||||
static void *hid (void *param)
|
||||
{
|
||||
|
||||
printf("%s:%d\n", __FILE__, __LINE__);
|
||||
char **names = (char **) param;
|
||||
char *status_name = names[0];
|
||||
int result = 0;
|
||||
@@ -1502,7 +1516,6 @@ special:
|
||||
|
||||
stall:
|
||||
if (verbose) {
|
||||
fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
|
||||
fprintf (stderr, "... protocol stall %02x.%02x\n",
|
||||
setup->bRequestType, setup->bRequest);
|
||||
for (tmp = 0; tmp<5; tmp++) {
|
||||
@@ -1678,11 +1691,53 @@ done:
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void util_print_usage_and_die(const char *app_name, const struct option options[],
|
||||
const char *option_help[])
|
||||
{
|
||||
int i = 0;
|
||||
printf("Usage: %s [OPTIONS]\nOptions:\n", app_name);
|
||||
|
||||
while (options[i].name) {
|
||||
char buf[40], tmp[5];
|
||||
const char *arg_str;
|
||||
|
||||
/* Skip "hidden" options */
|
||||
if (option_help[i] == NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options[i].val > 0 && options[i].val < 128)
|
||||
sprintf(tmp, ", -%c", options[i].val);
|
||||
else
|
||||
tmp[0] = 0;
|
||||
switch (options[i].has_arg) {
|
||||
case 1:
|
||||
arg_str = " <arg>";
|
||||
break;
|
||||
case 2:
|
||||
arg_str = " [arg]";
|
||||
break;
|
||||
default:
|
||||
arg_str = "";
|
||||
break;
|
||||
}
|
||||
sprintf(buf, "--%s%s%s", options[i].name, tmp, arg_str);
|
||||
if (strlen(buf) > 29) {
|
||||
printf(" %s\n", buf);
|
||||
buf[0] = '\0';
|
||||
}
|
||||
printf(" %-29s %s\n", buf, option_help[i]);
|
||||
i++;
|
||||
}
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int fd, c, i;
|
||||
/*int long_optind = 0;*/
|
||||
|
||||
/* random initial serial number */
|
||||
srand ((int) time (0));
|
||||
@@ -1721,8 +1776,9 @@ main (int argc, char **argv)
|
||||
(strcmp(argv[i], "-d") == 0)) {
|
||||
verbose++;
|
||||
if ((strcmp(argv[i], "--debug") == 0) ||
|
||||
(strcmp(argv[i], "-d") == 0))
|
||||
(strcmp(argv[i], "-d") == 0)) {
|
||||
debug++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp(argv[i], "--hid") == 0) {
|
||||
@@ -1768,6 +1824,27 @@ main (int argc, char **argv)
|
||||
fprintf(stderr, "unrecognized option \"%s\"\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
/*while (1) {*/
|
||||
/*c = getopt_long(argc, argv, "p:r:s:v:b", options, &long_optind);*/
|
||||
/*if (c == -1)*/
|
||||
/*break;*/
|
||||
/*if (c == '?')*/
|
||||
/*util_print_usage_and_die("ccid" , options, option_help);*/
|
||||
/*switch (c) {*/
|
||||
/*case 'r':*/
|
||||
/*opt_reader = atoi(optarg);*/
|
||||
/*break;*/
|
||||
/*case 'c':*/
|
||||
/*opt_driver = optarg;*/
|
||||
/*break;*/
|
||||
/*case 'w':*/
|
||||
/*opt_wait = 1;*/
|
||||
/*break;*/
|
||||
/*case 'v':*/
|
||||
/*verbose++;*/
|
||||
/*break;*/
|
||||
/*}*/
|
||||
/*}*/
|
||||
|
||||
if (verbose)
|
||||
fprintf (stderr, "serial=\"%s\"\n", serial);
|
||||
@@ -1777,6 +1854,11 @@ main (int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ccid_initialize(usb_reader_num, verbose)) {
|
||||
perror("can't initialize ccid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd = init_device ();
|
||||
if (fd < 0)
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user