From a68663cb5b0fa791a3846a0a2a47c31539f1993a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 19 Aug 2010 17:09:59 +0900 Subject: [PATCH] more impl. --- src/Makefile | 2 +- src/gnuk.h | 9 ++ src/gpg.c | 73 ++++++++--- src/main.c | 30 +++-- src/{usb.c => usb-icc.c} | 272 +++++++++++++++++++++++++++++++-------- src/usb_lld.c | 8 +- 6 files changed, 308 insertions(+), 86 deletions(-) create mode 100644 src/gnuk.h rename src/{usb.c => usb-icc.c} (61%) diff --git a/src/Makefile b/src/Makefile index bc25463..98139d1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -78,7 +78,7 @@ CSRC = $(PORTSRC) \ $(CHIBIOS)/os/various/syscalls.c \ $(STMUSBSRC) \ $(USBCDCSRC) \ - main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb.c + main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb-icc.c gpg.c # List ASM source files here ASMSRC = $(PORTASM) \ diff --git a/src/gnuk.h b/src/gnuk.h new file mode 100644 index 0000000..4ad4e5b --- /dev/null +++ b/src/gnuk.h @@ -0,0 +1,9 @@ +extern Thread *blinker_thread; +extern Thread *icc_thread; +extern Thread *gpg_thread; + +#define EV_EXEC_FINISHED (eventmask_t)2 /* GPG Execution finished */ + +#define put_string(STR) + +extern void _write (char *, int); diff --git a/src/gpg.c b/src/gpg.c index 73ae2d5..df45114 100644 --- a/src/gpg.c +++ b/src/gpg.c @@ -1,5 +1,5 @@ /* - * gpg.c -- + * gpg.c -- OpenPGP card protocol support * * Copyright (C) 2010 Free Software Initiative of Japan * Author: NIIBE Yutaka @@ -21,7 +21,11 @@ * */ -#define RSA_SIGNATURE_LENGTH 128 /* 128 byte == 1024-bit */ +#include "ch.h" +#include "hal.h" +#include "gnuk.h" + +#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */ extern unsigned char *rsa_sign (unsigned char *); #define INS_PUT_DATA 0xDA @@ -207,19 +211,20 @@ const char const do_5f50[] = * 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ... * 7a L-7a [93 L-93 ... ] */ +#if 0 static byte process_command_adpu (void) { if (icc_read_buf[1] == INS_GET_RESPONSE) { - stx_put_string (" - GET Response\r\n"); + put_string (" - GET Response\r\n"); if ((icc_result_flag & ICC_RESULT_BUF)) return 0; else { - stx_put_string ("Wrong GET Response\r\n"); + put_string ("Wrong GET Response\r\n"); return 1; } } @@ -239,7 +244,7 @@ INS_VERIFY if (icc_read_buf[1] == INS_PUT_DATA) { - stx_put_string (" - PUT DATA\r\n"); + put_string (" - PUT DATA\r\n"); icc_result_value = 0x9000; /* 6a88: No record */ icc_result_len = 0; icc_result_flag = 0; @@ -248,7 +253,7 @@ INS_VERIFY if (icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR) { - stx_put_string (" - Generate Asymmetric Key Pair\r\n"); + put_string (" - Generate Asymmetric Key Pair\r\n"); if (icc_read_buf[2] == 0x81) { @@ -346,7 +351,7 @@ INS_VERIFY } else if (icc_read_buf[1] == INS_READ_BINARY) { /* it must be for DF 0x2f02 */ - stx_put_string (" - Read binary\r\n"); + put_string (" - Read binary\r\n"); if (icc_read_buf[3] >= 6) { @@ -369,7 +374,7 @@ INS_VERIFY { if (icc_read_buf[2] == 4) /* Selection by DF name */ { - stx_put_string (" - select DF by name\r\n"); + put_string (" - select DF by name\r\n"); /* * XXX: Should return contents. */ @@ -385,7 +390,7 @@ INS_VERIFY && icc_read_buf[5] == 0x2f && icc_read_buf[6] == 02) { - stx_put_string (" - select 0x2f02 EF\r\n"); + put_string (" - select 0x2f02 EF\r\n"); /* * MF.EF-GDO -- Serial number of the card and name of the owner */ @@ -398,7 +403,7 @@ INS_VERIFY && icc_read_buf[5] == 0x3f && icc_read_buf[6] == 0) { - stx_put_string (" - select ROOT MF\r\n"); + put_string (" - select ROOT MF\r\n"); if (icc_read_buf[3] == 0x0c) { icc_result_value = 0x9000; @@ -414,7 +419,7 @@ INS_VERIFY } else { - stx_put_string (" - select ?? \r\n"); + put_string (" - select ?? \r\n"); icc_result_value = 0x6a82; /* File missing */ icc_result_len = 0; @@ -423,7 +428,7 @@ INS_VERIFY } else if (icc_read_buf[1] == INS_GET_DATA) { - stx_put_string (" - Get Data\r\n"); + put_string (" - Get Data\r\n"); switch (((icc_read_buf[2]<<8) | icc_read_buf[3])) { @@ -535,12 +540,12 @@ INS_VERIFY } else if (icc_read_buf[1] == INS_PSO) { - stx_put_string (" - PSO\r\n"); + put_string (" - PSO\r\n"); if (icc_read_buf[2] == 0x9E && icc_read_buf[3] == 0x9A) { if (icc_read_len != 5 + 35 && icc_read_len != 5 + 35 + 1) - stx_put_string (" wrong length\r\n"); + put_string (" wrong length\r\n"); else { icc_result_value = rsa_sign (&icc_read_buf[5]); @@ -548,11 +553,11 @@ INS_VERIFY icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_RAM; } - stx_put_string ("done.\r\n"); + put_string ("done.\r\n"); } else { - stx_put_string (" - ???\r\n"); + put_string (" - ???\r\n"); icc_result_value = 0x9000; icc_result_len = 0; icc_result_flag = 0; @@ -560,7 +565,7 @@ INS_VERIFY } else { - stx_put_string (" - ???\r\n"); + put_string (" - ???\r\n"); icc_result_value = 0x9000; icc_result_len = 0; icc_result_flag = 0; @@ -568,3 +573,37 @@ INS_VERIFY return 0; } +#endif + +Thread *gpg_thread; + +msg_t +GPGthread (void *arg) +{ + (void)arg; + + gpg_thread = chThdSelf (); + chEvtClear (ALL_EVENTS); + + while (1) + { + eventmask_t m; + + m = chEvtWaitOne (ALL_EVENTS); + + _write ("GPG!\r\n", 6); +#if 0 + receive_command_adpu (); +#endif +#if 0 + process_command_adpu (); +#endif +#if 0 + send_result_adpu (); +#endif + + chEvtSignal (icc_thread, EV_EXEC_FINISHED); + } + + return 0; +} diff --git a/src/main.c b/src/main.c index d833cec..03acfd6 100644 --- a/src/main.c +++ b/src/main.c @@ -35,19 +35,23 @@ #include "hw_config.h" #include "usb_pwr.h" +Thread *blinker_thread; /* * Red LEDs blinker thread, times are in milliseconds. */ static WORKING_AREA(waThread1, 128); -static msg_t Thread1(void *arg) { - +static msg_t +Thread1 (void *arg) +{ (void)arg; - while (TRUE) { - palClearPad (IOPORT3, GPIOC_LED); - chThdSleepMilliseconds (1000); - palSetPad (IOPORT3, GPIOC_LED); - chThdSleepMilliseconds (1000); - } + blinker_thread = chThdSelf (); + while (1) + { + palClearPad (IOPORT3, GPIOC_LED); + chEvtWaitOne (ALL_EVENTS); + palSetPad (IOPORT3, GPIOC_LED); + chEvtWaitOne (ALL_EVENTS); + } return 0; } @@ -160,8 +164,11 @@ static msg_t Thread2 (void *arg) return 0; } -static WORKING_AREA(waUSBThread, 128*2); -extern msg_t USBThread (void *arg); +static WORKING_AREA(waUSBthread, 128*2); +extern msg_t USBthread (void *arg); + +static WORKING_AREA(waGPGthread, 128*4); +extern msg_t GPGthread (void *arg); /* * Entry point, note, the main() function is already a thread in the system @@ -188,7 +195,8 @@ int main(int argc, char **argv) */ chThdCreateStatic (waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL); - chThdCreateStatic (waUSBThread, sizeof(waUSBThread), NORMALPRIO, USBThread, NULL); + chThdCreateStatic (waUSBthread, sizeof(waUSBthread), NORMALPRIO, USBthread, NULL); + chThdCreateStatic (waGPGthread, sizeof(waGPGthread), NORMALPRIO, GPGthread, NULL); while (1) { diff --git a/src/usb.c b/src/usb-icc.c similarity index 61% rename from src/usb.c rename to src/usb-icc.c index 1d84da3..fbd552e 100644 --- a/src/usb.c +++ b/src/usb-icc.c @@ -1,5 +1,5 @@ /* - * usb.c -- + * usb-icc.c -- USB CCID/ICCD protocol handling * * Copyright (C) 2010 Free Software Initiative of Japan * Author: NIIBE Yutaka @@ -24,31 +24,42 @@ #include "ch.h" #include "hal.h" +#include "gnuk.h" + #include "usb_lib.h" #include "usb_desc.h" #include "usb_mem.h" #include "hw_config.h" #include "usb_istr.h" -Mutex icc_in_mutex; - static uint8_t icc_buffer_out[64]; static uint8_t icc_buffer_in[64]; static __IO uint32_t icc_count_out = 0; static uint32_t icc_count_in = 0; +Thread *icc_thread; + +#define EV_RX_DATA_READY (eventmask_t)1 /* USB Rx data available */ + +/* + * Tx done + */ void -EP4_IN_Callback(void) +EP4_IN_Callback (void) { icc_count_in = 0; } +/* + * Rx data + */ void -EP5_OUT_Callback(void) +EP5_OUT_Callback (void) { /* Get the received data buffer and update the counter */ icc_count_out = USB_SIL_Read (EP5_OUT, icc_buffer_out); + chEvtSignalI (icc_thread, EV_RX_DATA_READY); } #define ICC_POWER_ON 0x62 @@ -168,32 +179,31 @@ HW_ERROR 0xFB The USB-ICC detected a hardware error. all others Reserved for future use (0x80 and those filling the gaps) - -extern const uchar *icc_power_on (void); -extern byte icc_get_status (void); - - -PC_to_RDR_IccPowerOff -RDR_to_PC_SlotStatus - -PC_to_RDR_IccPowerOn -RDR_to_PC_DataBlock - -PC_to_RDR_XfrBlock -RDR_to_PC_DataBlock #endif +enum icc_state +{ + ICC_STATE_START, /* Initial */ + ICC_STATE_WAIT, /* Waiting ADPU */ + /* Busy1, Busy2, Busy3, Busy5 */ + ICC_STATE_EXECUTE, /* Busy4 */ + ICC_STATE_RECEIVE, /* ADPU Received Partially */ + ICC_STATE_SEND /* ADPU Sent Partially */ +}; + +static enum icc_state icc_state; + /* Direct conversion, T=1, "FSIJ" */ static const char ATR[] = { '\x3B', '\x84', '\x01', 'F', 'S', 'I', 'J' }; -void +/* Send back ATR (Answer To Reset) */ +enum icc_state icc_power_on (char *buf, int len) { int i, size_atr; size_atr = sizeof (ATR); - chMtxLock (&icc_in_mutex); icc_buffer_in[0] = 0x80; icc_buffer_in[1] = size_atr; /* not including '\0' at the end */ @@ -212,16 +222,14 @@ icc_power_on (char *buf, int len) USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in); SetEPTxValid (ENDP4); - chMtxUnlock (); _write ("ON\r\n", 4); + return ICC_STATE_WAIT; } -void -icc_power_off (char *buf, int len) +static void +icc_send_status (char *buf, int len) { - chMtxLock (&icc_in_mutex); - icc_buffer_in[0] = 0x81; icc_buffer_in[1] = 0x00; icc_buffer_in[2] = 0x00; @@ -229,56 +237,212 @@ icc_power_off (char *buf, int len) icc_buffer_in[4] = 0x00; icc_buffer_in[5] = 0x00; /* Slot */ icc_buffer_in[ICC_MSG_SEQ_OFFSET] = buf[ICC_MSG_SEQ_OFFSET]; - icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 0x00; + if (icc_state == ICC_STATE_START) + icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 2; /* No ICC present */ + else + icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */ icc_buffer_in[ICC_MSG_ERROR_OFFSET] = 0x00; icc_buffer_in[9] = 0x00; icc_count_in = 10; USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in); SetEPTxValid (ENDP4); - chMtxUnlock (); - - _write ("OFF\r\n", 5); } -msg_t -USBThread (void *arg) +enum icc_state +icc_power_off (char *buf, int len) { + + icc_send_status (buf, len); + _write ("OFF\r\n", 5); + return ICC_STATE_START; +} + +static enum icc_state +icc_handle_data (void) +{ + enum icc_state next_state = icc_state; + +#if 1 char b[3]; - chMtxInit (&icc_in_mutex); + b[0] = icc_buffer_out[0]; + b[1] = '\r'; + b[2] = '\n'; - while (TRUE) + _write (b, 3); +#endif + + switch (icc_state) { - while (icc_count_out == 0) - chThdSleepMilliseconds (1); - - b[0] = icc_buffer_out[0]; - b[1] = '\r'; - b[2] = '\n'; - - _write (b, 3); + case ICC_STATE_START: if (icc_buffer_out[0] == ICC_POWER_ON) - { - /* Send back ATR (Answer To Reset) */ - icc_power_on (icc_buffer_out, icc_count_out); - } - else if (icc_buffer_out[0] == ICC_POWER_OFF - || icc_buffer_out[0] == ICC_SLOT_STATUS) - { - /* Kill ICC thread(s) and send back slot status */ - icc_power_off (icc_buffer_out, icc_count_out); + next_state = icc_power_on (icc_buffer_out, icc_count_out); + else if (icc_buffer_out[0] == ICC_POWER_OFF) + next_state = icc_power_off (icc_buffer_out, icc_count_out); + else if (icc_buffer_out[0] == ICC_SLOT_STATUS) + icc_send_status (icc_buffer_out, icc_count_out); + else + { /* XXX: error */ + _write ("ERR01\r\n", 7); } + break; + case ICC_STATE_WAIT: + if (icc_buffer_out[0] == ICC_POWER_OFF) + next_state = icc_power_off (icc_buffer_out, icc_count_out); + else if (icc_buffer_out[0] == ICC_SLOT_STATUS) + icc_send_status (icc_buffer_out, icc_count_out); else if (icc_buffer_out[0] == XFR_BLOCK) { - /* Give this message to ICC thread */ + if (icc_buffer_out[8] == 0 && icc_buffer_out[9] == 0) + { + /* Give this message to GPG thread */ + next_state = ICC_STATE_EXECUTE; + chEvtSignal (gpg_thread, (eventmask_t)1); + } + else if (icc_buffer_out[8] == 1 && icc_buffer_out[9] == 0) + { + /* XXX: return back RDR_to_PC_DataBlock */ + /* bChainParameter = 0x10, abData=empty */ + next_state = ICC_STATE_RECEIVE; + } + else + { + /* XXX: error */; + _write ("ERR02\r\n", 7); + } } else - { + { /* XXX: error */ + _write ("ERR03\r\n", 7); } + break; + case ICC_STATE_EXECUTE: + if (icc_buffer_out[0] == ICC_POWER_OFF) + { + /* XXX: Kill GPG thread */ + next_state = icc_power_off (icc_buffer_out, icc_count_out); + } + else if (icc_buffer_out[0] == ICC_SLOT_STATUS) + icc_send_status (icc_buffer_out, icc_count_out); + else + { /* XXX: error */ + _write ("ERR04\r\n", 7); + } + break; + case ICC_STATE_RECEIVE: + if (icc_buffer_out[0] == ICC_POWER_OFF) + { + /* XXX: release partial ADPU received */ + next_state = icc_power_off (icc_buffer_out, icc_count_out); + } + else if (icc_buffer_out[0] == ICC_SLOT_STATUS) + icc_send_status (icc_buffer_out, icc_count_out); + else if (icc_buffer_out[0] == XFR_BLOCK) + { + if (1 /* XXX */) /* Got final block */ + { + /* Give this message to GPG thread */ + next_state = ICC_STATE_EXECUTE; + chEvtSignal (gpg_thread, (eventmask_t)1); + } + } + else + { /* XXX: error */ + _write ("ERR05\r\n", 7); + } + break; + case ICC_STATE_SEND: + if (icc_buffer_out[0] == ICC_POWER_OFF) + { + /* XXX: release partial ADPU sending */ + next_state = icc_power_off (icc_buffer_out, icc_count_out); + } + else if (icc_buffer_out[0] == ICC_SLOT_STATUS) + icc_send_status (icc_buffer_out, icc_count_out); + else if (icc_buffer_out[0] == XFR_BLOCK) + { + /* XXX: send back to data */ + /* finished?, then go ICC_STATE_WAIT */ + next_state = ICC_STATE_WAIT; + } + else + { /* XXX: error */ + _write ("ERR06\r\n", 7); + } + break; + } - icc_count_out = 0; - SetEPRxValid (ENDP5); + icc_count_out = 0; + SetEPRxValid (ENDP5); + return next_state; +} + +static enum icc_state +icc_handle_timeout (void) +{ + enum icc_state next_state = icc_state; + + /* + * + * XXX: ICC_STATE_EXECUTE -> kill + * XXX: ICC_STATE_RECEIVE -> cancel + * XXX: ICC_STATE_SEND -> cancel + */ + if (icc_state == ICC_STATE_START + || icc_state == ICC_STATE_WAIT) + ; + else + { + next_state = ICC_STATE_WAIT; + } + + chEvtSignal (blinker_thread, (eventmask_t)1); + return next_state; +} + +#define USB_ICC_TIMEOUT MS2ST(1000) + +msg_t +USBthread (void *arg) +{ + (void)arg; + + icc_thread = chThdSelf (); + chEvtClear (ALL_EVENTS); + + icc_state = ICC_STATE_START; + + while (1) + { + eventmask_t m; + + m = chEvtWaitOneTimeout (ALL_EVENTS, USB_ICC_TIMEOUT); + + if (m == EV_RX_DATA_READY) + icc_state = icc_handle_data (); + else if (m == EV_EXEC_FINISHED) + { + if (icc_state == ICC_STATE_EXECUTE) + { + if (1/* message is short enough*/) + { + /* XXX: send back result */; + icc_state = ICC_STATE_WAIT; + } + else + { + /* XXX: send back part of result */; + icc_state = ICC_STATE_SEND; + } + } + else + { /* XXX: error */ + _write ("ERR07\r\n", 7); + } + } + else /* Timeout */ + icc_state = icc_handle_timeout (); } return 0; diff --git a/src/usb_lld.c b/src/usb_lld.c index 46ec98c..9429712 100644 --- a/src/usb_lld.c +++ b/src/usb_lld.c @@ -6,9 +6,11 @@ extern void USB_Istr (void); CH_IRQ_HANDLER (Vector90) { CH_IRQ_PROLOGUE(); + chSysLockFromIsr(); USB_Istr(); + chSysUnlockFromIsr(); CH_IRQ_EPILOGUE(); } @@ -17,9 +19,9 @@ void usb_lld_init (void) { NVICEnableVector (USB_LP_CAN1_RX0_IRQn, CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY)); /* - * Note that we also have other IRQs: - * USB_HP_CAN1_TX_IRQn - * USBWakeUp_IRQn + * Note that we also have other IRQ(s): + * USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous) + * USBWakeUp_IRQn (suspend/resume) */ RCC->APB1RSTR = RCC_APB1RSTR_USBRST; RCC->APB1RSTR = 0;