From 27d06166d3972b15749d8233459bde88764dae35 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 20 Oct 2004 09:39:56 +0000 Subject: [PATCH] * 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. --- g10/ChangeLog | 14 ++ g10/apdu.c | 508 +++++++++++++++++++++++++++++++++++++++++----- g10/apdu.h | 2 + g10/app-common.h | 12 +- g10/ccid-driver.c | 2 + g10/ccid-driver.h | 2 + g10/iso7816.c | 22 +- g10/iso7816.h | 2 + 8 files changed, 505 insertions(+), 59 deletions(-) diff --git a/g10/ChangeLog b/g10/ChangeLog index e0d03c2bb..495f7e865 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,17 @@ +2004-10-20 Werner Koch + + * 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 + + * ccid-driver.c (ccid_get_atr): Reset T=1 state info. + 2004-10-17 Werner Koch * passphrase.c (agent_get_passphrase): Cast UIDLEN to int. Noted diff --git a/g10/apdu.c b/g10/apdu.c index e58be590d..f4b32d141 100644 --- a/g10/apdu.c +++ b/g10/apdu.c @@ -125,6 +125,8 @@ struct reader_table_s { rapdu_t handle; } rapdu; #endif /*USE_G10CODE_RAPDU*/ + char *rdrname; /* Name of the connected reader or NULL if unknown. */ + int last_status; int status; unsigned char atr[33]; 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_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 pci_len; }; 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, const void *reserved1, const void *reserved2, @@ -184,12 +220,21 @@ long (* DLSTDCALL pcsc_release_context) (unsigned long context); long (* DLSTDCALL pcsc_list_readers) (unsigned long context, const char *groups, 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, const char *reader, unsigned long share_mode, unsigned long preferred_protocols, unsigned long *r_card, 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, unsigned long disposition); long (* DLSTDCALL pcsc_status) (unsigned long card, @@ -211,7 +256,6 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context, - /* Helper @@ -254,11 +298,13 @@ new_reader_slot (void) reader_table[reader].dump_status_reader = NULL; reader_table[reader].used = 1; + reader_table[reader].last_status = 0; #ifdef NEED_PCSC_WRAPPER reader_table[reader].pcsc.req_fd = -1; reader_table[reader].pcsc.rsp_fd = -1; reader_table[reader].pcsc.pid = (pid_t)(-1); #endif + 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 pcsc_get_status (int slot, unsigned int *status) { - *status = 1|2|4; /* FIXME!!!! */ - return 0; -} +#ifdef NEED_PCSC_WRAPPER + long err; + reader_table_t slotp; + size_t len, full_len; + int i, n; + unsigned char msgbuf[9]; + unsigned char buffer[12]; -static int -reset_pcsc_reader (int slot) -{ - return SW_HOST_NOT_SUPPORTED; + 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] = 0x04; /* STATUS 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 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*/ pcsc_release_context (reader_table[slot].pcsc.context); + xfree (reader_table[slot].rdrname); + reader_table[slot].rdrname = NULL; reader_table[slot].used = 0; return 0; #endif /*!NEED_PCSC_WRAPPER*/ @@ -999,8 +1322,14 @@ open_pcsc_reader (const char *portstr) slotp->pcsc.rsp_fd = rp[0]; /* 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. */ msgbuf[0] = 0x01; /* OPEN command. */ @@ -1041,12 +1370,23 @@ open_pcsc_reader (const char *portstr) log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err)); 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; - if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n) + if (n) { - log_error ("error receiving PC/SC OPEN response: %s\n", - i? strerror (errno) : "premature EOF"); - goto command_failed; + if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n) + { + log_error ("error receiving PC/SC OPEN response: %s\n", + i? strerror (errno) : "premature EOF"); + 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; @@ -1132,41 +1472,63 @@ open_pcsc_reader (const char *portstr) p += strlen (p) + 1; } - err = pcsc_connect (reader_table[slot].pcsc.context, - portstr? portstr : list, - PCSC_SHARE_EXCLUSIVE, - PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, - &reader_table[slot].pcsc.card, - &reader_table[slot].pcsc.protocol); - if (err) + reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1); + if (!reader_table[slot].rdrname) { - log_error ("pcsc_connect failed: %s (0x%lx)\n", - pcsc_error_string (err), err); - pcsc_release_context (reader_table[slot].pcsc.context); - reader_table[slot].used = 0; - xfree (list); - return -1; - } - - atrlen = 32; - /* (We need to pass a dummy buffer. We use LIST because it ought to - be large enough.) */ - err = pcsc_status (reader_table[slot].pcsc.card, - list, &listlen, - &card_state, &card_protocol, - reader_table[slot].atr, &atrlen); - xfree (list); - if (err) - { - log_error ("pcsc_status failed: %s (0x%lx)\n", - pcsc_error_string (err), err); + log_error ("error allocating memory for reader name\n"); pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; return -1; } - if (atrlen >= DIM (reader_table[0].atr)) - log_bug ("ATR returned by pcsc_status is too large\n"); - reader_table[slot].atrlen = atrlen; + strcpy (reader_table[slot].rdrname, portstr? portstr : list); + xfree (list); + + 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 == 0x8010000c) /* No smartcard. */ + reader_table[slot].pcsc.card = 0; + else if (err) + { + log_error ("pcsc_connect failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + pcsc_release_context (reader_table[slot].pcsc.context); + xfree (reader_table[slot].rdrname); + reader_table[slot].rdrname = NULL; + reader_table[slot].used = 0; + xfree (list); + return -1; + } + + reader_table[slot].atrlen = 0; + reader_table[slot].last_status = 0; + if (!err) + { + char reader[250]; + unsigned long readerlen; + + atrlen = 32; + readerlen = sizeof reader -1 ; + err = pcsc_status (reader_table[slot].pcsc.card, + reader, &readerlen, + &card_state, &card_protocol, + reader_table[slot].atr, &atrlen); + if (err) + log_error ("pcsc_status failed: %s (0x%lx) %lu\n", + pcsc_error_string (err), err, readerlen); + else + { + if (atrlen >= DIM (reader_table[0].atr)) + log_bug ("ATR returned by pcsc_status is too large\n"); + 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].reset_reader = reset_pcsc_reader; @@ -1311,6 +1673,12 @@ open_ccid_reader (const char *portstr) slotp->atrlen = 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].shutdown_reader = shutdown_ccid_reader; @@ -1970,11 +2338,21 @@ apdu_open_reader (const char *portstr) #ifdef _WIN32 if (!pcsc_list_readers) 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 pcsc_connect = dlsym (handle, "SCardConnect"); #ifdef _WIN32 if (!pcsc_connect) pcsc_connect = dlsym (handle, "SCardConnectA"); +#endif + pcsc_reconnect = dlsym (handle, "SCardReconnect"); +#ifdef _WIN32 + if (!pcsc_reconnect) + pcsc_reconnect = dlsym (handle, "SCardReconnectA"); #endif pcsc_disconnect = dlsym (handle, "SCardDisconnect"); pcsc_status = dlsym (handle, "SCardStatus"); @@ -1990,7 +2368,9 @@ apdu_open_reader (const char *portstr) 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 @@ -2001,11 +2381,13 @@ apdu_open_reader (const char *portstr) /* Note that set_timeout is currently not used and also not available under Windows. */ 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_release_context, !!pcsc_list_readers, + !!pcsc_get_status_change, !!pcsc_connect, + !!pcsc_reconnect, !!pcsc_disconnect, !!pcsc_status, !!pcsc_begin_transaction, @@ -2106,9 +2488,17 @@ apdu_reset (int slot) if ((sw = lock_slot (slot))) return sw; + reader_table[slot].last_status = 0; if (reader_table[slot].reset_reader) 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); return sw; } @@ -2143,7 +2533,16 @@ apdu_activate (int slot) /* We don't have an ATR or a card is present though inactive: do a reset now. */ if (reader_table[slot].reset_reader) - sw = reader_table[slot].reset_reader (slot); + { + reader_table[slot].last_status = 0; + 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); if (sw) - return sw; + { + reader_table[slot].last_status = 0; + 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) *status = s; diff --git a/g10/apdu.h b/g10/apdu.h index f31e42e3d..e0f50b72b 100644 --- a/g10/apdu.h +++ b/g10/apdu.h @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id$ */ #ifndef APDU_H diff --git a/g10/app-common.h b/g10/app-common.h index 8392b485d..f54f6da92 100644 --- a/g10/app-common.h +++ b/g10/app-common.h @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id$ */ #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_t select_application (ctrl_t ctrl, int slot, const char *name); 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_write_learn_status (app_t app, ctrl_t ctrl); 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 **fpr2, unsigned char **fpr3); -#endif /* GNUPG_MAJOR_VERSION != 1 */ int app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, 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, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen); -#if GNUPG_MAJOR_VERSION == 1 -#else /*-- app-nks.c --*/ int app_select_nks (app_t app); /*-- app-dinsig.c --*/ 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*/ diff --git a/g10/ccid-driver.c b/g10/ccid-driver.c index 0a876f0bc..01c8a9980 100644 --- a/g10/ccid-driver.c +++ b/g10/ccid-driver.c @@ -1307,6 +1307,8 @@ ccid_get_atr (ccid_driver_t handle, /* Note that we ignore the error code on purpose. */ 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. */ if (!handle->auto_ifsd) diff --git a/g10/ccid-driver.h b/g10/ccid-driver.h index 9cb23253b..82feed5c9 100644 --- a/g10/ccid-driver.h +++ b/g10/ccid-driver.h @@ -50,6 +50,8 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ */ #ifndef CCID_DRIVER_H diff --git a/g10/iso7816.c b/g10/iso7816.c index cbb314eb2..9eff9d3f7 100644 --- a/g10/iso7816.c +++ b/g10/iso7816.c @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id$ */ #include @@ -103,6 +105,17 @@ map_sw (int sw) 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. SLOT is the card and reader as created for example by apdu_open_reader (), AID is a buffer of size AIDLEN holding the @@ -113,15 +126,8 @@ map_sw (int sw) gpg_error_t 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 p1 = 0x0C; /* No FCI to be returned. */ - - 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); + sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid); return map_sw (sw); } diff --git a/g10/iso7816.h b/g10/iso7816.h index 97de9abbd..b9ba1800b 100644 --- a/g10/iso7816.h +++ b/g10/iso7816.h @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id$ */ #ifndef ISO7816_H