Package: libccid
Version: 1.4.4-1
Severity: normal
Tags: upstream patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Upstream commit r4987 ("Use libusb-1.0 instead of libusb-0.1") breaks
communication with my reader (REINER SCT cyberJack RFID basis, USB
0c4b:9102).

When sending an APDU to the reader, e.g. via scriptor, libccid hangs
while waiting for data from the reader.

The pcscd log shows:
00000009 APDU: 60
00000010 ifdhandler.c:1283:IFDHTransmitToICC() 
usb:0c4b/9102:libudev:0:/dev/bus/usb/002/047 (lun: 0)
00000018 commands.c:1456:CmdXfrBlockAPDU_extended() T=0 (extended): 1 bytes
00000020 -> 000000 6F 01 00 00 00 00 0C 00 00 00 60 
00006239 <- 000000 80 00 00 00 00 00 0C 80 02 00 80 08 00 00 00 00 0C 00 00 00 
AF 04 01 01 01 00 16 05 
00000025 commands.c:1391:CCID_Receive() Time extension requested: 0x02
(now hangs there)

So what's happening is that libusb_bulk_transfer in ReadUSB returns two
messages at once, CCID_Receive calls ReadUSB again but the data already
has been read. For some reason this used to be different with libusb
0.x - I have no idea whether this is a timing issue or what not:

00000022 APDU: 60
00000017 ifdhandler.c:1264:IFDHTransmitToICC() 
usb:0c4b/9102:libudev:0:/dev/bus/usb/002/045 (lun: 0)
00000024 commands.c:1412:CmdXfrBlockAPDU_extended() T=0 (extended): 1 bytes
00000029 -> 000000 6F 01 00 00 00 00 0F 00 00 00 60
00001543 <- 000000 80 00 00 00 00 00 0F 80 02 00
00000034 commands.c:1347:CCID_Receive() Time extension requested: 0x02
00001971 <- 000000 80 08 00 00 00 00 0F 00 00 00 AF 04 01 01 01 00 16 05
00000038 SW: AF 04 01 01 01 00 16 05

I have attached a patch (against svn trunk, yet it applies to the source
.tgz with -p3) which fixes that for me, though I'm unsure whether
handling this for different cases as CCID_TIME_EXTENSION might be
necessary.

Sebastian

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iD8DBQFOPvpMvBVic1oTsEgRAtfuAJ41KuYLg95oayPbpOUbDhlogGax5gCdFfpV
ffnq0SrZC9P1YOZUybTI/PI=
=K521
-----END PGP SIGNATURE-----
diff --git a/Drivers/ccid/src/commands.c b/Drivers/ccid/src/commands.c
index fec90cc..e2e13ab 100644
--- a/Drivers/ccid/src/commands.c
+++ b/Drivers/ccid/src/commands.c
@@ -1222,8 +1222,9 @@ RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
 RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
 	unsigned char rx_buffer[], unsigned char *chain_parameter)
 {
-	unsigned char cmd[10+CMD_BUF_SIZE];	/* CCID + APDU buffer */
-	unsigned int length;
+	unsigned char cmdbuf[10+CMD_BUF_SIZE];	/* CCID + APDU buffer */
+	unsigned char *cmd = cmdbuf;
+	unsigned int length, datalen;
 	RESPONSECODE return_value = IFD_SUCCESS;
 	status_t ret;
 
@@ -1341,9 +1342,12 @@ time_request_ICCD_B:
 	}
 #endif
 
-time_request:
-	length = sizeof(cmd);
-	ret = ReadPort(reader_index, &length, cmd);
+time_request_read:
+	length = sizeof(cmdbuf);
+	cmd = cmdbuf;
+	ret = ReadPort(reader_index, &length, cmdbuf);
+
+time_request_parse:
 	if (ret != STATUS_SUCCESS)
 	{
 		if (STATUS_NO_SUCH_DEVICE == ret)
@@ -1386,21 +1390,28 @@ time_request:
 		}
 	}
 
+	datalen = dw2i(cmd, 1);
 	if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
 	{
 		DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
-		goto time_request;
+		if (length-10 > datalen) {
+			DEBUG_COMM("Still data available, not reading again");
+			length -= (datalen+10);
+			cmd    += (datalen+10);
+			goto time_request_parse;
+		} else
+			goto time_request_read;
 	}
 
 	/* we have read less (or more) data than the CCID frame says to contain */
-	if (length-10 != dw2i(cmd, 1))
+	if (length-10 != datalen)
 	{
 		DEBUG_CRITICAL3("Can't read all data (%d out of %d expected)",
-			length-10, dw2i(cmd, 1));
+			length-10, datalen);
 		return_value = IFD_COMMUNICATION_ERROR;
 	}
 
-	length = dw2i(cmd, 1);
+	length = datalen;
 	if (length <= *rx_length)
 		*rx_length = length;
 	else

Reply via email to