The attached patch implements the eutron changes from my last message, including the T=1 fix. It also adds an ifsd negotiation function to proto-t1.c (taken from the copy of proto-t1.c in the pcsc-lite ccid driver), and makes use of it in the eutron driver.

The patch also attempts to flush the readers buffer before reading the ATR. This may be enough to deal with the pre-atr junk on the FIPS model.

The patch is relative to the current svn trunk, and any previous eutron patches from me should be rolled back before applying it.
Index: proto-t1.c
===================================================================
--- proto-t1.c  (revision 819)
+++ proto-t1.c  (working copy)
@@ -2,6 +2,9 @@
  * Implementation of T=1
  *
  * Copyright (C) 2003, Olaf Kirch <[EMAIL PROTECTED]>
+ *
+ * improvements by:
+ * Copyright (C) 2004 Ludovic Rousseau <[EMAIL PROTECTED]>
  */
 
 #include "internal.h"
@@ -576,3 +579,59 @@
 
        return n;
 }
+
+int t1_negotiate_ifsd(ifd_protocol_t * proto, unsigned int dad, int ifsd)
+{
+       t1_state_t *t1 = (t1_state_t *) proto;
+       ct_buf_t sbuf;
+       unsigned char sdata[T1_BUFFER_SIZE];
+       unsigned int slen;
+       unsigned int retries;
+       size_t snd_len;
+       int n;
+       unsigned char snd_buf[1], pcb;
+
+       retries = t1->retries;
+
+       /* S-block IFSD request */
+       snd_buf[0] = ifsd;
+       snd_len = 1;
+
+       /* Initialize send/recv buffer */
+       ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
+
+       while (1) {
+               /* Build the block */
+               slen =
+                   t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_IFS, &sbuf,
+                            NULL);
+
+               if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
+                       ifd_debug(1, "fatal: transmit/receive failed");
+                       t1->state = DEAD;
+                       goto error;
+               }
+
+               if (!t1_verify_checksum(t1, sdata, n)) {
+                       ifd_debug(1, "checksum failed");
+                       if (retries == 0)
+                               goto error;
+                       continue;
+               }
+               pcb = sdata[1];
+               if (t1_block_type(pcb) == T1_S_BLOCK &&
+                   T1_S_TYPE(pcb) == T1_S_IFS && T1_S_IS_RESPONSE(pcb)) {
+                       if (sdata[2] != 1 || sdata[3] != ifsd)
+                               goto error;
+                       break;
+               }
+               if (retries == 0)
+                       goto error;
+       }
+
+       return n;
+
+      error:
+       t1_resynchronize(proto, dad);
+       return -1;
+}
Index: atr.c
===================================================================
--- atr.c       (revision 819)
+++ atr.c       (working copy)
@@ -155,3 +155,18 @@
                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: atr.h
===================================================================
--- atr.h       (revision 819)
+++ atr.h       (working copy)
@@ -26,6 +26,7 @@
                                 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
 }
Index: ifd-eutron.c
===================================================================
--- ifd-eutron.c        (revision 819)
+++ ifd-eutron.c        (working copy)
@@ -3,21 +3,39 @@
  *
  * Copyright (C) 2003, Andreas Jellinghaus <[EMAIL PROTECTED]>
  * Copyright (C) 2003, Olaf Kirch <[EMAIL PROTECTED]>
+ * Copyright 2006, Chaskiel Grundman <[EMAIL PROTECTED]>
  */
 
 #include "internal.h"
+#include "atr.h"
+#include "usb-descriptors.h"
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 
+#define EUTRON_OUT IFD_USB_ENDPOINT_OUT | IFD_USB_TYPE_VENDOR | 
IFD_USB_RECIP_ENDPOINT
+#define EUTRON_IN IFD_USB_ENDPOINT_IN | IFD_USB_TYPE_VENDOR | 
IFD_USB_RECIP_ENDPOINT
+
+#define EUTRON_CMD_WRITE 0x1
+#define EUTRON_CMD_READ 0x2
+#define EUTRON_CMD_ATR 0x9
+#define EUTRON_CMD_SETPARAM 0x65
+
+typedef struct eut_priv {
+       unsigned char readbuffer[500];
+       int head;
+       int tail;
+} eut_priv_t;
 /*
  * Initialize the device
  */
 static int eutron_open(ifd_reader_t * reader, const char *device_name)
 {
        ifd_device_t *dev;
+       eut_priv_t *priv;
 
-       reader->name = "Eutron CryptoIdendity IT-SEC";
+       reader->name = "Eutron CryptoIdendity";
        reader->nslots = 1;
        if (!(dev = ifd_device_open(device_name)))
                return -1;
@@ -27,6 +45,14 @@
                return -1;
        }
 
