aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2004-09-20 13:15:37 +0000
committerWerner Koch <[email protected]>2004-09-20 13:15:37 +0000
commit5576f6ef6c08639638ae09730ea8454bae24da18 (patch)
tree603a98986c1c8a02a581fd52dc1334a1c80788a6
parent(apdu_open_reader): No fallback if a full CCID reader id has been (diff)
downloadgnupg-5576f6ef6c08639638ae09730ea8454bae24da18.tar.gz
gnupg-5576f6ef6c08639638ae09730ea8454bae24da18.zip
* cardglue.c (open_card): Use shutdown code if possible.
(check_card_serialno): Ditto. * ccid-driver.c (do_close_reader): Factored some code out from ... (ccid_close_reader): ..here. (ccid_shutdown_reader): New. * apdu.c (apdu_shutdown_reader): New. (shutdown_ccid_reader): New.
Diffstat (limited to '')
-rw-r--r--g10/ChangeLog12
-rw-r--r--g10/apdu.c24
-rw-r--r--g10/apdu.h1
-rw-r--r--g10/cardglue.c40
-rw-r--r--g10/ccid-driver.c144
-rw-r--r--g10/ccid-driver.h1
6 files changed, 179 insertions, 43 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 423e15a80..b4871247d 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,15 @@
+2004-09-20 Werner Koch <[email protected]>
+
+ * cardglue.c (open_card): Use shutdown code if possible.
+ (check_card_serialno): Ditto.
+
+ * ccid-driver.c (do_close_reader): Factored some code out from ...
+ (ccid_close_reader): ..here.
+ (ccid_shutdown_reader): New.
+
+ * apdu.c (apdu_shutdown_reader): New.
+ (shutdown_ccid_reader): New.
+
2004-09-17 Werner Koch <[email protected]>
* g10.c (list_config): New config option ccid-reader-id.
diff --git a/g10/apdu.c b/g10/apdu.c
index a3aa1ba9f..228fdec61 100644
--- a/g10/apdu.c
+++ b/g10/apdu.c
@@ -92,6 +92,7 @@ struct reader_table_s {
/* Function pointers intialized to the various backends. */
int (*close_reader)(int);
+ int (*shutdown_reader)(int);
int (*reset_reader)(int);
int (*get_status_reader)(int, unsigned int *);
int (*send_apdu_reader)(int,unsigned char *,size_t,
@@ -244,6 +245,7 @@ new_reader_slot (void)
}
#endif /*USE_GNU_PTH*/
reader_table[reader].close_reader = NULL;
+ reader_table[reader].shutdown_reader = NULL;
reader_table[reader].reset_reader = NULL;
reader_table[reader].get_status_reader = NULL;
reader_table[reader].send_apdu_reader = NULL;
@@ -1202,6 +1204,14 @@ close_ccid_reader (int slot)
static int
+shutdown_ccid_reader (int slot)
+{
+ ccid_shutdown_reader (reader_table[slot].ccid.handle);
+ return 0;
+}
+
+
+static int
reset_ccid_reader (int slot)
{
int err;
@@ -1300,6 +1310,7 @@ open_ccid_reader (const char *portstr)
}
reader_table[slot].close_reader = close_ccid_reader;
+ reader_table[slot].shutdown_reader = shutdown_ccid_reader;
reader_table[slot].reset_reader = reset_ccid_reader;
reader_table[slot].get_status_reader = get_status_ccid;
reader_table[slot].send_apdu_reader = send_apdu_ccid;
@@ -2051,6 +2062,19 @@ apdu_close_reader (int slot)
return SW_HOST_NOT_SUPPORTED;
}
+/* Shutdown a reader; that is basically the same as a close but keeps
+ the handle ready for later use. A apdu_reset_header should be used
+ to get it active again. */
+int
+apdu_shutdown_reader (int slot)
+{
+ if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+ return SW_HOST_NO_DRIVER;
+ if (reader_table[slot].shutdown_reader)
+ return reader_table[slot].shutdown_reader (slot);
+ return SW_HOST_NOT_SUPPORTED;
+}
+
/* Enumerate all readers and return information on whether this reader
is in use. The caller should start with SLOT set to 0 and
increment it with each call until an error is returned. */
diff --git a/g10/apdu.h b/g10/apdu.h
index a0654a242..f31e42e3d 100644
--- a/g10/apdu.h
+++ b/g10/apdu.h
@@ -76,6 +76,7 @@ int apdu_open_remote_reader (const char *portstr,
void *writefnc_value,
void (*closefnc) (void *opaque),
void *closefnc_value);
+int apdu_shutdown_reader (int slot);
int apdu_close_reader (int slot);
int apdu_enum_reader (int slot, int *used);
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
diff --git a/g10/cardglue.c b/g10/cardglue.c
index 7bb3c8488..5faa41bad 100644
--- a/g10/cardglue.c
+++ b/g10/cardglue.c
@@ -54,7 +54,6 @@ static APP current_app;
-
/* Create a serialno/fpr string from the serial number and the secret
key. caller must free the returned string. There is no error
return. [Taken from 1.9's keyid.c]*/
@@ -247,18 +246,25 @@ agent_release_card_info (struct agent_card_info_s *info)
static APP
open_card (void)
{
- int slot;
+ int slot = -1;
int rc;
APP app;
+ int did_shutdown = 0;
card_close ();
+
retry:
- slot = apdu_open_reader (default_reader_port);
- if (slot == -1)
+ if (did_shutdown)
+ apdu_reset (slot);
+ else
{
- log_error ("card reader not available\n");
- return NULL;
+ slot = apdu_open_reader (default_reader_port);
+ if (slot == -1)
+ {
+ log_error ("card reader not available\n");
+ return NULL;
+ }
}
app = xcalloc (1, sizeof *app);
@@ -268,11 +274,14 @@ open_card (void)
{
write_status_text (STATUS_CARDCTRL, "1");
+ did_shutdown = !!apdu_shutdown_reader (slot);
+
if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay",
_("Please insert the card and hit return or enter 'c' to cancel: "),
1) )
{
- apdu_close_reader (slot);
+ if (!did_shutdown)
+ apdu_close_reader (slot);
xfree (app);
goto retry;
}
@@ -323,7 +332,7 @@ card_close (void)
function return 0 is the present card is okay, -1 if the user
selected to insert a new card or an error value. Note that the
card context will be closed in all cases except for 0 as return
- value. */
+ value and if it was possible to merely shutdown the reader. */
static int
check_card_serialno (APP app, const char *serialno)
{
@@ -346,8 +355,12 @@ check_card_serialno (APP app, const char *serialno)
if (ask)
{
char buf[5+32+1];
+ int did_shutdown = 0;
- card_close ();
+ if (current_app && !apdu_shutdown_reader (current_app->slot))
+ did_shutdown = 1;
+ else
+ card_close ();
tty_printf (_("Please remove the current card and "
"insert the one with the serial number:\n"
" %.*s\n"), 32, serialno);
@@ -359,7 +372,14 @@ check_card_serialno (APP app, const char *serialno)
_("Hit return when ready "
"or enter 'c' to cancel: "),
1) )
- return -1;
+ {
+ card_close ();
+ return -1;
+ }
+ if (did_shutdown)
+ apdu_reset (current_app->slot);
+ else
+ card_close ();
return gpg_error (GPG_ERR_INV_ID);
}
return 0;
diff --git a/g10/ccid-driver.c b/g10/ccid-driver.c
index ccdcb461b..77fea944b 100644
--- a/g10/ccid-driver.c
+++ b/g10/ccid-driver.c
@@ -196,6 +196,7 @@ struct ccid_driver_s
int auto_ifsd;
int max_ifsd;
int ifsd;
+ int powered_off;
int has_pinpad;
};
@@ -863,6 +864,102 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
}
+static void
+do_close_reader (ccid_driver_t handle)
+{
+ int rc;
+ unsigned char msg[100];
+ size_t msglen;
+ unsigned char seqno;
+
+ if (!handle->powered_off)
+ {
+ msg[0] = PC_to_RDR_IccPowerOff;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, 0);
+ msglen = 10;
+
+ rc = bulk_out (handle, msg, msglen);
+ if (!rc)
+ bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno);
+ handle->powered_off = 1;
+ }
+ if (handle->idev)
+ {
+ usb_release_interface (handle->idev, 0);
+ usb_close (handle->idev);
+ handle->idev = NULL;
+ }
+}
+
+
+/* Reset a reader on HANDLE. This is useful in case a reader has been
+ plugged of and inserted at a different port. By resetting the
+ handle, the same reader will be get used. Note, that on error the
+ handle won't get released.
+
+ This does not return an ATR, so ccid_get_atr should be called right
+ after this one.
+*/
+int
+ccid_shutdown_reader (ccid_driver_t handle)
+{
+ int rc = 0;
+ struct usb_device *dev = NULL;
+ usb_dev_handle *idev = NULL;
+ unsigned char *ifcdesc_extra = NULL;
+ size_t ifcdesc_extra_len;
+
+ if (!handle || !handle->rid)
+ return CCID_DRIVER_ERR_INV_VALUE;
+
+ do_close_reader (handle);
+
+ idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
+ &ifcdesc_extra, &ifcdesc_extra_len);
+ if (!idev)
+ {
+ DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
+ return CCID_DRIVER_ERR_NO_READER;
+ }
+
+
+ handle->idev = idev;
+
+ if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
+ {
+ DEBUGOUT ("device not supported\n");
+ rc = CCID_DRIVER_ERR_NO_READER;
+ goto leave;
+ }
+
+ /* fixme: Do we need to claim and set the interface as
+ determined above? */
+ rc = usb_claim_interface (idev, 0);
+ if (rc)
+ {
+ DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+ rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+ goto leave;
+ }
+
+ leave:
+ free (ifcdesc_extra);
+ if (rc)
+ {
+ usb_close (handle->idev);
+ handle->idev = NULL;
+ }
+
+ return rc;
+
+}
+
+
/* Close the reader HANDLE. */
int
ccid_close_reader (ccid_driver_t handle)
@@ -870,34 +967,13 @@ ccid_close_reader (ccid_driver_t handle)
if (!handle || !handle->idev)
return 0;
- {
- int rc;
- unsigned char msg[100];
- size_t msglen;
- unsigned char seqno;
-
- msg[0] = PC_to_RDR_IccPowerOff;
- msg[5] = 0; /* slot */
- msg[6] = seqno = handle->seqno++;
- msg[7] = 0; /* RFU */
- msg[8] = 0; /* RFU */
- msg[9] = 0; /* RFU */
- set_msg_len (msg, 0);
- msglen = 10;
-
- rc = bulk_out (handle, msg, msglen);
- if (!rc)
- bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
- }
-
- usb_release_interface (handle->idev, 0);
- usb_close (handle->idev);
- handle->idev = NULL;
+ do_close_reader (handle);
free (handle->rid);
free (handle);
return 0;
}
+
/* Return False if a card is present and powered. */
int
ccid_check_card_presence (ccid_driver_t handle)
@@ -1120,6 +1196,8 @@ ccid_get_atr (ccid_driver_t handle,
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
if (rc)
return rc;
+
+ handle->powered_off = 0;
if (atr)
{
@@ -1680,16 +1758,16 @@ main (int argc, char **argv)
ccid_poll (ccid);
/* if (!ccid->has_pinpad) */
- {
- fputs ("verifying that CHV1 is 123456....\n", stderr);
- {
- static unsigned char apdu[] = {0, 0x20, 0, 0x81,
- 6, '1','2','3','4','5','6'};
- rc = ccid_transceive (ccid, apdu, sizeof apdu,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
- }
- }
+/* { */
+/* fputs ("verifying that CHV1 is 123456....\n", stderr); */
+/* { */
+/* static unsigned char apdu[] = {0, 0x20, 0, 0x81, */
+/* 6, '1','2','3','4','5','6'}; */
+/* rc = ccid_transceive (ccid, apdu, sizeof apdu, */
+/* result, sizeof result, &resultlen); */
+/* print_result (rc, result, resultlen); */
+/* } */
+/* } */
/* else */
/* { */
/* fputs ("verifying CHV1 using the PINPad ....\n", stderr); */
diff --git a/g10/ccid-driver.h b/g10/ccid-driver.h
index 23562b3b9..cbadb40c1 100644
--- a/g10/ccid-driver.h
+++ b/g10/ccid-driver.h
@@ -78,6 +78,7 @@ typedef struct ccid_driver_s *ccid_driver_t;
int ccid_set_debug_level (int level);
char *ccid_get_reader_list (void);
int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
+int ccid_shutdown_reader (ccid_driver_t handle);
int ccid_close_reader (ccid_driver_t handle);
int ccid_get_atr (ccid_driver_t handle,
unsigned char *atr, size_t maxatrlen, size_t *atrlen);