Esempio n. 1
0
/*
 * Lock/unlock a card
 */
int ct_card_lock(ct_handle * h, unsigned int slot, int type,
		 ct_lock_handle * res)
{
	ct_tlv_parser_t tlv;
	unsigned char buffer[256];
	ct_buf_t args, resp;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_LOCK);
	ct_buf_putc(&args, slot);

	ct_args_int(&args, CT_TAG_LOCKTYPE, type);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	if ((rc = ct_tlv_parse(&tlv, &resp)) < 0)
		return rc;

	if (ct_tlv_get_int(&tlv, CT_TAG_LOCK, res) == 0)
		return IFD_ERROR_GENERIC;

	return 0;
}
Esempio n. 2
0
/*
 * Transceive an APDU
 */
int ct_card_transact(ct_handle * h, unsigned int slot,
		     const void *send_data, size_t send_len,
		     void *recv_buf, size_t recv_size)
{
	ct_tlv_parser_t tlv;
	unsigned char buffer[CT_SOCKET_BUFSIZ];
	ct_buf_t args, resp;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_TRANSACT);
	ct_buf_putc(&args, slot);

	ct_args_opaque(&args, CT_TAG_CARD_REQUEST,
		       (const unsigned char *)send_data, send_len);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	if ((rc = ct_tlv_parse(&tlv, &resp)) < 0)
		return rc;

	/* Get the ATR */
	return ct_tlv_get_bytes(&tlv, CT_TAG_CARD_RESPONSE,
				recv_buf, recv_size);
}
Esempio n. 3
0
/*
 * Read from a synchronous card
 */
int ct_card_read_memory(ct_handle * h, unsigned int slot,
			unsigned short address, void *recv_buf, size_t recv_len)
{
	ct_tlv_parser_t tlv;
	unsigned char buffer[CT_SOCKET_BUFSIZ];
	ct_buf_t args, resp;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_MEMORY_READ);
	ct_buf_putc(&args, slot);

	ct_args_int(&args, CT_TAG_ADDRESS, address);
	ct_args_int(&args, CT_TAG_COUNT, recv_len);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	if ((rc = ct_tlv_parse(&tlv, &resp)) < 0)
		return rc;

	return ct_tlv_get_bytes(&tlv, CT_TAG_DATA, recv_buf, recv_len);
}
Esempio n. 4
0
int ct_card_request(ct_handle * h, unsigned int slot,
		    unsigned int timeout, const char *message,
		    void *atr, size_t atr_len)
{
	ct_tlv_parser_t tlv;
	unsigned char buffer[256];
	ct_buf_t args, resp;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_RESET);
	ct_buf_putc(&args, slot);

	/* Add arguments if given */
	if (timeout)
		ct_args_int(&args, CT_TAG_TIMEOUT, timeout);
	if (message)
		ct_args_string(&args, CT_TAG_MESSAGE, message);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	if ((rc = ct_tlv_parse(&tlv, &resp)) < 0)
		return rc;

	/* Get the ATR. There may be no ATR if the card is synchronous */
	rc = ct_tlv_get_bytes(&tlv, CT_TAG_ATR, atr, atr_len);
	if (rc < 0)
		rc = 0;

	return rc;
}
Esempio n. 5
0
/*
 * Verify PIN
 */
int ct_card_verify(ct_handle * h, unsigned int slot,
		   unsigned int timeout, const char *prompt,
		   unsigned int pin_encoding,
		   unsigned int pin_length,
		   unsigned int pin_offset,
		   const void *send_buf, size_t send_len,
		   void *recv_buf, size_t recv_len)
{
	unsigned char buffer[256];
	ct_buf_t args, resp;
	ct_tlv_builder_t builder;
	ct_tlv_parser_t parser;
	unsigned char control = 0x00;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, recv_buf, recv_len);

	ct_buf_putc(&args, CT_CMD_PERFORM_VERIFY);
	ct_buf_putc(&args, slot);

	if (timeout)
		ct_args_int(&args, CT_TAG_TIMEOUT, timeout);
	if (prompt)
		ct_args_string(&args, CT_TAG_MESSAGE, prompt);

	ct_tlv_builder_init(&builder, &args, 1);
	ct_tlv_put_tag(&builder, CT_TAG_PIN_DATA);

	/* Build the control byte */
	if (pin_encoding == IFD_PIN_ENCODING_ASCII)
		control |= 0x01;
	else if (pin_encoding != IFD_PIN_ENCODING_BCD)
		return IFD_ERROR_INVALID_ARG;
	if (pin_length)
		control |= pin_length << 4;
	ct_tlv_add_byte(&builder, control);

	/* Offset is 1 based */
	ct_tlv_add_byte(&builder, pin_offset + 1);
	ct_tlv_add_bytes(&builder, (const unsigned char *)send_buf, send_len);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	if ((rc = ct_tlv_parse(&parser, &resp)) < 0)
		return rc;

	/* Get the ATR */
	return ct_tlv_get_bytes(&parser,
				CT_TAG_CARD_RESPONSE, recv_buf, recv_len);
}
Esempio n. 6
0
int ct_card_set_protocol(ct_handle * h, unsigned int slot,
			 unsigned int protocol)
{
	unsigned char buffer[256];
	ct_buf_t args, resp;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_SET_PROTOCOL);
	ct_buf_putc(&args, slot);
	ct_args_int(&args, CT_TAG_PROTOCOL, protocol);
	return ct_socket_call(h->sock, &args, &resp);
}
Esempio n. 7
0
int ct_card_unlock(ct_handle * h, unsigned int slot, ct_lock_handle lock)
{
	unsigned char buffer[256];
	ct_buf_t args, resp;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_UNLOCK);
	ct_buf_putc(&args, slot);

	ct_args_int(&args, CT_TAG_LOCK, lock);

	return ct_socket_call(h->sock, &args, &resp);
}
Esempio n. 8
0
/*
 * Print something to the reader's display
 */
