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

Reply via email to