/* * 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); }
/* * 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; }
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; }
/* * 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); }
/* * 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); }
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); }
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); }
/* * 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; }
/* * 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); }
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); }
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; }
void ct_buf_set(ct_buf_t *bp, void *mem, size_t len) { ct_buf_init(bp, mem, len); bp->tail = len; }
/* * 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; }
/* * 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; }
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; }