Beispiel #1
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);
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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);
}
Beispiel #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);
}
Beispiel #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);
}
Beispiel #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);
}
Beispiel #8
0
/*
 * Parse the ifd config file
 */
int ifd_config_parse(const char *filename)
{
	char buffer[512];
	int rc;

	if ((config_filename = filename) == NULL)
		config_filename = OPENCT_CONF_PATH;

	/* If config file doesn't exist, quietly sneak out of here */
	if ((config_fd = open(config_filename, O_RDONLY)) < 0) {
		if (errno == ENOENT)
			return 0;
		ct_error("Unable to open %s: %m", filename);
		return -1;
	}

	/* Init parse buffer. */
	ct_buf_init(&config_buf, buffer, sizeof(buffer));
	config_line = 1;

	config_top.name = "<config>";
	rc = conf_parse_group(&config_top, END_OF_FILE);

	close(config_fd);
	config_fd = -1;

	if (ct_config.debug > 2)
		conf_dump(&config_top, 0);

	return rc;
}
Beispiel #9
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);
}
Beispiel #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);
}
Beispiel #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;
}
Beispiel #12
0
void
ct_buf_set(ct_buf_t *bp, void *mem, size_t len)
{
	ct_buf_init(bp, mem, len);
	bp->tail = len;
}
Beispiel #13
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;
}
Beispiel #14
0
/*
 * Request ICC
 */