+       priv = (eut_priv_t *) calloc(1, sizeof(eut_priv_t));
+       if (!priv) {
+               ct_error("out of memory");
+               return IFD_ERROR_NO_MEMORY;
+       }
+
+       reader->driver_data = priv;
+
        reader->device = dev;
 
        return 0;
@@ -63,19 +89,23 @@
 {
        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
-           || ifd_usb_control(dev, 0x41, 0xa1, 0, 0, NULL, 0, -1) != 0
-           || ifd_usb_control(dev, 0x41, 0xa2, 0, 0, NULL, 0, -1) != 0
-           || ifd_usb_control(dev, 0x41, 0xa0, 0, 0, NULL, 0, -1) != 0
-           || ifd_usb_control(dev, 0x41, 0x09, 0, 0, NULL, 0, -1) != 0)
+       if (ifd_usb_control(dev, EUTRON_OUT, 0xa3, 0, 0, NULL, 0, -1) != 0
+           || ifd_usb_control(dev, EUTRON_OUT, 0xa1, 0, 0, NULL, 0, -1) != 0
+           || ifd_usb_control(dev, EUTRON_OUT, 0xa2, 0, 0, NULL, 0, -1) != 0
+           || ifd_usb_control(dev, EUTRON_OUT, 0xa0, 0, 0, NULL, 0, -1) != 0)
                goto failed;
+       /* flush any leftover buffered data */
+       while (ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
+                              buffer, IFD_MAX_ATR_LEN + 100, 1000) > 0) ;
+       if (ifd_usb_control(dev, EUTRON_OUT, EUTRON_CMD_ATR, 0, 0, NULL, 0, -1)
+           != 0)
+               goto failed;
 
        for (lr = 0, c = 0; c < 20; c++) {
-               rc = ifd_usb_control(dev, 0xc1, 0x02, 0, 0,
-                                    &buffer[lr], 100, 1000);
+               rc = ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
+                                    &buffer[lr], IFD_MAX_ATR_LEN - lr, 1000);
 
                if (rc < 0)
                        goto failed;
@@ -96,31 +126,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 > IFD_MAX_ATR_LEN)
-                       goto failed;
-
-               if (lr >= 4)
-                       break;  /* heuristik: guess we got the full atr */
-               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;
-
        return atrlen;
 
       failed:
