The attached patch _should_ force the use of T=1 in a clean way. It
includes (and expands upon) the PTS/ccid patch I sent earlier. (I left the
ccid-specific parts out though).
If I decide to pick one of these devices up, I might try to fix the T=0
stuff, but the cost seems a bit high for experimentation.
Index: src/ifd/atr.c
===================================================================
--- src/ifd/atr.c (revision 815)
+++ src/ifd/atr.c (working copy)
@@ -108,8 +108,8 @@
ptsbuf[ptslen++] = info->TA[0];
ptsbuf[1] |= 0x10;
}
- if (info->TC[0] != -1) {
- ptsbuf[ptslen++] = info->TC[0];
+ if (info->TC[0] == 255) {
+ ptsbuf[ptslen++] = 1;
ptsbuf[1] |= 0x20;
}
@@ -123,3 +123,52 @@
memcpy(buf, ptsbuf, ptslen);
return ptslen;
}
+
+/* validate a PTS response according to ISO7816-3 */
+int
+ifd_verify_pts(ifd_atr_info_t *info,
+ int protocol, const unsigned char *buf, size_t len)
+{
+ int n,i;
+ int ptsr[3];
+ int pck;
+
+ if (len < 3)
+ return IFD_ERROR_BUFFER_TOO_SMALL;
+
+ if (buf[0] != 0xFF)
+ return IFD_ERROR_INCOMPATIBLE_DEVICE; /* not a pts response */
+
+ for (n = 0, pck = 0; n < len; n++)
+ pck ^= buf[n];
+
+ if (pck)
+ return IFD_ERROR_COMM_ERROR;
+ for (i = 0; i < 3; i++)
+ ptsr[i] = -1;
+ for (i = 0, n = 2; i < 3 && n < len - 1; i++) {
+ if (buf[1] & 1 << (i + 4))
+ ptsr[i] = buf[n++];
+ }
+ if (n < len - 1) /* extra bytes in response */
+ return IFD_ERROR_INCOMPATIBLE_DEVICE;
+ if (info->TA[0] != -1 && ptsr[0] != info->TA[0])
+ info->TA[0] = -1;
+ if (info->TC[0] == 255 && (ptsr[1] == -1 || (ptsr[1] & 1) == 0))
+ return IFD_ERROR_INCOMPATIBLE_DEVICE;
+ return 0;
+}
+
+int
+ifd_pts_complete(const unsigned char *pts, size_t len)
+{
+ unsigned int j=2;
+
+ if (j > len)
+ return 0;
+ j =+ ifd_count_bits(pts[1] & 0x70);
+ j++;
+ if (j > len)
+ return 0;
+ return 1;
+}
Index: src/ifd/atr.h
===================================================================
--- src/ifd/atr.h (revision 815)
+++ src/ifd/atr.h (working copy)
@@ -23,7 +23,9 @@
extern int ifd_atr_parse(ifd_atr_info_t *, const unsigned char *, size_t);
extern int ifd_build_pts(const ifd_atr_info_t *, int,
unsigned char *, size_t);
-
+extern int ifd_verify_pts(ifd_atr_info_t *, int,
+ const unsigned char *, size_t);
+extern int ifd_pts_complete(const unsigned char *pts, size_t len);
#ifdef __cplusplus
}
#endif
Index: src/ifd/ifd-eutron.c
===================================================================
--- src/ifd/ifd-eutron.c (revision 815)
+++ src/ifd/ifd-eutron.c (working copy)
@@ -6,6 +6,7 @@
*/
#include "internal.h"
+#include "atr.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -68,7 +69,6 @@
{
ifd_device_t *dev = reader->device;
unsigned char buffer[IFD_MAX_ATR_LEN+100];
- unsigned char cookie[] = { 0xff, 0x11, 0x98, 0x76 };
int rc, lr, c, atrlen;
if (ifd_usb_control(dev, 0x41, 0xa3, 0, 0, NULL, 0, -1) != 0
@@ -80,7 +80,7 @@
for (lr=0,c=0;c < 20;c++) {
rc = ifd_usb_control(dev, 0xc1, 0x02, 0, 0,
- &buffer[lr], 100, 1000);
+ &buffer[lr], IFD_MAX_ATR_LEN - lr, 1000);
if (rc < 0)
goto failed;
@@ -100,27 +100,6 @@
atrlen = lr;
memcpy(atr, buffer, atrlen);
- if (ifd_usb_control(dev, 0x41, 0x01, 0, 0,
- cookie, sizeof(cookie), 1000) != sizeof(cookie))
- goto failed;
-
- for (lr=0,c=0;c < 20;c++) {
- rc = ifd_usb_control(dev, 0xc1, 0x02, 0, 0,
- &buffer[lr], 100, 1000);
-
- if (rc < 0)
- goto failed;
- lr+=rc;
- if (lr >= 4)
- break;
-
- if (lr > IFD_MAX_ATR_LEN)
- goto failed;
- usleep(100000);
- }
- if (c >= 20)
- goto failed;
-
if (ifd_usb_control(dev, 0x41, 0x65, 0x98, 0, NULL, 0, -1) != 0
|| ifd_usb_control(dev, 0x41, 0xa0, 0, 0, NULL, 0, -1) != 0)
goto failed;
@@ -171,6 +150,78 @@
return -1;
}
+static int
+eutron_set_protocol(ifd_reader_t *reader, int nslot, int proto)
+{
+ ifd_slot_t *slot;
+ ifd_atr_info_t atr_info;
+ unsigned char pts[7], ptsret[7];
+ int ptslen, ptsrlen, r, c ;
+
+ slot = &reader->slot[nslot];
+ if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_T1) {
+ ct_error("%s: protocol not supported", reader->name);
+ return -1;
+ }
+
+ r = ifd_atr_parse(&atr_info, slot->atr, slot->atr_len);
+ if (r < 0) {
+ ct_error("%s: Bad ATR", reader->name);
+ return r;
+ }
+ /* If the card doesn't support T=1, use T=0 */
+ if (!(atr_info.supported_protocols & 0x2)) {
+ slot->proto = ifd_protocol_new(proto, reader, slot->dad);
+ if (slot->proto == NULL) {
+ ct_error("%s: internal error", reader->name);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* if the card _does_ support T=1, prefer it, even though
+ * it is not the default protocol */
+
+ ptslen = ifd_build_pts(&atr_info, IFD_PROTOCOL_T1, pts, 7);
+ if (ptslen < 0) {
+ return r;
+ }
+ if (eutron_send(reader, slot->dad, pts, ptslen) != ptslen)
+ return IFD_ERROR_COMM_ERROR;
+
+ for (ptsrlen=0,c=0;c < 20;c++) {
+ r = ifd_usb_control(reader->device, 0xc1, 0x02, 0, 0,
+ &ptsret[ptsrlen], sizeof(ptsret) - ptsrlen,
+ 1000);
+
+ if (r < 0)
+ return IFD_ERROR_COMM_ERROR;
+ ptsrlen+=r;
+ if (ifd_pts_complete(ptsret, ptsrlen))
+ break;
+
+ if (ptsrlen >= 7)
+ return IFD_ERROR_COMM_ERROR;
+ usleep(100000);
+ }
+ if (c >= 20)
+ return IFD_ERROR_TIMEOUT;
+
+ r = ifd_verify_pts(&atr_info, IFD_PROTOCOL_T1, ptsret, ptsrlen);
+ if (r < 0) {
+ ct_error("%s: Protocol selection failed", reader->name);
+ return r;
+ }
+
+ slot->proto = ifd_protocol_new(IFD_PROTOCOL_T1, reader, slot->dad);
+ if (slot->proto == NULL) {
+ ct_error("%s: internal error", reader->name);
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Driver operations
*/
@@ -189,6 +240,7 @@
eutron_driver.card_reset = eutron_card_reset;
eutron_driver.send = eutron_send;
eutron_driver.recv = eutron_recv;
+ eutron_driver.set_protocol = eutron_set_protocol;
ifd_driver_register("eutron", &eutron_driver);
}
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel