Blame src/openct/proto-t1.c

Packit 9f0df5
/*
Packit 9f0df5
 * Implementation of T=1
Packit 9f0df5
 *
Packit 9f0df5
 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
Packit 9f0df5
 *
Packit 9f0df5
 * improvements by:
Packit 9f0df5
 * Copyright (C) 2004 Ludovic Rousseau <ludovic.rousseau@free.fr>
Packit 9f0df5
 */
Packit 9f0df5
Packit 9f0df5
#include <config.h>
Packit 9f0df5
Packit 9f0df5
#include <pcsclite.h>
Packit 9f0df5
#include <ifdhandler.h>
Packit 9f0df5
#include "commands.h"
Packit 9f0df5
#include "buffer.h"
Packit 9f0df5
#include "debug.h"
Packit 9f0df5
#include "proto-t1.h"
Packit 9f0df5
#include "checksum.h"
Packit 9f0df5
Packit 9f0df5
#include "ccid.h"
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_STRING_H
Packit 9f0df5
#include <string.h>
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
/* I block */
Packit 9f0df5
#define T1_I_SEQ_SHIFT		6
Packit 9f0df5
Packit 9f0df5
/* R block */
Packit 9f0df5
#define T1_IS_ERROR(pcb)	((pcb) & 0x0F)
Packit 9f0df5
#define T1_EDC_ERROR		0x01
Packit 9f0df5
#define T1_OTHER_ERROR		0x02
Packit 9f0df5
#define T1_R_SEQ_SHIFT		4
Packit 9f0df5
Packit 9f0df5
/* S block stuff */
Packit 9f0df5
#define T1_S_IS_RESPONSE(pcb)	((pcb) & T1_S_RESPONSE)
Packit 9f0df5
#define T1_S_TYPE(pcb)		((pcb) & 0x0F)
Packit 9f0df5
#define T1_S_RESPONSE		0x20
Packit 9f0df5
#define T1_S_RESYNC		0x00
Packit 9f0df5
#define T1_S_IFS		0x01
Packit 9f0df5
#define T1_S_ABORT		0x02
Packit 9f0df5
#define T1_S_WTX		0x03
Packit 9f0df5
Packit 9f0df5
#define swap_nibbles(x) ( (x >> 4) | ((x & 0xF) << 4) )
Packit 9f0df5
Packit 9f0df5
#ifndef TRUE
Packit 9f0df5
#define TRUE 1
Packit 9f0df5
#define FALSE 0
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
#define NAD 0
Packit 9f0df5
#define PCB 1
Packit 9f0df5
#define LEN 2
Packit 9f0df5
#define DATA 3
Packit 9f0df5
Packit 9f0df5
/* internal state, do not mess with it. */
Packit 9f0df5
/* should be != DEAD after reset/init */
Packit 9f0df5
enum {
Packit 9f0df5
	SENDING, RECEIVING, RESYNCH, DEAD
Packit 9f0df5
};
Packit 9f0df5
Packit 9f0df5
static void t1_set_checksum(t1_state_t *, int);
Packit 9f0df5
static unsigned int t1_block_type(unsigned char);
Packit 9f0df5
static unsigned int t1_seq(unsigned char);
Packit 9f0df5
static unsigned int t1_rebuild(t1_state_t *t1, unsigned char *block);
Packit 9f0df5
static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
Packit 9f0df5
static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
Packit 9f0df5
static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Set default T=1 protocol parameters
Packit 9f0df5
 */
