implement downloading program
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 17 May 2012 08:02:49 +0000 (17:02 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 17 May 2012 08:02:49 +0000 (17:02 +0900)
ChangeLog
src/gnuk.h
src/openpgp.c
src/usb-icc.c
src/usb_lld.c
src/usb_lld.h
src/usb_prop.c
tool/gnuk_upgrade.py [new file with mode: 0755]

index 703ed63..4bfe9dd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,25 @@
 2012-05-17  Niibe Yutaka  <gniibe@fsij.org>
 
+       * tool/gnuk_upgrade.py: New tool.
+
+       * src/gnuk.h (ICC_STATE_EXITED, ICC_STATE_EXEC_REQUESTED): New.
+
+       * src/openpgp.c (INS_EXTERNAL_AUTHENTICATE)
+       (cmd_external_authenticate): New.
+       (INS_GET_CHALLENGE, cmd_get_challenge): New.
+
+       * src/usb-icc.c (USBthread): Finish the thread with
+       ICC_STATE_EXITED, after EXTERNAL_AUTHENTICATE.
+
        * src/usb_prop.c (gnuk_setup_endpoints_for_interface): Add STOP
        argument.
        (gnuk_usb_event): Disable all endpoints when configure(0).
+       (vcom_port_data_setup): Check direction and support
+       USB_CDC_REQ_SET_LINE_CODING.
+       (vcom_port_setup_with_nodata): Check direction.
+       (gnuk_setup_with_data): Check direction and add FSIJ_GNUK device
+       requests.
+       (gnuk_setup_with_nodata): Likewise.
 
        * src/usb_lld.c (LAST_OUT_DATA): Remove.
        (handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status.
        st103_ep_set_tx_status.
        (handle_setup0): Likewise.
        (handle_out0): Remove LAST_OUT_DATA.
+       (std_none, std_get_status, std_clear_feature, std_set_feature)
+       (std_set_address, std_get_descriptor, std_get_configuration)
+       (std_set_configuration, std_get_interface, std_set_interface):
+       Check direction.
+       (handle_setup0): Add length for setup_with_data
 
 2012-05-16  Niibe Yutaka  <gniibe@fsij.org>
 
index 1eb923f..1b1874a 100644 (file)
@@ -76,6 +76,9 @@ enum icc_state
   ICC_STATE_EXECUTE,           /* Busy4 */
   ICC_STATE_RECEIVE,           /* APDU Received Partially */
   ICC_STATE_SEND,              /* APDU Sent Partially */
+
+  ICC_STATE_EXITED,            /* ICC Thread Terminated */
+  ICC_STATE_EXEC_REQUESTED,    /* Exec requested */
 };
 
 extern enum icc_state *icc_state_p;
@@ -385,3 +388,5 @@ extern uint8_t pin_input_len;
 extern int pinpad_getline (int msg_code, systime_t timeout);
 
 #endif
+
+extern uint8_t __heap_base__, __heap_end__;
index 88c92fc..d062f11 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * openpgp.c -- OpenPGP card protocol support
  *
- * Copyright (C) 2010, 2011 Free Software Initiative of Japan
+ * Copyright (C) 2010, 2011, 2012 Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
  * This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -39,6 +39,8 @@
 #define INS_PSO                                        0x2a
 #define INS_RESET_RETRY_COUNTER                        0x2c
 #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR   0x47
+#define INS_EXTERNAL_AUTHENTICATE              0x82
+#define INS_GET_CHALLENGE                      0x84
 #define INS_INTERNAL_AUTHENTICATE              0x88
 #define INS_SELECT_FILE                                0xa4
 #define INS_READ_BINARY                                0xb0
@@ -821,6 +823,43 @@ cmd_write_binary (void)
 }
 
 
