mirror of
git://git.gnupg.org/gnupg.git
synced 2025-06-20 20:47:58 +02:00
Add support fro CardMan 4040
This commit is contained in:
parent
23cfe019e9
commit
4f34366389
@ -1,3 +1,17 @@
|
|||||||
|
2006-02-06 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9. Changes:
|
||||||
|
* ccid-driver.h (CCID_DRIVER_ERR_NO_KEYPAD): New.
|
||||||
|
* ccid-driver.c (send_escape_cmd): New args RESULT, RESULTLEN and
|
||||||
|
RESULTMAX. Changed all callers.
|
||||||
|
(ccid_transceive_escape): New.
|
||||||
|
* ccid-driver.c (special_transport): New
|
||||||
|
(ccid_open_reader, do_close_reader, ccid_shutdown_reader)
|
||||||
|
(bulk_out, bulk_in): Add support for CardMan 4040 reader.
|
||||||
|
* ccid-driver.c (scan_or_find_devices): Factored most code out to
|
||||||
|
(scan_or_find_usb_device): .. new.
|
||||||
|
(make_reader_id): Fixed vendor mask.
|
||||||
|
|
||||||
2006-01-24 David Shaw <dshaw@jabberwocky.com>
|
2006-01-24 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* keyserver.c (parse_keyserver_uri): If there is a path present,
|
* keyserver.c (parse_keyserver_uri): If there is a path present,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
|
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
|
||||||
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
* Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||||
* Written by Werner Koch.
|
* Written by Werner Koch.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
@ -67,8 +67,8 @@
|
|||||||
portable access to USB.
|
portable access to USB.
|
||||||
|
|
||||||
This driver has been tested with the SCM SCR335 and SPR532
|
This driver has been tested with the SCM SCR335 and SPR532
|
||||||
smartcard readers and requires that a reader implements the TPDU
|
smartcard readers and requires that a reader implements APDU or
|
||||||
level exchange and does fully automatic initialization.
|
TPDU level exchange and does fully automatic initialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@ -82,6 +82,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
|
||||||
@ -194,11 +197,29 @@ enum {
|
|||||||
|
|
||||||
/* We need to know the vendor to do some hacks. */
|
/* We need to know the vendor to do some hacks. */
|
||||||
enum {
|
enum {
|
||||||
VENDOR_SCM = 0x04e6,
|
|
||||||
VENDOR_CHERRY = 0x046a,
|
VENDOR_CHERRY = 0x046a,
|
||||||
|
VENDOR_SCM = 0x04e6,
|
||||||
|
VENDOR_OMNIKEY= 0x076b,
|
||||||
VENDOR_GEMPC = 0x08e6
|
VENDOR_GEMPC = 0x08e6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A list and a table with special transport descriptions. */
|
||||||
|
enum {
|
||||||
|
TRANSPORT_USB = 0, /* Standard USB transport. */
|
||||||
|
TRANSPORT_CM4040 = 1 /* As used by the Cardman 4040. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
char *name; /* Device name. */
|
||||||
|
int type;
|
||||||
|
|
||||||
|
} transports[] = {
|
||||||
|
{ "/dev/cmx0", TRANSPORT_CM4040 },
|
||||||
|
{ "/dev/cmx1", TRANSPORT_CM4040 },
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Store information on the driver's state. A pointer to such a
|
/* Store information on the driver's state. A pointer to such a
|
||||||
structure is used as handle for most functions. */
|
structure is used as handle for most functions. */
|
||||||
@ -206,6 +227,8 @@ struct ccid_driver_s
|
|||||||
{
|
{
|
||||||
usb_dev_handle *idev;
|
usb_dev_handle *idev;
|
||||||
char *rid;
|
char *rid;
|
||||||
|
int dev_fd; /* -1 for USB transport or file descriptor of the
|
||||||
|
transport device. */
|
||||||
unsigned short id_vendor;
|
unsigned short id_vendor;
|
||||||
unsigned short id_product;
|
unsigned short id_product;
|
||||||
unsigned short bcd_device;
|
unsigned short bcd_device;
|
||||||
@ -306,7 +329,34 @@ print_command_failed (const unsigned char *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a handle used for special transport prepare it for use. In
|
||||||
|
particular setup all information in way that resembles what
|
||||||
|
parse_cccid_descriptor does. */
|
||||||
|
static void
|
||||||
|
prepare_special_transport (ccid_driver_t handle)
|
||||||
|
{
|
||||||
|
assert (!handle->id_vendor);
|
||||||
|
|
||||||
|
handle->nonnull_nad = 0;
|
||||||
|
handle->auto_ifsd = 0;
|
||||||
|
handle->max_ifsd = 32;
|
||||||
|
handle->ifsd = 0;
|
||||||
|
handle->has_pinpad = 0;
|
||||||
|
handle->apdu_level = 0;
|
||||||
|
switch (handle->id_product)
|
||||||
|
{
|
||||||
|
case TRANSPORT_CM4040:
|
||||||
|
DEBUGOUT ("setting up transport for CardMan 4040\n");
|
||||||
|
/* Most values are guessed. */
|
||||||
|
handle->nonnull_nad = 1;
|
||||||
|
handle->auto_ifsd = 1;
|
||||||
|
handle->max_ifsd = 254;
|
||||||
|
handle->apdu_level = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: assert (!"transport not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse a CCID descriptor, optionally print all available features
|
/* Parse a CCID descriptor, optionally print all available features
|
||||||
and test whether this reader is usable by this driver. Returns 0
|
and test whether this reader is usable by this driver. Returns 0
|
||||||
@ -615,7 +665,7 @@ make_reader_id (usb_dev_handle *idev,
|
|||||||
char *rid;
|
char *rid;
|
||||||
char prefix[20];
|
char prefix[20];
|
||||||
|
|
||||||
sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff));
|
sprintf (prefix, "%04X:%04X:", (vendor & 0xffff), (product & 0xffff));
|
||||||
rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
|
rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
|
||||||
if (!rid)
|
if (!rid)
|
||||||
{
|
{
|
||||||
@ -658,10 +708,177 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for scan_or_find_devices. This function returns true if a
|
||||||
|
requested device has been found or the caller should stop scanning
|
||||||
|
for other reasons. */
|
||||||
|
static int
|
||||||
|
scan_or_find_usb_device (int scan_mode,
|
||||||
|
int *readerno, int *count, char **rid_list,
|
||||||
|
const char *readerid,
|
||||||
|
struct usb_device *dev,
|
||||||
|
char **r_rid,
|
||||||
|
struct usb_device **r_dev,
|
||||||
|
usb_dev_handle **r_idev,
|
||||||
|
unsigned char **ifcdesc_extra,
|
||||||
|
size_t *ifcdesc_extra_len,
|
||||||
|
int *interface_number,
|
||||||
|
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
|
||||||
|
{
|
||||||
|
int cfg_no;
|
||||||
|
int ifc_no;
|
||||||
|
int set_no;
|
||||||
|
struct usb_config_descriptor *config;
|
||||||
|
struct usb_interface *interface;
|
||||||
|
struct usb_interface_descriptor *ifcdesc;
|
||||||
|
char *rid;
|
||||||
|
usb_dev_handle *idev;
|
||||||
|
|
||||||
|
*r_idev = NULL;
|
||||||
|
|
||||||
|
for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
|
||||||
|
{
|
||||||
|
config = dev->config + cfg_no;
|
||||||
|
if(!config)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
|
||||||
|
{
|
||||||
|
interface = config->interface + ifc_no;
|
||||||
|
if (!interface)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (set_no=0; set_no < interface->num_altsetting; set_no++)
|
||||||
|
{
|
||||||
|
ifcdesc = (interface->altsetting + set_no);
|
||||||
|
/* The second condition is for older SCM SPR 532 who did
|
||||||
|
not know about the assigned CCID class. Instead of
|
||||||
|
trying to interpret the strings we simply check the
|
||||||
|
product ID. */
|
||||||
|
if (ifcdesc && ifcdesc->extra
|
||||||
|
&& ((ifcdesc->bInterfaceClass == 11
|
||||||
|
&& ifcdesc->bInterfaceSubClass == 0
|
||||||
|
&& ifcdesc->bInterfaceProtocol == 0)
|
||||||
|
|| (ifcdesc->bInterfaceClass == 255
|
||||||
|
&& dev->descriptor.idVendor == VENDOR_SCM
|
||||||
|
&& dev->descriptor.idProduct == 0xe003)))
|
||||||
|
{
|
||||||
|
idev = usb_open (dev);
|
||||||
|
if (!idev)
|
||||||
|
{
|
||||||
|
DEBUGOUT_1 ("usb_open failed: %s\n",
|
||||||
|
strerror (errno));
|
||||||
|
continue; /* with next setting. */
|
||||||
|
}
|
||||||
|
|
||||||
|
rid = make_reader_id (idev,
|
||||||
|
dev->descriptor.idVendor,
|
||||||
|
dev->descriptor.idProduct,
|
||||||
|
dev->descriptor.iSerialNumber);
|
||||||
|
if (rid)
|
||||||
|
{
|
||||||
|
if (scan_mode)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* We are collecting infos about all
|
||||||
|
available CCID readers. Store them and
|
||||||
|
continue. */
|
||||||
|
DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n",
|
||||||
|
*count, rid );
|
||||||
|
p = malloc ((*rid_list? strlen (*rid_list):0) + 1
|
||||||
|
+ strlen (rid) + 1);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
if (*rid_list)
|
||||||
|
{
|
||||||
|
strcat (p, *rid_list);
|
||||||
|
free (*rid_list);
|
||||||
|
}
|
||||||
|
strcat (p, rid);
|
||||||
|
strcat (p, "\n");
|
||||||
|
*rid_list = p;
|
||||||
|
}
|
||||||
|
else /* Out of memory. */
|
||||||
|
free (rid);
|
||||||
|
|
||||||
|
rid = NULL;
|
||||||
|
++*count;
|
||||||
|
}
|
||||||
|
else if (!*readerno
|
||||||
|
|| (*readerno < 0
|
||||||
|
&& readerid
|
||||||
|
&& !strcmp (readerid, rid)))
|
||||||
|
{
|
||||||
|
/* We found the requested reader. */
|
||||||
|
if (ifcdesc_extra && ifcdesc_extra_len)
|
||||||
|
{
|
||||||
|
*ifcdesc_extra = malloc (ifcdesc
|
||||||
|
->extralen);
|
||||||
|
if (!*ifcdesc_extra)
|
||||||
|
{
|
||||||
|
usb_close (idev);
|
||||||
|
free (rid);
|
||||||
|
return 1; /* Out of core. */
|
||||||
|
}
|
||||||
|
memcpy (*ifcdesc_extra, ifcdesc->extra,
|
||||||
|
ifcdesc->extralen);
|
||||||
|
*ifcdesc_extra_len = ifcdesc->extralen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface_number)
|
||||||
|
*interface_number = (ifcdesc->bInterfaceNumber);
|
||||||
|
|
||||||
|
if (ep_bulk_out)
|
||||||
|
*ep_bulk_out = find_endpoint (ifcdesc, 0);
|
||||||
|
if (ep_bulk_in)
|
||||||
|
*ep_bulk_in = find_endpoint (ifcdesc, 1);
|
||||||
|
if (ep_intr)
|
||||||
|
*ep_intr = find_endpoint (ifcdesc, 2);
|
||||||
|
|
||||||
|
if (r_dev)
|
||||||
|
*r_dev = dev;
|
||||||
|
if (r_rid)
|
||||||
|
{
|
||||||
|
*r_rid = rid;
|
||||||
|
rid = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
free (rid);
|
||||||
|
|
||||||
|
*r_idev = idev;
|
||||||
|
return 1; /* Found requested device. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is not yet the reader we want.
|
||||||
|
fixme: We should avoid the extra usb_open
|
||||||
|
in this case. */
|
||||||
|
if (*readerno >= 0)
|
||||||
|
--*readerno;
|
||||||
|
}
|
||||||
|
free (rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_close (idev);
|
||||||
|
idev = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Combination function to either scan all CCID devices or to find and
|
/* Combination function to either scan all CCID devices or to find and
|
||||||
open one specific device.
|
open one specific device.
|
||||||
|
|
||||||
|
The function returns 0 if a reader has been found or when a scan
|
||||||
|
returned without error.
|
||||||
|
|
||||||
|
FIXME!!
|
||||||
|
|
||||||
With READERNO = -1 and READERID is NULL, scan mode is used and
|
With READERNO = -1 and READERID is NULL, scan mode is used and
|
||||||
R_RID should be the address where to store the list of reader_ids
|
R_RID should be the address where to store the list of reader_ids
|
||||||
we found. If on return this list is empty, no CCID device has been
|
we found. If on return this list is empty, no CCID device has been
|
||||||
@ -671,11 +888,11 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
With READERNO >= 0 or READERID is not NULL find mode is used. This
|
With READERNO >= 0 or READERID is not NULL find mode is used. This
|
||||||
uses the same algorithm as the scan mode but stops and returns at
|
uses the same algorithm as the scan mode but stops and returns at
|
||||||
the entry number READERNO and return the handle for the the opened
|
the entry number READERNO and return the handle for the the opened
|
||||||
USB device. If R_ID is not NULL it will receive the reader ID of
|
USB device. If R_RID is not NULL it will receive the reader ID of
|
||||||
that device. If R_DEV is not NULL it will the device pointer of
|
that device. If R_DEV is not NULL it will the device pointer of
|
||||||
that device. If IFCDESC_EXTRA is NOT NULL it will receive a
|
that device. If IFCDESC_EXTRA is NOT NULL it will receive a
|
||||||
malloced copy of the interfaces "extra: data filed;
|
malloced copy of the interfaces "extra: data filed;
|
||||||
IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is
|
IFCDESC_EXTRA_LEN receive the length of this field. If there is
|
||||||
no reader with number READERNO or that reader is not usable by our
|
no reader with number READERNO or that reader is not usable by our
|
||||||
implementation NULL will be returned. The caller must close a
|
implementation NULL will be returned. The caller must close a
|
||||||
returned USB device handle and free (if not passed as NULL) the
|
returned USB device handle and free (if not passed as NULL) the
|
||||||
@ -684,17 +901,25 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if
|
IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if
|
||||||
the READERID was found.
|
the READERID was found.
|
||||||
|
|
||||||
|
If R_FD is not -1 on return the device is not using USB for
|
||||||
|
transport but the device associated with that file descriptor. In
|
||||||
|
this case INTERFACE will receive the transport type and the other
|
||||||
|
USB specific return values are not used; the return value is
|
||||||
|
(void*)(1).
|
||||||
|
|
||||||
Note that the first entry of the returned reader ID list in scan mode
|
Note that the first entry of the returned reader ID list in scan mode
|
||||||
corresponds with a READERNO of 0 in find mode.
|
corresponds with a READERNO of 0 in find mode.
|
||||||
*/
|
*/
|
||||||
static usb_dev_handle *
|
static int
|
||||||
scan_or_find_devices (int readerno, const char *readerid,
|
scan_or_find_devices (int readerno, const char *readerid,
|
||||||
char **r_rid,
|
char **r_rid,
|
||||||
struct usb_device **r_dev,
|
struct usb_device **r_dev,
|
||||||
unsigned char **ifcdesc_extra,
|
unsigned char **ifcdesc_extra,
|
||||||
size_t *ifcdesc_extra_len,
|
size_t *ifcdesc_extra_len,
|
||||||
int *interface_number,
|
int *interface_number,
|
||||||
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
|
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr,
|
||||||
|
usb_dev_handle **r_idev,
|
||||||
|
int *r_fd)
|
||||||
{
|
{
|
||||||
char *rid_list = NULL;
|
char *rid_list = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@ -702,6 +927,7 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
struct usb_device *dev = NULL;
|
struct usb_device *dev = NULL;
|
||||||
usb_dev_handle *idev = NULL;
|
usb_dev_handle *idev = NULL;
|
||||||
int scan_mode = (readerno == -1 && !readerid);
|
int scan_mode = (readerno == -1 && !readerid);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Set return values to a default. */
|
/* Set return values to a default. */
|
||||||
if (r_rid)
|
if (r_rid)
|
||||||
@ -714,6 +940,10 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
*ifcdesc_extra_len = 0;
|
*ifcdesc_extra_len = 0;
|
||||||
if (interface_number)
|
if (interface_number)
|
||||||
*interface_number = 0;
|
*interface_number = 0;
|
||||||
|
if (r_idev)
|
||||||
|
*r_idev = NULL;
|
||||||
|
if (r_fd)
|
||||||
|
*r_fd = -1;
|
||||||
|
|
||||||
/* See whether we want scan or find mode. */
|
/* See whether we want scan or find mode. */
|
||||||
if (scan_mode)
|
if (scan_mode)
|
||||||
@ -734,73 +964,58 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
{
|
{
|
||||||
for (dev = bus->devices; dev; dev = dev->next)
|
for (dev = bus->devices; dev; dev = dev->next)
|
||||||
{
|
{
|
||||||
int cfg_no;
|
if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
|
||||||
|
readerid,
|
||||||
for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
|
dev,
|
||||||
|
r_rid,
|
||||||
|
r_dev,
|
||||||
|
&idev,
|
||||||
|
ifcdesc_extra,
|
||||||
|
ifcdesc_extra_len,
|
||||||
|
interface_number,
|
||||||
|
ep_bulk_out, ep_bulk_in, ep_intr))
|
||||||
{
|
{
|
||||||
struct usb_config_descriptor *config = dev->config + cfg_no;
|
/* Found requested device or out of core. */
|
||||||
int ifc_no;
|
|
||||||
|
|
||||||
if(!config)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
|
|
||||||
{
|
|
||||||
struct usb_interface *interface
|
|
||||||
= config->interface + ifc_no;
|
|
||||||
int set_no;
|
|
||||||
|
|
||||||
if (!interface)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (set_no=0; set_no < interface->num_altsetting; set_no++)
|
|
||||||
{
|
|
||||||
struct usb_interface_descriptor *ifcdesc
|
|
||||||
= interface->altsetting + set_no;
|
|
||||||
char *rid;
|
|
||||||
|
|
||||||
/* The second condition is for some SCM Micro
|
|
||||||
SPR 532 which does not know about the
|
|
||||||
assigned CCID class. Instead of trying to
|
|
||||||
interpret the strings we simply look at the
|
|
||||||
product ID. */
|
|
||||||
if (ifcdesc && ifcdesc->extra
|
|
||||||
&& ( (ifcdesc->bInterfaceClass == 11
|
|
||||||
&& ifcdesc->bInterfaceSubClass == 0
|
|
||||||
&& ifcdesc->bInterfaceProtocol == 0)
|
|
||||||
|| (ifcdesc->bInterfaceClass == 255
|
|
||||||
&& dev->descriptor.idVendor == 0x04e6
|
|
||||||
&& dev->descriptor.idProduct == 0xe003)))
|
|
||||||
{
|
|
||||||
idev = usb_open (dev);
|
|
||||||
if (!idev)
|
if (!idev)
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("usb_open failed: %s\n",
|
free (rid_list);
|
||||||
strerror (errno));
|
return -1; /* error */
|
||||||
continue;
|
}
|
||||||
|
*r_idev = idev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rid = make_reader_id (idev,
|
/* Now check whether there are any devices with special transport types. */
|
||||||
dev->descriptor.idVendor,
|
for (i=0; transports[i].name; i++)
|
||||||
dev->descriptor.idProduct,
|
|
||||||
dev->descriptor.iSerialNumber);
|
|
||||||
if (rid)
|
|
||||||
{
|
{
|
||||||
|
int fd;
|
||||||
|
char *rid, *p;
|
||||||
|
|
||||||
|
fd = open (transports[i].name, O_RDWR);
|
||||||
|
if (fd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rid = malloc (strlen (transports[i].name) + 30 + 10);
|
||||||
|
if (!rid)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
free (rid_list);
|
||||||
|
return -1; /* Error. */
|
||||||
|
}
|
||||||
|
sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name);
|
||||||
if (scan_mode)
|
if (scan_mode)
|
||||||
{
|
{
|
||||||
char *p;
|
DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", count, rid);
|
||||||
|
p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1);
|
||||||
/* We are collecting infos about all
|
if (!p)
|
||||||
available CCID readers. Store
|
|
||||||
them and continue. */
|
|
||||||
DEBUGOUT_2 ("found CCID reader %d "
|
|
||||||
"(ID=%s)\n",
|
|
||||||
count, rid );
|
|
||||||
if ((p = malloc ((rid_list?
|
|
||||||
strlen (rid_list):0)
|
|
||||||
+ 1 + strlen (rid)
|
|
||||||
+ 1)))
|
|
||||||
{
|
{
|
||||||
|
close (fd);
|
||||||
|
free (rid_list);
|
||||||
|
free (rid);
|
||||||
|
return -1; /* Error. */
|
||||||
|
}
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if (rid_list)
|
if (rid_list)
|
||||||
{
|
{
|
||||||
@ -810,85 +1025,41 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
strcat (p, rid);
|
strcat (p, rid);
|
||||||
strcat (p, "\n");
|
strcat (p, "\n");
|
||||||
rid_list = p;
|
rid_list = p;
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
else /* Out of memory. */
|
else if (!readerno ||
|
||||||
free (rid);
|
(readerno < 0 && readerid && !strcmp (readerid, rid)))
|
||||||
rid = NULL;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
else if (!readerno
|
|
||||||
|| (readerno < 0
|
|
||||||
&& readerid
|
|
||||||
&& !strcmp (readerid, rid)))
|
|
||||||
{
|
{
|
||||||
/* We found the requested reader. */
|
/* Found requested device. */
|
||||||
if (ifcdesc_extra && ifcdesc_extra_len)
|
|
||||||
{
|
|
||||||
*ifcdesc_extra = malloc (ifcdesc
|
|
||||||
->extralen);
|
|
||||||
if (!*ifcdesc_extra)
|
|
||||||
{
|
|
||||||
usb_close (idev);
|
|
||||||
free (rid);
|
|
||||||
return NULL; /* Out of core. */
|
|
||||||
}
|
|
||||||
memcpy (*ifcdesc_extra, ifcdesc->extra,
|
|
||||||
ifcdesc->extralen);
|
|
||||||
*ifcdesc_extra_len = ifcdesc->extralen;
|
|
||||||
}
|
|
||||||
if (interface_number)
|
if (interface_number)
|
||||||
*interface_number = (ifcdesc->
|
*interface_number = transports[i].type;
|
||||||
bInterfaceNumber);
|
|
||||||
if (ep_bulk_out)
|
|
||||||
*ep_bulk_out = find_endpoint (ifcdesc, 0);
|
|
||||||
if (ep_bulk_in)
|
|
||||||
*ep_bulk_in = find_endpoint (ifcdesc, 1);
|
|
||||||
if (ep_intr)
|
|
||||||
*ep_intr = find_endpoint (ifcdesc, 2);
|
|
||||||
|
|
||||||
|
|
||||||
if (r_dev)
|
|
||||||
*r_dev = dev;
|
|
||||||
if (r_rid)
|
if (r_rid)
|
||||||
{
|
|
||||||
*r_rid = rid;
|
*r_rid = rid;
|
||||||
rid = NULL;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
free (rid);
|
free (rid);
|
||||||
return idev; /* READY. */
|
*r_fd = fd;
|
||||||
|
return 0; /* Okay, found device */
|
||||||
}
|
}
|
||||||
else
|
else /* This is not yet the reader we want. */
|
||||||
{
|
{
|
||||||
/* This is not yet the reader we
|
|
||||||
want. fixme: We could avoid the
|
|
||||||
extra usb_open in this case. */
|
|
||||||
if (readerno >= 0)
|
if (readerno >= 0)
|
||||||
readerno--;
|
--readerno;
|
||||||
}
|
}
|
||||||
free (rid);
|
free (rid);
|
||||||
}
|
close (fd);
|
||||||
|
|
||||||
usb_close (idev);
|
|
||||||
idev = NULL;
|
|
||||||
goto next_device;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_device:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scan_mode)
|
if (scan_mode)
|
||||||
|
{
|
||||||
*r_rid = rid_list;
|
*r_rid = rid_list;
|
||||||
|
return 0;
|
||||||
return NULL;
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set the level of debugging to to usea dn return the old level. -1
|
/* Set the level of debugging to LEVEL and return the old level. -1
|
||||||
just returns the old level. A level of 0 disables debugging, 1
|
just returns the old level. A level of 0 disables debugging, 1
|
||||||
enables debugging, 2 enables additional tracing of the T=1
|
enables debugging, 2 enables additional tracing of the T=1
|
||||||
protocol, other values are not yet defined. */
|
protocol, other values are not yet defined. */
|
||||||
@ -913,8 +1084,9 @@ ccid_get_reader_list (void)
|
|||||||
initialized_usb = 1;
|
initialized_usb = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL))
|
||||||
|
return NULL; /* Error. */
|
||||||
return reader_list;
|
return reader_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -927,6 +1099,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct usb_device *dev = NULL;
|
struct usb_device *dev = NULL;
|
||||||
usb_dev_handle *idev = NULL;
|
usb_dev_handle *idev = NULL;
|
||||||
|
int dev_fd = -1;
|
||||||
char *rid = NULL;
|
char *rid = NULL;
|
||||||
unsigned char *ifcdesc_extra = NULL;
|
unsigned char *ifcdesc_extra = NULL;
|
||||||
size_t ifcdesc_extra_len;
|
size_t ifcdesc_extra_len;
|
||||||
@ -959,10 +1132,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
else
|
else
|
||||||
readerno = 0; /* Default. */
|
readerno = 0; /* Default. */
|
||||||
|
|
||||||
idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
|
if (scan_or_find_devices (readerno, readerid, &rid, &dev,
|
||||||
&ifcdesc_extra, &ifcdesc_extra_len,
|
&ifcdesc_extra, &ifcdesc_extra_len,
|
||||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||||
if (!idev)
|
&idev, &dev_fd) )
|
||||||
{
|
{
|
||||||
if (readerno == -1)
|
if (readerno == -1)
|
||||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
|
DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
|
||||||
@ -980,8 +1153,11 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
|
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
(*handle)->idev = idev;
|
|
||||||
(*handle)->rid = rid;
|
(*handle)->rid = rid;
|
||||||
|
if (idev) /* Regular USB transport. */
|
||||||
|
{
|
||||||
|
(*handle)->idev = idev;
|
||||||
|
(*handle)->dev_fd = -1;
|
||||||
(*handle)->id_vendor = dev->descriptor.idVendor;
|
(*handle)->id_vendor = dev->descriptor.idVendor;
|
||||||
(*handle)->id_product = dev->descriptor.idProduct;
|
(*handle)->id_product = dev->descriptor.idProduct;
|
||||||
(*handle)->bcd_device = dev->descriptor.bcdDevice;
|
(*handle)->bcd_device = dev->descriptor.bcdDevice;
|
||||||
@ -989,10 +1165,24 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
(*handle)->ep_bulk_out = ep_bulk_out;
|
(*handle)->ep_bulk_out = ep_bulk_out;
|
||||||
(*handle)->ep_bulk_in = ep_bulk_in;
|
(*handle)->ep_bulk_in = ep_bulk_in;
|
||||||
(*handle)->ep_intr = ep_intr;
|
(*handle)->ep_intr = ep_intr;
|
||||||
|
}
|
||||||
|
else if (dev_fd != -1) /* Device transport. */
|
||||||
|
{
|
||||||
|
(*handle)->idev = NULL;
|
||||||
|
(*handle)->dev_fd = dev_fd;
|
||||||
|
(*handle)->id_vendor = 0; /* Magic vendor for special transport. */
|
||||||
|
(*handle)->id_product = ifc_no; /* Transport type */
|
||||||
|
prepare_special_transport (*handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert (!"no transport"); /* Bug. */
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
|
DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
|
||||||
|
|
||||||
|
if (idev)
|
||||||
|
{
|
||||||
if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
|
if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
|
||||||
{
|
{
|
||||||
DEBUGOUT ("device not supported\n");
|
DEBUGOUT ("device not supported\n");
|
||||||
@ -1007,6 +1197,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
free (ifcdesc_extra);
|
free (ifcdesc_extra);
|
||||||
@ -1015,6 +1206,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
free (rid);
|
free (rid);
|
||||||
if (idev)
|
if (idev)
|
||||||
usb_close (idev);
|
usb_close (idev);
|
||||||
|
if (dev_fd != -1)
|
||||||
|
close (dev_fd);
|
||||||
free (*handle);
|
free (*handle);
|
||||||
*handle = NULL;
|
*handle = NULL;
|
||||||
}
|
}
|
||||||
@ -1054,6 +1247,11 @@ do_close_reader (ccid_driver_t handle)
|
|||||||
usb_close (handle->idev);
|
usb_close (handle->idev);
|
||||||
handle->idev = NULL;
|
handle->idev = NULL;
|
||||||
}
|
}
|
||||||
|
if (handle->dev_fd != -1)
|
||||||
|
{
|
||||||
|
close (handle->dev_fd);
|
||||||
|
handle->dev_fd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1080,16 +1278,17 @@ ccid_shutdown_reader (ccid_driver_t handle)
|
|||||||
|
|
||||||
do_close_reader (handle);
|
do_close_reader (handle);
|
||||||
|
|
||||||
idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
|
if (scan_or_find_devices (-1, handle->rid, NULL, &dev,
|
||||||
&ifcdesc_extra, &ifcdesc_extra_len,
|
&ifcdesc_extra, &ifcdesc_extra_len,
|
||||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||||
if (!idev)
|
&idev, NULL) || !idev)
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
|
DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
|
||||||
return CCID_DRIVER_ERR_NO_READER;
|
return CCID_DRIVER_ERR_NO_READER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (idev)
|
||||||
|
{
|
||||||
handle->idev = idev;
|
handle->idev = idev;
|
||||||
handle->ifc_no = ifc_no;
|
handle->ifc_no = ifc_no;
|
||||||
handle->ep_bulk_out = ep_bulk_out;
|
handle->ep_bulk_out = ep_bulk_out;
|
||||||
@ -1110,13 +1309,18 @@ ccid_shutdown_reader (ccid_driver_t handle)
|
|||||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
free (ifcdesc_extra);
|
free (ifcdesc_extra);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
if (handle->idev)
|
||||||
usb_close (handle->idev);
|
usb_close (handle->idev);
|
||||||
handle->idev = NULL;
|
handle->idev = NULL;
|
||||||
|
if (handle->dev_fd != -1)
|
||||||
|
close (handle->dev_fd);
|
||||||
|
handle->dev_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -1147,6 +1351,31 @@ ccid_check_card_presence (ccid_driver_t handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write NBYTES of BUF to file descriptor FD. */
|
||||||
|
static int
|
||||||
|
writen (int fd, const void *buf, size_t nbytes)
|
||||||
|
{
|
||||||
|
size_t nleft = nbytes;
|
||||||
|
int nwritten;
|
||||||
|
|
||||||
|
while (nleft > 0)
|
||||||
|
{
|
||||||
|
nwritten = write (fd, buf, nleft);
|
||||||
|
if (nwritten < 0)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
nwritten = 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nleft -= nwritten;
|
||||||
|
buf = (const char*)buf + nwritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
||||||
Returns 0 on success. */
|
Returns 0 on success. */
|
||||||
static int
|
static int
|
||||||
@ -1154,17 +1383,28 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (handle->idev)
|
||||||
|
{
|
||||||
rc = usb_bulk_write (handle->idev,
|
rc = usb_bulk_write (handle->idev,
|
||||||
handle->ep_bulk_out,
|
handle->ep_bulk_out,
|
||||||
(char*)msg, msglen,
|
(char*)msg, msglen,
|
||||||
1000 /* ms timeout */);
|
1000 /* ms timeout */);
|
||||||
if (rc == msglen)
|
if (rc == msglen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (rc == -1)
|
if (rc == -1)
|
||||||
DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
|
DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
|
||||||
else
|
else
|
||||||
DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
|
DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = writen (handle->dev_fd, msg, msglen);
|
||||||
|
if (!rc)
|
||||||
|
return 0;
|
||||||
|
DEBUGOUT_2 ("writen to %d failed: %s\n",
|
||||||
|
handle->dev_fd, strerror (errno));
|
||||||
|
|
||||||
|
}
|
||||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,6 +1427,8 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
for USB IOCTLs. */
|
for USB IOCTLs. */
|
||||||
memset (buffer, 0, length);
|
memset (buffer, 0, length);
|
||||||
retry:
|
retry:
|
||||||
|
if (handle->idev)
|
||||||
|
{
|
||||||
rc = usb_bulk_read (handle->idev,
|
rc = usb_bulk_read (handle->idev,
|
||||||
handle->ep_bulk_in,
|
handle->ep_bulk_in,
|
||||||
(char*)buffer, length,
|
(char*)buffer, length,
|
||||||
@ -1196,8 +1438,20 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
||||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
*nread = msglen = rc;
|
*nread = msglen = rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = read (handle->dev_fd, buffer, length);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
DEBUGOUT_2 ("read from %d failed: %s\n",
|
||||||
|
handle->dev_fd, strerror (errno));
|
||||||
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
*nread = msglen = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (msglen < 10)
|
if (msglen < 10)
|
||||||
{
|
{
|
||||||
@ -1240,7 +1494,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
if (CCID_COMMAND_FAILED (buffer))
|
if (CCID_COMMAND_FAILED (buffer))
|
||||||
print_command_failed (buffer);
|
print_command_failed (buffer);
|
||||||
|
|
||||||
/* Check whether a card is at all available. */
|
/* Check whether a card is at all available. Note: If you add new
|
||||||
|
error codes here, check whether they need to be ignored in
|
||||||
|
send_escape_cmd. */
|
||||||
switch ((buffer[7] & 0x03))
|
switch ((buffer[7] & 0x03))
|
||||||
{
|
{
|
||||||
case 0: /* no error */ break;
|
case 0: /* no error */ break;
|
||||||
@ -1253,16 +1509,23 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
|
|
||||||
|
|
||||||
/* Note that this function won't return the error codes NO_CARD or
|
/* Note that this function won't return the error codes NO_CARD or
|
||||||
CARD_INACTIVE */
|
CARD_INACTIVE. IF RESULT is not NULL, the result from the
|
||||||
|
operation will get returned in RESULT and its length in RESULTLEN.
|
||||||
|
If the response is larger than RESULTMAX, an error is returned and
|
||||||
|
the required buffer length returned in RESULTLEN. */
|
||||||
static int
|
static int
|
||||||
send_escape_cmd (ccid_driver_t handle,
|
send_escape_cmd (ccid_driver_t handle,
|
||||||
const unsigned char *data, size_t datalen)
|
const unsigned char *data, size_t datalen,
|
||||||
|
unsigned char *result, size_t resultmax, size_t *resultlen)
|
||||||
{
|
{
|
||||||
int i, rc;
|
int i, rc;
|
||||||
unsigned char msg[100];
|
unsigned char msg[100];
|
||||||
size_t msglen;
|
size_t msglen;
|
||||||
unsigned char seqno;
|
unsigned char seqno;
|
||||||
|
|
||||||
|
if (resultlen)
|
||||||
|
*resultlen = 0;
|
||||||
|
|
||||||
if (datalen > sizeof msg - 10)
|
if (datalen > sizeof msg - 10)
|
||||||
return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */
|
return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */
|
||||||
|
|
||||||
@ -1285,11 +1548,42 @@ send_escape_cmd (ccid_driver_t handle,
|
|||||||
return rc;
|
return rc;
|
||||||
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
|
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
|
||||||
seqno, 5000, 0);
|
seqno, 5000, 0);
|
||||||
|
if (result)
|
||||||
|
switch (rc)
|
||||||
|
{
|
||||||
|
/* We need to ignore certain errorcode here. */
|
||||||
|
case 0:
|
||||||
|
case CCID_DRIVER_ERR_CARD_INACTIVE:
|
||||||
|
case CCID_DRIVER_ERR_NO_CARD:
|
||||||
|
{
|
||||||
|
if (msglen > resultmax)
|
||||||
|
rc = CCID_DRIVER_ERR_INV_VALUE; /* Response too large. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (result, msg, msglen);
|
||||||
|
*resultlen = msglen;
|
||||||
|
}
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ccid_transceive_escape (ccid_driver_t handle,
|
||||||
|
const unsigned char *data, size_t datalen,
|
||||||
|
unsigned char *resp, size_t maxresplen, size_t *nresp)
|
||||||
|
{
|
||||||
|
return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* experimental */
|
/* experimental */
|
||||||
int
|
int
|
||||||
ccid_poll (ccid_driver_t handle)
|
ccid_poll (ccid_driver_t handle)
|
||||||
@ -1299,12 +1593,17 @@ ccid_poll (ccid_driver_t handle)
|
|||||||
size_t msglen;
|
size_t msglen;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
if (handle->idev)
|
||||||
|
{
|
||||||
rc = usb_bulk_read (handle->idev,
|
rc = usb_bulk_read (handle->idev,
|
||||||
handle->ep_intr,
|
handle->ep_intr,
|
||||||
(char*)msg, sizeof msg,
|
(char*)msg, sizeof msg,
|
||||||
0 /* ms timeout */ );
|
0 /* ms timeout */ );
|
||||||
if (rc < 0 && errno == ETIMEDOUT)
|
if (rc < 0 && errno == ETIMEDOUT)
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
{
|
{
|
||||||
@ -1445,7 +1744,8 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
{
|
{
|
||||||
tried_iso = 1;
|
tried_iso = 1;
|
||||||
/* Try switching to ISO mode. */
|
/* Try switching to ISO mode. */
|
||||||
if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
|
if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2,
|
||||||
|
NULL, 0, NULL))
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
else if (CCID_COMMAND_FAILED (msg))
|
else if (CCID_COMMAND_FAILED (msg))
|
||||||
@ -1957,14 +2257,16 @@ ccid_transceive (ccid_driver_t handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send the CCID Secure command to the reader. APDU_BUF should contain the APDU template. PIN_MODE defines now the pin gets formatted:
|
/* Send the CCID Secure command to the reader. APDU_BUF should
|
||||||
|
contain the APDU template. PIN_MODE defines how the pin gets
|
||||||
|
formatted:
|
||||||
|
|
||||||
1 := The PIN is ASCII encoded and of variable length. The
|
1 := The PIN is ASCII encoded and of variable length. The
|
||||||
length of the PIN entered will be put into Lc by the reader.
|
length of the PIN entered will be put into Lc by the reader.
|
||||||
The APDU should me made up of 4 bytes without Lc.
|
The APDU should me made up of 4 bytes without Lc.
|
||||||
|
|
||||||
PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
|
PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
|
||||||
may be used t enable usbale defaults. PIN_PADLEN should be 0
|
may be used t enable reasonable defaults. PIN_PADLEN should be 0.
|
||||||
|
|
||||||
When called with RESP and NRESP set to NULL, the function will
|
When called with RESP and NRESP set to NULL, the function will
|
||||||
merely check whether the reader supports the secure command for the
|
merely check whether the reader supports the secure command for the
|
||||||
@ -1996,7 +2298,7 @@ ccid_transceive_secure (ccid_driver_t handle,
|
|||||||
else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
|
else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
|
||||||
return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
|
return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
|
||||||
else
|
else
|
||||||
return CCID_DRIVER_ERR_NOT_SUPPORTED;
|
return CCID_DRIVER_ERR_NO_KEYPAD;
|
||||||
|
|
||||||
if (pin_mode != 1)
|
if (pin_mode != 1)
|
||||||
return CCID_DRIVER_ERR_NOT_SUPPORTED;
|
return CCID_DRIVER_ERR_NOT_SUPPORTED;
|
||||||
@ -2027,7 +2329,8 @@ ccid_transceive_secure (ccid_driver_t handle,
|
|||||||
if (handle->id_vendor == VENDOR_SCM)
|
if (handle->id_vendor == VENDOR_SCM)
|
||||||
{
|
{
|
||||||
DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
|
DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
|
||||||
rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
|
rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3,
|
||||||
|
NULL, 0, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -2044,7 +2347,7 @@ ccid_transceive_secure (ccid_driver_t handle,
|
|||||||
if (handle->id_vendor == VENDOR_SCM)
|
if (handle->id_vendor == VENDOR_SCM)
|
||||||
{
|
{
|
||||||
/* For the SPR532 the next 2 bytes need to be zero. We do this
|
/* For the SPR532 the next 2 bytes need to be zero. We do this
|
||||||
for all SCM product. Kudos to to Martin Paljak for this
|
for all SCM product. Kudos to Martin Paljak for this
|
||||||
hint. */
|
hint. */
|
||||||
msg[13] = msg[14] = 0;
|
msg[13] = msg[14] = 0;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
#ifndef CCID_DRIVER_H
|
#ifndef CCID_DRIVER_H
|
||||||
#define CCID_DRIVER_H
|
#define CCID_DRIVER_H
|
||||||
|
|
||||||
/* The CID driver returns the same error codes as the statsu words
|
/* The CID driver returns the same error codes as the status words
|
||||||
used by GnuPG's apdu.h. For ease of maintenance they should always
|
used by GnuPG's apdu.h. For ease of maintenance they should always
|
||||||
match. */
|
match. */
|
||||||
#define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001
|
#define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001
|
||||||
@ -74,6 +74,7 @@
|
|||||||
#define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b
|
#define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b
|
||||||
#define CCID_DRIVER_ERR_NO_READER 0x1000c
|
#define CCID_DRIVER_ERR_NO_READER 0x1000c
|
||||||
#define CCID_DRIVER_ERR_ABORTED 0x1000d
|
#define CCID_DRIVER_ERR_ABORTED 0x1000d
|
||||||
|
#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e
|
||||||
|
|
||||||
struct ccid_driver_s;
|
struct ccid_driver_s;
|
||||||
typedef struct ccid_driver_s *ccid_driver_t;
|
typedef struct ccid_driver_s *ccid_driver_t;
|
||||||
@ -94,6 +95,10 @@ int ccid_transceive_secure (ccid_driver_t handle,
|
|||||||
int pin_mode,
|
int pin_mode,
|
||||||
int pinlen_min, int pinlen_max, int pin_padlen,
|
int pinlen_min, int pinlen_max, int pin_padlen,
|
||||||
unsigned char *resp, size_t maxresplen, size_t *nresp);
|
unsigned char *resp, size_t maxresplen, size_t *nresp);
|
||||||
|
int ccid_transceive_escape (ccid_driver_t handle,
|
||||||
|
const unsigned char *data, size_t datalen,
|
||||||
|
unsigned char *resp, size_t maxresplen,
|
||||||
|
size_t *nresp);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user