2008/12/19 Ludovic Rousseau <[email protected]>:
> I will try to merge my T=1 code in OpenCT. But not before a few weeks.
> I remembered some objections when I proposed to do this a few years
> ago. Maybe the situation has changed.
I patched the OpenSC version of src/ifd/proto-t1.c (patch attached)
THIS PATCH DOES NOT WORK. It is just a preview.
Notes:
- the t1_* functions use a "ifd_protocol_t * prot" parameter but I
need a "t1_state_t * t1" since some fields are only present in the
t1_state_t structure
- t1_negotiate_ifsd() is declared in src/ifd/internal.h and the only
external source using it is src/ifd/ifd-eutron.c. This function is
never used elsewhere. This function could be used by the CCID driver
if the reader does not negotiate the IFSD itself for example
- I changed my version of proto-t1.c in my CCID handler to make
comparison more easy
I can integrate some patches from my CCID driver. But integrating all
the error cases management will be very hard without major changes in
OpenCT.
What should I do?
Bye
--
Dr. Ludovic Rousseau
Index: proto-t1.c
===================================================================
--- proto-t1.c (révision 1127)
+++ proto-t1.c (copie de travail)
@@ -8,6 +8,8 @@
*/
#include "internal.h"
+#include "openct/buffer.h"
+
#include <sys/poll.h>
#include <unistd.h>
#include <stdlib.h>
@@ -15,6 +17,7 @@
typedef struct {
ifd_protocol_t base;
+ int lun;
int state;
int block_oriented;
@@ -29,6 +32,9 @@ typedef struct {
unsigned int (*checksum) (const unsigned char *,
size_t, unsigned char *);
+
+ char more; /* more data bit */
+ unsigned char previous_block[4]; /* to store the last R-block */
} t1_state_t;
/* T=1 protocol constants */
@@ -56,24 +62,40 @@ typedef struct {
#define T1_S_WTX 0x03
#define T1_BUFFER_SIZE (3 + 254 + 2)
+#define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
#define NAD 0
#define PCB 1
#define LEN 2
#define DATA 3
+#define DEBUG_INFO2(a, b) ifd_debug(1, a, b)
+#define DEBUG_CRITICAL(a) ifd_debug(1, a)
+#define DEBUG_CRITICAL2(a, b) ifd_debug(1, a, b)
+#define DEBUG_COMM(a) ifd_debug(3, a)
+#define DEBUG_COMM2(a, b) ifd_debug(3, a, b)
+#define DEBUG_COMM4(a, b, c, d) ifd_debug(3, a, b, c, d)
+#define DEBUG_XXD(a, b, c) do{}while(0)
+
/* internal state, do not mess with it. */
/* should be != DEAD after reset/init */
enum {
SENDING, RECEIVING, RESYNCH, DEAD
};
+static int t1_set_param(t1_state_t * t1, int type, long value);
static void t1_set_checksum(t1_state_t *, int);
static unsigned int t1_block_type(unsigned char);
static unsigned int t1_seq(unsigned char);
-static unsigned int t1_build(t1_state_t *, unsigned char *,
- unsigned char, unsigned char,
- ct_buf_t *, size_t *);
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+ unsigned char dad, unsigned char pcb,
+ ct_buf_t *bp, size_t *lenp);
+static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
@@ -111,24 +133,22 @@ static void t1_set_checksum(t1_state_t *
/*
* Attach t1 protocol
*/
-static int t1_init(ifd_protocol_t * prot)
+static int t1_init(t1_state_t * t1, int lun)
{
- t1_state_t *t1 = (t1_state_t *) prot;
-
t1_set_defaults(t1);
- t1_set_checksum(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC);
+ t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
+ t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
+ t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
+
+ t1->lun = lun;
- /* If the device is attached through USB etc, assume the
- * device will do the framing for us */
- if (prot->reader->device->type != IFD_DEVICE_TYPE_SERIAL)
- t1->block_oriented = 1;
return 0;
}
/*
* Detach t1 protocol
*/
-static void t1_release(ifd_protocol_t * prot)
+static void t1_release(t1_state_t * t1)
{
/* NOP */
}
@@ -136,17 +156,12 @@ static void t1_release(ifd_protocol_t *
/*
* Get/set parmaters for T1 protocol
*/
-static int t1_set_param(ifd_protocol_t * prot, int type, long value)
+static int t1_set_param(t1_state_t * t1, int type, long value)
{
- t1_state_t *t1 = (t1_state_t *) prot;
-
switch (type) {
case IFD_PROTOCOL_RECV_TIMEOUT:
t1->timeout = value;
break;
- case IFD_PROTOCOL_BLOCK_ORIENTED:
- t1->block_oriented = value;
- break;
case IFD_PROTOCOL_T1_CHECKSUM_LRC:
case IFD_PROTOCOL_T1_CHECKSUM_CRC:
t1_set_checksum(t1, type);
@@ -157,8 +172,14 @@ static int t1_set_param(ifd_protocol_t *
case IFD_PROTOCOL_T1_IFSD:
t1->ifsd = value;
break;
+ case IFD_PROTOCOL_T1_STATE:
+ t1->state = value;
+ break;
+ case IFD_PROTOCOL_T1_MORE:
+ t1->more = value;
+ break;
default:
- ct_error("Unsupported parameter %d", type);
+ DEBUG_INFO2("Unsupported parameter %d", type);
return -1;
}
@@ -191,10 +212,10 @@ static int t1_get_param(ifd_protocol_t *
/*
* Send an APDU through T=1
*/
-static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
- size_t snd_len, void *rcv_buf, size_t rcv_len)
+static int t1_transceive(t1_state_t * t1, unsigned int dad,
+ const void *snd_buf, size_t snd_len,
+ void *rcv_buf, size_t rcv_len)
{
- t1_state_t *t1 = (t1_state_t *) prot;
ct_buf_t sbuf, rbuf, tbuf;
unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
unsigned int slen, retries, resyncs, sent_length = 0;
@@ -205,7 +226,10 @@ static int t1_transceive(ifd_protocol_t
/* we can't talk to a dead card / reader. Reset it! */
if (t1->state == DEAD)
+ {
+ DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card
first.");
return -1;
+ }
t1->state = SENDING;
retries = t1->retries;
@@ -224,34 +248,140 @@ static int t1_transceive(ifd_protocol_t
retries--;
- if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
- ifd_debug(1, "fatal: transmit/receive failed");
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+ if (-2 == n)
+ {
+ DEBUG_COMM("Parity error");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (n < 0) {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
t1->state = DEAD;
goto error;
}
- if (!t1_verify_checksum(t1, sdata, n)) {
- ifd_debug(1, "checksum failed");
- if (retries == 0 || sent_length)
+ if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (sdata[LEN] == 0xFF)) /* length == 0xFF
(illegal) */
+ {
+ DEBUG_COMM("R-BLOCK required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
slen = t1_build(t1, sdata,
- dad, T1_R_BLOCK | T1_EDC_ERROR,
+ dad, T1_R_BLOCK | T1_OTHER_ERROR,
NULL, NULL);
continue;
}
+ if (!t1_verify_checksum(t1, sdata, n)) {
+ DEBUG_COMM("checksum failed");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK | T1_EDC_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
pcb = sdata[PCB];
switch (t1_block_type(pcb)) {
case T1_R_BLOCK:
- if (T1_IS_ERROR(pcb)) {
- ifd_debug(1, "received error block, err=%d",
- T1_IS_ERROR(pcb));
- goto resync;
+ if ((sdata[LEN] != 0x00) /* length != 0x00
(illegal) */
+ || (pcb & 0x20) /* b6 of pcb is
set */
+ )
+ {
+ DEBUG_COMM("R-Block required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[1]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK |
T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ if (((t1_seq(pcb) != t1->ns) /* wrong sequence
number & no bit more */
+ && ! t1->more)
+ )
+ {
+ DEBUG_COMM4("received: %d, expected: %d, more:
%d",
+ t1_seq(pcb), t1->ns, t1->more);
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("R-Block required");
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto resync;
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK |
T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
}
if (t1->state == RECEIVING) {
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[1]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_COMM("");
slen = t1_build(t1, sdata,
- dad, T1_R_BLOCK, NULL, NULL);
+ dad, T1_R_BLOCK,
+ NULL, NULL);
break;
}
@@ -278,6 +408,7 @@ static int t1_transceive(ifd_protocol_t
/* The first I-block sent by the ICC indicates
* the last block we sent was received successfully. */
if (t1->state == SENDING) {
+ DEBUG_COMM("");
ct_buf_get(&sbuf, NULL, last_send);
last_send = 0;
t1->ns ^= 1;
@@ -289,6 +420,7 @@ static int t1_transceive(ifd_protocol_t
* what we expected it to send, reply with
* an R block */
if (t1_seq(pcb) != t1->nr) {
+ DEBUG_COMM("wrong nr");
slen = t1_build(t1, sdata, dad,
T1_R_BLOCK | T1_OTHER_ERROR,
NULL, NULL);
@@ -298,7 +430,10 @@ static int t1_transceive(ifd_protocol_t
t1->nr ^= 1;
if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
+ {
+ DEBUG_CRITICAL2("buffer overrun by %d bytes",
sdata[LEN] - (rbuf.size - rbuf.tail));
goto error;
+ }
if ((pcb & T1_MORE_BLOCKS) == 0)
goto done;
@@ -308,6 +443,9 @@ static int t1_transceive(ifd_protocol_t
case T1_S_BLOCK:
if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
+ /* ISO 7816-3 Rule 6.2 */
+ DEBUG_COMM("S-Block answer received");
+ /* ISO 7816-3 Rule 6.3 */
t1->state = SENDING;
sent_length = 0;
last_send = 0;
@@ -320,65 +458,126 @@ static int t1_transceive(ifd_protocol_t
}
if (T1_S_IS_RESPONSE(pcb))
- goto resync;
+ {
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto resync;
+
+ /* ISO 7816-3 Rule 7.2 */
+ if (T1_R_BLOCK ==
t1_block_type(t1->previous_block[PCB]))
+ {
+ DEBUG_COMM("Rule 7.2");
+ slen = t1_rebuild(t1, sdata);
+ continue;
+ }
+
+ DEBUG_CRITICAL("wrong response S-BLOCK
received");
+ slen = t1_build(t1, sdata,
+ dad, T1_R_BLOCK |
T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
ct_buf_init(&tbuf, sblk, sizeof(sblk));
+ DEBUG_COMM("S-Block request received");
switch (T1_S_TYPE(pcb)) {
case T1_S_RESYNC:
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d",
sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_COMM("Resync requested");
/* the card is not allowed to send a resync. */
goto resync;
+
case T1_S_ABORT:
- ifd_debug(1, "abort requested");
+ if (sdata[LEN] != 0)
+ {
+ DEBUG_COMM2("Wrong length: %d",
sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ /* ISO 7816-3 Rule 9 */
+ DEBUG_CRITICAL("abort requested");
break;
+
case T1_S_IFS:
- ifd_debug(1, "CT sent S-block with ifs=%u",
- sdata[DATA]);
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d",
sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_CRITICAL2("CT sent S-block with ifs=%u",
sdata[DATA]);
if (sdata[DATA] == 0)
goto resync;
t1->ifsc = sdata[DATA];
ct_buf_putc(&tbuf, sdata[DATA]);
break;
+
case T1_S_WTX:
- /* We don't handle the wait time extension
- * yet */
- ifd_debug(1, "CT sent S-block with wtx=%u",
- sdata[DATA]);
+ if (sdata[LEN] != 1)
+ {
+ DEBUG_COMM2("Wrong length: %d",
sdata[LEN]);
+ slen = t1_build(t1, sdata, dad,
+ T1_R_BLOCK | T1_OTHER_ERROR,
+ NULL, NULL);
+ continue;
+ }
+
+ DEBUG_CRITICAL2("CT sent S-block with wtx=%u",
sdata[DATA]);
t1->wtx = sdata[DATA];
ct_buf_putc(&tbuf, sdata[DATA]);
break;
+
default:
- ct_error("T=1: Unknown S block type 0x%02x",
- T1_S_TYPE(pcb));
+ DEBUG_CRITICAL2("T=1: Unknown S block type
0x%02x", T1_S_TYPE(pcb));
goto resync;
}
slen = t1_build(t1, sdata, dad,
- T1_S_BLOCK | T1_S_RESPONSE |
- T1_S_TYPE(pcb), &tbuf, NULL);
+ T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
+ &tbuf, NULL);
}
/* Everything went just splendid */
retries = t1->retries;
continue;
- resync:
+resync:
/* the number or resyncs is limited, too */
+ /* ISO 7816-3 Rule 6.4 */
if (resyncs == 0)
goto error;
+
+ /* ISO 7816-3 Rule 6 */
resyncs--;
t1->ns = 0;
t1->nr = 0;
slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
NULL);
t1->state = RESYNCH;
+ t1->more = FALSE;
+ retries = 1;
continue;
}
- done:
+done:
return ct_buf_avail(&rbuf);
- error:
+error:
t1->state = DEAD;
return -1;
}
@@ -443,16 +642,18 @@ static unsigned int t1_seq(unsigned char
}
}
-static unsigned int t1_build(t1_state_t * t1, unsigned char *block,
- unsigned char dad, unsigned char pcb,
- ct_buf_t * bp, size_t * lenp)
+unsigned int t1_build(t1_state_t * t1, unsigned char *block,
+ unsigned char dad, unsigned char pcb,
+ ct_buf_t *bp, size_t *lenp)
{
unsigned int len;
+ char more = FALSE;
len = bp ? ct_buf_avail(bp) : 0;
if (len > t1->ifsc) {
pcb |= T1_MORE_BLOCKS;
len = t1->ifsc;
+ more = TRUE;
}
/* Add the sequence number */
@@ -462,6 +663,8 @@ static unsigned int t1_build(t1_state_t
break;
case T1_I_BLOCK:
pcb |= t1->ns << T1_I_SEQ_SHIFT;
+ t1->more = more;
+ DEBUG_COMM2("more bit: %d", more);
break;
}
@@ -474,7 +677,13 @@ static unsigned int t1_build(t1_state_t
if (lenp)
*lenp = len;
- return t1_compute_checksum(t1, block, len + 3);
+ len = t1_compute_checksum(t1, block, len + 3);
+
+ /* memorize the last sent block */
+ /* only 4 bytes since we are only interesed in R-blocks */
+ memcpy(t1->previous_block, block, 4);
+
+ return len;
}
/*
@@ -494,16 +703,34 @@ struct ifd_protocol_ops ifd_protocol_t1
NULL, /* sync_write */
};
+static unsigned int
+t1_rebuild(t1_state_t *t1, unsigned char *block)
+{
+ unsigned char pcb = t1 -> previous_block[1];
+
+ /* copy the last sent block */
+ if (T1_R_BLOCK == t1_block_type(pcb))
+ memcpy(block, t1 -> previous_block, 4);
+ else
+ {
+ DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
+ return 0;
+ }
+
+ return 4;
+}
+
/*
* Build/verify checksum
*/
-static unsigned int t1_compute_checksum(t1_state_t * t1, unsigned char *data,
- size_t len)
+static unsigned int t1_compute_checksum(t1_state_t * t1,
+ unsigned char *data, size_t len)
{
return len + t1->checksum(data, len, data + len);
}
-static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf, size_t len)
+static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
+ size_t len)
{
unsigned char csum[2];
int m, n;
@@ -525,76 +752,103 @@ static int t1_verify_checksum(t1_state_t
* Send/receive block
*/
static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
- size_t rmax)
+ size_t rmax)
{
ifd_protocol_t *prot = &t1->base;
- unsigned int rlen, timeout;
int n, m;
+ unsigned int rmax_int;
- if (ct_config.debug >= 3)
- ifd_debug(3, "sending %s", ct_hexdump(block, slen));
-
- n = ifd_send_command(prot, block, slen);
- if (n < 0)
- return n;
-
- /* Maximum amount of data we'll receive - some devices
- * such as the eToken need this. If you request more, it'll
- * just barf */
- rlen = 3 + t1->ifsd + t1->rc_bytes;
+ DEBUG_XXD("sending: ", block, slen);
- /* timeout. For now our WTX treatment is very dumb */
- timeout = t1->timeout + 1000 * t1->wtx;
- t1->wtx = 0;
+ if (t1->wtx > 1)
+ {
+ /* set the new temporary timeout at WTX card request */
+ t1->timeout *= t1->wtx;
+ DEBUG_INFO2("New timeout at WTX request: %d sec",
+ t1->timeout);
+ }
+
+#if 0
+ if (isCharLevel(t1->lun))
+ {
+ rmax = 3;
+
+ n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return n;
+
+ /* the second argument of CCID_Receive() is (unsigned int *)
+ * so we can't use &rmax since &rmax is a (size_t *) and may not
+ * be the same on 64-bits architectures for example (iMac G5) */
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
+ rmax = rmax_int;
+
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
+ return -1;
- if (t1->block_oriented) {
- /* Note - Linux USB seems to have an off by one error, you
- * actually need the + 1 to get the RC byte */
- rlen++;
- if (rlen < rmax)
- rmax = rlen;
+ rmax = block[2] + 1;
- /* Get the response en bloc */
- n = ifd_recv_response(prot, block, rmax, timeout);
- if (n >= 0) {
- m = block[2] + 3 + t1->rc_bytes;
- if (m < n)
- n = m;
- }
- } else {
- /* Get the header */
- if (ifd_recv_response(prot, block, 3, timeout) < 0)
+ n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
+ if (n != IFD_SUCCESS)
+ return n;
+
+ rmax_int = rmax;
+ n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
+ rmax = rmax_int;
+ if (n == IFD_PARITY_ERROR)
+ return -2;
+ if (n != IFD_SUCCESS)
return -1;
- n = block[2] + t1->rc_bytes;
- if (n + 3 > rmax || block[2] >= 254) {
- ct_error("receive buffer too small");
- return -1;
- }
+ n = rmax + 3;
+ }
+ else
+#endif
+ {
+ /*n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);*/
+ n = ifd_send_command(prot, block, slen);
+ t1->wtx = 0; /* reset to default value */
+ if (n != IFD_SUCCESS)
+ return n;
- /* Now get the rest */
- if (ifd_recv_response(prot, block + 3, n, t1->timeout) < 0)
+ /* Get the response en bloc */
+ rmax_int = rmax;
+ /*n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);*/
+ n = ifd_recv_response(prot, block, rmax_int, t1->timeout);
+ rmax = rmax_int;
+ /*if (n == IFD_PARITY_ERROR)
+ return -2;*/
+ if (n != IFD_SUCCESS)
return -1;
- n += 3;
+ n = rmax;
+ }
+
+ if (n >= 0)
+ {
+ m = block[2] + 3 + t1->rc_bytes;
+ if (m < n)
+ n = m;
}
- if (n >= 0 && ct_config.debug >= 3)
- ifd_debug(3, "received %s", ct_hexdump(block, n));
+ if (n >= 0)
+ DEBUG_XXD("received: ", block, n);
return n;
}
-int t1_negotiate_ifsd(ifd_protocol_t * proto, unsigned int dad, int ifsd)
+int t1_negotiate_ifsd(t1_state_t * t1, 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;
+ unsigned char snd_buf[1];
retries = t1->retries;
@@ -605,38 +859,42 @@ int t1_negotiate_ifsd(ifd_protocol_t * p
/* Initialize send/recv buffer */
ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
- while (1) {
+ while (TRUE)
+ {
/* Build the block */
- slen =
- t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_IFS, &sbuf,
- NULL);
+ slen = t1_build(t1, sdata, 0, 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;
+ /* Send the block */
+ n = t1_xcv(t1, sdata, slen, sizeof(sdata));
+
+ retries--;
+ /* ISO 7816-3 Rule 7.4.2 */
+ if (retries == 0)
+ goto error;
+
+ if (-1 == n)
+ {
+ DEBUG_CRITICAL("fatal: transmit/receive failed");
goto error;
}
- if (!t1_verify_checksum(t1, sdata, n)) {
- ifd_debug(1, "checksum failed");
- if (retries == 0)
- goto error;
+ if ((-2 == n)
/* Parity error */
+ || (sdata[DATA] != ifsd)
/* Wrong ifsd received */
+ || (sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
+ || (!t1_verify_checksum(t1, sdata, n)) /* checksum
failed */
+ || (n != 4 + t1->rc_bytes)
/* wrong frame length */
+ || (sdata[LEN] != 1)
/* wrong data length */
+ || (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE |
T1_S_IFS))) /* wrong PCB */
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[LEN] != 1 || sdata[DATA] != ifsd)
- goto error;
- break;
- }
- if (retries == 0)
- goto error;
+
+ /* no more error */
+ goto done;
}
+done:
return n;
- error:
- t1_resynchronize(proto, dad);
+error:
+ t1->state = DEAD;
return -1;
}
Index: internal.h
===================================================================
--- internal.h (révision 1127)
+++ internal.h (copie de travail)
@@ -202,6 +202,6 @@ extern int ifd_sync_detect_icc(ifd_reade
extern unsigned int ifd_protocols_list(const char **, unsigned int);
/* proto-t1.c */
-extern int t1_negotiate_ifsd(ifd_protocol_t *, unsigned int, int);
+//extern int t1_negotiate_ifsd(ifd_protocol_t *, unsigned int, int);
#endif /* IFD_INTERNAL_H */
Index: ifd-eutron.c
===================================================================
--- ifd-eutron.c (révision 1127)
+++ ifd-eutron.c (copie de travail)
@@ -291,11 +291,13 @@ static int eutron_set_protocol(ifd_reade
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 0
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]);
+#endif
}
return 0;
_______________________________________________
opensc-devel mailing list
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel