The attached patch fixes some broken PTS behavior that resulted from two misconceptions that I had about PTS:

1) that the PTS response from the card must be an exact reflection of the request in order to be considered successful. 7816-3 says that the card may refuse the PTS1 byte by sending a response that doesn't include PTS1. 2) that the PTS2 byte was an N (guard time) value. PTS2 is in fact a coded-value, of which only the low 2 bits are defined.

The patch adds a new function, ifd_verify_pts, that validates a pts response according to the pts request that would have been sent for a given atr_info. it clears the TA1 field from the atr_info if PTS1 was refused by the card.

There's more to do here for CCID.

1) the ccid paramater setting must be done in 2 passes, one that doesn't set Fi/Di to non-default values (before PTS is performed) and one that does (after we know the card accepts the non-default baudrate)
2) the pcsc ccid driver does validation of whether the reader supports a
given baud rate, rather than blindly assuming that it will be able to deal with whatever preferred/maximum baud rate the card's atr specify's. We should do that too.

It's unlikely that I'm going to work on this anytime soon, but I thought I'd let people know about the issue...
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,38 @@
        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;
+}
Index: src/ifd/atr.h
===================================================================
--- src/ifd/atr.h       (revision 815)
+++ src/ifd/atr.h       (working copy)
@@ -23,6 +23,8 @@
 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);
 
 #ifdef __cplusplus
 }
Index: src/ifd/ifd-ccid.c
===================================================================
--- src/ifd/ifd-ccid.c  (revision 815)
+++ src/ifd/ifd-ccid.c  (working copy)
@@ -863,7 +863,7 @@
      /* is PTS available? N (guard time) must be changed before PTS
       * is performed. What about F and D? */
      if (proto == IFD_PROTOCOL_T1 || atr_info.TA[0] != -1 
-        || atr_info.TC[0] != -1)
+        || atr_info.TC[0] == 255)
      {
          unsigned char pts[7], ptsret[7];
          int ptslen; 
@@ -878,13 +878,13 @@
                          sizeof(ptsret));
          if (r<0)
               return r;
-         if (r < ptslen || memcmp(pts,ptsret,ptslen)) {
+         r=ifd_verify_pts(&atr_info, proto, ptsret, r);
+         if (r) {
               ct_error("%s: Bad PTS response", reader->name);
-              return IFD_ERROR_INCOMPATIBLE_DEVICE;
+              return r;
          }
      }
 
-     memset(&parambuf[r], 0, sizeof(parambuf) - r);
      if (proto == IFD_PROTOCOL_T0) {
          p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
                               reader, slot->dad);
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to