int ct_reader_output(ct_handle * h, const char *message)
{
	unsigned char buffer[256];
	ct_buf_t args, resp;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_OUTPUT);
	ct_buf_putc(&args, CT_UNIT_READER);

	/* Add arguments if given */
	if (message)
		ct_args_string(&args, CT_TAG_MESSAGE, message);

	return ct_socket_call(h->sock, &args, &resp);
}
Esempio n. 9
0
File: tlv.c Progetto: OpenSC/openct
void ct_tlv_put_tag(ct_tlv_builder_t * builder, ifd_tag_t tag)
{
	ct_buf_t *bp = builder->buf;

	if (builder->error < 0)
		return;
	if (builder->use_large_tags)
		tag |= __CT_TAG_LARGE;
	if (ct_buf_putc(bp, tag) < 0)
		goto err;
	builder->len = 0;
	builder->lenp = (unsigned char *)ct_buf_tail(bp);
	if (ct_buf_putc(bp, 0) < 0
	    || (builder->use_large_tags && ct_buf_putc(bp, 0) < 0))
		goto err;
	return;

      err:builder->error = -1;
}
Esempio n. 10
0
int ct_card_eject(ct_handle * h, unsigned int slot,
		  unsigned int timeout, const char *message)
{
	unsigned char buffer[256];
	ct_buf_t args, resp;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_EJECT_ICC);
	ct_buf_putc(&args, slot);

	/* Add arguments if given */
	if (timeout)
		ct_args_int(&args, CT_TAG_TIMEOUT, timeout);
	if (message)
		ct_args_string(&args, CT_TAG_MESSAGE, message);

	return ct_socket_call(h->sock, &args, &resp);
}
Esempio n. 11
0
int ct_card_write_memory(ct_handle * h, unsigned int slot,
			 unsigned short address,
			 const void *send_buf, size_t send_len)
{
	unsigned char buffer[CT_SOCKET_BUFSIZ];
	ct_buf_t args, resp;
	int rc;

	ct_buf_init(&args, buffer, sizeof(buffer));
	ct_buf_init(&resp, buffer, sizeof(buffer));

	ct_buf_putc(&args, CT_CMD_MEMORY_WRITE);
	ct_buf_putc(&args, slot);

	ct_args_int(&args, CT_TAG_ADDRESS, address);
	ct_args_opaque(&args, CT_TAG_DATA, (const unsigned char *)send_buf,
		       send_len);

	rc = ct_socket_call(h->sock, &args, &resp);
	if (rc < 0)
		return rc;

	return 0;
}
Esempio n. 12
0
/*
 * 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)
{
	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;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* we can't talk to a dead card / reader. Reset it! */
	if (t1->state == DEAD)
		return -1;

	t1->state = SENDING;
	retries = t1->retries;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		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 || sent_length)
				goto resync;
			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 (t1->state == RECEIVING) {
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK, NULL, NULL);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* The first I-block sent by the ICC indicates
			 * the last block we sent was received successfully. */
			if (t1->state == SENDING) {
				ct_buf_get(&sbuf, NULL, last_send);
				last_send = 0;
				t1->ns ^= 1;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * what we expected it to send, reply with
			 * an R block */
			if (t1_seq(pcb) != t1->nr) {
				slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			t1->nr ^= 1;

			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
				goto error;

			if ((pcb & T1_MORE_BLOCKS) == 0)
				goto done;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		case T1_S_BLOCK:
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
				t1->state = SENDING;
				sent_length = 0;
				last_send = 0;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
				goto resync;

			ct_buf_init(&tbuf, sblk, sizeof(sblk));

			switch (T1_S_TYPE(pcb)) {
			case T1_S_RESYNC:
				/* the card is not allowed to send a resync. */
				goto resync;
			case T1_S_ABORT:
				ifd_debug(1, "abort requested");
				break;
			case T1_S_IFS:
				ifd_debug(1, "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]);
				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));
				goto resync;
			}

			slen = t1_build(t1, sdata, dad,
					T1_S_BLOCK | T1_S_RESPONSE |
					T1_S_TYPE(pcb), &tbuf, NULL);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

	      resync:
		/* the number or resyncs is limited, too */
		if (resyncs == 0)
			goto error;
		resyncs--;
		t1->ns = 0;
		t1->nr = 0;
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
				NULL);
		t1->state = RESYNCH;
		continue;
	}

      done:
	return ct_buf_avail(&rbuf);

      error:
	t1->state = DEAD;
	return -1;
}
/*
 * Send an APDU through T=1
 */
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)
{
	ct_buf_t sbuf, rbuf, tbuf;
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
	unsigned int slen, retries, resyncs, sent_length = 0;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* 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;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		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 ((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_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 ((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);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* 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;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * 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);
				continue;
			}

			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;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		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;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
			{
				/* 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:
				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:
				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:
				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_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
				t1->wtx = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;

			default:
				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);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

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:
	return ct_buf_avail(&rbuf);

error:
	t1->state = DEAD;
	return -1;
}