diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/apdu.c | 560 | ||||
-rw-r--r-- | scd/apdu.h | 2 | ||||
-rw-r--r-- | scd/app-common.h | 6 | ||||
-rw-r--r-- | scd/app-nks.c | 37 | ||||
-rw-r--r-- | scd/app-openpgp.c | 11 | ||||
-rw-r--r-- | scd/app-p15.c | 2 | ||||
-rw-r--r-- | scd/app-piv.c | 27 | ||||
-rw-r--r-- | scd/app-sc-hsm.c | 2 | ||||
-rw-r--r-- | scd/app.c | 558 | ||||
-rw-r--r-- | scd/ccid-driver.c | 26 | ||||
-rw-r--r-- | scd/ccid-driver.h | 8 | ||||
-rw-r--r-- | scd/command.c | 102 | ||||
-rw-r--r-- | scd/iso7816.c | 1 | ||||
-rw-r--r-- | scd/scdaemon.c | 1 | ||||
-rw-r--r-- | scd/scdaemon.h | 3 |
15 files changed, 920 insertions, 426 deletions
diff --git a/scd/apdu.c b/scd/apdu.c index 2df113c5e..f86a63897 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -55,7 +55,7 @@ #include "ccid-driver.h" struct dev_list { - struct ccid_dev_table *ccid_table; + void *table; const char *portstr; int idx; int idx_max; @@ -76,6 +76,19 @@ typedef unsigned int pcsc_dword_t; typedef unsigned long pcsc_dword_t; #endif +#ifdef HAVE_W32_SYSTEM +#define HANDLE uintptr_t +#else +#define HANDLE long +#endif + +/* PC/SC context to access readers. Shared among all readers. */ +static struct pcsc_global_data { + HANDLE context; + int count; + const char *rdrname[MAX_READER]; +} pcsc; + /* A structure to collect information pertaining to one reader slot. */ struct reader_table_s { @@ -101,8 +114,7 @@ struct reader_table_s { ccid_driver_t handle; } ccid; struct { - long context; - long card; + HANDLE card; pcsc_dword_t protocol; pcsc_dword_t verify_ioctl; pcsc_dword_t modify_ioctl; @@ -288,35 +300,35 @@ typedef struct pcsc_readerstate_s *pcsc_readerstate_t; long (* DLSTDCALL pcsc_establish_context) (pcsc_dword_t scope, const void *reserved1, const void *reserved2, - long *r_context); -long (* DLSTDCALL pcsc_release_context) (long context); -long (* DLSTDCALL pcsc_list_readers) (long context, + HANDLE *r_context); +long (* DLSTDCALL pcsc_release_context) (HANDLE context); +long (* DLSTDCALL pcsc_list_readers) (HANDLE context, const char *groups, char *readers, pcsc_dword_t*readerslen); -long (* DLSTDCALL pcsc_get_status_change) (long context, +long (* DLSTDCALL pcsc_get_status_change) (HANDLE context, pcsc_dword_t timeout, pcsc_readerstate_t readerstates, pcsc_dword_t nreaderstates); -long (* DLSTDCALL pcsc_connect) (long context, +long (* DLSTDCALL pcsc_connect) (HANDLE context, const char *reader, pcsc_dword_t share_mode, pcsc_dword_t preferred_protocols, - long *r_card, + HANDLE *r_card, pcsc_dword_t *r_active_protocol); -long (* DLSTDCALL pcsc_reconnect) (long card, +long (* DLSTDCALL pcsc_reconnect) (HANDLE card, pcsc_dword_t share_mode, pcsc_dword_t preferred_protocols, pcsc_dword_t initialization, pcsc_dword_t *r_active_protocol); -long (* DLSTDCALL pcsc_disconnect) (long card, +long (* DLSTDCALL pcsc_disconnect) (HANDLE card, pcsc_dword_t disposition); -long (* DLSTDCALL pcsc_status) (long card, +long (* DLSTDCALL pcsc_status) (HANDLE card, char *reader, pcsc_dword_t *readerlen, pcsc_dword_t *r_state, pcsc_dword_t *r_protocol, unsigned char *atr, pcsc_dword_t *atrlen); long (* DLSTDCALL pcsc_begin_transaction) (long card); -long (* DLSTDCALL pcsc_end_transaction) (long card, +long (* DLSTDCALL pcsc_end_transaction) (HANDLE card, pcsc_dword_t disposition); long (* DLSTDCALL pcsc_transmit) (long card, const pcsc_io_request_t send_pci, @@ -325,9 +337,9 @@ long (* DLSTDCALL pcsc_transmit) (long card, pcsc_io_request_t recv_pci, unsigned char *recv_buffer, pcsc_dword_t *recv_len); -long (* DLSTDCALL pcsc_set_timeout) (long context, +long (* DLSTDCALL pcsc_set_timeout) (HANDLE context, pcsc_dword_t timeout); -long (* DLSTDCALL pcsc_control) (long card, +long (* DLSTDCALL pcsc_control) (HANDLE card, pcsc_dword_t control_code, const void *send_buffer, pcsc_dword_t send_len, @@ -652,9 +664,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire) memset (rdrstates, 0, sizeof *rdrstates); rdrstates[0].reader = reader_table[slot].rdrname; rdrstates[0].current_state = reader_table[slot].pcsc.current_state; - err = pcsc_get_status_change (reader_table[slot].pcsc.context, - 0, - rdrstates, 1); + err = pcsc_get_status_change (pcsc.context, 0, rdrstates, 1); if (err == PCSC_E_TIMEOUT) err = 0; /* Timeout is no error here. */ if (err) @@ -788,7 +798,16 @@ control_pcsc (int slot, pcsc_dword_t ioctl_code, static int close_pcsc_reader (int slot) { - pcsc_release_context (reader_table[slot].pcsc.context); + (void)slot; + if (--pcsc.count == 0) + { + int i; + + pcsc_release_context (pcsc.context); + pcsc.context = 0; + for (i = 0; i < MAX_READER; i++) + pcsc.rdrname[i] = NULL; + } return 0; } @@ -807,7 +826,7 @@ connect_pcsc_card (int slot) reader_table[slot].atrlen = 0; reader_table[slot].is_t0 = 0; - err = pcsc_connect (reader_table[slot].pcsc.context, + err = pcsc_connect (pcsc.context, reader_table[slot].rdrname, PCSC_SHARE_EXCLUSIVE, PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, @@ -829,7 +848,7 @@ connect_pcsc_card (int slot) pcsc_vendor_specific_init (slot); atrlen = DIM (reader_table[0].atr); - readerlen = sizeof reader -1 ; + readerlen = sizeof reader - 1; err = pcsc_status (reader_table[slot].pcsc.card, reader, &readerlen, &card_state, &card_protocol, @@ -1042,94 +1061,128 @@ pcsc_vendor_specific_init (int slot) return 0; } - -/* Open the PC/SC reader without using the wrapper. Returns -1 on - error or a slot number for the reader. */ static int -open_pcsc_reader (const char *portstr) +pcsc_init (void) { + static int pcsc_api_loaded; long err; - int slot; - char *list = NULL; - char *rdrname = NULL; - pcsc_dword_t nreader; - char *p; - - slot = new_reader_slot (); - if (slot == -1) - return -1; - /* Fixme: Allocating a context for each slot is not required. One - global context should be sufficient. */ - err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, - &reader_table[slot].pcsc.context); - if (err) + /* Lets try the PC/SC API */ + if (!pcsc_api_loaded) { - log_error ("pcsc_establish_context failed: %s (0x%lx)\n", - pcsc_error_string (err), err); - reader_table[slot].used = 0; - unlock_slot (slot); - return -1; - } + void *handle; - err = pcsc_list_readers (reader_table[slot].pcsc.context, - NULL, NULL, &nreader); - if (!err) - { - list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */ - if (!list) + handle = dlopen (opt.pcsc_driver, RTLD_LAZY); + if (!handle) { - log_error ("error allocating memory for reader list\n"); - pcsc_release_context (reader_table[slot].pcsc.context); - reader_table[slot].used = 0; - unlock_slot (slot); - return -1 /*SW_HOST_OUT_OF_CORE*/; + log_error ("apdu_open_reader: failed to open driver '%s': %s\n", + opt.pcsc_driver, dlerror ()); + return -1; + } + + pcsc_establish_context = dlsym (handle, "SCardEstablishContext"); + pcsc_release_context = dlsym (handle, "SCardReleaseContext"); + pcsc_list_readers = dlsym (handle, "SCardListReaders"); +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcsc_list_readers) + pcsc_list_readers = dlsym (handle, "SCardListReadersA"); +#endif + pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange"); +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcsc_get_status_change) + pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA"); +#endif + pcsc_connect = dlsym (handle, "SCardConnect"); +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcsc_connect) + pcsc_connect = dlsym (handle, "SCardConnectA"); +#endif + pcsc_reconnect = dlsym (handle, "SCardReconnect"); +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcsc_reconnect) + pcsc_reconnect = dlsym (handle, "SCardReconnectA"); +#endif + pcsc_disconnect = dlsym (handle, "SCardDisconnect"); + pcsc_status = dlsym (handle, "SCardStatus"); +#if defined(_WIN32) || defined(__CYGWIN__) + if (!pcsc_status) + pcsc_status = dlsym (handle, "SCardStatusA"); +#endif + pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction"); + pcsc_end_transaction = dlsym (handle, "SCardEndTransaction"); + pcsc_transmit = dlsym (handle, "SCardTransmit"); + pcsc_set_timeout = dlsym (handle, "SCardSetTimeout"); + pcsc_control = dlsym (handle, "SCardControl"); + + 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 + || !pcsc_end_transaction + || !pcsc_transmit + || !pcsc_control + /* || !pcsc_set_timeout */) + { + /* 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%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, + !!pcsc_end_transaction, + !!pcsc_transmit, + !!pcsc_set_timeout, + !!pcsc_control ); + dlclose (handle); + return -1; } - err = pcsc_list_readers (reader_table[slot].pcsc.context, - NULL, list, &nreader); + pcsc_api_loaded = 1; } + + err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, + &pcsc.context); if (err) { - log_error ("pcsc_list_readers failed: %s (0x%lx)\n", + log_error ("pcsc_establish_context 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); - unlock_slot (slot); return -1; } - p = list; - while (nreader) - { - if (!*p && !p[1]) - break; - log_info ("detected reader '%s'\n", p); - if (nreader < (strlen (p)+1)) - { - log_error ("invalid response from pcsc_list_readers\n"); - break; - } - if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr))) - rdrname = p; - nreader -= strlen (p)+1; - p += strlen (p) + 1; - } + return 0; +} - if (!rdrname) - rdrname = list; +/* Open the PC/SC reader. Returns -1 on error or a slot number for + the reader. */ +static int +open_pcsc_reader (const char *rdrname) +{ + int slot; + + slot = new_reader_slot (); + if (slot == -1) + return -1; reader_table[slot].rdrname = xtrystrdup (rdrname); if (!reader_table[slot].rdrname) { log_error ("error allocating memory for reader name\n"); - pcsc_release_context (reader_table[slot].pcsc.context); + close_pcsc_reader (0); reader_table[slot].used = 0; unlock_slot (slot); return -1; } - xfree (list); - list = NULL; reader_table[slot].pcsc.card = 0; reader_table[slot].atrlen = 0; @@ -1142,6 +1195,7 @@ open_pcsc_reader (const char *portstr) reader_table[slot].send_apdu_reader = pcsc_send_apdu; reader_table[slot].dump_status_reader = dump_pcsc_reader_status; + pcsc.count++; dump_reader_status (slot); unlock_slot (slot); return slot; @@ -1520,7 +1574,7 @@ open_ccid_reader (struct dev_list *dl) return -1; slotp = reader_table + slot; - err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table, + err = ccid_open_reader (dl->portstr, dl->idx, dl->table, &slotp->ccid.handle, &slotp->rdrname); if (!err) { @@ -1866,51 +1920,111 @@ gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p) { struct dev_list *dl = xtrymalloc (sizeof (struct dev_list)); + gpg_error_t err; *l_p = NULL; if (!dl) return gpg_error_from_syserror (); + dl->table = NULL; dl->portstr = portstr; dl->idx = 0; + dl->idx_max = 0; npth_mutex_lock (&reader_table_lock); #ifdef HAVE_LIBUSB - if (opt.disable_ccid) + if (!opt.disable_ccid) { - dl->ccid_table = NULL; - dl->idx_max = 1; + err = ccid_dev_scan (&dl->idx_max, &dl->table); + if (err) + { + npth_mutex_unlock (&reader_table_lock); + return err; + } + + if (dl->idx_max == 0) + { + if (DBG_READER) + log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n"); + + xfree (dl); + npth_mutex_unlock (&reader_table_lock); + return gpg_error (GPG_ERR_ENODEV); + } } else - { - gpg_error_t err; +#endif + { /* PC/SC readers. */ + long r; + pcsc_dword_t nreader; + char *p = NULL; - err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table); - if (err) - return err; + if (!pcsc.context) + if (pcsc_init () < 0) + { + npth_mutex_unlock (&reader_table_lock); + return gpg_error (GPG_ERR_NO_SERVICE); + } - if (dl->idx_max == 0) + r = pcsc_list_readers (pcsc.context, NULL, NULL, &nreader); + if (!r) { - /* If a CCID reader specification has been given, the user does - not want a fallback to other drivers. */ - if (portstr && strlen (portstr) > 5 && portstr[4] == ':') + p = xtrymalloc (nreader); + if (!p) { - if (DBG_READER) - log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n"); + err = gpg_error_from_syserror (); - xfree (dl); + log_error ("error allocating memory for reader list\n"); + close_pcsc_reader (0); npth_mutex_unlock (&reader_table_lock); - return gpg_error (GPG_ERR_ENODEV); + return err; + } + r = pcsc_list_readers (pcsc.context, NULL, p, &nreader); + } + if (r) + { + log_error ("pcsc_list_readers failed: %s (0x%lx)\n", + pcsc_error_string (r), r); + xfree (p); + close_pcsc_reader (0); + npth_mutex_unlock (&reader_table_lock); + return gpg_error (GPG_ERR_NO_SERVICE); + } + + dl->table = p; + dl->idx_max = 0; + + while (nreader > 0) + { + size_t n; + + if (!*p) + break; + + for (n = 0; n < nreader; n++) + if (!p[n]) + break; + + if (n >= nreader) + { + log_error ("invalid response from pcsc_list_readers\n"); + break; + } + + log_info ("detected reader '%s'\n", p); + pcsc.rdrname[dl->idx_max] = p; + nreader -= n + 1; + p += n + 1; + dl->idx_max++; + if (dl->idx_max > MAX_READER) + { + log_error ("too many readers from pcsc_list_readers\n"); + dl->idx_max--; + break; } - else - dl->idx_max = 1; } } -#else - dl->ccid_table = NULL; - dl->idx_max = 1; -#endif /* HAVE_LIBUSB */ *l_p = dl; return 0; @@ -1920,161 +2034,65 @@ void apdu_dev_list_finish (struct dev_list *dl) { #ifdef HAVE_LIBUSB - if (dl->ccid_table) - ccid_dev_scan_finish (dl->ccid_table, dl->idx_max); + if (!opt.disable_ccid) + { + if (dl->table) + ccid_dev_scan_finish (dl->table, dl->idx_max); + } + else #endif + { /* PC/SC readers. */ + int i; + + xfree (dl->table); + for (i = 0; i < MAX_READER; i++) + pcsc.rdrname[i] = NULL; + } xfree (dl); npth_mutex_unlock (&reader_table_lock); } -/* Open the reader and return an internal slot number or -1 on - error. If PORTSTR is NULL we default to a suitable port (for ctAPI: - the first USB reader. For PC/SC the first listed reader). */ -static int -apdu_open_one_reader (const char *portstr) +int +apdu_open_reader (struct dev_list *dl) { - static int pcsc_api_loaded; int slot; + int readerno; - if (DBG_READER) - log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr); + if (!dl->table) + return -1; - /* Lets try the PC/SC API */ - if (!pcsc_api_loaded) + /* See whether we want to use the reader ID string or a reader + number. A readerno of -1 indicates that the reader ID string is + to be used. */ + if (dl->portstr && strchr (dl->portstr, ':')) + readerno = -1; /* We want to use the readerid. */ + else if (dl->portstr) { - void *handle; - - handle = dlopen (opt.pcsc_driver, RTLD_LAZY); - if (!handle) - { - log_error ("apdu_open_reader: failed to open driver '%s': %s\n", - opt.pcsc_driver, dlerror ()); - return -1; - } + readerno = atoi (dl->portstr); + if (readerno < 0 || readerno >= dl->idx_max) + return -1; - pcsc_establish_context = dlsym (handle, "SCardEstablishContext"); - pcsc_release_context = dlsym (handle, "SCardReleaseContext"); - pcsc_list_readers = dlsym (handle, "SCardListReaders"); -#if defined(_WIN32) || defined(__CYGWIN__) - if (!pcsc_list_readers) - pcsc_list_readers = dlsym (handle, "SCardListReadersA"); -#endif - pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange"); -#if defined(_WIN32) || defined(__CYGWIN__) - if (!pcsc_get_status_change) - pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA"); -#endif - pcsc_connect = dlsym (handle, "SCardConnect"); -#if defined(_WIN32) || defined(__CYGWIN__) - if (!pcsc_connect) - pcsc_connect = dlsym (handle, "SCardConnectA"); -#endif - pcsc_reconnect = dlsym (handle, "SCardReconnect"); -#if defined(_WIN32) || defined(__CYGWIN__) - if (!pcsc_reconnect) - pcsc_reconnect = dlsym (handle, "SCardReconnectA"); -#endif - pcsc_disconnect = dlsym (handle, "SCardDisconnect"); - pcsc_status = dlsym (handle, "SCardStatus"); -#if defined(_WIN32) || defined(__CYGWIN__) - if (!pcsc_status) - pcsc_status = dlsym (handle, "SCardStatusA"); -#endif - pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction"); - pcsc_end_transaction = dlsym (handle, "SCardEndTransaction"); - pcsc_transmit = dlsym (handle, "SCardTransmit"); - pcsc_set_timeout = dlsym (handle, "SCardSetTimeout"); - pcsc_control = dlsym (handle, "SCardControl"); - - 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 - || !pcsc_end_transaction - || !pcsc_transmit - || !pcsc_control - /* || !pcsc_set_timeout */) - { - /* 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%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, - !!pcsc_end_transaction, - !!pcsc_transmit, - !!pcsc_set_timeout, - !!pcsc_control ); - dlclose (handle); - return -1; - } - pcsc_api_loaded = 1; + dl->idx = readerno; + dl->portstr = NULL; } - - slot = open_pcsc_reader (portstr); - - if (DBG_READER) - log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot); - return slot; -} - -int -apdu_open_reader (struct dev_list *dl, int app_empty) -{ - int slot; + else + readerno = 0; /* Default. */ #ifdef HAVE_LIBUSB - if (dl->ccid_table) + if (!opt.disable_ccid) { /* CCID readers. */ - int readerno; - - /* See whether we want to use the reader ID string or a reader - number. A readerno of -1 indicates that the reader ID string is - to be used. */ - if (dl->portstr && strchr (dl->portstr, ':')) - readerno = -1; /* We want to use the readerid. */ - else if (dl->portstr) - { - readerno = atoi (dl->portstr); - if (readerno < 0) - { - return -1; - } - } - else - readerno = 0; /* Default. */ - if (readerno > 0) { /* Use single, the specific reader. */ - if (readerno >= dl->idx_max) - return -1; - - dl->idx = readerno; - dl->portstr = NULL; slot = open_ccid_reader (dl); + /* And stick the reader and no scan. */ dl->idx = dl->idx_max; - if (slot >= 0) - return slot; - else - return -1; + return slot; } while (dl->idx < dl->idx_max) { - unsigned int bai = ccid_get_BAI (dl->idx, dl->ccid_table); + unsigned int bai = ccid_get_BAI (dl->idx, dl->table); if (DBG_READER) log_debug ("apdu_open_reader: BAI=%x\n", bai); @@ -2107,25 +2125,60 @@ apdu_open_reader (struct dev_list *dl, int app_empty) dl->idx++; } - /* Not found. Try one for PC/SC, only when it's the initial scan. */ - if (app_empty && dl->idx == dl->idx_max) - { - dl->idx++; - slot = apdu_open_one_reader (dl->portstr); - } - else - slot = -1; + /* Not found. */ + slot = -1; } else #endif { /* PC/SC readers. */ - if (app_empty && dl->idx == 0) + if (readerno > 0) + { /* Use single, the specific reader. */ + slot = open_pcsc_reader (pcsc.rdrname[readerno]); + /* And stick the reader and no scan. */ + dl->idx = dl->idx_max; + return slot; + } + + while (dl->idx < dl->idx_max) { - dl->idx++; - slot = apdu_open_one_reader (dl->portstr); + const char *rdrname = pcsc.rdrname[dl->idx]; + + if (DBG_READER) + log_debug ("apdu_open_reader: %s\n", rdrname); + + /* Check the identity of reader against already opened one. */ + for (slot = 0; slot < MAX_READER; slot++) + if (reader_table[slot].used + && !strcmp (reader_table[slot].rdrname, rdrname)) + break; + + if (slot == MAX_READER) + { /* Found a new device. */ + if (DBG_READER) + log_debug ("apdu_open_reader: new device=%s\n", rdrname); + + /* When reader string is specified, check if it is the one. */ + if (readerno < 0 && strcmp (rdrname, dl->portstr) != 0) + continue; + + slot = open_pcsc_reader (rdrname); + + dl->idx++; + if (slot >= 0) + return slot; + else + { + /* Skip this reader. */ + log_error ("pcsc open error: skip\n"); + continue; + } + } + else + dl->idx++; } - else - slot = -1; + + /* Not found. */ + slot = -1; } return slot; @@ -3305,6 +3358,11 @@ apdu_init (void) gpg_error_t err; int i; + pcsc.count = 0; + pcsc.context = 0; + for (i = 0; i < MAX_READER; i++) + pcsc.rdrname[i] = NULL; + if (npth_mutex_init (&reader_table_lock, NULL)) goto leave; diff --git a/scd/apdu.h b/scd/apdu.h index 89df45cb8..cdf94ccca 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -93,7 +93,7 @@ gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p); void apdu_dev_list_finish (struct dev_list *l); /* Note, that apdu_open_reader returns no status word but -1 on error. */ -int apdu_open_reader (struct dev_list *l, int app_empty); +int apdu_open_reader (struct dev_list *l); int apdu_open_remote_reader (const char *portstr, const unsigned char *cookie, size_t length, int (*readfnc) (void *opaque, diff --git a/scd/app-common.h b/scd/app-common.h index 5866c9b32..87f63bb7e 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -39,9 +39,13 @@ /* Flags used with app_readkey. */ #define APP_READKEY_FLAG_INFO 1 /* Send also a KEYPAIRINFO line. */ -/* Bit flags set by the decipher function into R_INFO. */ +/* Flags set by the decipher function into R_INFO. */ #define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */ +/* Flags used by the app_write_learn_status. */ +#define APP_LEARN_FLAG_KEYPAIRINFO 1 /* Return only keypair infos. */ +#define APP_LEARN_FLAG_MULTI 2 /* Return info for all apps. */ + /* List of supported card types. Generic is the usual ISO7817-4 * compliant card. More specific card or token versions can be given diff --git a/scd/app-nks.c b/scd/app-nks.c index d12720cf6..bb5329bfe 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -309,8 +309,10 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) int special; } table[] = { { "$AUTHKEYID", 1 }, - { "NKS-VERSION", 2 }, - { "CHV-STATUS", 3 }, + { "$ENCRKEYID", 2 }, + { "$SIGNKEYID", 3 }, + { "NKS-VERSION", 4 }, + { "CHV-STATUS", 5 }, { NULL, 0 } }; gpg_error_t err = 0; @@ -340,13 +342,27 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } break; - case 2: /* NKS-VERSION */ + case 2: /* $ENCRKEYID */ + { + char const tmp[] = "NKS-NKS3.45B1"; + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + } + break; + + case 3: /* $SIGNKEYID */ + { + char const tmp[] = "NKS-NKS3.4531"; + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + } + break; + + case 4: /* NKS-VERSION */ snprintf (buffer, sizeof buffer, "%d", app->app_local->nks_version); send_status_info (ctrl, table[idx].name, buffer, strlen (buffer), NULL, 0); break; - case 3: /* CHV-STATUS */ + case 5: /* CHV-STATUS */ { /* Returns: PW1.CH PW2.CH PW1.CH.SIG PW2.CH.SIG That are the two global passwords followed by the two SigG passwords. @@ -386,6 +402,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg) char ct_buf[100], id_buf[100]; int i; const char *tag; + const char *usage; if (is_sigg) tag = "SIGG"; @@ -403,7 +420,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg) if (!!filelist[i].is_sigg != !!is_sigg) continue; - if (filelist[i].certtype && !(flags &1)) + if (filelist[i].certtype && !(flags & APP_LEARN_FLAG_KEYPAIRINFO)) { size_t len; @@ -435,9 +452,19 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg) { snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X", tag, filelist[i].fid); + if (filelist[i].issignkey && filelist[i].isenckey) + usage = "sae"; + else if (filelist[i].issignkey) + usage = "sa"; + else if (filelist[i].isenckey) + usage = "e"; + else + usage = ""; + send_status_info (ctrl, "KEYPAIRINFO", gripstr, 40, id_buf, strlen (id_buf), + usage, strlen (usage), NULL, (size_t)0); } } diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 767f29d26..4f76caac3 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4296,7 +4296,8 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key) KEYIDSTR is either: (1) Serial number (2) Serial number "/" fingerprint - (3) keygrip + (3) Serial number "[CHV3]" + (4) keygrip When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should be to be compared is the first one (keygrip for signing). @@ -4335,8 +4336,6 @@ check_keyidstr (app_t app, const char *keyidstr, int keyno) ; /* no fingerprint given: we allow this for now. */ else if (*s == '/') fpr = s + 1; - else - return gpg_error (GPG_ERR_INV_ID); for (s=keyidstr, n=0; n < 16; s += 2, n++) tmp_sn[n] = xtoi_2 (s); @@ -5229,6 +5228,12 @@ do_reselect (app_t app, ctrl_t ctrl) * a special flag value. */ err = iso7816_select_application (app_get_slot (app), openpgp_aid, sizeof openpgp_aid, 0x0001); + if (!err) + { + app->did_chv1 = 0; + app->did_chv2 = 0; + app->did_chv3 = 0; + } return err; } diff --git a/scd/app-p15.c b/scd/app-p15.c index ce82b34a9..348242f4f 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -2500,7 +2500,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) { gpg_error_t err; - if ((flags & 1)) + if ((flags & APP_LEARN_FLAG_KEYPAIRINFO)) err = 0; else { diff --git a/scd/app-piv.c b/scd/app-piv.c index 3b94a28e4..3cc7754df 100644 --- a/scd/app-piv.c +++ b/scd/app-piv.c @@ -1176,7 +1176,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) for (i=0; data_objects[i].tag; i++) if (data_objects[i].keypair) - send_keypair_and_cert_info (app, ctrl, data_objects + i, !!(flags & 1)); + send_keypair_and_cert_info (app, ctrl, data_objects + i, + !!(flags & APP_LEARN_FLAG_KEYPAIRINFO)); return 0; @@ -1365,7 +1366,7 @@ find_dobj_by_keyref (app_t app, const char *keyref) (void)app; - if (!ascii_strncasecmp (keyref, "PIV.", 4)) + if (!ascii_strncasecmp (keyref, "PIV.", 4)) /* Standard keyref */ { keyref += 4; for (i=0; data_objects[i].tag; i++) @@ -1375,7 +1376,7 @@ find_dobj_by_keyref (app_t app, const char *keyref) return data_objects + i; } } - else if (!strncmp (keyref, "2.16.840.1.101.3.7.", 19)) + else if (!strncmp (keyref, "2.16.840.1.101.3.7.", 19)) /* OID */ { keyref += 19; for (i=0; data_objects[i].tag; i++) @@ -1385,6 +1386,26 @@ find_dobj_by_keyref (app_t app, const char *keyref) return data_objects + i; } } + else if (strlen (keyref) == 40) /* A keygrip */ + { + char *keygripstr = NULL; + int tag, dummy_got_cert; + + for (i=0; (tag=data_objects[i].tag); i++) + { + if (!data_objects[i].keypair) + continue; + xfree (keygripstr); + if (get_keygrip_by_tag (app, tag, &keygripstr, &dummy_got_cert)) + continue; + if (!strcmp (keygripstr, keyref)) + { + xfree (keygripstr); + return data_objects + i; + } + } + xfree (keygripstr); + } return NULL; } diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index 16d25b581..2f1ab2074 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -1407,7 +1407,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) { gpg_error_t err; - if ((flags & 1)) + if ((flags & APP_LEARN_FLAG_KEYPAIRINFO)) err = 0; else { @@ -30,6 +30,11 @@ #include "apdu.h" #include "../common/tlv.h" + +/* Forward declaration of internal function. */ +static gpg_error_t +select_additional_application_internal (card_t card, apptype_t req_apptype); + /* Lock to protect the list of cards and its associated * applications. */ static npth_mutex_t card_list_lock; @@ -91,6 +96,13 @@ strapptype (apptype_t t) } +const char * +xstrapptype (app_t app) +{ + return app? strapptype (app->apptype) : "[no_app]"; +} + + /* Return the apptype for NAME. */ static apptype_t apptype_from_name (const char *name) @@ -109,6 +121,31 @@ apptype_from_name (const char *name) } +/* Return the apptype for KEYREF. This is the first part of the + * KEYREF up to the dot. */ +static apptype_t +apptype_from_keyref (const char *keyref) +{ + int i; + unsigned int n; + const char *s; + + if (!keyref) + return APPTYPE_NONE; + s = strchr (keyref, '.'); + if (!s || s == keyref || !s[1]) + return APPTYPE_NONE; /* Not a valid keyref. */ + n = s - keyref; + + for (i=0; app_priority_list[i].apptype; i++) + if (strlen (app_priority_list[i].name) == n + && !ascii_strncasecmp (app_priority_list[i].name, keyref, n)) + return app_priority_list[i].apptype; + + return APPTYPE_NONE; +} + + /* Initialization function to change the default app_priority_list. * LIST is a list of comma or space separated strings with application * names. Unknown names will only result in warning message. @@ -231,6 +268,7 @@ app_dump_state (void) { log_info ("app_dump_state: card=%p slot=%d type=%s\n", c, c->slot, strcardtype (c->cardtype)); + /* FIXME The use of log_info risks a race! */ for (a=c->app; a; a = a->next) log_info ("app_dump_state: app=%p type='%s'\n", a, strapptype (a->apptype)); @@ -270,7 +308,7 @@ check_application_conflict (card_t card, const char *name, const unsigned char *serialno_bin, size_t serialno_bin_len) { - app_t app; + apptype_t apptype; if (!card || !name) return 0; @@ -284,11 +322,9 @@ check_application_conflict (card_t card, const char *name, return 0; /* The card does not match the requested S/N. */ } - /* Check whether the requested NAME matches any already selected - * application. */ - for (app = card->app; app; app = app->next) - if (!ascii_strcasecmp (strapptype (app->apptype), name)) - return 0; + apptype = apptype_from_name (name); + if (card->app->apptype == apptype) + return 0; if (card->app->apptype == APPTYPE_UNDEFINED) return 0; @@ -339,6 +375,7 @@ card_reset (card_t card, ctrl_t ctrl, int send_reset) else { ctrl->card_ctx = NULL; + ctrl->current_apptype = APPTYPE_NONE; card_unref (card); } @@ -608,7 +645,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, int slot; int periodical_check_needed_this; - slot = apdu_open_reader (l, !card_top); + slot = apdu_open_reader (l); if (slot < 0) break; @@ -652,6 +689,22 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, { err = check_application_conflict (card, name, NULL, 0); if (!err) + ctrl->current_apptype = card->app ? card->app->apptype : APPTYPE_NONE; + else if (gpg_err_code (err) == GPG_ERR_FALSE) + { + apptype_t req_apptype = apptype_from_name (name); + + if (!req_apptype) + err = gpg_error (GPG_ERR_NOT_FOUND); + else + { + err = select_additional_application_internal (card, req_apptype); + if (!err) + ctrl->current_apptype = req_apptype; + } + } + + if (!err) { /* Note: We do not use card_ref as we are already locked. */ card->ref_count++; @@ -662,8 +715,6 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, card->next = card_top; card_top = card; } - - ctrl->current_apptype = card->app ? card->app->apptype : 0; } unlock_card (card); } @@ -676,32 +727,13 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, } -/* This function needs to be called with the NAME of the new - * application to be selected on CARD. On success the application is - * added to the list of the card's active applications as currently - * active application. On error no new application is allocated. - * Selecting an already selected application has no effect. */ -gpg_error_t -select_additional_application (ctrl_t ctrl, const char *name) +static gpg_error_t +select_additional_application_internal (card_t card, apptype_t req_apptype) { gpg_error_t err = 0; - apptype_t req_apptype; - card_t card; - app_t app = NULL; + app_t app; int i; - req_apptype = apptype_from_name (name); - if (!req_apptype) - err = gpg_error (GPG_ERR_NOT_FOUND); - - card = ctrl->card_ctx; - if (!card) - return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - - err = lock_card (card, ctrl); - if (err) - return err; - /* Check that the requested app has not yet been put onto the list. */ for (app = card->app; app; app = app->next) if (app->apptype == req_apptype) @@ -713,7 +745,6 @@ select_additional_application (ctrl_t ctrl, const char *name) app = NULL; goto leave; } - app = NULL; /* Allocate a new app object. */ app = xtrycalloc (1, sizeof *app); @@ -723,13 +754,17 @@ select_additional_application (ctrl_t ctrl, const char *name) log_info ("error allocating app context: %s\n", gpg_strerror (err)); goto leave; } + app->card = card; /* Find the app and run the select. */ for (i=0; app_priority_list[i].apptype; i++) { if (app_priority_list[i].apptype == req_apptype && is_app_allowed (app_priority_list[i].name)) - err = app_priority_list[i].select_func (app); + { + err = app_priority_list[i].select_func (app); + break; + } } if (!app_priority_list[i].apptype || (err && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE)) @@ -742,12 +777,131 @@ select_additional_application (ctrl_t ctrl, const char *name) * reselect by maybe_switch_app after the select we just did. */ app->next = card->app; card->app = app; - ctrl->current_apptype = app->apptype; - log_error ("added app '%s' to the card context\n", strapptype(app->apptype)); + log_info ("added app '%s' to the card context and switched\n", + strapptype (app->apptype)); leave: + if (err) + xfree (app); + return err; +} + + +/* Add all possible additional applications to the card context but do + * not change the current one. This current works only for Yubikeys. */ +static gpg_error_t +select_all_additional_applications_internal (card_t card) +{ + gpg_error_t err = 0; + apptype_t candidates[3]; + int i, j; + + if (card->cardtype == CARDTYPE_YUBIKEY) + { + candidates[0] = APPTYPE_OPENPGP; + candidates[1] = APPTYPE_PIV; + candidates[2] = APPTYPE_NONE; + } + else + { + candidates[0] = APPTYPE_NONE; + } + + /* Find the app and run the select. */ + for (i=0; app_priority_list[i].apptype; i++) + { + app_t app, app_r, app_prev; + + for (j=0; candidates[j]; j++) + if (candidates[j] == app_priority_list[i].apptype + && is_app_allowed (app_priority_list[i].name)) + break; + if (!candidates[j]) + continue; + + for (app = card->app; app; app = app->next) + if (app->apptype == candidates[j]) + break; + if (app) + continue; /* Already on the list of apps. */ + + app = xtrycalloc (1, sizeof *app); + if (!app) + { + err = gpg_error_from_syserror (); + log_info ("error allocating app context: %s\n", gpg_strerror (err)); + goto leave; + } + app->card = card; + err = app_priority_list[i].select_func (app); + if (err) + { + log_error ("error selecting additional app '%s': %s - skipped\n", + strapptype (candidates[j]), gpg_strerror (err)); + err = 0; + xfree (app); + } + else + { + /* Append to the list of apps. */ + app_prev = card->app; + for (app_r=app_prev->next; app_r; app_prev=app_r, app_r=app_r->next) + ; + app_prev->next = app; + log_info ("added app '%s' to the card context\n", + strapptype (app->apptype)); + } + } + + leave: + return err; +} + + +/* This function needs to be called with the NAME of the new + * application to be selected on CARD. On success the application is + * added to the list of the card's active applications as currently + * active application. On error no new application is allocated. + * Selecting an already selected application has no effect. */ +gpg_error_t +select_additional_application (ctrl_t ctrl, const char *name) +{ + gpg_error_t err = 0; + apptype_t req_apptype; + card_t card; + + if (!name) + req_apptype = 0; + else + { + req_apptype = apptype_from_name (name); + if (!req_apptype) + return gpg_error (GPG_ERR_NOT_FOUND); + } + + card = ctrl->card_ctx; + if (!card) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + + err = lock_card (card, ctrl); + if (err) + return err; + + if (req_apptype) + { + err = select_additional_application_internal (card, req_apptype); + if (!err) + { + ctrl->current_apptype = req_apptype; + log_debug ("current_apptype is set to %s\n", name); + } + } + else + { + err = select_all_additional_applications_internal (card); + } + unlock_card (card); - xfree (app); return err; } @@ -809,8 +963,6 @@ deallocate_card (card_t card) xfree (a); } - scd_clear_current_app (card); - xfree (card->serialno); unlock_card (card); xfree (card); @@ -944,10 +1096,12 @@ app_get_serialno (app_t app) * that the new active app will be moved to the head of the list at * CARD->app. Thus function must be called with the card lock held. */ static gpg_error_t -maybe_switch_app (ctrl_t ctrl, card_t card) +maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref) { gpg_error_t err; - app_t app, app_prev; + app_t app; + app_t app_prev = NULL; + apptype_t apptype; if (!card->ref_count || !card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); @@ -958,51 +1112,117 @@ maybe_switch_app (ctrl_t ctrl, card_t card) ctrl->current_apptype = card->app->apptype; return 0; } - log_debug ("card=%p want=%s card->app=%s\n", - card, strapptype (ctrl->current_apptype), - strapptype (card->app->apptype)); - app_dump_state (); - if (ctrl->current_apptype == card->app->apptype) - return 0; /* No need to switch. */ - app_prev = card->app; - for (app = app_prev->next; app; app_prev = app, app = app->next) - if (app->apptype == ctrl->current_apptype) - break; + if (DBG_APP) + log_debug ("slot %d: have=%s want=%s keyref=%s\n", + card->slot, strapptype (card->app->apptype), + strapptype (ctrl->current_apptype), + keyref? keyref:"[none]"); + + app = NULL; + if (keyref) + { + /* Switch based on the requested KEYREF. */ + apptype = apptype_from_keyref (keyref); + if (apptype) + { + for (app = card->app; app; app_prev = app, app = app->next) + if (app->apptype == apptype) + break; + if (!app_prev && ctrl->current_apptype == card->app->apptype) + return 0; /* Already the first app - no need to switch. */ + } + else if (strlen (keyref) == 40) + { + /* This looks like a keygrip. Iterate over all apps to find + * the corresponding app. */ + for (app = card->app; app; app_prev = app, app = app->next) + if (app->fnc.with_keygrip + && !app->fnc.with_keygrip (app, ctrl, + KEYGRIP_ACTION_LOOKUP, keyref)) + break; + if (!app_prev && ctrl->current_apptype == card->app->apptype) + return 0; /* Already the first app - no need to switch. */ + } + } + + if (!app) + { + /* Switch based on the current application of this connection or + * if a keyref based switch didn't worked. */ + if (ctrl->current_apptype == card->app->apptype) + return 0; /* No need to switch. */ + app_prev = card->app; + for (app = app_prev->next; app; app_prev = app, app = app->next) + if (app->apptype == ctrl->current_apptype) + break; + } if (!app) return gpg_error (GPG_ERR_WRONG_CARD); if (!app->fnc.reselect) { log_error ("oops: reselect function missing for '%s'\n", - strapptype(app->apptype)); + strapptype (app->apptype)); return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); } err = app->fnc.reselect (app, ctrl); if (err) { - log_error ("error re-selecting '%s': %s\n", - strapptype(app->apptype), gpg_strerror (err)); + log_error ("card %d: error re-selecting '%s': %s\n", + card->slot, xstrapptype (app), gpg_strerror (err)); return err; } - /* Swap APP with the head of the app list. Note that APP is not the - * head of the list. */ - app_prev->next = app->next; - app->next = card->app; - card->app = app; + + /* Swap APP with the head of the app list if needed. Note that APP + * is not the head of the list. */ + if (app_prev) + { + app_prev->next = app->next; + app->next = card->app; + card->app = app; + } + + if (opt.verbose) + log_info ("card %d: %s '%s'\n", + card->slot, app_prev? "switched to":"re-selected", + xstrapptype (app)); + ctrl->current_apptype = app->apptype; - log_error ("switched to '%s'\n", strapptype(app->apptype)); return 0; } +/* Helper for app_write_learn_status. */ +static gpg_error_t +write_learn_status_core (card_t card, app_t app, ctrl_t ctrl, + unsigned int flags) +{ + /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ + if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO)) + { + if (card && card->cardtype) + send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); + if (card && card->cardversion) + send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); + if (app->apptype) + send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype)); + if (app->appversion) + send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); + } + + return app->fnc.learn_status (app, ctrl, flags); +} + + /* Write out the application specific status lines for the LEARN command. */ gpg_error_t app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) { - gpg_error_t err; + gpg_error_t err, err2; app_t app; + int any_reselect = 0; if (!card) return gpg_error (GPG_ERR_INV_VALUE); @@ -1011,29 +1231,43 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags) if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + /* Always make sure that the current app for this connection has + * been selected and is at the top of the list. */ + if ((err = maybe_switch_app (ctrl, card, NULL))) ; else if (!card->app->fnc.learn_status) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else { - app = card->app; - - /* We do not send CARD and APPTYPE if only keypairinfo is requested. */ - if (!(flags &1)) + err = write_learn_status_core (card, card->app, ctrl, flags); + if (!err && card->app->fnc.reselect && (flags & APP_LEARN_FLAG_MULTI)) { - if (card->cardtype) - send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype)); - if (card->cardversion) - send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion); - if (app->apptype) - send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype)); - if (app->appversion) - send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); - /* FIXME: Send info for the other active apps of the card? */ + /* The current app has the reselect feature so that we can + * loop over all other apps which are capable of a reselect + * and finally reselect the first app again. Note that we + * did the learn for the currently selected card above. */ + app = card->app; + for (app = app->next; app && !err; app = app->next) + if (app->fnc.reselect) + { + any_reselect = 1; + err = app->fnc.reselect (app, ctrl); + if (!err) + err = write_learn_status_core (NULL, app, ctrl, flags); + } + app = card->app; + if (any_reselect) + { + err2 = app->fnc.reselect (app, ctrl); + if (err2) + { + log_error ("error re-selecting '%s': %s\n", + strapptype(app->apptype), gpg_strerror (err2)); + if (!err) + err = err2; + } + } } - - err = app->fnc.learn_status (app, ctrl, flags); } unlock_card (card); @@ -1057,12 +1291,17 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, certid))) ; else if (!card->app->fnc.readcert) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.readcert (card->app, certid, cert, certlen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling readcert(%s)\n", + card->slot, xstrapptype (card->app), certid); + err = card->app->fnc.readcert (card->app, certid, cert, certlen); + } unlock_card (card); return err; @@ -1094,12 +1333,17 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keyid))) ; else if (!card->app->fnc.readkey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling readkey(%s)\n", + card->slot, xstrapptype (card->app), keyid); + err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); + } unlock_card (card); return err; @@ -1118,7 +1362,7 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, NULL))) ; else if (name && !strcmp (name, "CARDTYPE")) { @@ -1144,7 +1388,12 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name) else if (!card->app->fnc.getattr) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.getattr (card->app, ctrl, name); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling getattr(%s)\n", + card->slot, xstrapptype (card->app), name); + err = card->app->fnc.getattr (card->app, ctrl, name); + } unlock_card (card); return err; @@ -1166,13 +1415,18 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, NULL))) ; else if (!card->app->fnc.setattr) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg, - value, valuelen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling setattr(%s)\n", + card->slot, xstrapptype (card->app), name); + err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg, + value, valuelen); + } unlock_card (card); return err; @@ -1197,15 +1451,20 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keyidstr))) ; else if (!card->app->fnc.sign) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.sign (card->app, keyidstr, hashalgo, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling sign(%s)\n", + card->slot, xstrapptype (card->app), keyidstr); + err = card->app->fnc.sign (card->app, keyidstr, hashalgo, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + } unlock_card (card); if (opt.verbose) @@ -1233,15 +1492,20 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keyidstr))) ; else if (!card->app->fnc.auth) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.auth (card->app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling auth(%s)\n", + card->slot, xstrapptype (card->app), keyidstr); + err = card->app->fnc.auth (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + } unlock_card (card); if (opt.verbose) @@ -1271,16 +1535,21 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keyidstr))) ; else if (!card->app->fnc.decipher) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.decipher (card->app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen, - r_info); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling decipher(%s)\n", + card->slot, xstrapptype (card->app), keyidstr); + err = card->app->fnc.decipher (card->app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen, + r_info); + } unlock_card (card); if (opt.verbose) @@ -1305,13 +1574,18 @@ app_writecert (card_t card, ctrl_t ctrl, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, certidstr))) ; else if (!card->app->fnc.writecert) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.writecert (card->app, ctrl, certidstr, - pincb, pincb_arg, data, datalen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling writecert(%s)\n", + card->slot, xstrapptype (card->app), certidstr); + err = card->app->fnc.writecert (card->app, ctrl, certidstr, + pincb, pincb_arg, data, datalen); + } unlock_card (card); if (opt.verbose) @@ -1336,13 +1610,18 @@ app_writekey (card_t card, ctrl_t ctrl, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keyidstr))) ; else if (!card->app->fnc.writekey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, - pincb, pincb_arg, keydata, keydatalen); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling writekey(%s)\n", + card->slot, xstrapptype (card->app), keyidstr); + err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, + pincb, pincb_arg, keydata, keydatalen); + } unlock_card (card); if (opt.verbose) @@ -1366,13 +1645,18 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, keynostr))) ; else if (!card->app->fnc.genkey) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, - createtime, pincb, pincb_arg); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling genkey(%s)\n", + card->slot, xstrapptype (card->app), keynostr); + err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, + createtime, pincb, pincb_arg); + } unlock_card (card); if (opt.verbose) @@ -1421,13 +1705,18 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, NULL))) ; else if (!card->app->fnc.change_pin) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.change_pin (card->app, ctrl, - chvnostr, flags, pincb, pincb_arg); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling change_pin(%s)\n", + card->slot, xstrapptype (card->app), chvnostr); + err = card->app->fnc.change_pin (card->app, ctrl, + chvnostr, flags, pincb, pincb_arg); + } unlock_card (card); if (opt.verbose) @@ -1452,12 +1741,17 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr, if (err) return err; - if ((err = maybe_switch_app (ctrl, card))) + if ((err = maybe_switch_app (ctrl, card, NULL))) ; else if (!card->app->fnc.check_pin) err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); else - err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg); + { + if (DBG_APP) + log_debug ("slot %d app %s: calling check_pin(%s)\n", + card->slot, xstrapptype (card->app), keyidstr); + err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg); + } unlock_card (card); if (opt.verbose) @@ -1691,24 +1985,33 @@ app_send_card_list (ctrl_t ctrl) card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) { - gpg_error_t err; + int locked = 0; card_t c; app_t a; npth_mutex_lock (&card_list_lock); for (c = card_top; c; c = c->next) - for (a = c->app; a; a = a->next) - if (a->fnc.with_keygrip) + { + if (lock_card (c, ctrl)) { - if (!lock_card (c, ctrl)) - { - err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str); - unlock_card (c); - if (!err) - goto leave_the_loop; - } + c = NULL; + goto leave_the_loop; } + locked = 1; + for (a = c->app; a; a = a->next) + if (a->fnc.with_keygrip) + { + if (DBG_APP) + log_debug ("slot %d app %s: calling with_keygrip(action=%d)\n", + c->slot, xstrapptype (a), action); + if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) + goto leave_the_loop; + } + unlock_card (c); + locked = 0; + } + leave_the_loop: @@ -1721,6 +2024,11 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) if (c && c->app && c->app->apptype != a->apptype) ctrl->current_apptype = a->apptype; + if (locked && c) + { + unlock_card (c); + locked = 0; + } npth_mutex_unlock (&card_list_lock); return c; } diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index d762490c8..d3e9ef024 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1276,7 +1276,7 @@ static libusb_device **ccid_usb_dev_list; static struct ccid_dev_table ccid_dev_table[MAX_DEVICE]; gpg_error_t -ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p) +ccid_dev_scan (int *idx_max_p, void **t_p) { ssize_t n; libusb_device *dev; @@ -1403,9 +1403,10 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p) } void -ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max) +ccid_dev_scan_finish (void *tbl0, int max) { int i; + struct ccid_dev_table *tbl = tbl0; for (i = 0; i < max; i++) { @@ -1424,12 +1425,13 @@ ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max) } unsigned int -ccid_get_BAI (int idx, struct ccid_dev_table *tbl) +ccid_get_BAI (int idx, void *tbl0) { int n; int bus, addr, intf; unsigned int bai; libusb_device *dev; + struct ccid_dev_table *tbl = tbl0; n = tbl[idx].n; dev = ccid_usb_dev_list[n]; @@ -1537,7 +1539,7 @@ ccid_usb_thread (void *arg) static int ccid_open_usb_reader (const char *spec_reader_name, - int idx, struct ccid_dev_table *ccid_table, + int idx, void *ccid_table0, ccid_driver_t *handle, char **rdrname_p) { libusb_device *dev; @@ -1549,6 +1551,7 @@ ccid_open_usb_reader (const char *spec_reader_name, int n; int bus, addr; unsigned int bai; + struct ccid_dev_table *ccid_table = ccid_table0; n = ccid_table[idx].n; ifc_no = ccid_table[idx].interface_number; @@ -1678,9 +1681,11 @@ ccid_open_usb_reader (const char *spec_reader_name, pointer to be used as handle in HANDLE. Returns 0 on success. */ int ccid_open_reader (const char *spec_reader_name, int idx, - struct ccid_dev_table *ccid_table, + void *ccid_table0, ccid_driver_t *handle, char **rdrname_p) { + struct ccid_dev_table *ccid_table = ccid_table0; + *handle = calloc (1, sizeof **handle); if (!*handle) { @@ -1940,6 +1945,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, int rc; int msglen; int notified = 0; + int bwi = 1; /* Fixme: The next line for the current Valgrind without support for USB IOCTLs. */ @@ -1950,7 +1956,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, npth_unprotect (); #endif rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in, - buffer, length, &msglen, timeout); + buffer, length, &msglen, bwi*timeout); #ifdef USE_NPTH npth_protect (); #endif @@ -1998,6 +2004,10 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, DEBUGOUT_2 ("time extension requested (%02X,%02X)\n", buffer[7], buffer[8]); + bwi = 1; + if (buffer[8] != 0 && buffer[8] != 0xff) + bwi = buffer[8]; + /* Gnuk enhancement to prompt user input by ack button */ if (buffer[8] == 0xff && !notified) { @@ -2855,7 +2865,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle, size_t apdu_part_len; size_t msglen; unsigned char seqno; - int bwi = 4; + int bwi = 0; unsigned char chain = 0; if (apdu_len == 0 || apdu_len > sizeof (msg) - 10) @@ -3107,7 +3117,7 @@ ccid_transceive (ccid_driver_t handle, msg[0] = PC_to_RDR_XfrBlock; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; - msg[7] = (wait_more ? wait_more : 1); /* bBWI */ + msg[7] = wait_more; /* bBWI */ msg[8] = 0; /* RFU */ msg[9] = 0; /* RFU */ set_msg_len (msg, tpdulen); diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 1550b3eba..8e7ff4482 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -116,12 +116,12 @@ struct ccid_dev_table; int ccid_set_debug_level (int level); char *ccid_get_reader_list (void); -gpg_error_t ccid_dev_scan (int *idx_max, struct ccid_dev_table **t_p); -void ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max); -unsigned int ccid_get_BAI (int, struct ccid_dev_table *tbl); +gpg_error_t ccid_dev_scan (int *idx_max, void **t_p); +void ccid_dev_scan_finish (void *tbl0, int max); +unsigned int ccid_get_BAI (int, void *tbl0); int ccid_compare_BAI (ccid_driver_t handle, unsigned int); int ccid_open_reader (const char *spec_reader_name, - int idx, struct ccid_dev_table *ccid_table, + int idx, void *ccid_table0, ccid_driver_t *handle, char **rdrname_p); int ccid_set_progress_cb (ccid_driver_t handle, void (*cb)(void *, const char *, int, int, int), diff --git a/scd/command.c b/scd/command.c index 0096ca96d..73a524b49 100644 --- a/scd/command.c +++ b/scd/command.c @@ -105,6 +105,12 @@ static struct server_local_s *session_list; in this variable. */ static struct server_local_s *locked_session; + + +/* Local prototypes. */ +static int command_has_option (const char *cmd, const char *cmdopt); + + /* Convert the STRING into a newly allocated buffer while translating the hex numbers. Stops at the first invalid character. Blanks and @@ -218,10 +224,12 @@ open_card (ctrl_t ctrl) return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0); } -/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */ +/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. + * If OPT_ALL ist set also add all possible additional apps. */ static gpg_error_t open_card_with_request (ctrl_t ctrl, - const char *apptypestr, const char *serialno) + const char *apptypestr, const char *serialno, + int opt_all) { gpg_error_t err; unsigned char *serialno_bin = NULL; @@ -249,10 +257,13 @@ open_card_with_request (ctrl_t ctrl, /* Re-scan USB devices. Release CARD, before the scan. */ /* FIXME: Is a card_unref sufficient or do we need to deallocate? */ ctrl->card_ctx = NULL; + ctrl->current_apptype = APPTYPE_NONE; card_unref (card); err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1, serialno_bin, serialno_bin_len); + if (!err && opt_all) + err = select_additional_application (ctrl, APPTYPE_NONE); leave: xfree (serialno_bin); @@ -261,7 +272,7 @@ open_card_with_request (ctrl_t ctrl, static const char hlp_serialno[] = - "SERIALNO [--demand=<serialno>] [<apptype>]\n" + "SERIALNO [--demand=<serialno>] [--all] [<apptype>]\n" "\n" "Return the serial number of the card using a status response. This\n" "function should be used to check for the presence of a card.\n" @@ -269,6 +280,9 @@ static const char hlp_serialno[] = "If --demand is given, an application on the card with SERIALNO is\n" "selected and an error is returned if no such card available.\n" "\n" + "If --all is given, all possible other applications of the card are\n" + "will also be selected for on-the-fly swicthing.\n" + "\n" "If APPTYPE is given, an application of that type is selected and an\n" "error is returned if the application is not supported or available.\n" "The default is to auto-select the application using a hardwired\n" @@ -290,6 +304,7 @@ cmd_serialno (assuan_context_t ctx, char *line) int rc = 0; char *serial; const char *demand; + int opt_all = has_option (line, "--all"); if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); @@ -307,11 +322,13 @@ cmd_serialno (assuan_context_t ctx, char *line) else demand = NULL; + line = skip_options (line); + /* Clear the remove flag so that the open_card is able to reread it. */ if (ctrl->server_local->card_removed) ctrl->server_local->card_removed = 0; - if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand))) + if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand, opt_all))) { ctrl->server_local->card_removed = 1; return rc; @@ -337,7 +354,7 @@ cmd_serialno (assuan_context_t ctx, char *line) static const char hlp_learn[] = - "LEARN [--force] [--keypairinfo]\n" + "LEARN [--force] [--keypairinfo] [--multi]\n" "\n" "Learn all useful information of the currently inserted card. When\n" "used without the force options, the command might do an INQUIRE\n" @@ -365,7 +382,8 @@ static const char hlp_learn[] = " PIV = PIV card\n" " NKS = NetKey card\n" "\n" - "are implemented. These strings are aliases for the AID\n" + "are implemented. These strings are aliases for the AID. With option\n" + "--multi information for all switchable apps are returned.\n" "\n" " S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id> [<usage>]\n" "\n" @@ -412,6 +430,7 @@ cmd_learn (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); int rc = 0; int only_keypairinfo = has_option (line, "--keypairinfo"); + int opt_multi = has_option (line, "--multi"); if ((rc = open_card (ctrl))) return rc; @@ -474,7 +493,10 @@ cmd_learn (assuan_context_t ctx, char *line) /* Let the application print out its collection of useful status information. */ if (!rc) - rc = app_write_learn_status (ctrl->card_ctx, ctrl, only_keypairinfo); + rc = app_write_learn_status + (ctrl->card_ctx, ctrl, + ( (only_keypairinfo? APP_LEARN_FLAG_KEYPAIRINFO : 0) + | (opt_multi? APP_LEARN_FLAG_MULTI : 0)) ); return rc; } @@ -1557,7 +1579,9 @@ static const char hlp_getinfo[] = " application per line, fields delimited by colons,\n" " first field is the name.\n" " card_list - Return a list of serial numbers of active cards,\n" - " using a status response."; + " using a status response.\n" + " cmd_has_option CMD OPT\n" + " - Returns OK if command CMD has option OPT.\n"; static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { @@ -1575,6 +1599,38 @@ cmd_getinfo (assuan_context_t ctx, char *line) snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ()); rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); } + else if (!strncmp (line, "cmd_has_option", 14) + && (line[14] == ' ' || line[14] == '\t' || !line[14])) + { + char *cmd, *cmdopt; + line += 14; + while (*line == ' ' || *line == '\t') + line++; + if (!*line) + rc = gpg_error (GPG_ERR_MISSING_VALUE); + else + { + cmd = line; + while (*line && (*line != ' ' && *line != '\t')) + line++; + if (!*line) + rc = gpg_error (GPG_ERR_MISSING_VALUE); + else + { + *line++ = 0; + while (*line == ' ' || *line == '\t') + line++; + if (!*line) + rc = gpg_error (GPG_ERR_MISSING_VALUE); + else + { + cmdopt = line; + if (!command_has_option (cmd, cmdopt)) + rc = gpg_error (GPG_ERR_FALSE); + } + } + } + } else if (!strcmp (line, "socket_name")) { const char *s = scd_get_socket_name (); @@ -1661,6 +1717,7 @@ cmd_restart (assuan_context_t ctx, char *line) if (card) { ctrl->card_ctx = NULL; + ctrl->current_apptype = APPTYPE_NONE; card_unref (card); } if (locked_session && ctrl->server_local == locked_session) @@ -1917,6 +1974,20 @@ send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, +/* Return true if the command CMD implements the option OPT. */ +static int +command_has_option (const char *cmd, const char *cmdopt) +{ + if (!strcmp (cmd, "SERIALNO")) + { + if (!strcmp (cmdopt, "all")) + return 1; + } + + return 0; +} + + /* Tell the assuan library about our commands */ static int register_commands (assuan_context_t ctx) @@ -2079,20 +2150,6 @@ scd_command_handler (ctrl_t ctrl, int fd) } -/* Clear the current application info for CARD from all sessions. - * This is used while deallocating a card. */ -void -scd_clear_current_app (card_t card) -{ - struct server_local_s *sl; - - for (sl=session_list; sl; sl = sl->next_session) - { - if (sl->ctrl_backlink->card_ctx == card) - sl->ctrl_backlink->current_apptype = APPTYPE_NONE; - } -} - /* Send a line with status information via assuan and escape all given buffers. The variable elements are pairs of (char *, size_t), terminated with a (NULL, 0). */ @@ -2234,6 +2291,7 @@ send_client_notifications (card_t card, int removal) if (removal) { sl->ctrl_backlink->card_ctx = NULL; + sl->ctrl_backlink->current_apptype = APPTYPE_NONE; sl->card_removed = 1; card_unref_locked (card); } diff --git a/scd/iso7816.c b/scd/iso7816.c index 954aa3d4a..d44046e67 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -67,6 +67,7 @@ map_sw (int sw) case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break; case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break; case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break; + case SW_INCORRECT_P0_P1:ec = GPG_ERR_INV_VALUE; break; case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break; case SW_EXACT_LENGTH: ec = GPG_ERR_INV_VALUE; break; case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index e89569e5d..1796db386 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -177,6 +177,7 @@ static struct debug_flags_s debug_flags [] = { DBG_IPC_VALUE , "ipc" }, { DBG_CARD_IO_VALUE, "cardio" }, { DBG_READER_VALUE , "reader" }, + { DBG_APP_VALUE , "app" }, { 0, NULL } }; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index b709b1cbc..3f2e3ed55 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -67,6 +67,7 @@ struct } opt; +#define DBG_APP_VALUE 1 /* Debug app speific stuff. */ #define DBG_MPI_VALUE 2 /* debug mpi details */ #define DBG_CRYPTO_VALUE 4 /* debug low level crypto */ #define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */ @@ -77,6 +78,7 @@ struct #define DBG_CARD_IO_VALUE 2048 #define DBG_READER_VALUE 4096 /* Trace reader related functions. */ +#define DBG_APP (opt.debug & DBG_APP_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) #define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE) #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) @@ -127,7 +129,6 @@ const char *scd_get_socket_name (void); /*-- command.c --*/ gpg_error_t initialize_module_command (void); int scd_command_handler (ctrl_t, int); -void scd_clear_current_app (card_t card); void send_status_info (ctrl_t ctrl, const char *keyword, ...) GPGRT_ATTR_SENTINEL(1); void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args); |