implement downloading program

This commit is contained in:
NIIBE Yutaka 2012-05-17 17:02:49 +09:00
parent e2e2e1a045
commit ce338a9727
8 changed files with 471 additions and 66 deletions

View File

@ -1,8 +1,25 @@
2012-05-17 Niibe Yutaka <gniibe@fsij.org> 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 * src/usb_prop.c (gnuk_setup_endpoints_for_interface): Add STOP
argument. argument.
(gnuk_usb_event): Disable all endpoints when configure(0). (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. * src/usb_lld.c (LAST_OUT_DATA): Remove.
(handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status. (handle_datastage_out): Cleanup and call st103_ep_set_rxtx_status.
@ -10,6 +27,11 @@
st103_ep_set_tx_status. st103_ep_set_tx_status.
(handle_setup0): Likewise. (handle_setup0): Likewise.
(handle_out0): Remove LAST_OUT_DATA. (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> 2012-05-16 Niibe Yutaka <gniibe@fsij.org>

View File

@ -76,6 +76,9 @@ enum icc_state
ICC_STATE_EXECUTE, /* Busy4 */ ICC_STATE_EXECUTE, /* Busy4 */
ICC_STATE_RECEIVE, /* APDU Received Partially */ ICC_STATE_RECEIVE, /* APDU Received Partially */
ICC_STATE_SEND, /* APDU Sent 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; 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); extern int pinpad_getline (int msg_code, systime_t timeout);
#endif #endif
extern uint8_t __heap_base__, __heap_end__;

View File

@ -1,7 +1,7 @@
/* /*
* openpgp.c -- OpenPGP card protocol support * 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> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Gnuk, a GnuPG USB Token implementation. * This file is a part of Gnuk, a GnuPG USB Token implementation.
@ -39,6 +39,8 @@
#define INS_PSO 0x2a #define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c #define INS_RESET_RETRY_COUNTER 0x2c
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47 #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_INTERNAL_AUTHENTICATE 0x88
#define INS_SELECT_FILE 0xa4 #define INS_SELECT_FILE 0xa4
#define INS_READ_BINARY 0xb0 #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 struct command
{ {
uint8_t command; uint8_t command;
@ -833,11 +872,14 @@ const struct command cmds[] = {
{ INS_PSO, cmd_pso }, { INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, { 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_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
{ INS_SELECT_FILE, cmd_select_file }, { INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary }, { INS_READ_BINARY, cmd_read_binary },
{ INS_GET_DATA, cmd_get_data }, { 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) #if defined(CERTDO_SUPPORT)
{ INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */ { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
#endif #endif

View File

@ -1273,6 +1273,7 @@ icc_handle_timeout (struct ccid *c)
static struct ccid ccid; static struct ccid ccid;
#define GPG_THREAD_TERMINATED 0xffff
msg_t msg_t
USBthread (void *arg) USBthread (void *arg)
@ -1303,6 +1304,16 @@ USBthread (void *arg)
else if (m == EV_EXEC_FINISHED) else if (m == EV_EXEC_FINISHED)
if (c->icc_state == ICC_STATE_EXECUTE) 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->a->cmd_apdu_data_len = 0;
c->sw1sw2[0] = c->a->sw >> 8; c->sw1sw2[0] = c->a->sw >> 8;
c->sw1sw2[1] = c->a->sw & 0xff; c->sw1sw2[1] = c->a->sw & 0xff;

View File

@ -4,8 +4,6 @@
#define USB_MAX_PACKET_SIZE 64 /* For FS device */ #define USB_MAX_PACKET_SIZE 64 /* For FS device */
#define RECIPIENT 0x1F /* Mask to get recipient */
enum STANDARD_REQUESTS enum STANDARD_REQUESTS
{ {
GET_STATUS = 0, GET_STATUS = 0,
@ -450,25 +448,27 @@ static void handle_datastage_in (void)
st103_ep_set_tx_status (ENDP0, EP_TX_VALID); 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); 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) 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; 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) uint16_t value, uint16_t index, uint16_t length)
{ {
static uint16_t status_info; static uint16_t status_info;
uint8_t rcp = req & RECIPIENT;
status_info = 0; /* Reset Status Information */ status_info = 0; /* Reset Status Information */
data_p->addr = (uint8_t *)&status_info; 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; return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
@ -540,9 +540,14 @@ static int std_get_status (uint8_t rcp,
return USB_UNSUPPORT; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
{ {
if (length != 0 || index != 0) if (length != 0 || index != 0)
@ -598,9 +603,14 @@ static int std_clear_feature (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
{ {
if (length != 0 || index != 0) if (length != 0 || index != 0)
@ -646,9 +656,14 @@ static int std_set_feature (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
{ {
if (length == 0 && value <= 127 && index == 0 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; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
(void)length; (void)length;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
return (*method_p->get_descriptor) ((value >> 8), index, value); 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; 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) 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; (void)value; (void)index; (void)length;
if (rcp == DEVICE_RECIPIENT) if (rcp == DEVICE_RECIPIENT)
{ {
@ -683,9 +708,14 @@ static int std_get_configuration (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT; 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) 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) if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
{ {
int r; int r;
@ -698,9 +728,14 @@ static int std_set_configuration (uint8_t rcp, uint16_t value,
return USB_UNSUPPORT; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 0)
return USB_UNSUPPORT;
if (rcp == INTERFACE_RECIPIENT) if (rcp == INTERFACE_RECIPIENT)
{ {
if (value != 0 || (index >> 8) != 0 || length != 1) 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; 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) uint16_t index, uint16_t length)
{ {
uint8_t rcp = req & RECIPIENT;
if ((req & REQUEST_DIR) == 1)
return USB_UNSUPPORT;
if (rcp == INTERFACE_RECIPIENT) if (rcp == INTERFACE_RECIPIENT)
{ {
int r; int r;
@ -759,7 +799,6 @@ static void handle_setup0 (void)
uint8_t req; uint8_t req;
int r = USB_UNSUPPORT; int r = USB_UNSUPPORT;
HANDLER handler; HANDLER handler;
uint8_t type_rcp;
pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2)); pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
w = *pw++; w = *pw++;
@ -776,34 +815,35 @@ static void handle_setup0 (void)
data_p->len = 0; data_p->len = 0;
data_p->offset = 0; data_p->offset = 0;
type_rcp = (ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT)); if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) /* Interface */
|| (ctrl_p->bmRequestType & REQUEST_TYPE) == VENDOR_REQUEST)
{
if (ctrl_p->wLength == 0)
r = (*method_p->setup_with_nodata) (type_rcp, req, ctrl_p->wIndex);
else
{
(*method_p->setup_with_data) (type_rcp, req, ctrl_p->wIndex);
if (data_p->len != 0)
r = USB_SUCCESS;
}
}
else if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
{ {
if (req < TOTAL_REQUEST) if (req < TOTAL_REQUEST)
{ {
handler = std_request_handler[req]; handler = std_request_handler[req];
r = (*handler) (ctrl_p->bmRequestType & RECIPIENT, r = (*handler) (ctrl_p->bmRequestType,
ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength); ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
} }
} }
else
{
if (ctrl_p->wLength == 0)
r = (*method_p->setup_with_nodata) (ctrl_p->bmRequestType,
req, ctrl_p->wIndex);
else
{
(*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) if (r != USB_SUCCESS)
dev_p->state = STALLED; dev_p->state = STALLED;
else else
{ {
if (ctrl_p->bmRequestType & 0x80) if (ctrl_p->bmRequestType & REQUEST_DIR)
{ {
uint32_t len = ctrl_p->wLength; uint32_t len = ctrl_p->wLength;

View File

@ -39,10 +39,12 @@ enum DESCRIPTOR_TYPE
ENDPOINT_DESCRIPTOR ENDPOINT_DESCRIPTOR
}; };
#define REQUEST_DIR 0x80 /* Mask to get request dir */
#define REQUEST_TYPE 0x60 /* Mask to get request type */ #define REQUEST_TYPE 0x60 /* Mask to get request type */
#define STANDARD_REQUEST 0x00 /* Standard request */ #define STANDARD_REQUEST 0x00 /* Standard request */
#define CLASS_REQUEST 0x20 /* Class request */ #define CLASS_REQUEST 0x20 /* Class request */
#define VENDOR_REQUEST 0x40 /* Vendor request */ #define VENDOR_REQUEST 0x40 /* Vendor request */
#define RECIPIENT 0x1F /* Mask to get recipient */
struct Descriptor struct Descriptor
{ {
@ -60,7 +62,8 @@ struct usb_device_method
{ {
void (*init) (void); void (*init) (void);
void (*reset) (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 (*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 (*get_descriptor) (uint8_t desc_type, uint16_t index, uint16_t value);
int (*event) (uint8_t event_type, 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_feature (uint8_t feature);
extern void usb_lld_set_data_to_send (const void *p, size_t len); 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);
}

View File

@ -28,6 +28,7 @@
#include "ch.h" #include "ch.h"
#include "usb_lld.h" #include "usb_lld.h"
#include "usb_conf.h" #include "usb_conf.h"
#include "gnuk.h"
#ifdef ENABLE_VIRTUAL_COM_PORT #ifdef ENABLE_VIRTUAL_COM_PORT
#include "usb-cdc.h" #include "usb-cdc.h"
@ -40,7 +41,7 @@ struct line_coding
uint8_t datatype; uint8_t datatype;
}; };
static const struct line_coding line_coding = { static struct line_coding line_coding = {
115200, /* baud rate: 115200 */ 115200, /* baud rate: 115200 */
0x00, /* stop bits: 1 */ 0x00, /* stop bits: 1 */
0x00, /* parity: none */ 0x00, /* parity: none */
@ -48,20 +49,19 @@ static const struct line_coding line_coding = {
}; };
static void 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) if ((req & REQUEST_DIR) == 1 && req_no == USB_CDC_REQ_GET_LINE_CODING)
return; usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
/* RequestNo == USB_CDC_REQ_SET_LINE_CODING is not supported */ if ((req & REQUEST_DIR) == 0 && req_no == USB_CDC_REQ_SET_LINE_CODING)
usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
} }
static int 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 */ /* Do nothing and success */
return USB_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, }; static const uint8_t lun_table[] = { 0, 0, 0, 0, };
#endif #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 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 (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)); usb_lld_set_data_to_send (freq_table, sizeof (freq_table));
else if (RequestNo == USB_CCID_REQ_GET_DATA_RATES) else if ((req & REQUEST_DIR) == 1
usb_lld_set_data_to_send (data_rate_table, sizeof (data_rate_table)); && 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 #ifdef ENABLE_VIRTUAL_COM_PORT
else if (index == 1) else if (index == 1)
vcom_port_data_setup (RequestNo); vcom_port_data_setup (req, req_no);
#endif #endif
#ifdef PINPAD_DND_SUPPORT #ifdef PINPAD_DND_SUPPORT
else if (index == MSC_INTERFACE_NO) 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)); usb_lld_set_data_to_send (lun_table, sizeof (lun_table));
} }
#endif #endif
@ -211,12 +239,28 @@ gnuk_setup_with_data (uint8_t recipient, uint8_t RequestNo, uint16_t index)
static int 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 (index == 0)
{ {
if (RequestNo == USB_CCID_REQ_ABORT) if (req_no == USB_CCID_REQ_ABORT)
/* wValue: bSeq, bSlot */ /* wValue: bSeq, bSlot */
/* Abortion is not supported in Gnuk */ /* Abortion is not supported in Gnuk */
return USB_UNSUPPORT; 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 #ifdef ENABLE_VIRTUAL_COM_PORT
else if (index == 1) else if (index == 1)
return vcom_port_setup_with_nodata (RequestNo); return vcom_port_setup_with_nodata (req, req_no);
#endif #endif
#ifdef PINPAD_DND_SUPPORT #ifdef PINPAD_DND_SUPPORT
else if (index == MSC_INTERFACE_NO) 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() */ /* Should call resetting MSC thread, something like msc_reset() */
return USB_SUCCESS; return USB_SUCCESS;
} }
else
return USB_UNSUPPORT;
} }
#endif #endif
else
return USB_UNSUPPORT; return USB_UNSUPPORT;
else
return USB_UNSUPPORT;
} }
static int 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) static int gnuk_usb_event (uint8_t event_type, uint16_t value)
{ {
int i;
switch (event_type) switch (event_type)
{ {
case USB_EVENT_RESET: case USB_EVENT_RESET:
@ -288,10 +330,6 @@ static int gnuk_usb_event (uint8_t event_type, uint16_t value)
case USB_EVENT_CONFIG: case USB_EVENT_CONFIG:
if (usb_lld_current_configuration () == 0) if (usb_lld_current_configuration () == 0)
{ {
int i;
extern void *main_thread;
#define LED_STATUS_MODE (8)
if (value != 1) if (value != 1)
return USB_UNSUPPORT; return USB_UNSUPPORT;

239
tool/gnuk_upgrade.py Executable file
View File

@ -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)