+static void
+cmd_external_authenticate (void)
+{
+  DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
+
+  if (!ac_check_status (AC_ADMIN_AUTHORIZED))
+    {
+      GPG_SECURITY_FAILURE ();
+      return;
+    }
+
+  chThdTerminate (chThdSelf ());
+  set_res_sw (0xff, 0xff);
+  DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n");
+}
+
+static void
+cmd_get_challenge (void)
+{
+  const uint8_t *rand;
+  int i;
+
+  DEBUG_INFO (" - GET CHALLENGE\r\n");
+
+  for (i = 0; i < 6; i++)
+    {
+      rand = random_bytes_get ();
+      memcpy (res_APDU + i * 16, rand, 16);
+      random_bytes_free (rand);
+    }
+
+  res_APDU_size = 96;
+  GPG_SUCCESS ();
+  DEBUG_INFO ("GET CHALLENGE done.\r\n");
+}
+
+
 struct command
 {
   uint8_t command;
@@ -833,11 +872,14 @@ const struct command cmds[] = {
   { INS_PSO, cmd_pso },
   { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
   { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
+  { INS_EXTERNAL_AUTHENTICATE,             /* Not in OpenPGP card protocol */
+    cmd_external_authenticate },
+  { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
   { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
   { INS_SELECT_FILE, cmd_select_file },
   { INS_READ_BINARY, cmd_read_binary },
   { INS_GET_DATA, cmd_get_data },
-  { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
+  { INS_WRITE_BINARY, cmd_write_binary},    /* Not in OpenPGP card protocol */
 #if defined(CERTDO_SUPPORT)
   { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
 #endif
index 1f875bc..67b04e5 100644 (file)
@@ -1273,6 +1273,7 @@ icc_handle_timeout (struct ccid *c)
 
 static struct ccid ccid;
 
+#define GPG_THREAD_TERMINATED 0xffff
 
 msg_t
 USBthread (void *arg)
@@ -1303,6 +1304,16 @@ USBthread (void *arg)
       else if (m == EV_EXEC_FINISHED)
        if (c->icc_state == ICC_STATE_EXECUTE)
          {
+           if (c->a->sw == GPG_THREAD_TERMINATED)
+             {
+               c->sw1sw2[0] = 0x90;
+               c->sw1sw2[1] = 0x00;
+               c->state = APDU_STATE_RESULT;
+               icc_send_data_block (c, 0);
+               c->icc_state = ICC_STATE_EXITED;
+               break;
+             }
+
            c->a->cmd_apdu_data_len = 0;
            c->sw1sw2[0] = c->a->sw >> 8;
            c->sw1sw2[1] = c->a->sw & 0xff;
index f90cd8c..13fa6c3 100644 (file)
@@ -4,8 +4,6 @@
 
 #define USB_MAX_PACKET_SIZE 64 /* For FS device */
 
-#define RECIPIENT         0x1F  /* Mask to get recipient    */
-
 enum STANDARD_REQUESTS
 {
   GET_STATUS = 0,
@@ -450,25 +448,27 @@ static void handle_datastage_in (void)
   st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
 }
 
-typedef int (*HANDLER) (uint8_t rcp,
+typedef int (*HANDLER) (uint8_t req,
                        uint16_t value, uint16_t index, uint16_t length);
 
-static int std_none (uint8_t rcp,
+static int std_none (uint8_t req,
                     uint16_t value, uint16_t index, uint16_t length)
 {
-  (void)rcp; (void)value; (void)index; (void)length;
+  (void)req; (void)value; (void)index; (void)length;
   return USB_UNSUPPORT;
 }
 
-static int std_get_status (uint8_t rcp,
+static int std_get_status (uint8_t req,
                           uint16_t value, uint16_t index, uint16_t length)
 {
   static uint16_t status_info;
+  uint8_t rcp = req & RECIPIENT;
 
   status_info = 0;             /* Reset Status Information */
   data_p->addr = (uint8_t *)&status_info;
 
-  if (value != 0 || length != 2 || (index >> 8) != 0)
+  if (value != 0 || length != 2 || (index >> 8) != 0
+      || (req & REQUEST_DIR) == 0)
     return USB_UNSUPPORT;
 
   if (rcp == DEVICE_RECIPIENT)
@@ -540,9 +540,14 @@ static int std_get_status (uint8_t rcp,
   return USB_UNSUPPORT;
 }
 
-static int std_clear_feature (uint8_t rcp, uint16_t value,
+static int std_clear_feature (uint8_t req, uint16_t value,
                              uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
   if (rcp == DEVICE_RECIPIENT)
     {
       if (length != 0 || index != 0)
@@ -598,9 +603,14 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_set_feature (uint8_t rcp, uint16_t value,
+static int std_set_feature (uint8_t req, uint16_t value,
                            uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
   if (rcp == DEVICE_RECIPIENT)
     {
       if (length != 0 || index != 0)
@@ -646,9 +656,14 @@ static int std_set_feature (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_set_address (uint8_t rcp, uint16_t value,
+static int std_set_address (uint8_t req, uint16_t value,
                            uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
   if (rcp == DEVICE_RECIPIENT)
     {
       if (length == 0 && value <= 127 && index == 0
@@ -659,9 +674,14 @@ static int std_set_address (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_get_descriptor (uint8_t rcp, uint16_t value,
+static int std_get_descriptor (uint8_t req, uint16_t value,
                               uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
   (void)length;
   if (rcp == DEVICE_RECIPIENT)
     return (*method_p->get_descriptor) ((value >> 8), index, value);
@@ -669,9 +689,14 @@ static int std_get_descriptor (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_get_configuration (uint8_t rcp, uint16_t value,
+static int std_get_configuration (uint8_t req, uint16_t value,
                                  uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
   (void)value;  (void)index;  (void)length;
   if (rcp == DEVICE_RECIPIENT)
     {
@@ -683,9 +708,14 @@ static int std_get_configuration (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_set_configuration (uint8_t rcp, uint16_t value,
+static int std_set_configuration (uint8_t req, uint16_t value,
                                  uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
   if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
     {
       int r;
@@ -698,9 +728,14 @@ static int std_set_configuration (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_get_interface (uint8_t rcp, uint16_t value,
+static int std_get_interface (uint8_t req, uint16_t value,
                              uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
   if (rcp == INTERFACE_RECIPIENT)
     {
       if (value != 0 || (index >> 8) != 0 || length != 1)
@@ -715,9 +750,14 @@ static int std_get_interface (uint8_t rcp, uint16_t value,
   return USB_UNSUPPORT;
 }
 
-static int std_set_interface (uint8_t rcp, uint16_t value,
+static int std_set_interface (uint8_t req, uint16_t value,
                              uint16_t index, uint16_t length)
 {
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
   if (rcp == INTERFACE_RECIPIENT)
     {
       int r;
@@ -759,7 +799,6 @@ static void handle_setup0 (void)
   uint8_t req;
   int r = USB_UNSUPPORT;
   HANDLER handler;
-  uint8_t type_rcp;
 
   pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
   w = *pw++;
@@ -776,34 +815,35 @@ static void handle_setup0 (void)
   data_p->len = 0;
   data_p->offset = 0;
 
-  type_rcp = (ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT));
-  if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) /* Interface */
-      || (ctrl_p->bmRequestType & REQUEST_TYPE) == VENDOR_REQUEST)
+  if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
     {
-      if (ctrl_p->wLength == 0)
-       r = (*method_p->setup_with_nodata) (type_rcp, req, ctrl_p->wIndex);
-      else
+      if (req < TOTAL_REQUEST)
        {
-         (*method_p->setup_with_data) (type_rcp, req, ctrl_p->wIndex);
-         if (data_p->len != 0)
-           r = USB_SUCCESS;
+         handler = std_request_handler[req];
+         r = (*handler) (ctrl_p->bmRequestType,
+                         ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
        }
     }
-  else if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
+  else
     {
-      if (req < TOTAL_REQUEST)
+      if (ctrl_p->wLength == 0)
+       r = (*method_p->setup_with_nodata) (ctrl_p->bmRequestType,
+                                           req, ctrl_p->wIndex);
+      else
        {
-         handler = std_request_handler[req];
-         r = (*handler) (ctrl_p->bmRequestType & RECIPIENT,
-                         ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
+         (*method_p->setup_with_data) (ctrl_p->bmRequestType, req,
+                                       ctrl_p->wIndex, ctrl_p->wLength);
+         if (data_p->len != 0)
+           r = USB_SUCCESS;
        }
     }
 
+
   if (r != USB_SUCCESS)
     dev_p->state = STALLED;
   else
     {
-      if (ctrl_p->bmRequestType & 0x80)
+      if (ctrl_p->bmRequestType & REQUEST_DIR)
        {
          uint32_t len = ctrl_p->wLength;
      
index f27d017..7355ba3 100644 (file)
@@ -39,10 +39,12 @@ enum DESCRIPTOR_TYPE
   ENDPOINT_DESCRIPTOR
 };
 
+#define REQUEST_DIR       0x80  /* Mask to get request dir  */
 #define REQUEST_TYPE      0x60  /* Mask to get request type */
 #define STANDARD_REQUEST  0x00  /* Standard request         */
 #define CLASS_REQUEST     0x20  /* Class request            */
 #define VENDOR_REQUEST    0x40  /* Vendor request           */
+#define RECIPIENT         0x1F  /* Mask to get recipient    */
 
 struct Descriptor
 {
@@ -60,7 +62,8 @@ struct usb_device_method
 {
   void (*init) (void);
   void (*reset) (void);
-  void (*setup_with_data) (uint8_t rcp, uint8_t req_no, uint16_t index);
+  void (*setup_with_data) (uint8_t rcp, uint8_t req_no, uint16_t index,
+                          uint16_t len);
   int (*setup_with_nodata) (uint8_t rcp, uint8_t req_no, uint16_t index);
   int (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
   int (*event) (uint8_t event_type, uint16_t value);
@@ -141,3 +144,8 @@ extern uint8_t usb_lld_current_configuration (void);
 extern void usb_lld_set_feature (uint8_t feature);
 
 extern void usb_lld_set_data_to_send (const void *p, size_t len);
+
+extern inline void usb_lld_set_data_to_recv (void *p, size_t len)
+{
+  usb_lld_set_data_to_send ((const void *)p, len);
+}
index 1787156..f2996f9 100644 (file)
@@ -28,6 +28,7 @@
 #include "ch.h"
 #include "usb_lld.h"
 #include "usb_conf.h"
+#include "gnuk.h"
 
 #ifdef ENABLE_VIRTUAL_COM_PORT
 #include "usb-cdc.h"
@@ -40,7 +41,7 @@ struct line_coding
   uint8_t datatype;
 };
 
-static const struct line_coding line_coding = {
+static struct line_coding line_coding = {
   115200, /* baud rate: 115200    */
   0x00,   /* stop bits: 1         */
   0x00,   /* parity:    none      */
@@ -48,20 +49,19 @@ static const struct line_coding line_coding = {
 };
 
 static void
-vcom_port_data_setup (uint8_t RequestNo)
+vcom_port_data_setup (uint8_t req, uint8_t req_no)
 {
-  if (RequestNo != USB_CDC_REQ_GET_LINE_CODING)
-    return;
+  if ((req & REQUEST_DIR) == 1 && req_no == USB_CDC_REQ_GET_LINE_CODING)
+    usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
 
-  /* RequestNo == USB_CDC_REQ_SET_LINE_CODING is not supported */
-
-  usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
+  if ((req & REQUEST_DIR) == 0 && req_no == USB_CDC_REQ_SET_LINE_CODING)
+    usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
 }
 
 static int
-vcom_port_setup_with_nodata (uint8_t RequestNo)
+vcom_port_setup_with_nodata (uint8_t req, uint8_t req_no)
 {
-  if (RequestNo == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+  if ((req & REQUEST_DIR) == 0 && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
     /* Do nothing and success  */
     return USB_SUCCESS;
 
@@ -183,26 +183,54 @@ static const uint8_t data_rate_table[] = { 0x80, 0x25, 0, 0, }; /* dwDataRate */
 static const uint8_t lun_table[] = { 0, 0, 0, 0, };
 #endif
 
+static const uint8_t *mem_info[] = { &__heap_base__,  &__heap_end__, };
+
+#define USB_FSIJ_GNUK_MEMINFO  0
+#define USB_FSIJ_GNUK_DOWNLOAD 1
+#define USB_FSIJ_GNUK_EXEC     2
+
 static void
-gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
+gnuk_setup_with_data (uint8_t req, uint8_t req_no, uint16_t index,
+                     uint16_t len)
 {
-  if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
+  uint8_t recipient = req & RECIPIENT;
+
+  if (recipient == (VENDOR_REQUEST | DEVICE_RECIPIENT))
+    {
+      if ((req & REQUEST_DIR) == 1 && req_no == USB_FSIJ_GNUK_MEMINFO)
+       usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
+      else if ((req & REQUEST_DIR) == 0 && req_no == USB_FSIJ_GNUK_DOWNLOAD)
+       {
+         if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
+           return;
+
+         if ((uint32_t)(index * 0x100) < (uint32_t)&__heap_base__
+             || (uint32_t)((index * 0x100) + len) > (uint32_t)&__heap_end__)
+           return;
+
+         usb_lld_set_data_to_recv ((void *)0x20000000 + index*0x100, len);
+       }
+    }
+  else if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
     {
       if (index == 0)
        {
-         if (RequestNo == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
+         if ((req & REQUEST_DIR) == 1
+             && req_no == USB_CCID_REQ_GET_CLOCK_FREQUENCIES)
            usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
-         else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES)
-           usb_lld_set_data_to_send (data_rate_table, sizeof (data_rate_table));
+         else if ((req & REQUEST_DIR) == 1
+                  && req_no == USB_CCID_REQ_GET_DATA_RATES)
+           usb_lld_set_data_to_send (data_rate_table,
+                                     sizeof (data_rate_table));
        }
 #ifdef ENABLE_VIRTUAL_COM_PORT
       else if (index == 1)
-       vcom_port_data_setup (RequestNo);
+       vcom_port_data_setup (req, req_no);
 #endif
 #ifdef PINPAD_DND_SUPPORT
       else if (index == MSC_INTERFACE_NO)
        {
-         if (RequestNo == MSC_GET_MAX_LUN_COMMAND)
+         if ((req & REQUEST_DIR) == 1 && req_no == MSC_GET_MAX_LUN_COMMAND)
            usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
        }
 #endif
@@ -211,12 +239,28 @@ gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
 
 
 static int
-gnuk_setup_with_nodata (uint8_t recipient, uint8_t RequestNo, uint16_t index)
+gnuk_setup_with_nodata (uint8_t req, uint8_t req_no, uint16_t index)
 {
-  if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) /* Interface */
+  uint8_t recipient = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (recipient == (VENDOR_REQUEST | DEVICE_RECIPIENT))
+    {
+      if (req_no == USB_FSIJ_GNUK_EXEC)
+       {
+         if (icc_state_p == NULL || *icc_state_p != ICC_STATE_EXITED)
+           return USB_UNSUPPORT;
+
+         *icc_state_p = ICC_STATE_EXEC_REQUESTED;
+         return USB_SUCCESS;
+       }
+    }
+  else if (recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
     if (index == 0)
       {
-       if (RequestNo == USB_CCID_REQ_ABORT)
+       if (req_no == USB_CCID_REQ_ABORT)
          /* wValue: bSeq, bSlot */
          /* Abortion is not supported in Gnuk */
          return USB_UNSUPPORT;
@@ -225,24 +269,20 @@ gnuk_setup_with_nodata (uint8_t recipient, uint8_t RequestNo, uint16_t index)
       }
 #ifdef ENABLE_VIRTUAL_COM_PORT
     else if (index == 1)
-      return vcom_port_setup_with_nodata (RequestNo);
+      return vcom_port_setup_with_nodata (req, req_no);
 #endif
 #ifdef PINPAD_DND_SUPPORT
     else if (index == MSC_INTERFACE_NO)
       {
-       if (RequestNo == MSC_MASS_STORAGE_RESET_COMMAND)
+       if (req_no == MSC_MASS_STORAGE_RESET_COMMAND)
          {
            /* Should call resetting MSC thread, something like msc_reset() */
            return USB_SUCCESS;
          }
-       else
-         return USB_UNSUPPORT;
       }
 #endif
-    else
-      return USB_UNSUPPORT;
-  else
-    return USB_UNSUPPORT;
+
+  return USB_UNSUPPORT;
 }
 
 static int
@@ -278,6 +318,8 @@ gnuk_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
 
 static int gnuk_usb_event (uint8_t event_type, uint16_t value)
 {
+  int i;
+
   switch (event_type)
     {
     case USB_EVENT_RESET:
@@ -288,10 +330,6 @@ static int gnuk_usb_event (uint8_t event_type, uint16_t value)
     case USB_EVENT_CONFIG:
       if (usb_lld_current_configuration () == 0)
        {
-         int i;
-         extern void *main_thread;
-#define LED_STATUS_MODE   (8)
-
          if (value != 1)
            return USB_UNSUPPORT;
 
diff --git a/tool/gnuk_upgrade.py b/tool/gnuk_upgrade.py
new file mode 100755 (executable)
index 0000000..c041ef6
--- /dev/null
@@ -0,0 +1,239 @@
+#! /usr/bin/python
+
+"""
+gnuk_upgrade.py - a tool to upgrade firmware of Gnuk Token
+
+Copyright (C) 2012 Free Software Initiative of Japan
+Author: NIIBE Yutaka <gniibe@fsij.org>
+
+This file is a part of Gnuk, a GnuPG USB Token implementation.
+
+Gnuk is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Gnuk is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+from intel_hex import *
+from struct import *
+import sys, time, os, binascii, string
+
+# INPUT: binary file
+
+# Assume only single CCID device is attached to computer, and it's Gnuk Token
+
+import usb
+
+# USB class, subclass, protocol
+CCID_CLASS = 0x0B
+CCID_SUBCLASS = 0x00
+CCID_PROTOCOL_0 = 0x00
+
+def icc_compose(msg_type, data_len, slot, seq, param, data):
+    return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data
+
+def iso7816_compose(ins, p1, p2, data):
+    cls = 0x00 
+    data_len = len(data)
+    if data_len == 0:
+        return pack('>BBBB', cls, ins, p1, p2)
+    else:
+        return pack('>BBBBBh', cls, ins, p1, p2, 0, data_len) + data
+
+# This class only supports Gnuk (for now) 
+class gnuk_token:
+    def __init__(self, device, configuration, interface):
+        """
+        __init__(device, configuration, interface) -> None
+        Initialize the device.
+        device: usb.Device object.
+        configuration: configuration number.
+        interface: usb.Interface object representing the interface and altenate setting.
+        """
+        if interface.interfaceClass != CCID_CLASS:
+            raise ValueError, "Wrong interface class"
+        if interface.interfaceSubClass != CCID_SUBCLASS:
+            raise ValueError, "Wrong interface sub class"
+        self.__devhandle = device.open()
+        try:
+            self.__devhandle.setConfiguration(configuration)
+        except:
+            pass
+        self.__devhandle.claimInterface(interface)
+        self.__devhandle.setAltInterface(interface)
+
+        self.__intf = interface.interfaceNumber
+        self.__alt = interface.alternateSetting
+        self.__conf = configuration
+
+        self.__bulkout = 2
+        self.__bulkin  = 0x81
+
+        self.__timeout = 10000
+        self.__seq = 0
+
+    def icc_get_result(self):
+        msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout)
+        if len(msg) < 10:
+            print msg
+            raise ValueError, "icc_get_result"
+        msg_type = msg[0]
+        data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24)
+        slot = msg[5]
+        seq = msg[6]
+        status = msg[7]
+        error = msg[8]
+        chain = msg[9]
+        data = msg[10:]
+        # XXX: check msg_type, data_len, slot, seq, error
+        return (status, chain, data)
+
+    def icc_get_status(self):
+        msg = icc_compose(0x65, 0, 0, self.__seq, 0, "")
+        self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
+        self.__seq += 1
+        status, chain, data = self.icc_get_result()
+        # XXX: check chain, data
+        return status
+
+    def icc_power_on(self):
+        msg = icc_compose(0x62, 0, 0, self.__seq, 0, "")
+        self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
+        self.__seq += 1
+        status, chain, data = self.icc_get_result()
+        # XXX: check status, chain
+        return data             # ATR
+
+    def icc_power_off(self):
+        msg = icc_compose(0x63, 0, 0, self.__seq, 0, "")
+        self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
+        self.__seq += 1
+        status, chain, data = self.icc_get_result()
+        # XXX: check chain, data
+        return status
+
+    def icc_send_data_block(self, data):
+        msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data)
+        self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
+        self.__seq += 1
+        return self.icc_get_result()
+
+    def icc_send_cmd(self, data):
+        status, chain, data_rcv = self.icc_send_data_block(data)
+        if chain == 0:
+            return data_rcv
+        elif chain == 1:
+            d = data_rcv
+            while True:
+                msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "")
+                self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
+                self.__seq += 1
+                status, chain, data_rcv = self.icc_get_result()
+                # XXX: check status
+                d += data_rcv
+                if chain == 2:
+                    break
+                elif chain == 3:
+                    continue
+                else:
+                    raise ValueError, "icc_send_cmd chain"
+            return d
+        else:
+            raise ValueError, "icc_send_cmd"
+
+    def cmd_get_response(self, expected_len):
+        cmd_data = iso7816_compose(0xc0, 0x00, 0x00, [expected_len])
+        response = self.icc_send_cmd(cmd_data)
+        return response
+
+    def cmd_verify(self, who, passwd):
+        cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd)
+        sw = self.icc_send_cmd(cmd_data)
+        if len(sw) != 2:
+            raise ValueError, "cmd_verify"
+        if not (sw[0] == 0x90 and sw[1] == 0x00):
+            raise ValueError, "cmd_verify"
+
+    def cmd_select_openpgp(self):
+        cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
+        sw = self.icc_send_cmd(cmd_data)
+        if len(sw) != 2:
+            raise ValueError, "cmd_select_openpgp"
+        if not (sw[0] == 0x90 and sw[1] == 0x00):
+            raise ValueError, ("%02x%02x" % (sw[0], sw[1]))
+
+    def cmd_external_authenticate(self, who, signed):
+        cmd_data = iso7816_compose(0x82, 0x00, 0x00, signed)
+        sw = self.icc_send_cmd(cmd_data)
+        if len(sw) != 2:
+            raise ValueError, "cmd_external_authenticate"
+        if not (sw[0] == 0x90 and sw[1] == 0x00):
+            raise ValueError, "cmd_external_authenticate"
+
+def compare(data_original, data_in_device):
+    i = 0 
+    for d in data_original:
+        if ord(d) != data_in_device[i]:
+            raise ValueError, "verify failed at %08x" % i
+        i += 1
+
+def get_device():
+    busses = usb.busses()
+    for bus in busses:
+        devices = bus.devices
+        for dev in devices:
+            for config in dev.configurations:
+                for intf in config.interfaces:
+                    for alt in intf:
+                        if alt.interfaceClass == CCID_CLASS and \
+                                alt.interfaceSubClass == CCID_SUBCLASS and \
+                                alt.interfaceProtocol == CCID_PROTOCOL_0:
+                            return dev, config, alt
+    raise ValueError, "Device not found"
+
+def main(passwd, data):
+    dev, config, intf = get_device()
+    print "Device: ", dev.filename
+    print "Configuration: ", config.value
+    print "Interface: ", intf.interfaceNumber
+    icc = gnuk_token(dev, config, intf)
+    if icc.icc_get_status() == 2:
+        raise ValueError, "No ICC present"
+    elif icc.icc_get_status() == 1:
+        icc.icc_power_on()
+    icc.cmd_verify(3, passwd)
+    icc.cmd_select_openpgp()
+    challenge = icc.cmd_get_challenge()
+    signed = challenge
+    icc.cmd_external_authenticate(signed)
+    # set_configure(0) to disable all interfaces but control pipe
+    # check mem_info
+    # download flash install program
+    # exec
+    # ...
+    # Then, send upgrade program...
+    return 0
+
+DEFAULT_PW3 = "12345678"
+
+if __name__ == '__main__':
+    passwd = DEFAULT_PW3
+    if sys.argv[1] == '-p':
+        from getpass import getpass
+        passwd = getpass("Admin password: ")
+        sys.argv.pop(1)
+    filename = sys.argv[1]
+    f = open(filename)
+    data = f.read()
+    f.close()
+    print "%s: %d" % (filename, len(data))
+    print "Downloading flash upgrade program"
+    main(passwd, data)