mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
* sc-investigate: Removed.
* Makefile.am (sc_investigate): Removed. * pcsc-wrapper.c (load_pcsc_driver): Load get_status_change func. (handle_open): Succeed even without a present card. (handle_status, handle_reset): New. * apdu.c (apdu_open_reader): Load pcsc_get_status_change fucntion. (pcsc_get_status): Implemented. (reset_pcsc_reader): Implemented. (open_pcsc_reader): Succeed even with no card inserted. (open_ccid_reader): Set LAST_STATUS. * iso7816.c (iso7816_select_application): Always use 0 for P1.
This commit is contained in:
parent
837c74f7e4
commit
d33703e5fe
12 changed files with 739 additions and 929 deletions
|
@ -86,6 +86,26 @@ static int verbose;
|
|||
#define PCSC_UNPOWER_CARD 2
|
||||
#define PCSC_EJECT_CARD 3
|
||||
|
||||
#define PCSC_UNKNOWN 0x0001
|
||||
#define PCSC_ABSENT 0x0002 /* Card is absent. */
|
||||
#define PCSC_PRESENT 0x0004 /* Card is present. */
|
||||
#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
|
||||
#define PCSC_POWERED 0x0010 /* Card is powered. */
|
||||
#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
|
||||
#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
|
||||
|
||||
#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
|
||||
#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
|
||||
#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
|
||||
#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
|
||||
#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
|
||||
#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
|
||||
#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
|
||||
#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
|
||||
#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
|
||||
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
|
||||
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
|
||||
|
||||
struct pcsc_io_request_s {
|
||||
unsigned long protocol;
|
||||
unsigned long pci_len;
|
||||
|
@ -93,12 +113,25 @@ struct pcsc_io_request_s {
|
|||
|
||||
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
||||
|
||||
struct pcsc_readerstate_s
|
||||
{
|
||||
const char *reader;
|
||||
void *user_data;
|
||||
unsigned long current_state;
|
||||
unsigned long event_state;
|
||||
unsigned long atrlen;
|
||||
unsigned char atr[33];
|
||||
};
|
||||
|
||||
typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
|
||||
|
||||
|
||||
static int driver_is_open; /* True if the PC/SC driver has been
|
||||
initialzied and is ready for
|
||||
operations. The follwoing variables
|
||||
operations. The following variables
|
||||
are then valid. */
|
||||
static unsigned long pcsc_context; /* The current PC/CS context. */
|
||||
static char *current_rdrname;
|
||||
static unsigned long pcsc_card;
|
||||
static unsigned long pcsc_protocol;
|
||||
static unsigned char current_atr[33];
|
||||
|
@ -112,12 +145,21 @@ long (* pcsc_release_context) (unsigned long context);
|
|||
long (* pcsc_list_readers) (unsigned long context,
|
||||
const char *groups,
|
||||
char *readers, unsigned long*readerslen);
|
||||
long (* pcsc_get_status_change) (unsigned long context,
|
||||
unsigned long timeout,
|
||||
pcsc_readerstate_t readerstates,
|
||||
unsigned long nreaderstates);
|
||||
long (* pcsc_connect) (unsigned long context,
|
||||
const char *reader,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long *r_card,
|
||||
unsigned long *r_active_protocol);
|
||||
long (* pcsc_reconnect) (unsigned long card,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long initialization,
|
||||
unsigned long *r_active_protocol);
|
||||
long (* pcsc_disconnect) (unsigned long card,
|
||||
unsigned long disposition);
|
||||
long (* pcsc_status) (unsigned long card,
|
||||
|
@ -284,7 +326,9 @@ load_pcsc_driver (const char *libname)
|
|||
pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
|
||||
pcsc_release_context = dlsym (handle, "SCardReleaseContext");
|
||||
pcsc_list_readers = dlsym (handle, "SCardListReaders");
|
||||
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
|
||||
pcsc_connect = dlsym (handle, "SCardConnect");
|
||||
pcsc_reconnect = dlsym (handle, "SCardReconnect");
|
||||
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
|
||||
pcsc_status = dlsym (handle, "SCardStatus");
|
||||
pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
|
||||
|
@ -295,7 +339,9 @@ load_pcsc_driver (const char *libname)
|
|||
if (!pcsc_establish_context
|
||||
|| !pcsc_release_context
|
||||
|| !pcsc_list_readers
|
||||
|| !pcsc_get_status_change
|
||||
|| !pcsc_connect
|
||||
|| !pcsc_reconnect
|
||||
|| !pcsc_disconnect
|
||||
|| !pcsc_status
|
||||
|| !pcsc_begin_transaction
|
||||
|
@ -307,11 +353,13 @@ load_pcsc_driver (const char *libname)
|
|||
available under Windows. */
|
||||
fprintf (stderr,
|
||||
"apdu_open_reader: invalid PC/SC driver "
|
||||
"(%d%d%d%d%d%d%d%d%d%d)\n",
|
||||
"(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
|
||||
!!pcsc_establish_context,
|
||||
!!pcsc_release_context,
|
||||
!!pcsc_list_readers,
|
||||
!!pcsc_get_status_change,
|
||||
!!pcsc_connect,
|
||||
!!pcsc_reconnect,
|
||||
!!pcsc_disconnect,
|
||||
!!pcsc_status,
|
||||
!!pcsc_begin_transaction,
|
||||
|
@ -327,8 +375,8 @@ load_pcsc_driver (const char *libname)
|
|||
|
||||
|
||||
/* Handle a open request. The argument is expected to be a string
|
||||
with the port indentification. ARGBUF is always guaranteed to be
|
||||
terminted by a 0 which is not counted in ARGLEN. We may modifiy
|
||||
with the port identification. ARGBUF is always guaranteed to be
|
||||
terminted by a 0 which is not counted in ARGLEN. We may modifiy
|
||||
ARGBUF. */
|
||||
static void
|
||||
handle_open (unsigned char *argbuf, size_t arglen)
|
||||
|
@ -350,6 +398,7 @@ handle_open (unsigned char *argbuf, size_t arglen)
|
|||
{
|
||||
fprintf (stderr, PGM ": PC/SC has already been opened\n");
|
||||
request_failed (-1);
|
||||
return;
|
||||
}
|
||||
|
||||
err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
|
||||
|
@ -398,45 +447,64 @@ handle_open (unsigned char *argbuf, size_t arglen)
|
|||
p += strlen (p) + 1;
|
||||
}
|
||||
|
||||
current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
|
||||
if (!current_rdrname)
|
||||
{
|
||||
fprintf (stderr, PGM": error allocating memory for reader name\n");
|
||||
exit (1);
|
||||
}
|
||||
strcpy (current_rdrname, portstr && *portstr? portstr:list);
|
||||
free (list);
|
||||
|
||||
err = pcsc_connect (pcsc_context,
|
||||
portstr && *portstr? portstr : list,
|
||||
current_rdrname,
|
||||
PCSC_SHARE_EXCLUSIVE,
|
||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||
&pcsc_card,
|
||||
&pcsc_protocol);
|
||||
if (err)
|
||||
if (err == 0x8010000c) /* No smartcard. */
|
||||
{
|
||||
pcsc_card = 0;
|
||||
}
|
||||
else if (err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
pcsc_release_context (pcsc_context);
|
||||
free (list);
|
||||
free (current_rdrname);
|
||||
current_rdrname = NULL;
|
||||
request_failed (err);
|
||||
return;
|
||||
}
|
||||
|
||||
atrlen = 32;
|
||||
/* (We need to pass a dummy buffer. We use LIST because it ought to
|
||||
be large enough.) */
|
||||
err = pcsc_status (pcsc_card,
|
||||
list, &listlen,
|
||||
&card_state, &card_protocol,
|
||||
atr, &atrlen);
|
||||
free (list);
|
||||
if (err)
|
||||
current_atrlen = 0;
|
||||
if (!err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
pcsc_release_context (pcsc_context);
|
||||
request_failed (err);
|
||||
return;
|
||||
char reader[250];
|
||||
unsigned long readerlen;
|
||||
|
||||
atrlen = 33;
|
||||
readerlen = sizeof reader -1;
|
||||
err = pcsc_status (pcsc_card,
|
||||
reader, &readerlen,
|
||||
&card_state, &card_protocol,
|
||||
atr, &atrlen);
|
||||
if (err)
|
||||
fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
else
|
||||
{
|
||||
if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
|
||||
{
|
||||
fprintf (stderr, PGM": ATR returned by pcsc_status"
|
||||
" is too large\n");
|
||||
exit (4);
|
||||
}
|
||||
memcpy (current_atr, atr, atrlen);
|
||||
current_atrlen = atrlen;
|
||||
}
|
||||
}
|
||||
if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
|
||||
{
|
||||
fprintf (stderr, PGM": ATR returned by pcsc_status is too large\n");
|
||||
exit (4);
|
||||
}
|
||||
memcpy (current_atr, atr, atrlen);
|
||||
current_atrlen = atrlen;
|
||||
|
||||
driver_is_open = 1;
|
||||
request_succeeded (current_atr, current_atrlen);
|
||||
}
|
||||
|
@ -452,8 +520,11 @@ handle_close (unsigned char *argbuf, size_t arglen)
|
|||
{
|
||||
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
|
||||
request_failed (-1);
|
||||
return;
|
||||
}
|
||||
|
||||
free (current_rdrname);
|
||||
current_rdrname = NULL;
|
||||
pcsc_release_context (pcsc_context);
|
||||
|
||||
request_succeeded (NULL, 0);
|
||||
|
@ -461,7 +532,133 @@ handle_close (unsigned char *argbuf, size_t arglen)
|
|||
|
||||
|
||||
|
||||
/* Handle a transmit request. The argument is expected to be a bufer
|
||||
/* Handle a status request. We expect no arguments. We may modifiy
|
||||
ARGBUF. */
|
||||
static void
|
||||
handle_status (unsigned char *argbuf, size_t arglen)
|
||||
{
|
||||
long err;
|
||||
struct pcsc_readerstate_s rdrstates[1];
|
||||
int status;
|
||||
unsigned char buf[20];
|
||||
|
||||
if (!driver_is_open)
|
||||
{
|
||||
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
|
||||
request_failed (-1);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (rdrstates, 0, sizeof *rdrstates);
|
||||
rdrstates[0].reader = current_rdrname;
|
||||
rdrstates[0].current_state = PCSC_STATE_UNAWARE;
|
||||
err = pcsc_get_status_change (pcsc_context,
|
||||
0,
|
||||
rdrstates, 1);
|
||||
if (err == 0x8010000a) /* Timeout. */
|
||||
err = 0;
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
request_failed (err);
|
||||
return;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
|
||||
status |= 2;
|
||||
if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
|
||||
status |= 4;
|
||||
/* We indicate a useful card if it is not in use by another
|
||||
application. This is because we only use exclusive access
|
||||
mode. */
|
||||
if ( (status & 6) == 6
|
||||
&& !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
|
||||
status |= 1;
|
||||
|
||||
/* First word is identical to the one used by apdu.c. */
|
||||
buf[0] = 0;
|
||||
buf[1] = 0;
|
||||
buf[2] = 0;
|
||||
buf[3] = status;
|
||||
/* The second word is the native PCSC state. */
|
||||
buf[4] = (rdrstates[0].event_state >> 24);
|
||||
buf[5] = (rdrstates[0].event_state >> 16);
|
||||
buf[6] = (rdrstates[0].event_state >> 8);
|
||||
buf[7] = (rdrstates[0].event_state >> 0);
|
||||
|
||||
request_succeeded (buf, 8);
|
||||
}
|
||||
|
||||
|
||||
/* Handle a reset request. We expect no arguments. We may modifiy
|
||||
ARGBUF. */
|
||||
static void
|
||||
handle_reset (unsigned char *argbuf, size_t arglen)
|
||||
{
|
||||
long err;
|
||||
char reader[250];
|
||||
unsigned long nreader, atrlen;
|
||||
unsigned long card_state, card_protocol;
|
||||
|
||||
if (!driver_is_open)
|
||||
{
|
||||
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
|
||||
request_failed (-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pcsc_card)
|
||||
{
|
||||
err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
request_failed (err);
|
||||
return;
|
||||
}
|
||||
pcsc_card = 0;
|
||||
}
|
||||
|
||||
err = pcsc_connect (pcsc_context,
|
||||
current_rdrname,
|
||||
PCSC_SHARE_EXCLUSIVE,
|
||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||
&pcsc_card,
|
||||
&pcsc_protocol);
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
pcsc_card = 0;
|
||||
request_failed (err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
atrlen = 33;
|
||||
nreader = sizeof reader - 1;
|
||||
err = pcsc_status (pcsc_card,
|
||||
reader, &nreader,
|
||||
&card_state, &card_protocol,
|
||||
current_atr, &atrlen);
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
current_atrlen = 0;
|
||||
request_failed (err);
|
||||
return;
|
||||
}
|
||||
|
||||
request_succeeded (current_atr, current_atrlen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Handle a transmit request. The argument is expected to be a buffer
|
||||
with the APDU. We may modifiy ARGBUF. */
|
||||
static void
|
||||
handle_transmit (unsigned char *argbuf, size_t arglen)
|
||||
|
@ -479,8 +676,8 @@ handle_transmit (unsigned char *argbuf, size_t arglen)
|
|||
{
|
||||
fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
|
||||
request_failed (-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pcsc_protocol & PCSC_PROTOCOL_T1))
|
||||
send_pci.protocol = PCSC_PROTOCOL_T1;
|
||||
else
|
||||
|
@ -502,15 +699,6 @@ handle_transmit (unsigned char *argbuf, size_t arglen)
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
print_version (int with_help)
|
||||
{
|
||||
|
@ -613,6 +801,14 @@ main (int argc, char **argv)
|
|||
handle_transmit (argbuffer, arglen);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
handle_status (argbuffer, arglen);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
handle_reset (argbuffer, arglen);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
|
||||
exit (1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue