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

@@ -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__;

View 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

View 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;

View 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->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 ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
{
if (req < TOTAL_REQUEST)
{
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);
}
}
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)
dev_p->state = STALLED;
else
{
if (ctrl_p->bmRequestType & 0x80)
if (ctrl_p->bmRequestType & REQUEST_DIR)
{
uint32_t len = ctrl_p->wLength;

View 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);
}

View 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;