Packit 9f0df5
static void t1_set_defaults(t1_state_t * t1)
Packit 9f0df5
{
Packit 9f0df5
	t1->retries = 3;
Packit 9f0df5
	/* This timeout is rather insane, but we need this right now
Packit 9f0df5
	 * to support cryptoflex keygen */
Packit 9f0df5
	t1->ifsc = 32;
Packit 9f0df5
	t1->ifsd = 32;
Packit 9f0df5
	t1->nr = 0;
Packit 9f0df5
	t1->ns = 0;
Packit 9f0df5
	t1->wtx = 0;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static void t1_set_checksum(t1_state_t * t1, int csum)
Packit 9f0df5
{
Packit 9f0df5
	switch (csum) {
Packit 9f0df5
	case IFD_PROTOCOL_T1_CHECKSUM_LRC:
Packit 9f0df5
		t1->rc_bytes = 1;
Packit 9f0df5
		t1->checksum = csum_lrc_compute;
Packit 9f0df5
		break;
Packit 9f0df5
	case IFD_PROTOCOL_T1_CHECKSUM_CRC:
Packit 9f0df5
		t1->rc_bytes = 2;
Packit 9f0df5
		t1->checksum = csum_crc_compute;
Packit 9f0df5
		break;
Packit 9f0df5
	}
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Attach t1 protocol
Packit 9f0df5
 */
Packit 9f0df5
int t1_init(t1_state_t * t1, int lun)
Packit 9f0df5
{
Packit 9f0df5
	t1_set_defaults(t1);
Packit 9f0df5
	t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
Packit 9f0df5
	t1_set_param(t1, IFD_PROTOCOL_T1_STATE, SENDING);
Packit 9f0df5
	t1_set_param(t1, IFD_PROTOCOL_T1_MORE, FALSE);
Packit 9f0df5
Packit 9f0df5
	t1->lun = lun;
Packit 9f0df5
Packit 9f0df5
	return 0;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Detach t1 protocol
Packit 9f0df5
 */
Packit 9f0df5
void t1_release(/*@unused@*/ t1_state_t * t1)
Packit 9f0df5
{
Packit 9f0df5
	(void)t1;
Packit 9f0df5
	/* NOP */
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Get/set parmaters for T1 protocol
Packit 9f0df5
 */
Packit 9f0df5
int t1_set_param(t1_state_t * t1, int type, long value)
Packit 9f0df5
{
Packit 9f0df5
	switch (type) {
Packit 9f0df5
	case IFD_PROTOCOL_T1_CHECKSUM_LRC:
Packit 9f0df5
	case IFD_PROTOCOL_T1_CHECKSUM_CRC:
Packit 9f0df5
		t1_set_checksum(t1, type);
Packit 9f0df5
		break;
Packit 9f0df5
	case IFD_PROTOCOL_T1_IFSC:
Packit 9f0df5
		t1->ifsc = value;
Packit 9f0df5
		break;
Packit 9f0df5
	case IFD_PROTOCOL_T1_IFSD:
Packit 9f0df5
		t1->ifsd = value;
Packit 9f0df5
		break;
Packit 9f0df5
	case IFD_PROTOCOL_T1_STATE:
Packit 9f0df5
		t1->state = value;
Packit 9f0df5
		break;
Packit 9f0df5
	case IFD_PROTOCOL_T1_MORE:
Packit 9f0df5
		t1->more = value;
Packit 9f0df5
		break;
Packit 9f0df5
	default:
Packit 9f0df5
		DEBUG_INFO2("Unsupported parameter %d", type);
Packit 9f0df5
		return -1;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return 0;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Send an APDU through T=1
Packit 9f0df5
 */
Packit 9f0df5
int t1_transceive(t1_state_t * t1, unsigned int dad,
Packit 9f0df5
		const void *snd_buf, size_t snd_len,
Packit 9f0df5
		void *rcv_buf, size_t rcv_len)
Packit 9f0df5
{
Packit 9f0df5
	ct_buf_t sbuf, rbuf, tbuf;
Packit 9f0df5
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
Packit 9f0df5
	unsigned int slen, retries, resyncs;
Packit 9f0df5
	size_t last_send = 0;
Packit 9f0df5
Packit 9f0df5
	if (snd_len == 0)
Packit 9f0df5
		return -1;
Packit 9f0df5
Packit 9f0df5
	/* we can't talk to a dead card / reader. Reset it! */
Packit 9f0df5
	if (t1->state == DEAD)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
Packit 9f0df5
		return -1;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	t1->state = SENDING;
Packit 9f0df5
	retries = t1->retries;
Packit 9f0df5
	resyncs = 3;
Packit 9f0df5
Packit 9f0df5
	/* Initialize send/recv buffer */
Packit 9f0df5
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
Packit 9f0df5
	ct_buf_init(&rbuf, rcv_buf, rcv_len);
Packit 9f0df5
Packit 9f0df5
	/* Send the first block */
Packit 9f0df5
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
Packit 9f0df5
Packit 9f0df5
	while (1) {
Packit 9f0df5
		unsigned char pcb;
Packit 9f0df5
		int n;
Packit 9f0df5
Packit 9f0df5
		retries--;
Packit 9f0df5
Packit 9f0df5
		n = t1_xcv(t1, sdata, slen, sizeof(sdata));
Packit 9f0df5
		if (-2 == n)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM("Parity error");
Packit 9f0df5
			/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
			if (retries <= 0)
Packit 9f0df5
				goto resync;
Packit 9f0df5
Packit 9f0df5
			/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM("Rule 7.2");
Packit 9f0df5
				slen = t1_rebuild(t1, sdata);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata,
Packit 9f0df5
					dad, T1_R_BLOCK | T1_EDC_ERROR,
Packit 9f0df5
					NULL, NULL);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if (n < 0) {
Packit 9f0df5
			DEBUG_CRITICAL("fatal: transmit/receive failed");
Packit 9f0df5
			t1->state = DEAD;
Packit 9f0df5
			goto error;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
Packit 9f0df5
			|| (sdata[LEN] == 0xFF))	/* length == 0xFF (illegal) */
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM("R-BLOCK required");
Packit 9f0df5
			/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
			if (retries <= 0)
Packit 9f0df5
				goto resync;
Packit 9f0df5
Packit 9f0df5
			/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM("Rule 7.2");
Packit 9f0df5
				slen = t1_rebuild(t1, sdata);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata,
Packit 9f0df5
				dad, T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
				NULL, NULL);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if (!t1_verify_checksum(t1, sdata, n)) {
Packit 9f0df5
			DEBUG_COMM("checksum failed");
Packit 9f0df5
			/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
			if (retries <= 0)
Packit 9f0df5
				goto resync;
Packit 9f0df5
Packit 9f0df5
			/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM("Rule 7.2");
Packit 9f0df5
				slen = t1_rebuild(t1, sdata);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata,
Packit 9f0df5
				dad, T1_R_BLOCK | T1_EDC_ERROR,
Packit 9f0df5
				NULL, NULL);
Packit 9f0df5
			continue;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		pcb = sdata[PCB];
Packit 9f0df5
		switch (t1_block_type(pcb)) {
Packit 9f0df5
		case T1_R_BLOCK:
Packit 9f0df5
			if ((sdata[LEN] != 0x00)	/* length != 0x00 (illegal) */
Packit 9f0df5
				|| (pcb & 0x20)			/* b6 of pcb is set */
Packit 9f0df5
			   )
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM("R-Block required");
Packit 9f0df5
				/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
				if (retries <= 0)
Packit 9f0df5
					goto resync;
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM("Rule 7.2");
Packit 9f0df5
					slen = t1_rebuild(t1, sdata);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				slen = t1_build(t1, sdata,
Packit 9f0df5
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			if (((t1_seq(pcb) != t1->ns)	/* wrong sequence number & no bit more */
Packit 9f0df5
					&& ! t1->more)
Packit 9f0df5
			   )
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM4("received: %d, expected: %d, more: %d",
Packit 9f0df5
					t1_seq(pcb), t1->ns, t1->more);
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
				if (retries <= 0)
Packit 9f0df5
					goto resync;
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM("Rule 7.2");
Packit 9f0df5
					slen = t1_rebuild(t1, sdata);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_COMM("R-Block required");
Packit 9f0df5
				slen = t1_build(t1, sdata,
Packit 9f0df5
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			if (t1->state == RECEIVING) {
Packit 9f0df5
				/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
Packit 9f0df5
				{
Packit 9f0df5
					/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
					if (retries <= 0)
Packit 9f0df5
						goto resync;
Packit 9f0df5
Packit 9f0df5
					DEBUG_COMM("Rule 7.2");
Packit 9f0df5
					slen = t1_rebuild(t1, sdata);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_COMM("");
Packit 9f0df5
				slen = t1_build(t1, sdata,
Packit 9f0df5
						dad, T1_R_BLOCK,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
				break;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* If the card terminal requests the next
Packit 9f0df5
			 * sequence number, it received the previous
Packit 9f0df5
			 * block successfully */
Packit 9f0df5
			if (t1_seq(pcb) != t1->ns) {
Packit 9f0df5
				ct_buf_get(&sbuf, NULL, last_send);
Packit 9f0df5
				last_send = 0;
Packit 9f0df5
				t1->ns ^= 1;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* If there's no data available, the ICC
Packit 9f0df5
			 * shouldn't be asking for more */
Packit 9f0df5
			if (ct_buf_avail(&sbuf) == 0)
Packit 9f0df5
				goto resync;
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
Packit 9f0df5
					&sbuf, &last_send);
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case T1_I_BLOCK:
Packit 9f0df5
			/* The first I-block sent by the ICC indicates
Packit 9f0df5
			 * the last block we sent was received successfully. */
Packit 9f0df5
			if (t1->state == SENDING) {
Packit 9f0df5
				DEBUG_COMM("");
Packit 9f0df5
				ct_buf_get(&sbuf, NULL, last_send);
Packit 9f0df5
				last_send = 0;
Packit 9f0df5
				t1->ns ^= 1;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			t1->state = RECEIVING;
Packit 9f0df5
Packit 9f0df5
			/* If the block sent by the card doesn't match
Packit 9f0df5
			 * what we expected it to send, reply with
Packit 9f0df5
			 * an R block */
Packit 9f0df5
			if (t1_seq(pcb) != t1->nr) {
Packit 9f0df5
				DEBUG_COMM("wrong nr");
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
				if (retries <= 0)
Packit 9f0df5
					goto resync;
Packit 9f0df5
Packit 9f0df5
				slen = t1_build(t1, sdata, dad,
Packit 9f0df5
						T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			t1->nr ^= 1;
Packit 9f0df5
Packit 9f0df5
			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
Packit 9f0df5
				goto error;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			if ((pcb & T1_MORE_BLOCKS) == 0)
Packit 9f0df5
				goto done;
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case T1_S_BLOCK:
Packit 9f0df5
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
Packit 9f0df5
				/* ISO 7816-3 Rule 6.2 */
Packit 9f0df5
				DEBUG_COMM("S-Block answer received");
Packit 9f0df5
				/* ISO 7816-3 Rule 6.3 */
Packit 9f0df5
				t1->state = SENDING;
Packit 9f0df5
				last_send = 0;
Packit 9f0df5
				resyncs = 3;
Packit 9f0df5
				retries = t1->retries;
Packit 9f0df5
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
Packit 9f0df5
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
Packit 9f0df5
						&sbuf, &last_send);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			if (T1_S_IS_RESPONSE(pcb))
Packit 9f0df5
			{
Packit 9f0df5
				/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
				if (retries <= 0)
Packit 9f0df5
					goto resync;
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 7.2 */
Packit 9f0df5
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM("Rule 7.2");
Packit 9f0df5
					slen = t1_rebuild(t1, sdata);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_CRITICAL("wrong response S-BLOCK received");
Packit 9f0df5
				slen = t1_build(t1, sdata,
Packit 9f0df5
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
				continue;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			ct_buf_init(&tbuf, sblk, sizeof(sblk));
Packit 9f0df5
Packit 9f0df5
			DEBUG_COMM("S-Block request received");
Packit 9f0df5
			switch (T1_S_TYPE(pcb)) {
Packit 9f0df5
			case T1_S_RESYNC:
Packit 9f0df5
				if (sdata[LEN] != 0)
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
Packit 9f0df5
					slen = t1_build(t1, sdata, dad,
Packit 9f0df5
						T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_COMM("Resync requested");
Packit 9f0df5
				/* the card is not allowed to send a resync. */
Packit 9f0df5
				goto resync;
Packit 9f0df5
Packit 9f0df5
			case T1_S_ABORT:
Packit 9f0df5
				if (sdata[LEN] != 0)
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
Packit 9f0df5
					slen = t1_build(t1, sdata, dad,
Packit 9f0df5
						T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				/* ISO 7816-3 Rule 9 */
Packit 9f0df5
				DEBUG_CRITICAL("abort requested");
Packit 9f0df5
				break;
Packit 9f0df5
Packit 9f0df5
			case T1_S_IFS:
Packit 9f0df5
				if (sdata[LEN] != 1)
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
Packit 9f0df5
					slen = t1_build(t1, sdata, dad,
Packit 9f0df5
						T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
Packit 9f0df5
				if (sdata[DATA] == 0)
Packit 9f0df5
					goto resync;
Packit 9f0df5
				t1->ifsc = sdata[DATA];
Packit 9f0df5
				ct_buf_putc(&tbuf, sdata[DATA]);
Packit 9f0df5
				break;
Packit 9f0df5
Packit 9f0df5
			case T1_S_WTX:
Packit 9f0df5
				if (sdata[LEN] != 1)
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
Packit 9f0df5
					slen = t1_build(t1, sdata, dad,
Packit 9f0df5
						T1_R_BLOCK | T1_OTHER_ERROR,
Packit 9f0df5
						NULL, NULL);
Packit 9f0df5
					continue;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
Packit 9f0df5
				t1->wtx = sdata[DATA];
Packit 9f0df5
				ct_buf_putc(&tbuf, sdata[DATA]);
Packit 9f0df5
				break;
Packit 9f0df5
Packit 9f0df5
			default:
Packit 9f0df5
				DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
Packit 9f0df5
				goto resync;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			slen = t1_build(t1, sdata, dad,
Packit 9f0df5
				T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
Packit 9f0df5
				&tbuf, NULL);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Everything went just splendid */
Packit 9f0df5
		retries = t1->retries;
Packit 9f0df5
		continue;
Packit 9f0df5
Packit 9f0df5
resync:
Packit 9f0df5
		/* the number or resyncs is limited, too */
Packit 9f0df5
		/* ISO 7816-3 Rule 6.4 */
Packit 9f0df5
		if (resyncs == 0)
Packit 9f0df5
			goto error;
Packit 9f0df5
Packit 9f0df5
		/* ISO 7816-3 Rule 6 */
Packit 9f0df5
		resyncs--;
Packit 9f0df5
		t1->ns = 0;
Packit 9f0df5
		t1->nr = 0;
Packit 9f0df5
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
Packit 9f0df5
				NULL);
Packit 9f0df5
		t1->state = RESYNCH;
Packit 9f0df5
		t1->more = FALSE;
Packit 9f0df5
		retries = 1;
Packit 9f0df5
		continue;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
done:
Packit 9f0df5
	return ct_buf_avail(&rbuf);
Packit 9f0df5
Packit 9f0df5
error:
Packit 9f0df5
	t1->state = DEAD;
Packit 9f0df5
	return -1;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static unsigned t1_block_type(unsigned char pcb)
Packit 9f0df5
{
Packit 9f0df5
	switch (pcb & 0xC0) {
Packit 9f0df5
	case T1_R_BLOCK:
Packit 9f0df5
		return T1_R_BLOCK;
Packit 9f0df5
	case T1_S_BLOCK:
Packit 9f0df5
		return T1_S_BLOCK;
Packit 9f0df5
	default:
Packit 9f0df5
		return T1_I_BLOCK;
Packit 9f0df5
	}
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static unsigned int t1_seq(unsigned char pcb)
Packit 9f0df5
{
Packit 9f0df5
	switch (pcb & 0xC0) {
Packit 9f0df5
	case T1_R_BLOCK:
Packit 9f0df5
		return (pcb >> T1_R_SEQ_SHIFT) & 1;
Packit 9f0df5
	case T1_S_BLOCK:
Packit 9f0df5
		return 0;
Packit 9f0df5
	default:
Packit 9f0df5
		return (pcb >> T1_I_SEQ_SHIFT) & 1;
Packit 9f0df5
	}
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
unsigned int t1_build(t1_state_t * t1, unsigned char *block,
Packit 9f0df5
	unsigned char dad, unsigned char pcb,
Packit 9f0df5
	ct_buf_t *bp, size_t *lenp)
Packit 9f0df5
{
Packit 9f0df5
	unsigned int len;
Packit 9f0df5
	char more = FALSE;
Packit 9f0df5
Packit 9f0df5
	len = bp ? ct_buf_avail(bp) : 0;
Packit 9f0df5
	if (len > t1->ifsc) {
Packit 9f0df5
		pcb |= T1_MORE_BLOCKS;
Packit 9f0df5
		len = t1->ifsc;
Packit 9f0df5
		more = TRUE;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Add the sequence number */
Packit 9f0df5
	switch (t1_block_type(pcb)) {
Packit 9f0df5
	case T1_R_BLOCK:
Packit 9f0df5
		pcb |= t1->nr << T1_R_SEQ_SHIFT;
Packit 9f0df5
		break;
Packit 9f0df5
	case T1_I_BLOCK:
Packit 9f0df5
		pcb |= t1->ns << T1_I_SEQ_SHIFT;
Packit 9f0df5
		t1->more = more;
Packit 9f0df5
		DEBUG_COMM2("more bit: %d", more);
Packit 9f0df5
		break;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	block[0] = dad;
Packit 9f0df5
	block[1] = pcb;
Packit 9f0df5
	block[2] = len;
Packit 9f0df5
Packit 9f0df5
	if (len)
Packit 9f0df5
		memcpy(block + 3, ct_buf_head(bp), len);
Packit 9f0df5
	if (lenp)
Packit 9f0df5
		*lenp = len;
Packit 9f0df5
Packit 9f0df5
	len = t1_compute_checksum(t1, block, len + 3);
Packit 9f0df5
Packit 9f0df5
	/* memorize the last sent block */
Packit 9f0df5
	/* only 4 bytes since we are only interesed in R-blocks */
Packit 9f0df5
	memcpy(t1->previous_block, block, 4);
Packit 9f0df5
Packit 9f0df5
	return len;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static unsigned int
Packit 9f0df5
t1_rebuild(t1_state_t *t1, unsigned char *block)
Packit 9f0df5
{
Packit 9f0df5
	unsigned char pcb = t1 -> previous_block[1];
Packit 9f0df5
Packit 9f0df5
	/* copy the last sent block */
Packit 9f0df5
	if (T1_R_BLOCK == t1_block_type(pcb))
Packit 9f0df5
		memcpy(block, t1 -> previous_block, 4);
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL2("previous block was not R-Block: %02X", pcb);
Packit 9f0df5
		return 0;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return 4;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Build/verify checksum
Packit 9f0df5
 */
Packit 9f0df5
static unsigned int t1_compute_checksum(t1_state_t * t1,
Packit 9f0df5
	unsigned char *data, size_t len)
Packit 9f0df5
{
Packit 9f0df5
	return len + t1->checksum(data, len, data + len);
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf,
Packit 9f0df5
	size_t len)
Packit 9f0df5
{
Packit 9f0df5
	unsigned char csum[2];
Packit 9f0df5
	int m, n;
Packit 9f0df5
Packit 9f0df5
	m = len - t1->rc_bytes;
Packit 9f0df5
	n = t1->rc_bytes;
Packit 9f0df5
Packit 9f0df5
	if (m < 0)
Packit 9f0df5
		return 0;
Packit 9f0df5
Packit 9f0df5
	t1->checksum(rbuf, m, csum);
Packit 9f0df5
	if (!memcmp(rbuf + m, csum, n))
Packit 9f0df5
		return 1;
Packit 9f0df5
Packit 9f0df5
	return 0;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/*
Packit 9f0df5
 * Send/receive block
Packit 9f0df5
 */
Packit 9f0df5
static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
Packit 9f0df5
	size_t rmax)
Packit 9f0df5
{
Packit 9f0df5
	int n;
Packit 9f0df5
	_ccid_descriptor *ccid_desc ;
Packit 9f0df5
	int oldReadTimeout;
Packit 9f0df5
	unsigned int rmax_int;
Packit 9f0df5
Packit 9f0df5
	DEBUG_XXD("sending: ", block, slen);
Packit 9f0df5
Packit 9f0df5
	ccid_desc = get_ccid_descriptor(t1->lun);
Packit 9f0df5
	oldReadTimeout = ccid_desc->readTimeout;
Packit 9f0df5
Packit 9f0df5
	if (t1->wtx > 1)
Packit 9f0df5
	{
Packit 9f0df5
		/* set the new temporary timeout at WTX card request */
Packit 9f0df5
		ccid_desc->readTimeout *=  t1->wtx;
Packit 9f0df5
		DEBUG_INFO2("New timeout at WTX request: %d sec",
Packit 9f0df5
			ccid_desc->readTimeout);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if (isCharLevel(t1->lun))
Packit 9f0df5
	{
Packit 9f0df5
		rmax = 3;
Packit 9f0df5
Packit 9f0df5
		n = CCID_Transmit(t1 -> lun, slen, block, rmax, t1->wtx);
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		/* the second argument of CCID_Receive() is (unsigned int *)
Packit 9f0df5
		 * so we can't use &rmax since &rmax is a (size_t *) and may not
Packit 9f0df5
		 * be the same on 64-bits architectures for example (iMac G5) */
Packit 9f0df5
		rmax_int = rmax;
Packit 9f0df5
		n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
Packit 9f0df5
Packit 9f0df5
		if (n == IFD_PARITY_ERROR)
Packit 9f0df5
			return -2;
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		rmax = block[2] + 1;
Packit 9f0df5
Packit 9f0df5
		n = CCID_Transmit(t1 -> lun, 0, block, rmax, t1->wtx);
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		rmax_int = rmax;
Packit 9f0df5
		n = CCID_Receive(t1 -> lun, &rmax_int, &block[3], NULL);
Packit 9f0df5
		rmax = rmax_int;
Packit 9f0df5
		if (n == IFD_PARITY_ERROR)
Packit 9f0df5
			return -2;
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		n = rmax + 3;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		n = CCID_Transmit(t1 -> lun, slen, block, 0, t1->wtx);
Packit 9f0df5
		t1->wtx = 0;	/* reset to default value */
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		/* Get the response en bloc */
Packit 9f0df5
		rmax_int = rmax;
Packit 9f0df5
		n = CCID_Receive(t1 -> lun, &rmax_int, block, NULL);
Packit 9f0df5
		rmax = rmax_int;
Packit 9f0df5
		if (n == IFD_PARITY_ERROR)
Packit 9f0df5
			return -2;
Packit 9f0df5
		if (n != IFD_SUCCESS)
Packit 9f0df5
			return -1;
Packit 9f0df5
Packit 9f0df5
		n = rmax;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if (n >= 0)
Packit 9f0df5
	{
Packit 9f0df5
		int m;
Packit 9f0df5
Packit 9f0df5
		m = block[2] + 3 + t1->rc_bytes;
Packit 9f0df5
		if (m < n)
Packit 9f0df5
			n = m;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if (n >= 0)
Packit 9f0df5
		DEBUG_XXD("received: ", block, n);
Packit 9f0df5
Packit 9f0df5
	/* Restore initial timeout */
Packit 9f0df5
	ccid_desc->readTimeout = oldReadTimeout;
Packit 9f0df5
Packit 9f0df5
	return n;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
int t1_negotiate_ifsd(t1_state_t * t1, unsigned int dad, int ifsd)
Packit 9f0df5
{
Packit 9f0df5
	ct_buf_t sbuf;
Packit 9f0df5
	unsigned char sdata[T1_BUFFER_SIZE];
Packit 9f0df5
	unsigned int slen;
Packit 9f0df5
	unsigned int retries;
Packit 9f0df5
	size_t snd_len;
Packit 9f0df5
	int n;
Packit 9f0df5
	unsigned char snd_buf[1];
Packit 9f0df5
Packit 9f0df5
	retries = t1->retries;
Packit 9f0df5
Packit 9f0df5
	/* S-block IFSD request */
Packit 9f0df5
	snd_buf[0] = ifsd;
Packit 9f0df5
	snd_len = 1;
Packit 9f0df5
Packit 9f0df5
	/* Initialize send/recv buffer */
Packit 9f0df5
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
Packit 9f0df5
Packit 9f0df5
	while (TRUE)
Packit 9f0df5
	{
Packit 9f0df5
		/* Build the block */
Packit 9f0df5
		slen = t1_build(t1, sdata, 0, T1_S_BLOCK | T1_S_IFS, &sbuf, NULL);
Packit 9f0df5
Packit 9f0df5
		/* Send the block */
Packit 9f0df5
		n = t1_xcv(t1, sdata, slen, sizeof(sdata));
Packit 9f0df5
Packit 9f0df5
		retries--;
Packit 9f0df5
		/* ISO 7816-3 Rule 7.4.2 */
Packit 9f0df5
		if (retries <= 0)
Packit 9f0df5
			goto error;
Packit 9f0df5
Packit 9f0df5
		if (-1 == n)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL("fatal: transmit/receive failed");
Packit 9f0df5
			goto error;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((-2 == n)								/* Parity error */
Packit 9f0df5
			|| (sdata[DATA] != ifsd)				/* Wrong ifsd received */
Packit 9f0df5
			|| (sdata[NAD] != swap_nibbles(dad))	/* wrong NAD */
Packit 9f0df5
			|| (!t1_verify_checksum(t1, sdata, n))	/* checksum failed */
Packit 9f0df5
			|| (n != 4 + (int)t1->rc_bytes)				/* wrong frame length */
Packit 9f0df5
			|| (sdata[LEN] != 1)					/* wrong data length */
Packit 9f0df5
			|| (sdata[PCB] != (T1_S_BLOCK | T1_S_RESPONSE | T1_S_IFS))) /* wrong PCB */
Packit 9f0df5
			continue;
Packit 9f0df5
Packit 9f0df5
		/* no more error */
Packit 9f0df5
		goto done;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
done:
Packit 9f0df5
	return n;
Packit 9f0df5
Packit 9f0df5
error:
Packit 9f0df5
	t1->state = DEAD;
Packit 9f0df5
	return -1;
Packit 9f0df5
}