int ifd_card_request(ifd_reader_t * reader, unsigned int idx, time_t timeout,
		     const char *message, void *atr, size_t size)
{
	const ifd_driver_t *drv = reader->driver;
	ifd_device_t *dev = reader->device;
	ifd_slot_t *slot;
	unsigned int count;
	int n, parity;

	if (idx > reader->nslots) {
		ct_error("%s: invalid slot number %u", reader->name, idx);
		return IFD_ERROR_INVALID_ARG;
	}

	if (dev == NULL)
		return IFD_ERROR_INVALID_ARG;

	if (!drv || !drv->ops || !drv->ops->card_reset)
		return IFD_ERROR_NOT_SUPPORTED;

	slot = &reader->slot[idx];
	slot->atr_len = 0;

	if (slot->proto) {
		ifd_protocol_free(slot->proto);
		slot->proto = NULL;
	}

	/* Do the reset thing - if the driver supports
	 * request ICC, call the function if needed.
	 * Otherwise fall back to ordinary reset.
	 *
	 * For asynchronous cards, the driver's card_reset
	 * function should perform the reset, and start to
	 * read the ATR. It should either read the first byte
	 * of the ATR, and leave it to the caller to read
	 * the remaining bytes of it, or it should read the
	 * whole ATR (as done by the B1 driver, for instance).
	 *
	 * When receiving the complete ATR, we will select
	 * the default protocol as specified by the card.
	 * 
	 * If the driver was unable to receive the ATR
	 * (e.g. because the command timed out) it should
	 * return IFD_ERROR_NO_ATR. This will allow us
	 * to retry with different parity.
	 *
	 * For synchronous cards, the driver can call
	 * ifd_sync_detect_icc to detect whether the card
	 * is synchronous. This will also set the slot's
	 * protocol.
	 *
	 * If the card driver does it's own handling of sync
	 * ICCs, it should call ifd_set_protocol to signal
	 * that card detection was successful.
	 */
	if (drv->ops->card_request && (timeout || message)) {
		n = drv->ops->card_request(reader, idx,
					   timeout, message, slot->atr,
					   sizeof(slot->atr));
		if (n <= 0)
			return n;
		count = n;
	} else
	    if (dev->type != IFD_DEVICE_TYPE_SERIAL
		|| !drv->ops->change_parity) {
		n = drv->ops->card_reset(reader, idx,
					 slot->atr, sizeof(slot->atr));
		if (n <= 0)
			return n;
		count = n;
	} else {
		parity = IFD_SERIAL_PARITY_EVEN;
		if ((n = drv->ops->change_parity(reader, parity)) < 0)
			return n;

		/* Reset the card */
		n = drv->ops->card_reset(reader, idx,
					 slot->atr, sizeof(slot->atr));

		/* If there was no ATR, try again with odd parity */
		if (n == IFD_ERROR_NO_ATR) {
			parity = IFD_SERIAL_PARITY_TOGGLE(parity);
			if (drv->ops->change_parity(reader, parity) < 0)
				return -1;
			n = drv->ops->card_reset(reader, idx,
						 slot->atr, sizeof(slot->atr));
		}

		/* Bail out in case of general error */
		if (n < 0)
			return -1;

		count = n;

		/* If we got just the first byte of the (async) ATR,
		 * get the rest now */
		if (count == 1) {
			ct_buf_t rbuf;
			unsigned char c;
			unsigned int num, proto = 0;
			int revert_bits = 0;

			if (slot->atr[0] == 0x03) {
				revert_bits = 1;
				slot->atr[0] = 0x3F;
			}

			ct_buf_init(&rbuf, slot->atr, sizeof(slot->atr));
			rbuf.tail++;

			if (ifd_recv_atr(dev, &rbuf, 1, revert_bits) < 0)
				return -1;

			c = rbuf.base[1];
			while (1) {
				num = ifd_count_bits(c & 0xF0);
				if (ifd_recv_atr(dev, &rbuf, num, revert_bits) <
				    0)
					return -1;

				if (!(c & 0x80))
					break;

				c = rbuf.base[rbuf.tail - 1];
				proto = c & 0xF;
			}

			/* Historical bytes */
			c = rbuf.base[1] & 0xF;
			if (ifd_recv_atr(dev, &rbuf, c, revert_bits) < 0)
				return -1;

			/* If a protocol other than T0 was specified,
			 * read check byte */
			if (proto
			    && ifd_recv_atr(dev, &rbuf, 1, revert_bits) < 0)
				return -1;

			if (slot->atr[0] == 0x3F)
				parity = IFD_SERIAL_PARITY_TOGGLE(parity);
			count = rbuf.tail - rbuf.head;
		}

		ifd_debug(1, "received atr:%s", ct_hexdump(slot->atr, count));

		/* Set the parity in case it was toggled */
		if (drv->ops->change_parity(reader, parity) < 0)
			return -1;
	}

	slot->atr_len = count;

	if (count > size)
		size = count;
	if (atr)
		memcpy(atr, slot->atr, count);

	/* For synchronous cards, the slot's protocol will already
	 * be set when we get here. */
	if (slot->proto == NULL) {
		if (!ifd_protocol_select(reader, idx, IFD_PROTOCOL_DEFAULT))
			ct_error("Protocol selection failed");
	}

	return count;
}
/*
 * 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;
}
Beispiel #16
0
static int t0_xcv(ifd_protocol_t * prot, const void *sdata, size_t slen,
		  void *rdata, size_t rlen)
{
	t0_state_t *t0 = (t0_state_t *) prot;
	ct_buf_t sbuf, rbuf;
	unsigned int null_count = 0;
	unsigned int ins;

	/* Let the driver handle any chunking etc */
	if (t0->block_oriented) {
		int rc;

		if ((rc = ifd_send_command(prot, sdata, slen)) >= 0)
			rc = ifd_recv_response(prot, rdata, rlen, t0->timeout);
		return rc;
	}

	/* Set up the send buffer */
	ct_buf_set(&sbuf, (void *)sdata, slen);
	ct_buf_init(&rbuf, rdata, rlen);

	/* Get the INS */
	ins = sbuf.base[1];

	if (t0_send(prot, &sbuf, 5) < 0)
		goto failed;

	while (1) {
		unsigned char byte;
		int count;

		if (ifd_recv_response(prot, &byte, 1, t0->timeout) < 0)
			goto failed;

		/* Null byte to extend wait time */
		if (byte == 0x60) {
			usleep(100000);
			if (++null_count > t0->max_nulls)
				goto failed;
			continue;
		}

		/* ICC sends SW1 SW2 */
		if ((byte & 0xF0) == 0x60 || (byte & 0xF0) == 0x90) {
			/* Store SW1, then get SW2 and store it */
			if (ct_buf_put(&rbuf, &byte, 1) < 0
			    || t0_recv(prot, &rbuf, 1, t0->timeout) < 0)
				goto failed;

			break;
		}

		/* Send/receive data.
		 * ACK byte means transfer everything in one go,
		 * ~ACK means do it octet by octet.
		 * SCEZ masks off using 0xFE, but the Towitoko
		 * driver uses 0x0E.
		 * Do we need to make this configurable?
		 */
		if (((byte ^ ins) & 0xFE) == 0) {
			/* Send/recv as much as we can */
			count = -1;
		} else if (((~byte ^ ins) & 0xFE) == 0) {
			count = 1;
		} else {
			ifd_debug(2, "unexpected byte 0x%02x", byte);
			return -1;
		}

		if (t0->state == SENDING) {
			if (t0_send(prot, &sbuf, count) < 0)
				goto failed;
		} else {
			if (t0_recv(prot, &rbuf, count, t0->timeout) < 0)
				goto failed;
			if (ct_buf_tailroom(&rbuf) == 0)
				break;
		}
	}

	return ct_buf_avail(&rbuf);

      failed:t0->state = CONFUSED;
	return -1;
}