@@ -134,42 +139,158 @@
 static int eutron_send(ifd_reader_t * reader, unsigned int dad,
                       const unsigned char *buffer, size_t len)
 {
-       return ifd_usb_control(reader->device, 0x42, 0x01, 0, 0,
-                              (void *)buffer, len, 1000);
+       return ifd_usb_control(reader->device, EUTRON_OUT, EUTRON_CMD_WRITE, 0,
+                              0, (void *)buffer, len, 1000);
 }
 
 static int eutron_recv(ifd_reader_t * reader, unsigned int dad,
                       unsigned char *buffer, size_t len, long timeout)
 {
-       int rc, lr, c, rbs;
+       int rc, c, rbs;
+       eut_priv_t *priv = reader->driver_data;
 
-       for (lr = 0, c = 0; c < 200; c++) {
-               rbs = len - lr;
-               if (rbs > 100)
-                       rbs = 100;
+       ct_debug("eutron_recv: len=%d", len);
+       if (len <= priv->head - priv->tail) {
+               memcpy(buffer, priv->readbuffer + priv->tail, len);
+               priv->tail += len;
+               ct_debug("eutron_recv: returning buffered data, %d bytes left",
+                        priv->head - priv->tail);
+               return len;
+       }
+
+       /* move the data to the beginning of the buffer, so there's a big
+        * contiguous chunk */
+       memcpy(priv->readbuffer, &priv->readbuffer[priv->tail],
+              priv->head - priv->tail);
+       priv->head -= priv->tail;
+       /* since we set tail=0 here, the rest of the function can ignore it */
+       priv->tail = 0;
+       for (c = 0; c < 20; c++) {
+               rbs = 499 - priv->head;
                if (rbs == 0)
-                       goto failed;
+                       break;
 
-               rc = ifd_usb_control(reader->device, 0xc1, 0x02, 0, 0,
-                                    &buffer[lr], rbs, timeout);
+               rc = ifd_usb_control(reader->device, EUTRON_IN, EUTRON_CMD_READ,
+                                    0, 0, &priv->readbuffer[priv->head], rbs,
+                                    timeout);
 
                if (rc < 0)
                        goto failed;
-               lr += rc;
+               priv->head += rc;
 
-               if (lr >= 4 && lr >= buffer[2] + 4)
+               if (priv->head >= len)
                        break;
                usleep(100000);
        }
-       if (c >= 200)
-               goto failed;
+       if (len > priv->head)
+               len = priv->head;
+       memcpy(buffer, priv->readbuffer, len);
+       priv->tail += len;
+       if (priv->head - priv->tail)
+               ct_debug("eutron_recv: buffering %d bytes of data",
+                        priv->head - priv->tail);
 
-       return lr;
+       return len;
       failed:
-       ct_error("eutron: failed to receive t=1 frame");
+       ct_error("eutron: receive failed");
        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, speedparam;
+
+       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 supports T=1, prefer it, even if
+        * it is not the default protocol */
+       if (atr_info.supported_protocols & 0x2) {
+               proto = IFD_PROTOCOL_T1;
+       }
+
+       /* XXX disable baud change */
+       atr_info.TA[0] = -1;
+       /* ITSEC-P does not respond correctly to request with PTS2 present */
+       atr_info.TC[0] = -1;
+
+       ptslen = ifd_build_pts(&atr_info, proto, 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, EUTRON_IN, EUTRON_CMD_READ,
+                                   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, proto, ptsret, ptsrlen);
+       if (r < 0) {
+               ct_error("%s: Protocol selection failed", reader->name);
+               return r;
+       }
+
+       if (atr_info.TA[0] != -1)
+               speedparam = atr_info.TA[0];
+       else
+               speedparam = 1;
+       if (ifd_usb_control
+           (reader->device, EUTRON_OUT, EUTRON_CMD_SETPARAM, speedparam, 0,
+            NULL, 0, -1) != 0
+           || ifd_usb_control(reader->device, EUTRON_OUT, 0xa1, 0, 0, NULL, 0,
+                              -1) != 0
+           || ifd_usb_control(reader->device, EUTRON_OUT, 0xa0, 0, 0, NULL, 0,
+                              -1) != 0)
+               return IFD_ERROR_COMM_ERROR;
+
+       slot->proto = ifd_protocol_new(proto, reader, slot->dad);
+       if (slot->proto == NULL) {
+               ct_error("%s: internal error", reader->name);
+               return -1;
+       }
+       /* device is not guaranteed to return whole frames */
+       ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 0);
+       /* Enable larger transfers */
+       if (proto == IFD_PROTOCOL_T1 && atr_info.TA[2] != -1) {
+               ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_T1_IFSC,
+                                          atr_info.TA[2]);
+               if (t1_negotiate_ifsd(slot->proto, slot->dad, atr_info.TA[2]) >
+                   0)
+                       ifd_protocol_set_parameter(slot->proto,
+                                                  IFD_PROTOCOL_T1_IFSD,
+                                                  atr_info.TA[2]);
+
+       }
+       return 0;
+}
+
 /*
  * Driver operations
  */
@@ -187,6 +308,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);
 }
Index: internal.h
===================================================================
--- internal.h  (revision 819)
+++ internal.h  (working copy)
@@ -198,4 +198,7 @@
 extern int ifd_sync_detect_icc(ifd_reader_t *, int, void *, size_t);
 extern unsigned int ifd_protocols_list(const char **, unsigned int);
 
+/* proto-t1.c */
+extern int t1_negotiate_ifsd(ifd_protocol_t *, unsigned int, int);
+
 #endif                         /* IFD_INTERNAL_H */
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to