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(¶mbuf[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