diff --git a/CMakeLists.txt b/CMakeLists.txt index f22f1fa..bc6f3ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,10 +14,11 @@ add_executable(hsm2040) target_sources(hsm2040 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/hsm2040.c ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c +# ${CMAKE_CURRENT_LIST_DIR}/openpgp-do.c ) target_include_directories(hsm2040 PUBLIC ${CMAKE_CURRENT_LIST_DIR}) pico_add_extra_outputs(hsm2040) -target_link_libraries(hsm2040 PRIVATE pico_stdlib tinyusb_device tinyusb_board) \ No newline at end of file +target_link_libraries(hsm2040 PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore) \ No newline at end of file diff --git a/ccid.h b/ccid.h index 5abcdc6..6a8e241 100644 --- a/ccid.h +++ b/ccid.h @@ -20,6 +20,21 @@ struct apdu { extern struct apdu apdu; +/* CCID thread */ +#define EV_CARD_CHANGE 1 +#define EV_TX_FINISHED 2 /* CCID Tx finished */ +#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */ +#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */ +#define EV_RX_DATA_READY 16 /* USB Rx data available */ + +/* OpenPGPcard thread */ +#define EV_MODIFY_CMD_AVAILABLE 1 +#define EV_VERIFY_CMD_AVAILABLE 2 +#define EV_CMD_AVAILABLE 4 +#define EV_EXIT 8 +#define EV_PINPAD_INPUT_DONE 16 + + enum ccid_state { CCID_STATE_NOCARD, /* No card available */ CCID_STATE_START, /* Initial */ diff --git a/hsm2040.c b/hsm2040.c index 570941e..379fb46 100644 --- a/hsm2040.c +++ b/hsm2040.c @@ -16,6 +16,9 @@ #include "tusb.h" #include "usb_descriptors.h" #include "device/usbd_pvt.h" +#include "pico/util/queue.h" +#include "pico/multicore.h" + // Device descriptors #include "hsm2040.h" @@ -69,63 +72,144 @@ static uint8_t ccid_buffer[USB_BUF_SIZE]; #define CCID_OFFSET_DATA_LEN 1 #define CCID_OFFSET_PARAM 8 +struct ep_in { + uint8_t ep_num; + uint8_t tx_done; + const uint8_t *buf; + size_t cnt; + size_t buf_len; + void *priv; + void (*next_buf) (struct ep_in *epi, size_t len); +}; + +static void epi_init (struct ep_in *epi, int ep_num, void *priv) +{ + epi->ep_num = ep_num; + epi->tx_done = 0; + epi->buf = NULL; + epi->cnt = 0; + epi->buf_len = 0; + epi->priv = priv; + epi->next_buf = NULL; +} + +struct ep_out { + uint8_t ep_num; + uint8_t err; + uint8_t *buf; + size_t cnt; + size_t buf_len; + void *priv; + void (*next_buf) (struct ep_out *epo, size_t len); + int (*end_rx) (struct ep_out *epo, size_t orig_len); +}; + +static struct ep_out endpoint_out; +static struct ep_in endpoint_in; + +static void epo_init (struct ep_out *epo, int ep_num, void *priv) +{ + epo->ep_num = ep_num; + epo->err = 0; + epo->buf = NULL; + epo->cnt = 0; + epo->buf_len = 0; + epo->priv = priv; + epo->next_buf = NULL; + epo->end_rx = NULL; +} struct ccid_header { - uint8_t msg_type; - uint32_t data_len; - uint8_t slot; - uint8_t seq; - uint8_t rsvd; - uint16_t param; + uint8_t msg_type; + uint32_t data_len; + uint8_t slot; + uint8_t seq; + uint8_t rsvd; + uint16_t param; } __attribute__((packed)); /* Data structure handled by CCID layer */ struct ccid { - uint32_t ccid_state : 4; - uint32_t state : 4; - uint32_t err : 1; - uint32_t tx_busy : 1; - uint32_t timeout_cnt: 3; + uint32_t ccid_state : 4; + uint32_t state : 4; + uint32_t err : 1; + uint32_t tx_busy : 1; + uint32_t timeout_cnt: 3; - uint8_t *p; - size_t len; + uint8_t *p; + size_t len; - struct ccid_header ccid_header; + struct ccid_header ccid_header; - uint8_t sw1sw2[2]; - uint8_t chained_cls_ins_p1_p2[4]; + uint8_t sw1sw2[2]; + uint8_t chained_cls_ins_p1_p2[4]; - struct apdu *a; + struct ep_out *epo; + struct ep_in *epi; + + queue_t ccid_comm; + queue_t openpgp_comm; + + uint8_t application; + + struct apdu *a; }; +static uint8_t endp1_rx_buf[64]; +static uint8_t endp1_tx_buf[64]; + +#define APDU_STATE_WAIT_COMMAND 0 +#define APDU_STATE_COMMAND_CHAINING 1 +#define APDU_STATE_COMMAND_RECEIVED 2 +#define APDU_STATE_RESULT 3 +#define APDU_STATE_RESULT_GET_RESPONSE 4 + +static void ccid_reset (struct ccid *c) +{ + c->err = 0; + c->tx_busy = 0; + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->a->cmd_apdu_data_len = 0; + c->a->expected_res_size = 0; +} + static void ccid_init(struct ccid *c, struct apdu *a) { - c->ccid_state = CCID_STATE_START; - c->err = 0; - c->tx_busy = 0; - c->state = APDU_STATE_WAIT_COMMAND; - c->p = a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - memset (&c->ccid_header, 0, sizeof (struct ccid_header)); - c->sw1sw2[0] = 0x90; - c->sw1sw2[1] = 0x00; - c->a = a; + c->ccid_state = CCID_STATE_START; + c->err = 0; + c->tx_busy = 0; + c->state = APDU_STATE_WAIT_COMMAND; + c->p = a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + memset (&c->ccid_header, 0, sizeof (struct ccid_header)); + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + c->a = a; + queue_init(&c->openpgp_comm, sizeof(uint32_t), 64); + queue_init(&c->ccid_comm, sizeof(uint32_t), 64); } +#define CMD_APDU_HEAD_SIZE 5 + static void apdu_init (struct apdu *a) { - a->seq = 0; /* will be set by lower layer */ - a->cmd_apdu_head = &ccid_buffer[0]; - a->cmd_apdu_data = &ccid_buffer[5]; - a->cmd_apdu_data_len = 0; /* will be set by lower layer */ - a->expected_res_size = 0; /* will be set by lower layer */ + a->seq = 0; /* will be set by lower layer */ + a->cmd_apdu_head = &ccid_buffer[0]; + a->cmd_apdu_data = &ccid_buffer[5]; + a->cmd_apdu_data_len = 0; /* will be set by lower layer */ + a->expected_res_size = 0; /* will be set by lower layer */ - a->sw = 0x9000; /* will be set by upper layer */ - a->res_apdu_data = &ccid_buffer[5]; /* will be set by upper layer */ - a->res_apdu_data_len = 0; /* will be set by upper layer */ + a->sw = 0x9000; /* will be set by upper layer */ + a->res_apdu_data = &ccid_buffer[5]; /* will be set by upper layer */ + a->res_apdu_data_len = 0; /* will be set by upper layer */ } +/* +!!!! IT USES ENDP2, Interruption + #define NOTIFY_SLOT_CHANGE 0x50 static void ccid_notify_slot_change(struct ccid *c) { @@ -142,17 +226,23 @@ static void ccid_notify_slot_change(struct ccid *c) tud_vendor_write(notification, sizeof(notification)); } +*/ + +#define USB_CCID_TIMEOUT (1950*1000) + +#define GPG_THREAD_TERMINATED 0xffff +#define GPG_ACK_TIMEOUT 0x6600 static void ccid_init_cb(void) { struct ccid *c = &ccid; TU_LOG2("-------- CCID INIT\r\n"); vendord_init(); - - ccid_notify_slot_change(c); + + //ccid_notify_slot_change(c); } -static void ccid_reset(uint8_t rhport) { +static void ccid_reset_cb(uint8_t rhport) { TU_LOG2("-------- CCID RESET\r\n"); itf_num = 0; vendord_reset(rhport); @@ -162,7 +252,7 @@ static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, tusb_desc_interface_t itf_vendor; TU_LOG2("-------- CCID OPEN\r\n"); TU_VERIFY(itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0); - + //vendord_open expects a CLASS_VENDOR interface class memcpy(&itf_vendor, itf_desc, sizeof(tusb_desc_interface_t)); itf_vendor.bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC; @@ -181,7 +271,7 @@ static bool ccid_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_co TU_LOG2("-------- CCID CTRL XFER\r\n"); if (stage != CONTROL_STAGE_SETUP) return true; - if (request->wIndex == itf_num) + if (request->wIndex == itf_num) { TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\r\n",request->bmRequestType,request->bRequest, request->wValue, request->wLength); /* @@ -227,7 +317,7 @@ static usbd_class_driver_t const ccid_driver = .name = "CCID", #endif .init = ccid_init_cb, - .reset = ccid_reset, + .reset = ccid_reset_cb, .open = ccid_open, .control_xfer_cb = ccid_control_xfer_cb, .xfer_cb = ccid_xfer_cb, @@ -241,59 +331,1158 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { } enum { - BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, - BLINK_RED = 18, - BLINK_GREEN = 19, - BLINK_BLUE = 20, + BLINK_RED = 18, + BLINK_GREEN = 19, + BLINK_BLUE = 20, - BLINK_ALWAYS_ON = UINT32_MAX, - BLINK_ALWAYS_OFF = 0 + BLINK_ALWAYS_ON = UINT32_MAX, + BLINK_ALWAYS_OFF = 0 }; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -//--------------------------------------------------------------------+ -// USB CDC -//--------------------------------------------------------------------+ -void vendor_task(void) +void usb_tx_enable(const void *buf, uint32_t len) { - if ( tud_vendor_mounted() ) - { - // connected and there are data available - if ( tud_vendor_available() ) - { - TU_LOG2("---- TASK VENDR AVAILABLE\r\n"); - uint8_t buf[64]; + tud_vendor_write(buf, len); +} - uint32_t count = tud_vendor_read(buf, sizeof(buf)); - TU_LOG2("-------- RECEIVED %d, %x %x %x",count,buf[0],buf[1],buf[2]); - // echo back to both web serial and cdc - //echo_all(buf, count); +/* + * ATR (Answer To Reset) string + * + * TS = 0x3b: Direct conversion + * T0 = 0xda: TA1, TC1 and TD1 follow, 10 historical bytes + * TA1 = 0x11: FI=1, DI=1 + * TC1 = 0xff + * TD1 = 0x81: TD2 follows, T=1 + * TD2 = 0xb1: TA3, TB3 and TD3 follow, T=1 + * TA3 = 0xFE: IFSC = 254 bytes + * TB3 = 0x55: BWI = 5, CWI = 5 (BWT timeout 3.2 sec) + * TD3 = 0x1f: TA4 follows, T=15 + * TA4 = 0x03: 5V or 3.3V + * + * Minimum: 0x3b, 0x8a, 0x80, 0x01 + * + */ +static const uint8_t ATR_head[] = { + 0x3b, 0xda, 0x11, 0xff, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0x03, +}; + +/* Send back ATR (Answer To Reset) */ +static enum ccid_state ccid_power_on (struct ccid *c) +{ + uint8_t p[CCID_MSG_HEADER_SIZE+1]; /* >= size of historical_bytes -1 */ + int hist_len = 0;// historical_bytes[0]; + size_t size_atr = sizeof (ATR_head) + hist_len + 1; + uint8_t xor_check = 0; + int i; + + if (c->application == 0) + { + //multicore_launch_core1(openpgp_card_thread); + c->application = 1; + } + p[0] = CCID_DATA_BLOCK_RET; + p[1] = size_atr; + p[2] = 0x00; + p[3] = 0x00; + p[4] = 0x00; + p[5] = 0x00; /* Slot */ + p[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; + p[CCID_MSG_STATUS_OFFSET] = 0x00; + p[CCID_MSG_ERROR_OFFSET] = 0x00; + p[CCID_MSG_CHAIN_OFFSET] = 0x00; + + memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, ATR_head, sizeof (ATR_head)); + + for (i = 1; i < (int)sizeof (ATR_head); i++) + xor_check ^= ATR_head[i]; + //memcpy (p, historical_bytes + 1, hist_len); +#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT + if (file_selection == 255) + p[7] = 0x03; +#endif + for (i = 0; i < hist_len; i++) + xor_check ^= p[i]; + p[i] = xor_check; + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE+sizeof (ATR_head), p, hist_len+1); + + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE + size_atr); + + DEBUG_INFO ("ON\r\n"); + c->tx_busy = 1; + return CCID_STATE_WAIT; +} + +static void ccid_send_status (struct ccid *c) +{ + uint8_t ccid_reply[CCID_MSG_HEADER_SIZE]; + + ccid_reply[0] = CCID_SLOT_STATUS_RET; + ccid_reply[1] = 0x00; + ccid_reply[2] = 0x00; + ccid_reply[3] = 0x00; + ccid_reply[4] = 0x00; + ccid_reply[5] = 0x00; /* Slot */ + ccid_reply[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; + if (c->ccid_state == CCID_STATE_NOCARD) + ccid_reply[CCID_MSG_STATUS_OFFSET] = 2; /* 2: No ICC present */ + else if (c->ccid_state == CCID_STATE_START) + /* 1: ICC present but not activated */ + ccid_reply[CCID_MSG_STATUS_OFFSET] = 1; + else + ccid_reply[CCID_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */ + ccid_reply[CCID_MSG_ERROR_OFFSET] = 0x00; + ccid_reply[CCID_MSG_CHAIN_OFFSET] = 0x00; + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + + memcpy (endp1_tx_buf, ccid_reply, CCID_MSG_HEADER_SIZE); + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE); + c->tx_busy = 1; +} + +static enum ccid_state ccid_power_off (struct ccid *c) +{ + if (c->application) + { + uint32_t flag = EV_EXIT; + queue_try_add(&c->openpgp_comm, &flag); + c->application = 0; + } + + c->ccid_state = CCID_STATE_START; /* This status change should be here */ + ccid_send_status (c); + DEBUG_INFO ("OFF\r\n"); + c->tx_busy = 1; + return CCID_STATE_START; +} + +static void no_buf (struct ep_in *epi, size_t len) +{ + (void)len; + epi->buf = NULL; + epi->cnt = 0; + epi->buf_len = 0; +} + +static void set_sw1sw2 (struct ccid *c, size_t chunk_len) +{ + if (c->a->expected_res_size >= c->len) + { + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + } + else + { + c->sw1sw2[0] = 0x61; + if (c->len - chunk_len >= 256) + c->sw1sw2[1] = 0; + else + c->sw1sw2[1] = (uint8_t)(c->len - chunk_len); + } +} + +static void get_sw1sw2 (struct ep_in *epi, size_t len) +{ + struct ccid *c = (struct ccid *)epi->priv; + + (void)len; + epi->buf = c->sw1sw2; + epi->cnt = 0; + epi->buf_len = 2; + epi->next_buf = no_buf; +} + +static void ccid_send_data_block_internal (struct ccid *c, uint8_t status, uint8_t error) +{ + int tx_size = USB_LL_BUF_SIZE; + uint8_t p[CCID_MSG_HEADER_SIZE]; + size_t len; + + if (status == 0) + len = c->a->res_apdu_data_len + 2; + else + len = 0; + + p[0] = CCID_DATA_BLOCK_RET; + p[1] = len & 0xFF; + p[2] = (len >> 8)& 0xFF; + p[3] = (len >> 16)& 0xFF; + p[4] = (len >> 24)& 0xFF; + p[5] = 0x00; /* Slot */ + p[CCID_MSG_SEQ_OFFSET] = c->a->seq; + p[CCID_MSG_STATUS_OFFSET] = status; + p[CCID_MSG_ERROR_OFFSET] = error; + p[CCID_MSG_CHAIN_OFFSET] = 0; + + memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); + + if (len == 0) + { + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE); + c->tx_busy = 1; + return; + } + + if (CCID_MSG_HEADER_SIZE + len <= USB_LL_BUF_SIZE) + { + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE+c->a->res_apdu_data_len, c->sw1sw2, 2); + + c->epi->buf = NULL; + if (CCID_MSG_HEADER_SIZE + len < USB_LL_BUF_SIZE) + c->epi->tx_done = 1; + tx_size = CCID_MSG_HEADER_SIZE + len; + } + else if (CCID_MSG_HEADER_SIZE + len - 1 == USB_LL_BUF_SIZE) + { + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE+c->a->res_apdu_data_len, c->sw1sw2, 1); + + c->epi->buf = &c->sw1sw2[1]; + c->epi->cnt = 1; + c->epi->buf_len = 1; + c->epi->next_buf = no_buf; + } + else if (CCID_MSG_HEADER_SIZE + len - 2 == USB_LL_BUF_SIZE) + { + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); + + c->epi->buf = &c->sw1sw2[0]; + c->epi->cnt = 0; + c->epi->buf_len = 2; + c->epi->next_buf = no_buf; + } + else + { + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); + + c->epi->buf = c->a->res_apdu_data + USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; + c->epi->cnt = USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; + c->epi->buf_len = c->a->res_apdu_data_len - (USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); + c->epi->next_buf = get_sw1sw2; + } + usb_tx_enable (endp1_tx_buf, tx_size); + c->tx_busy = 1; +} + +static void ccid_send_data_block (struct ccid *c) +{ + ccid_send_data_block_internal (c, 0, 0); +} + +static void ccid_send_data_block_time_extension (struct ccid *c) +{ + ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff); +} + +static void ccid_send_data_block_0x9000 (struct ccid *c) +{ + uint8_t p[CCID_MSG_HEADER_SIZE+2]; + size_t len = 2; + + p[0] = CCID_DATA_BLOCK_RET; + p[1] = len & 0xFF; + p[2] = (len >> 8)& 0xFF; + p[3] = (len >> 16)& 0xFF; + p[4] = (len >> 24)& 0xFF; + p[5] = 0x00; /* Slot */ + p[CCID_MSG_SEQ_OFFSET] = c->a->seq; + p[CCID_MSG_STATUS_OFFSET] = 0; + p[CCID_MSG_ERROR_OFFSET] = 0; + p[CCID_MSG_CHAIN_OFFSET] = 0; + p[CCID_MSG_CHAIN_OFFSET+1] = 0x90; + p[CCID_MSG_CHAIN_OFFSET+2] = 0x00; + + memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE + len); + + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE + len); + c->tx_busy = 1; +} + +static void ccid_send_data_block_gr (struct ccid *c, size_t chunk_len) +{ + int tx_size = USB_LL_BUF_SIZE; + uint8_t p[CCID_MSG_HEADER_SIZE]; + size_t len = chunk_len + 2; + + p[0] = CCID_DATA_BLOCK_RET; + p[1] = len & 0xFF; + p[2] = (len >> 8)& 0xFF; + p[3] = (len >> 16)& 0xFF; + p[4] = (len >> 24)& 0xFF; + p[5] = 0x00; /* Slot */ + p[CCID_MSG_SEQ_OFFSET] = c->a->seq; + p[CCID_MSG_STATUS_OFFSET] = 0; + p[CCID_MSG_ERROR_OFFSET] = 0; + p[CCID_MSG_CHAIN_OFFSET] = 0; + + memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); + + set_sw1sw2 (c, chunk_len); + + if (chunk_len <= USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE) + { + int size_for_sw; + + if (chunk_len <= USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE - 2) + size_for_sw = 2; + else if (chunk_len == USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE - 1) + size_for_sw = 1; + else + size_for_sw = 0; + + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->p, chunk_len); + + if (size_for_sw) + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE+chunk_len, c->sw1sw2, size_for_sw); + + tx_size = CCID_MSG_HEADER_SIZE + chunk_len + size_for_sw; + if (size_for_sw == 2) + { + c->epi->buf = NULL; + if (tx_size < USB_LL_BUF_SIZE) + c->epi->tx_done = 1; + /* Don't set epi->tx_done = 1, when it requires ZLP */ + } + else + { + c->epi->buf = c->sw1sw2 + size_for_sw; + c->epi->cnt = size_for_sw; + c->epi->buf_len = 2 - size_for_sw; + c->epi->next_buf = no_buf; + } + } + else + { + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->p, USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); + + c->epi->buf = c->p + USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; + c->epi->cnt = 0; + c->epi->buf_len = chunk_len - (USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); + c->epi->next_buf = get_sw1sw2; + } + + c->p += chunk_len; + c->len -= chunk_len; + usb_tx_enable (endp1_tx_buf, tx_size); + c->tx_busy = 1; +} + +static void ccid_send_params (struct ccid *c) +{ + uint8_t p[CCID_MSG_HEADER_SIZE]; + const uint8_t params[] = { + 0x11, /* bmFindexDindex */ + 0x11, /* bmTCCKST1 */ + 0xFE, /* bGuardTimeT1 */ + 0x55, /* bmWaitingIntegersT1 */ + 0x03, /* bClockStop */ + 0xFE, /* bIFSC */ + 0 /* bNadValue */ + }; + + p[0] = CCID_PARAMS_RET; + p[1] = 0x07; /* Length = 0x00000007 */ + p[2] = 0; + p[3] = 0; + p[4] = 0; + p[5] = 0x00; /* Slot */ + p[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; + p[CCID_MSG_STATUS_OFFSET] = 0; + p[CCID_MSG_ERROR_OFFSET] = 0; + p[CCID_MSG_CHAIN_OFFSET] = 0x01; /* ProtocolNum: T=1 */ + + memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); + memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, params, sizeof params); + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE + sizeof params); + c->tx_busy = 1; +} + +static void ccid_error (struct ccid *c, int offset) +{ + uint8_t ccid_reply[CCID_MSG_HEADER_SIZE]; + + ccid_reply[0] = CCID_SLOT_STATUS_RET; /* Any value should be OK */ + ccid_reply[1] = 0x00; + ccid_reply[2] = 0x00; + ccid_reply[3] = 0x00; + ccid_reply[4] = 0x00; + ccid_reply[5] = 0x00; /* Slot */ + ccid_reply[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; + if (c->ccid_state == CCID_STATE_NOCARD) + ccid_reply[CCID_MSG_STATUS_OFFSET] = 2; /* 2: No ICC present */ + else if (c->ccid_state == CCID_STATE_START) + /* 1: ICC present but not activated */ + ccid_reply[CCID_MSG_STATUS_OFFSET] = 1; + else + ccid_reply[CCID_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */ + ccid_reply[CCID_MSG_STATUS_OFFSET] |= CCID_CMD_STATUS_ERROR; /* Failed */ + ccid_reply[CCID_MSG_ERROR_OFFSET] = offset; + ccid_reply[CCID_MSG_CHAIN_OFFSET] = 0x00; + + /* This is a single packet Bulk-IN transaction */ + c->epi->buf = NULL; + c->epi->tx_done = 1; + memcpy (endp1_tx_buf, ccid_reply, CCID_MSG_HEADER_SIZE); + usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE); + c->tx_busy = 1; +} + +#define INS_GET_RESPONSE 0xc0 + +static enum ccid_state ccid_handle_data(struct ccid *c) +{ + enum ccid_state next_state = c->ccid_state; + + if (c->err != 0) + { + ccid_reset (c); + ccid_error (c, CCID_OFFSET_DATA_LEN); + return next_state; + } + + switch (c->ccid_state) + { + case CCID_STATE_NOCARD: + if (c->ccid_header.msg_type == CCID_SLOT_STATUS) + ccid_send_status (c); + else + { + DEBUG_INFO ("ERR00\r\n"); + ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); + } + break; + case CCID_STATE_START: + if (c->ccid_header.msg_type == CCID_POWER_ON) + { + ccid_reset (c); + next_state = ccid_power_on (c); + } + else if (c->ccid_header.msg_type == CCID_POWER_OFF) + { + ccid_reset (c); + next_state = ccid_power_off (c); + } + else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) + ccid_send_status (c); + else + { + DEBUG_INFO ("ERR01\r\n"); + ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); + } + break; + case CCID_STATE_WAIT: + if (c->ccid_header.msg_type == CCID_POWER_ON) + { + /* Not in the spec., but pcscd/libccid */ + ccid_reset (c); + next_state = ccid_power_on (c); + } + else if (c->ccid_header.msg_type == CCID_POWER_OFF) + { + ccid_reset (c); + next_state = ccid_power_off (c); + } + else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) + ccid_send_status (c); + else if (c->ccid_header.msg_type == CCID_XFR_BLOCK) + { + if (c->ccid_header.param == 0) + { + if ((c->a->cmd_apdu_head[0] & 0x10) == 0) + { + if (c->state == APDU_STATE_COMMAND_CHAINING) + { /* command chaining finished */ + c->p += c->a->cmd_apdu_head[4]; + c->a->cmd_apdu_head[4] = 0; + DEBUG_INFO ("CMD chaning finished.\r\n"); + } + + if (c->a->cmd_apdu_head[1] == INS_GET_RESPONSE && c->state == APDU_STATE_RESULT_GET_RESPONSE) + { + size_t len = c->a->expected_res_size; + + if (c->len <= c->a->expected_res_size) + len = c->len; + + ccid_send_data_block_gr (c, len); + if (c->len == 0) + c->state = APDU_STATE_RESULT; + c->ccid_state = CCID_STATE_WAIT; + DEBUG_INFO ("GET Response.\r\n"); + } + else + { /* Give this message to GPG thread */ + c->state = APDU_STATE_COMMAND_RECEIVED; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &ccid_buffer[5]; + + uint32_t flag = EV_CMD_AVAILABLE; + queue_try_add(&c->openpgp_comm, &flag); + + next_state = CCID_STATE_EXECUTE; + } + } + else + { + if (c->state == APDU_STATE_WAIT_COMMAND) + { /* command chaining is started */ + c->a->cmd_apdu_head[0] &= ~0x10; + memcpy (c->chained_cls_ins_p1_p2, c->a->cmd_apdu_head, 4); + c->state = APDU_STATE_COMMAND_CHAINING; + } + + c->p += c->a->cmd_apdu_head[4]; + c->len -= c->a->cmd_apdu_head[4]; + ccid_send_data_block_0x9000 (c); + DEBUG_INFO ("CMD chaning...\r\n"); + } + } + else + { /* ICC block chaining is not supported. */ + DEBUG_INFO ("ERR02\r\n"); + ccid_error (c, CCID_OFFSET_PARAM); + } + } + else if (c->ccid_header.msg_type == CCID_SET_PARAMS || c->ccid_header.msg_type == CCID_GET_PARAMS || c->ccid_header.msg_type == CCID_RESET_PARAMS) + ccid_send_params (c); + else if (c->ccid_header.msg_type == CCID_SECURE) + { + if (c->p != c->a->cmd_apdu_data) + { + /* SECURE received in the middle of command chaining */ + ccid_reset (c); + ccid_error (c, CCID_OFFSET_DATA_LEN); + return next_state; + } + + if (c->p[10-10] == 0x00) /* PIN verification */ + { + c->a->cmd_apdu_head[0] = c->p[25-10]; + c->a->cmd_apdu_head[1] = c->p[26-10]; + c->a->cmd_apdu_head[2] = c->p[27-10]; + c->a->cmd_apdu_head[3] = c->p[28-10]; + /**/ + c->a->cmd_apdu_data[0] = 0; /* bConfirmPIN */ + c->a->cmd_apdu_data[1] = c->p[17-10]; /* bEntryValidationCondition */ + c->a->cmd_apdu_data[2] = c->p[18-10]; /* bNumberMessage */ + c->a->cmd_apdu_data[3] = c->p[19-10]; /* wLangId L */ + c->a->cmd_apdu_data[4] = c->p[20-10]; /* wLangId H */ + c->a->cmd_apdu_data[5] = c->p[21-10]; /* bMsgIndex */ + + c->a->cmd_apdu_data_len = 6; + c->a->expected_res_size = 0; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &c->p[5]; + + c->state = APDU_STATE_COMMAND_RECEIVED; + uint32_t flag = EV_VERIFY_CMD_AVAILABLE; + queue_try_add(&c->openpgp_comm, &flag); + next_state = CCID_STATE_EXECUTE; + } + else if (c->p[10-10] == 0x01) /* PIN Modification */ + { + uint8_t num_msgs = c->p[21-10]; + + if (num_msgs == 0x00) + num_msgs = 1; + else if (num_msgs == 0xff) + num_msgs = 3; + c->a->cmd_apdu_head[0] = c->p[27 + num_msgs-10]; + c->a->cmd_apdu_head[1] = c->p[28 + num_msgs-10]; + c->a->cmd_apdu_head[2] = c->p[29 + num_msgs-10]; + c->a->cmd_apdu_head[3] = c->p[30 + num_msgs-10]; + /**/ + c->a->cmd_apdu_data[0] = c->p[19-10]; /* bConfirmPIN */ + c->a->cmd_apdu_data[1] = c->p[20-10]; /* bEntryValidationCondition */ + c->a->cmd_apdu_data[2] = c->p[21-10]; /* bNumberMessage */ + c->a->cmd_apdu_data[3] = c->p[22-10]; /* wLangId L */ + c->a->cmd_apdu_data[4] = c->p[23-10]; /* wLangId H */ + c->a->cmd_apdu_data[5] = c->p[24-10]; /* bMsgIndex, bMsgIndex1 */ + if (num_msgs >= 2) + c->a->cmd_apdu_data[6] = c->p[25-10]; /* bMsgIndex2 */ + if (num_msgs == 3) + c->a->cmd_apdu_data[7] = c->p[26-10]; /* bMsgIndex3 */ + + c->a->cmd_apdu_data_len = 5 + num_msgs; + c->a->expected_res_size = 0; + + c->a->sw = 0x9000; + c->a->res_apdu_data_len = 0; + c->a->res_apdu_data = &ccid_buffer[5]; + + c->state = APDU_STATE_COMMAND_RECEIVED; + uint32_t flag = EV_MODIFY_CMD_AVAILABLE; + queue_try_add(&c->openpgp_comm, &flag); + next_state = CCID_STATE_EXECUTE; + } + else + ccid_error (c, CCID_MSG_DATA_OFFSET); + } + else + { + DEBUG_INFO ("ERR03\r\n"); + DEBUG_BYTE (c->ccid_header.msg_type); + ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); + } + break; + case CCID_STATE_EXECUTE: + case CCID_STATE_ACK_REQUIRED_0: + case CCID_STATE_ACK_REQUIRED_1: + if (c->ccid_header.msg_type == CCID_POWER_OFF) + next_state = ccid_power_off (c); + else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) + ccid_send_status (c); + else + { + DEBUG_INFO ("ERR04\r\n"); + DEBUG_BYTE (c->ccid_header.msg_type); + ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); + } + break; + default: + next_state = CCID_STATE_START; + DEBUG_INFO ("ERR10\r\n"); + break; + } + + return next_state; +} + +static enum ccid_state ccid_handle_timeout (struct ccid *c) +{ + enum ccid_state next_state = c->ccid_state; + + switch (c->ccid_state) + { + case CCID_STATE_EXECUTE: + case CCID_STATE_ACK_REQUIRED_0: + case CCID_STATE_ACK_REQUIRED_1: + ccid_send_data_block_time_extension (c); + break; + default: + break; + } + + return next_state; +} + + +static void notify_icc (struct ep_out *epo) +{ + struct ccid *c = (struct ccid *)epo->priv; + + c->err = epo->err; + uint32_t val = EV_RX_DATA_READY; + queue_try_add(&c->ccid_comm, &val); +} + +static int end_ccid_rx (struct ep_out *epo, size_t orig_len) +{ + (void)orig_len; + if (epo->cnt < sizeof (struct ccid_header)) + /* short packet, just ignore */ + return 1; + + /* icc message with no abdata */ + return 0; +} + +static int end_abdata (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + size_t len = epo->cnt; + + if (orig_len == USB_LL_BUF_SIZE && len < c->ccid_header.data_len) + /* more packet comes */ + return 1; + + if (len != c->ccid_header.data_len) + epo->err = 1; + + return 0; +} + +static int end_cmd_apdu_head (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)orig_len; + + if (epo->cnt < 4 || epo->cnt != c->ccid_header.data_len) + { + epo->err = 1; + return 0; + } + + if ((c->state == APDU_STATE_COMMAND_CHAINING) + && (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) + || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] + || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] + || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3])) + /* + * Handling exceptional request. + * + * Host stops sending command APDU using command chaining, + * and start another command APDU. + * + * Discard old one, and start handling new one. + */ + { + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + } + + if (epo->cnt == 4) + /* No Lc and Le */ + c->a->expected_res_size = 0; + else if (epo->cnt == 5) + { + /* No Lc but Le */ + c->a->expected_res_size = c->a->cmd_apdu_head[4]; + if (c->a->expected_res_size == 0) + c->a->expected_res_size = 256; + c->a->cmd_apdu_head[4] = 0; + } + + c->a->cmd_apdu_data_len = 0; + return 0; +} + +static int end_nomore_data (struct ep_out *epo, size_t orig_len) +{ + (void)epo; + if (orig_len == USB_LL_BUF_SIZE) + return 1; + else + return 0; +} + +static int end_cmd_apdu_data (struct ep_out *epo, size_t orig_len) +{ + struct ccid *c = (struct ccid *)epo->priv; + size_t len = epo->cnt; + + if (orig_len == USB_LL_BUF_SIZE && CMD_APDU_HEAD_SIZE + len < c->ccid_header.data_len) + /* more packet comes */ + return 1; + + if (CMD_APDU_HEAD_SIZE + len != c->ccid_header.data_len) + goto error; + + if (len == c->a->cmd_apdu_head[4]) + /* No Le field*/ + c->a->expected_res_size = 0; + else if (len == (size_t)c->a->cmd_apdu_head[4] + 1) + { + /* it has Le field*/ + c->a->expected_res_size = epo->buf[-1]; + if (c->a->expected_res_size == 0) + c->a->expected_res_size = 256; + len--; + } + else + { + error: + epo->err = 1; + return 0; + } + + c->a->cmd_apdu_data_len += len; + return 0; +} + +static void nomore_data (struct ep_out *epo, size_t len) +{ + (void)len; + epo->err = 1; + epo->end_rx = end_nomore_data; + epo->buf = NULL; + epo->buf_len = 0; + epo->cnt = 0; + epo->next_buf = nomore_data; +} + +static void ccid_cmd_apdu_data (struct ep_out *epo, size_t len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)len; + if (c->state == APDU_STATE_RESULT_GET_RESPONSE && c->a->cmd_apdu_head[1] != INS_GET_RESPONSE) + { + /* + * Handling exceptional request. + * + * Host didn't finish receiving the whole response APDU by GET RESPONSE, + * but initiates another command. + */ + + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + } + else if (c->state == APDU_STATE_COMMAND_CHAINING) + { + if (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) + || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] + || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] + || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3]) + /* + * Handling exceptional request. + * + * Host stops sending command APDU using command chaining, + * and start another command APDU. + * + * Discard old one, and start handling new one. + */ + { + c->state = APDU_STATE_WAIT_COMMAND; + c->p = c->a->cmd_apdu_data; + c->len = MAX_CMD_APDU_DATA_SIZE; + c->a->cmd_apdu_data_len = 0; + } + } + + epo->end_rx = end_cmd_apdu_data; + epo->buf = c->p; + epo->buf_len = c->len; + epo->cnt = 0; + epo->next_buf = nomore_data; +} + +static void ccid_abdata (struct ep_out *epo, size_t len) +{ + struct ccid *c = (struct ccid *)epo->priv; + + (void)len; + c->a->seq = c->ccid_header.seq; + if (c->ccid_header.msg_type == CCID_XFR_BLOCK) + { + c->a->seq = c->ccid_header.seq; + epo->end_rx = end_cmd_apdu_head; + epo->buf = c->a->cmd_apdu_head; + epo->buf_len = 5; + epo->cnt = 0; + epo->next_buf = ccid_cmd_apdu_data; + } + else + { + epo->end_rx = end_abdata; + epo->buf = c->p; + epo->buf_len = c->len; + epo->cnt = 0; + epo->next_buf = nomore_data; + } +} + +static void ccid_prepare_receive (struct ccid *c) +{ + c->epo->err = 0; + c->epo->buf = (uint8_t *)&c->ccid_header; + c->epo->buf_len = sizeof (struct ccid_header); + c->epo->cnt = 0; + c->epo->next_buf = ccid_abdata; + c->epo->end_rx = end_ccid_rx; + DEBUG_INFO ("Rx ready\r\n"); +} + +static void ccid_rx_ready (uint16_t len) +{ + /* + * If we support multiple CCID interfaces, we select endpoint object + * by EP_NUM. Because it has only single CCID interface now, it's + * hard-coded, here. + */ + struct ep_out *epo = &endpoint_out; + int offset = 0; + int cont; + size_t orig_len = len; + + while (epo->err == 0) + { + if (len == 0) + break; + else if (len <= epo->buf_len) + { + memcpy (epo->buf, endp1_rx_buf + offset, len); + epo->buf += len; + epo->cnt += len; + epo->buf_len -= len; + break; + } + else /* len > buf_len */ + { + memcpy (epo->buf, endp1_rx_buf + offset, epo->buf_len); + len -= epo->buf_len; + offset += epo->buf_len; + epo->next_buf (epo, len); /* Update epo->buf, cnt, buf_len */ + } + } + + + /* + * ORIG_LEN to distingush ZLP and the end of transaction + * (ORIG_LEN != USB_LL_BUF_SIZE) + */ + cont = epo->end_rx (epo, orig_len); + + if (cont == 0) + notify_icc (epo); +} + +static void notify_tx (struct ep_in *epi) +{ + struct ccid *c = (struct ccid *)epi->priv; + + /* The sequence of Bulk-IN transactions finished */ + uint32_t flag = EV_TX_FINISHED; + queue_try_add(&c->ccid_comm, &flag); +} + +static void ccid_tx_done () +{ + /* + * If we support multiple CCID interfaces, we select endpoint object + * by EP_NUM. Because it has only single CCID interface now, it's + * hard-coded, here. + */ + struct ep_in *epi = &endpoint_in; + + if (epi->buf == NULL) + { + if (epi->tx_done) + notify_tx (epi); + else + { + epi->tx_done = 1; + usb_tx_enable (endp1_tx_buf, 0); + } + } + else + { + int tx_size = 0; + size_t remain = USB_LL_BUF_SIZE; + int offset = 0; + + while (epi->buf) + { + if (epi->buf_len < remain) + { + memcpy (endp1_tx_buf+offset, epi->buf, epi->buf_len); + offset += epi->buf_len; + remain -= epi->buf_len; + tx_size += epi->buf_len; + epi->next_buf (epi, remain); /* Update epi->buf, cnt, buf_len */ + } + else + { + memcpy (endp1_tx_buf+offset, epi->buf, remain); + epi->buf += remain; + epi->cnt += remain; + epi->buf_len -= remain; + tx_size += remain; + break; + } + } + if (tx_size < USB_LL_BUF_SIZE) + epi->tx_done = 1; + + usb_tx_enable (endp1_tx_buf, tx_size); + } +} + +static int usb_event_handle() +{ + if (tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE) + { + ccid_tx_done (); + } + else if (tud_vendor_available()) + { + uint32_t count = tud_vendor_read(endp1_rx_buf, sizeof(endp1_rx_buf)); + ccid_rx_ready(count); + TU_LOG2("-------- RECEIVED %d, %x %x %x",count,buf[0],buf[1],buf[2]); + } + return 0; +} + +uint32_t timeout = USB_CCID_TIMEOUT; +static uint32_t prev_millis = 0; + +void prepare_ccid() +{ + struct ep_in *epi = &endpoint_in; + struct ep_out *epo = &endpoint_out; + struct ccid *c = &ccid; + struct apdu *a = &apdu; + + epi_init (epi, 1, c); + epo_init (epo, 2, c); + + apdu_init(a); + ccid_init(c, a); +} + +void ccid_task(void) +{ + struct ccid *c = &ccid; + if (tud_vendor_mounted()) + { + // connected and there are data available + if (tud_vendor_available() || tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE) + { + if (usb_event_handle () == 0) + return; + if (c->application) + { + uint32_t flag = EV_EXIT; + queue_try_add(&c->ccid_comm, &flag); + c->application = 0; + } + prepare_ccid(); + return; + } + timeout -= MIN(board_millis()-prev_millis,timeout); + if (timeout == 0) + { + timeout = USB_CCID_TIMEOUT; + c->timeout_cnt++; + } + uint32_t m = 0x0; + bool has_m = queue_try_remove(&c->ccid_comm, &m); + if (has_m) + { + if (m == EV_CARD_CHANGE) + { + if (c->ccid_state == CCID_STATE_NOCARD) + /* Inserted! */ + c->ccid_state = CCID_STATE_START; + else + { /* Removed! */ + if (c->application) + { + uint32_t flag = EV_EXIT; + queue_try_add(&c->openpgp_comm, &flag); + c->application = 0; + } + c->ccid_state = CCID_STATE_NOCARD; + } + //ccid_notify_slot_change (c); + } + else if (m == EV_RX_DATA_READY) + { + c->ccid_state = ccid_handle_data (c); + timeout = 0; + c->timeout_cnt = 0; + } + else if (m == EV_EXEC_FINISHED) + { + if (c->ccid_state == CCID_STATE_EXECUTE) + { + exec_done: + if (c->a->sw == GPG_THREAD_TERMINATED) + { + c->sw1sw2[0] = 0x90; + c->sw1sw2[1] = 0x00; + c->state = APDU_STATE_RESULT; + ccid_send_data_block (c); + c->ccid_state = CCID_STATE_EXITED; + c->application = 0; + return; + } + + c->a->cmd_apdu_data_len = 0; + c->sw1sw2[0] = c->a->sw >> 8; + c->sw1sw2[1] = c->a->sw & 0xff; + + if (c->a->res_apdu_data_len <= c->a->expected_res_size) + { + c->state = APDU_STATE_RESULT; + ccid_send_data_block (c); + c->ccid_state = CCID_STATE_WAIT; + } + else + { + c->state = APDU_STATE_RESULT_GET_RESPONSE; + c->p = c->a->res_apdu_data; + c->len = c->a->res_apdu_data_len; + ccid_send_data_block_gr (c, c->a->expected_res_size); + c->ccid_state = CCID_STATE_WAIT; + } + } + else + { + DEBUG_INFO ("ERR05\r\n"); + } + } + else if (m == EV_TX_FINISHED) + { + if (c->state == APDU_STATE_RESULT) + ccid_reset (c); + else + c->tx_busy = 0; + + if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE) + ccid_prepare_receive (c); + } + } + else /* Timeout */ + { + if (c->timeout_cnt == 7 && c->ccid_state == CCID_STATE_ACK_REQUIRED_1) + { + c->a->sw = GPG_ACK_TIMEOUT; + c->a->res_apdu_data_len = 0; + goto exec_done; + } + else + c->ccid_state = ccid_handle_timeout (c); + } } - } } // Invoked when cdc when line state changed e.g connected/disconnected void tud_vendor_line_state_cb(uint8_t itf, bool dtr, bool rts) { - (void) itf; + (void) itf; - // connected - if ( dtr && rts ) - { - // print initial message when connected - tud_vendor_write_str("\r\nTinyUSB WebUSB device example\r\n"); - } + // connected + if ( dtr && rts ) + { + // print initial message when connected + tud_vendor_write_str("\r\nTinyUSB WebUSB device example\r\n"); + } } // Invoked when CDC interface received data from host void tud_vendor_rx_cb(uint8_t itf) { - (void) itf; + (void) itf; TU_LOG3("!!!!!!! RX_CB\r\n"); } @@ -304,30 +1493,31 @@ void tud_mount_cb() void led_blinking_task(void) { - static uint32_t start_ms = 0; - static uint8_t led_state = false; - static uint8_t led_color = BLINK_RED; + static uint32_t start_ms = 0; + static uint8_t led_state = false; + static uint8_t led_color = BLINK_RED; - // Blink every interval ms - if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time - start_ms += blink_interval_ms; + // Blink every interval ms + if ( board_millis() - start_ms < blink_interval_ms) + return; // not enough time + start_ms += blink_interval_ms; - gpio_put(led_color, led_state); - led_state ^= 1; // toggle + gpio_put(led_color, led_state); + led_state ^= 1; // toggle } -void led_off_all() +void led_off_all() { - gpio_put(18, 1); - gpio_put(19, 1); - gpio_put(20, 1); + gpio_put(18, 1); + gpio_put(19, 1); + gpio_put(20, 1); } int main(void) { struct apdu *a = &apdu; struct ccid *c = &ccid; - + printf("BOARD INIT\r\n"); board_init(); @@ -342,12 +1532,12 @@ int main(void) tusb_init(); - apdu_init(a); - ccid_init(c, a); + prepare_ccid(); while (1) { - vendor_task(); + prev_millis = board_millis(); + ccid_task(); tud_task(); // tinyusb device task led_blinking_task(); } diff --git a/hsm2040.h b/hsm2040.h index 36e4156..1b22f0f 100644 --- a/hsm2040.h +++ b/hsm2040.h @@ -11,4 +11,33 @@ #define USB_REQ_CCID 0xA1 +#define USB_LL_BUF_SIZE 64 + +extern const uint8_t historical_bytes[]; + +#define DEBUG_INFO(s) TU_LOG2(s) + +static void put_hex (uint8_t nibble) +{ + uint8_t c; + + if (nibble < 0x0a) + c = '0' + nibble; + else + c = 'a' + nibble - 0x0a; + + TU_LOG3("%c",c); +} + +void +put_byte (uint8_t b) +{ + put_hex (b >> 4); + put_hex (b &0x0f); + TU_LOG3("\r\n"); +} + +#define DEBUG_BYTE(b) put_byte(b) + + #endif \ No newline at end of file