1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-09 12:54:23 +01:00

* 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:
Werner Koch 2004-10-20 09:39:56 +00:00
parent 3f769cb717
commit 27d06166d3
8 changed files with 505 additions and 59 deletions

View File

@ -1,3 +1,17 @@
2004-10-20 Werner Koch <wk@g10code.com>
* 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.
2004-10-18 Werner Koch <wk@g10code.com>
* ccid-driver.c (ccid_get_atr): Reset T=1 state info.
2004-10-17 Werner Koch <wk@g10code.com> 2004-10-17 Werner Koch <wk@g10code.com>
* passphrase.c (agent_get_passphrase): Cast UIDLEN to int. Noted * passphrase.c (agent_get_passphrase): Cast UIDLEN to int. Noted

View File

@ -125,6 +125,8 @@ struct reader_table_s {
rapdu_t handle; rapdu_t handle;
} rapdu; } rapdu;
#endif /*USE_G10CODE_RAPDU*/ #endif /*USE_G10CODE_RAPDU*/
char *rdrname; /* Name of the connected reader or NULL if unknown. */
int last_status;
int status; int status;
unsigned char atr[33]; unsigned char atr[33];
size_t atrlen; /* A zero length indicates that the ATR has size_t atrlen; /* A zero length indicates that the ATR has
@ -169,13 +171,47 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
#define PCSC_UNPOWER_CARD 2 #define PCSC_UNPOWER_CARD 2
#define PCSC_EJECT_CARD 3 #define PCSC_EJECT_CARD 3
struct pcsc_io_request_s { #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 protocol;
unsigned long pci_len; unsigned long pci_len;
}; };
typedef struct pcsc_io_request_s *pcsc_io_request_t; 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;
long (* DLSTDCALL pcsc_establish_context) (unsigned long scope, long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
const void *reserved1, const void *reserved1,
const void *reserved2, const void *reserved2,
@ -184,12 +220,21 @@ long (* DLSTDCALL pcsc_release_context) (unsigned long context);
long (* DLSTDCALL pcsc_list_readers) (unsigned long context, long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
const char *groups, const char *groups,
char *readers, unsigned long*readerslen); char *readers, unsigned long*readerslen);
long (* DLSTDCALL pcsc_get_status_change) (unsigned long context,
unsigned long timeout,
pcsc_readerstate_t readerstates,
unsigned long nreaderstates);
long (* DLSTDCALL pcsc_connect) (unsigned long context, long (* DLSTDCALL pcsc_connect) (unsigned long context,
const char *reader, const char *reader,
unsigned long share_mode, unsigned long share_mode,
unsigned long preferred_protocols, unsigned long preferred_protocols,
unsigned long *r_card, unsigned long *r_card,
unsigned long *r_active_protocol); unsigned long *r_active_protocol);
long (* DLSTDCALL pcsc_reconnect) (unsigned long card,
unsigned long share_mode,
unsigned long preferred_protocols,
unsigned long initialization,
unsigned long *r_active_protocol);
long (* DLSTDCALL pcsc_disconnect) (unsigned long card, long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
unsigned long disposition); unsigned long disposition);
long (* DLSTDCALL pcsc_status) (unsigned long card, long (* DLSTDCALL pcsc_status) (unsigned long card,
@ -211,7 +256,6 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
/* /*
Helper Helper
@ -254,11 +298,13 @@ new_reader_slot (void)
reader_table[reader].dump_status_reader = NULL; reader_table[reader].dump_status_reader = NULL;
reader_table[reader].used = 1; reader_table[reader].used = 1;
reader_table[reader].last_status = 0;
#ifdef NEED_PCSC_WRAPPER #ifdef NEED_PCSC_WRAPPER
reader_table[reader].pcsc.req_fd = -1; reader_table[reader].pcsc.req_fd = -1;
reader_table[reader].pcsc.rsp_fd = -1; reader_table[reader].pcsc.rsp_fd = -1;
reader_table[reader].pcsc.pid = (pid_t)(-1); reader_table[reader].pcsc.pid = (pid_t)(-1);
#endif #endif
return reader; return reader;
} }
@ -662,18 +708,293 @@ dump_pcsc_reader_status (int slot)
} }
static int
reset_pcsc_reader (int slot)
{
#ifdef NEED_PCSC_WRAPPER
long err;
reader_table_t slotp;
size_t len;
int i, n;
unsigned char msgbuf[9];
slotp = reader_table + slot;
if (slotp->pcsc.req_fd == -1
|| slotp->pcsc.rsp_fd == -1
|| slotp->pcsc.pid == (pid_t)(-1) )
{
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
return SW_HOST_CARD_IO_ERROR;
}
msgbuf[0] = 0x05; /* RESET command. */
len = 0;
msgbuf[1] = (len >> 24);
msgbuf[2] = (len >> 16);
msgbuf[3] = (len >> 8);
msgbuf[4] = (len );
if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
{
log_error ("error sending PC/SC RESET request: %s\n",
strerror (errno));
goto command_failed;
}
/* Read the response. */
if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
{
log_error ("error receiving PC/SC RESET response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
if (msgbuf[0] != 0x81 || len < 4)
{
log_error ("invalid response header from PC/SC received\n");
goto command_failed;
}
len -= 4; /* Already read the error code. */
if (len > DIM (slotp->atr))
{
log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
goto command_failed;
}
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
if (err)
{
log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err));
goto command_failed;
}
/* The open fucntion may return a zero for the ATR length to
indicate that no card is present. */
n = len;
if (n)
{
if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
{
log_error ("error receiving PC/SC RESET response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
}
slotp->atrlen = len;
return 0;
command_failed:
close (slotp->pcsc.req_fd);
close (slotp->pcsc.rsp_fd);
slotp->pcsc.req_fd = -1;
slotp->pcsc.rsp_fd = -1;
kill (slotp->pcsc.pid, SIGTERM);
slotp->pcsc.pid = (pid_t)(-1);
slotp->used = 0;
return -1;
#else /* !NEED_PCSC_WRAPPER */
long err;
char reader[250];
unsigned long nreader, atrlen;
unsigned long card_state, card_protocol;
if (reader_table[slot].pcsc.card)
{
err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
if (err)
{
log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
return SW_HOST_CARD_IO_ERROR;
}
reader_table[slot].pcsc.card = 0;
}
err = pcsc_connect (reader_table[slot].pcsc.context,
reader_table[slot].rdrname,
PCSC_SHARE_EXCLUSIVE,
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
&reader_table[slot].pcsc.card,
&reader_table[slot].pcsc.protocol);
if (err)
{
log_error ("pcsc_connect failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
reader_table[slot].pcsc.card = 0;
return SW_HOST_CARD_IO_ERROR;
}
atrlen = 33;
nreader = sizeof reader - 1;
err = pcsc_status (reader_table[slot].pcsc.card,
reader, &nreader,
&card_state, &card_protocol,
reader_table[slot].atr, &atrlen);
if (err)
{
log_error ("pcsc_status failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
reader_table[slot].atrlen = 0;
return SW_HOST_CARD_IO_ERROR;
}
if (atrlen >= DIM (reader_table[0].atr))
log_bug ("ATR returned by pcsc_status is too large\n");
reader_table[slot].atrlen = atrlen;
return 0;
#endif /* !NEED_PCSC_WRAPPER */
}
static int static int
pcsc_get_status (int slot, unsigned int *status) pcsc_get_status (int slot, unsigned int *status)
{ {
*status = 1|2|4; /* FIXME!!!! */ #ifdef NEED_PCSC_WRAPPER
return 0; long err;
reader_table_t slotp;
size_t len, full_len;
int i, n;
unsigned char msgbuf[9];
unsigned char buffer[12];
slotp = reader_table + slot;
if (slotp->pcsc.req_fd == -1
|| slotp->pcsc.rsp_fd == -1
|| slotp->pcsc.pid == (pid_t)(-1) )
{
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
return SW_HOST_CARD_IO_ERROR;
} }
static int msgbuf[0] = 0x04; /* STATUS command. */
reset_pcsc_reader (int slot) len = 0;
msgbuf[1] = (len >> 24);
msgbuf[2] = (len >> 16);
msgbuf[3] = (len >> 8);
msgbuf[4] = (len );
if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
{ {
return SW_HOST_NOT_SUPPORTED; log_error ("error sending PC/SC STATUS request: %s\n",
strerror (errno));
goto command_failed;
}
/* Read the response. */
if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
{
log_error ("error receiving PC/SC STATUS response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
if (msgbuf[0] != 0x81 || len < 4)
{
log_error ("invalid response header from PC/SC received\n");
goto command_failed;
}
len -= 4; /* Already read the error code. */
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
if (err)
{
log_error ("pcsc_status failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
return SW_HOST_CARD_IO_ERROR;
}
full_len = len;
n = 8 < len ? 8 : len;
if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8)
{
log_error ("error receiving PC/SC STATUS response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
full_len -= len;
/* Newer versions of the wrapper might send more status bytes.
Read them. */
while (full_len)
{
unsigned char dummybuf[128];
n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
{
log_error ("error receiving PC/SC TRANSMIT response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
full_len -= n;
}
/* We are lucky: The wrapper already returns the data in the
required format. */
*status = buffer[3];
return 0;
command_failed:
close (slotp->pcsc.req_fd);
close (slotp->pcsc.rsp_fd);
slotp->pcsc.req_fd = -1;
slotp->pcsc.rsp_fd = -1;
kill (slotp->pcsc.pid, SIGTERM);
slotp->pcsc.pid = (pid_t)(-1);
slotp->used = 0;
return -1;
#else /*!NEED_PCSC_WRAPPER*/
long err;
struct pcsc_readerstate_s rdrstates[1];
memset (rdrstates, 0, sizeof *rdrstates);
rdrstates[0].reader = reader_table[slot].rdrname;
rdrstates[0].current_state = PCSC_STATE_UNAWARE;
err = pcsc_get_status_change (reader_table[slot].pcsc.context,
0,
rdrstates, 1);
if (err == 0x8010000a) /* Timeout. */
err = 0;
if (err)
{
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
return SW_HOST_CARD_IO_ERROR;
}
/* log_debug */
/* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
/* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
/* (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
/* (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
/* (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
/* (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
/* (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
/* (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
/* (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
/* (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
/* (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
*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;
return 0;
#endif /*!NEED_PCSC_WRAPPER*/
} }
@ -889,6 +1210,8 @@ close_pcsc_reader (int slot)
#else /*!NEED_PCSC_WRAPPER*/ #else /*!NEED_PCSC_WRAPPER*/
pcsc_release_context (reader_table[slot].pcsc.context); pcsc_release_context (reader_table[slot].pcsc.context);
xfree (reader_table[slot].rdrname);
reader_table[slot].rdrname = NULL;
reader_table[slot].used = 0; reader_table[slot].used = 0;
return 0; return 0;
#endif /*!NEED_PCSC_WRAPPER*/ #endif /*!NEED_PCSC_WRAPPER*/
@ -999,8 +1322,14 @@ open_pcsc_reader (const char *portstr)
slotp->pcsc.rsp_fd = rp[0]; slotp->pcsc.rsp_fd = rp[0];
/* Wait for the intermediate child to terminate. */ /* Wait for the intermediate child to terminate. */
while ( (i=pth_waitpid (pid, NULL, 0)) == -1 && errno == EINTR) #ifdef USE_GNU_PTH
#define WAIT pth_waitpid
#else
#define WAIT waitpid
#endif
while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
; ;
#undef X
/* Now send the open request. */ /* Now send the open request. */
msgbuf[0] = 0x01; /* OPEN command. */ msgbuf[0] = 0x01; /* OPEN command. */
@ -1041,13 +1370,24 @@ open_pcsc_reader (const char *portstr)
log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err)); log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
goto command_failed; goto command_failed;
} }
slotp->last_status = 0;
/* The open fucntion may return a zero for the ATR length to
indicate that no card is present. */
n = len; n = len;
if (n)
{
if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n) if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
{ {
log_error ("error receiving PC/SC OPEN response: %s\n", log_error ("error receiving PC/SC OPEN response: %s\n",
i? strerror (errno) : "premature EOF"); i? strerror (errno) : "premature EOF");
goto command_failed; goto command_failed;
} }
/* If we got to here we know that a card is present
and usable. Thus remember this. */
slotp->last_status = (1|2|4| 0x8000);
}
slotp->atrlen = len; slotp->atrlen = len;
reader_table[slot].close_reader = close_pcsc_reader; reader_table[slot].close_reader = close_pcsc_reader;
@ -1132,41 +1472,63 @@ open_pcsc_reader (const char *portstr)
p += strlen (p) + 1; p += strlen (p) + 1;
} }
reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
if (!reader_table[slot].rdrname)
{
log_error ("error allocating memory for reader name\n");
pcsc_release_context (reader_table[slot].pcsc.context);
reader_table[slot].used = 0;
return -1;
}
strcpy (reader_table[slot].rdrname, portstr? portstr : list);
xfree (list);
err = pcsc_connect (reader_table[slot].pcsc.context, err = pcsc_connect (reader_table[slot].pcsc.context,
portstr? portstr : list, reader_table[slot].rdrname,
PCSC_SHARE_EXCLUSIVE, PCSC_SHARE_EXCLUSIVE,
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
&reader_table[slot].pcsc.card, &reader_table[slot].pcsc.card,
&reader_table[slot].pcsc.protocol); &reader_table[slot].pcsc.protocol);
if (err) if (err == 0x8010000c) /* No smartcard. */
reader_table[slot].pcsc.card = 0;
else if (err)
{ {
log_error ("pcsc_connect failed: %s (0x%lx)\n", log_error ("pcsc_connect failed: %s (0x%lx)\n",
pcsc_error_string (err), err); pcsc_error_string (err), err);
pcsc_release_context (reader_table[slot].pcsc.context); pcsc_release_context (reader_table[slot].pcsc.context);
xfree (reader_table[slot].rdrname);
reader_table[slot].rdrname = NULL;
reader_table[slot].used = 0; reader_table[slot].used = 0;
xfree (list); xfree (list);
return -1; return -1;
} }
reader_table[slot].atrlen = 0;
reader_table[slot].last_status = 0;
if (!err)
{
char reader[250];
unsigned long readerlen;
atrlen = 32; atrlen = 32;
/* (We need to pass a dummy buffer. We use LIST because it ought to readerlen = sizeof reader -1 ;
be large enough.) */
err = pcsc_status (reader_table[slot].pcsc.card, err = pcsc_status (reader_table[slot].pcsc.card,
list, &listlen, reader, &readerlen,
&card_state, &card_protocol, &card_state, &card_protocol,
reader_table[slot].atr, &atrlen); reader_table[slot].atr, &atrlen);
xfree (list);
if (err) if (err)
log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
pcsc_error_string (err), err, readerlen);
else
{ {
log_error ("pcsc_status failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
pcsc_release_context (reader_table[slot].pcsc.context);
reader_table[slot].used = 0;
return -1;
}
if (atrlen >= DIM (reader_table[0].atr)) if (atrlen >= DIM (reader_table[0].atr))
log_bug ("ATR returned by pcsc_status is too large\n"); log_bug ("ATR returned by pcsc_status is too large\n");
reader_table[slot].atrlen = atrlen; reader_table[slot].atrlen = atrlen;
/* If we got to here we know that a card is present
and usable. Thus remember this. */
reader_table[slot].last_status = (1|2|4| 0x8000);
}
}
reader_table[slot].close_reader = close_pcsc_reader; reader_table[slot].close_reader = close_pcsc_reader;
reader_table[slot].reset_reader = reset_pcsc_reader; reader_table[slot].reset_reader = reset_pcsc_reader;
@ -1311,6 +1673,12 @@ open_ccid_reader (const char *portstr)
slotp->atrlen = 0; slotp->atrlen = 0;
err = 0; err = 0;
} }
else
{
/* If we got to here we know that a card is present
and usable. Thus remember this. */
reader_table[slot].last_status = (1|2|4| 0x8000);
}
reader_table[slot].close_reader = close_ccid_reader; reader_table[slot].close_reader = close_ccid_reader;
reader_table[slot].shutdown_reader = shutdown_ccid_reader; reader_table[slot].shutdown_reader = shutdown_ccid_reader;
@ -1970,11 +2338,21 @@ apdu_open_reader (const char *portstr)
#ifdef _WIN32 #ifdef _WIN32
if (!pcsc_list_readers) if (!pcsc_list_readers)
pcsc_list_readers = dlsym (handle, "SCardListReadersA"); pcsc_list_readers = dlsym (handle, "SCardListReadersA");
#endif
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
#ifdef _WIN32
if (!pcsc_get_status_change)
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
#endif #endif
pcsc_connect = dlsym (handle, "SCardConnect"); pcsc_connect = dlsym (handle, "SCardConnect");
#ifdef _WIN32 #ifdef _WIN32
if (!pcsc_connect) if (!pcsc_connect)
pcsc_connect = dlsym (handle, "SCardConnectA"); pcsc_connect = dlsym (handle, "SCardConnectA");
#endif
pcsc_reconnect = dlsym (handle, "SCardReconnect");
#ifdef _WIN32
if (!pcsc_reconnect)
pcsc_reconnect = dlsym (handle, "SCardReconnectA");
#endif #endif
pcsc_disconnect = dlsym (handle, "SCardDisconnect"); pcsc_disconnect = dlsym (handle, "SCardDisconnect");
pcsc_status = dlsym (handle, "SCardStatus"); pcsc_status = dlsym (handle, "SCardStatus");
@ -1990,7 +2368,9 @@ apdu_open_reader (const char *portstr)
if (!pcsc_establish_context if (!pcsc_establish_context
|| !pcsc_release_context || !pcsc_release_context
|| !pcsc_list_readers || !pcsc_list_readers
|| !pcsc_get_status_change
|| !pcsc_connect || !pcsc_connect
|| !pcsc_reconnect
|| !pcsc_disconnect || !pcsc_disconnect
|| !pcsc_status || !pcsc_status
|| !pcsc_begin_transaction || !pcsc_begin_transaction
@ -2001,11 +2381,13 @@ apdu_open_reader (const char *portstr)
/* Note that set_timeout is currently not used and also not /* Note that set_timeout is currently not used and also not
available under Windows. */ available under Windows. */
log_error ("apdu_open_reader: invalid PC/SC driver " log_error ("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_establish_context,
!!pcsc_release_context, !!pcsc_release_context,
!!pcsc_list_readers, !!pcsc_list_readers,
!!pcsc_get_status_change,
!!pcsc_connect, !!pcsc_connect,
!!pcsc_reconnect,
!!pcsc_disconnect, !!pcsc_disconnect,
!!pcsc_status, !!pcsc_status,
!!pcsc_begin_transaction, !!pcsc_begin_transaction,
@ -2106,9 +2488,17 @@ apdu_reset (int slot)
if ((sw = lock_slot (slot))) if ((sw = lock_slot (slot)))
return sw; return sw;
reader_table[slot].last_status = 0;
if (reader_table[slot].reset_reader) if (reader_table[slot].reset_reader)
sw = reader_table[slot].reset_reader (slot); sw = reader_table[slot].reset_reader (slot);
if (!sw)
{
/* If we got to here we know that a card is present
and usable. Thus remember this. */
reader_table[slot].last_status = (1|2|4| 0x8000);
}
unlock_slot (slot); unlock_slot (slot);
return sw; return sw;
} }
@ -2143,7 +2533,16 @@ apdu_activate (int slot)
/* We don't have an ATR or a card is present though inactive: /* We don't have an ATR or a card is present though inactive:
do a reset now. */ do a reset now. */
if (reader_table[slot].reset_reader) if (reader_table[slot].reset_reader)
{
reader_table[slot].last_status = 0;
sw = reader_table[slot].reset_reader (slot); sw = reader_table[slot].reset_reader (slot);
if (!sw)
{
/* If we got to here we know that a card is present
and usable. Thus remember this. */
reader_table[slot].last_status = (1|2|4| 0x8000);
}
}
} }
} }
@ -2205,7 +2604,22 @@ apdu_get_status (int slot, int hang,
unlock_slot (slot); unlock_slot (slot);
if (sw) if (sw)
{
reader_table[slot].last_status = 0;
return sw; return sw;
}
/* Keep track of changes. We use one extra bit to test whether we
have checked the status at least once. */
if ( s != (reader_table[slot].last_status & 0x07ff)
|| !reader_table[slot].last_status )
{
reader_table[slot].change_counter++;
/* Make sure that the ATR is invalid so that a reset will be by
activate. */
reader_table[slot].atrlen = 0;
}
reader_table[slot].last_status = (s | 0x8000);
if (status) if (status)
*status = s; *status = s;

View File

@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id$
*/ */
#ifndef APDU_H #ifndef APDU_H

View File

@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id$
*/ */
#ifndef GNUPG_SCD_APP_COMMON_H #ifndef GNUPG_SCD_APP_COMMON_H
@ -95,6 +97,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/ /*-- app.c --*/
app_t select_application (ctrl_t ctrl, int slot, const char *name); app_t select_application (ctrl_t ctrl, int slot, const char *name);
void release_application (app_t app); void release_application (app_t app);
int app_munge_serialno (app_t app);
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
int app_write_learn_status (app_t app, ctrl_t ctrl); int app_write_learn_status (app_t app, ctrl_t ctrl);
int app_readcert (app_t app, const char *certid, int app_readcert (app_t app, const char *certid,
@ -143,7 +146,6 @@ int app_openpgp_cardinfo (app_t app,
unsigned char **fpr1, unsigned char **fpr1,
unsigned char **fpr2, unsigned char **fpr2,
unsigned char **fpr3); unsigned char **fpr3);
#endif /* GNUPG_MAJOR_VERSION != 1 */
int app_openpgp_storekey (app_t app, int keyno, int app_openpgp_storekey (app_t app, int keyno,
unsigned char *template, size_t template_len, unsigned char *template, size_t template_len,
time_t created_at, time_t created_at,
@ -154,16 +156,18 @@ int app_openpgp_storekey (app_t app, int keyno,
int app_openpgp_readkey (app_t app, int keyno, int app_openpgp_readkey (app_t app, int keyno,
unsigned char **m, size_t *mlen, unsigned char **m, size_t *mlen,
unsigned char **e, size_t *elen); unsigned char **e, size_t *elen);
#if GNUPG_MAJOR_VERSION == 1
#else
/*-- app-nks.c --*/ /*-- app-nks.c --*/
int app_select_nks (app_t app); int app_select_nks (app_t app);
/*-- app-dinsig.c --*/ /*-- app-dinsig.c --*/
int app_select_dinsig (app_t app); int app_select_dinsig (app_t app);
/*-- app-p15.c --*/
int app_select_p15 (app_t app);
#endif
#endif /* GNUPG_MAJOR_VERSION != 1 */
#endif /*GNUPG_SCD_APP_COMMON_H*/ #endif /*GNUPG_SCD_APP_COMMON_H*/

View File

@ -1307,6 +1307,8 @@ ccid_get_atr (ccid_driver_t handle,
/* Note that we ignore the error code on purpose. */ /* Note that we ignore the error code on purpose. */
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno); bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
handle->t1_ns = 0;
handle->t1_nr = 0;
/* Send an S-Block with our maximun IFSD to the CCID. */ /* Send an S-Block with our maximun IFSD to the CCID. */
if (!handle->auto_ifsd) if (!handle->auto_ifsd)

View File

@ -50,6 +50,8 @@
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/ */
#ifndef CCID_DRIVER_H #ifndef CCID_DRIVER_H

View File

@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id$
*/ */
#include <config.h> #include <config.h>
@ -103,6 +105,17 @@ map_sw (int sw)
return gpg_error (ec); return gpg_error (ec);
} }
/* Map a status word from the APDU layer to a gpg-error code. */
gpg_error_t
iso7816_map_sw (int sw)
{
/* All APDU functions should return 0x9000 on success but for
historical reasons of the implementation some return 0 to
indicate success. We allow for that here. */
return sw? map_sw (sw) : 0;
}
/* This function is specialized version of the SELECT FILE command. /* This function is specialized version of the SELECT FILE command.
SLOT is the card and reader as created for example by SLOT is the card and reader as created for example by
apdu_open_reader (), AID is a buffer of size AIDLEN holding the apdu_open_reader (), AID is a buffer of size AIDLEN holding the
@ -113,15 +126,8 @@ map_sw (int sw)
gpg_error_t gpg_error_t
iso7816_select_application (int slot, const char *aid, size_t aidlen) iso7816_select_application (int slot, const char *aid, size_t aidlen)
{ {
static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
int sw; int sw;
int p1 = 0x0C; /* No FCI to be returned. */ sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
if (aidlen == sizeof openpgp_aid
&& !memcmp (aid, openpgp_aid, sizeof openpgp_aid))
p1 = 0; /* The current openpgp cards don't allow 0x0c. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, p1, aidlen, aid);
return map_sw (sw); return map_sw (sw);
} }

View File

@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id$
*/ */
#ifndef ISO7816_H #ifndef ISO7816_H