add factory reset support (not-full yet)

This commit is contained in:
NIIBE Yutaka
2016-10-13 15:06:19 +09:00
parent 5795dc9877
commit 34d0b34144
5 changed files with 167 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
/*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -75,7 +75,7 @@ static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x01, 0x00, 0xff, 0xff
0x00, 0x00, 0xff, 0xff
};
/* Linker set this symbol */
@@ -114,22 +114,51 @@ flash_init (void)
flash_page_size = 2048;
gen1_p = (uint16_t *)(&_data_pool + flash_page_size);
data_pool = &_data_pool;
/* Check data pool generation and choose the page */
gen0 = *gen0_p;
gen1 = *gen1_p;
if (gen0 == 0xffff && gen1 == 0xffff)
/* It's terminated. */
return NULL;
if (gen0 == 0xffff)
/* Use another page if a page is erased. */
data_pool = &_data_pool + flash_page_size;
else if (gen1 == 0xffff)
/* Or use different page if another page is erased. */
data_pool = &_data_pool;
else if (gen1 > gen0)
else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0)
/* When both pages have valid header, use newer page. */
data_pool = &_data_pool + flash_page_size;
else
data_pool = &_data_pool;
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
}
static uint8_t *flash_key_getpage (enum kind_of_key kk);
void
flash_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
flash_erase_page ((uint32_t)flash_key_getpage (i));
flash_erase_page ((uint32_t)&_data_pool);
flash_erase_page ((uint32_t)(&_data_pool + flash_page_size));
data_pool = &_data_pool;
last_p = &_data_pool + FLASH_DATA_POOL_HEADER_SIZE;
}
void
flash_activate (void)
{
flash_program_halfword ((uint32_t)&_data_pool, 0);
}
void
flash_init_keys (void)
{
@@ -209,8 +238,12 @@ flash_copying_gc (void)
generation = *(uint16_t *)src;
data_pool = dst;
gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE);
if (generation == 0xfffe)
generation = 0;
else
generation++;
flash_program_halfword ((uint32_t)dst, generation);
flash_erase_page ((uint32_t)src);
flash_program_halfword ((uint32_t)dst, generation+1);
return 0;
}

View File

@@ -107,6 +107,7 @@ extern uint16_t data_objects_number_of_bytes;
void gpg_data_scan (const uint8_t *p);
void gpg_data_copy (const uint8_t *p);
void gpg_do_terminate (void);
void gpg_do_get_data (uint16_t tag, int with_tag);
void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
void gpg_do_public_key (uint8_t kk_byte);
@@ -138,6 +139,8 @@ int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
const uint8_t *flash_init (void);
void flash_terminate (void);
void flash_activate (void);
void flash_init_keys (void);
void flash_do_release (const uint8_t *);
const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);

View File

@@ -1074,6 +1074,28 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full)
}
}
void
gpg_do_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
kd[i].pubkey = NULL;
for (i = 0; i < NR_DO__LAST__; i++)
do_ptr[i] = NULL;
num_prv_keys = 0;
data_objects_number_of_bytes = 0;
digital_signature_counter = 0;
pw1_lifetime_p = NULL;
pw_err_counter_p[PW_ERR_PW1] = NULL;
pw_err_counter_p[PW_ERR_RC] = NULL;
pw_err_counter_p[PW_ERR_PW3] = NULL;
algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
}
static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
int prvkey_len, const uint8_t *keystring_admin,
@@ -1549,7 +1571,7 @@ gpg_data_scan (const uint8_t *p_start)
/* Traverse DO, counters, etc. in DATA pool */
p = p_start;
while (*p != NR_EMPTY)
while (p && *p != NR_EMPTY)
{
uint8_t nr = *p++;
uint8_t second_byte = *p;

View File

@@ -48,6 +48,7 @@ static struct eventflag *openpgp_comm;
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a
#define INS_RESET_RETRY_COUNTER 0x2c
#define INS_ACTIVATE_FILE 0x44
#define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR 0x47
#define INS_EXTERNAL_AUTHENTICATE 0x82
#define INS_GET_CHALLENGE 0x84
@@ -59,6 +60,7 @@ static struct eventflag *openpgp_comm;
#define INS_UPDATE_BINARY 0xd6
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */
#define INS_TERMINATE_DF 0xe6
static const uint8_t *challenge; /* Random bytes */
@@ -96,6 +98,8 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
#define FILE_EF_UPDATE_KEY_2 7
#define FILE_EF_UPDATE_KEY_3 8
#define FILE_EF_CH_CERTIFICATE 9
#define FILE_CARD_TERMINATED_OPENPGP 254
#define FILE_CARD_TERMINATED 255
static uint8_t file_selection;
@@ -104,10 +108,15 @@ gpg_init (void)
{
const uint8_t *flash_data_start;
file_selection = FILE_NONE;
flash_data_start = flash_init ();
gpg_data_scan (flash_data_start);
flash_init_keys ();
flash_data_start = flash_init ();
if (flash_data_start == NULL)
file_selection = FILE_CARD_TERMINATED;
else
file_selection = FILE_NONE;
gpg_data_scan (flash_data_start);
}
static void
@@ -616,9 +625,6 @@ cmd_put_data (void)
DEBUG_INFO (" - PUT DATA\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD();
tag = ((P1 (apdu)<<8) | P2 (apdu));
len = apdu.cmd_apdu_data_len;
data = apdu.cmd_apdu_data;
@@ -751,6 +757,13 @@ cmd_select_file (void)
return;
}
if (file_selection == FILE_CARD_TERMINATED)
{
file_selection = FILE_CARD_TERMINATED_OPENPGP;
GPG_APPLICATION_TERMINATED();
return;
}
file_selection = FILE_DF_OPENPGP;
if ((P2 (apdu) & 0x0c) == 0x0c) /* No FCI */
GPG_SUCCESS ();
@@ -813,9 +826,6 @@ cmd_get_data (void)
DEBUG_INFO (" - Get Data\r\n");
if (file_selection != FILE_DF_OPENPGP)
GPG_NO_RECORD ();
gpg_do_get_data (tag, 0);
}
@@ -1317,6 +1327,64 @@ cmd_get_challenge (void)
}
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
static void
cmd_activate_file (void)
{
if (file_selection != FILE_CARD_TERMINATED_OPENPGP)
{
GPG_NO_RECORD();
return;
}
flash_activate ();
file_selection = FILE_DF_OPENPGP;
GPG_SUCCESS ();
}
static void
cmd_terminate_df (void)
{
uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
if (file_selection != FILE_DF_OPENPGP)
{
GPG_NO_RECORD();
return;
}
if (p1 != 0 || p2 != 0)
{
GPG_BAD_P1_P2();
return;
}
if (apdu.cmd_apdu_data_len != 0)
{
GPG_WRONG_LENGTH();
return;
}
if (!ac_check_status (AC_ADMIN_AUTHORIZED) && !gpg_pw_locked (PW_ERR_PW3))
{
/* Only allow the case admin authorized, or, admin pass is locked. */
GPG_SECURITY_FAILURE();
return;
}
ac_reset_admin ();
ac_reset_pso_cds ();
ac_reset_other ();
gpg_do_terminate ();
flash_terminate ();
file_selection = FILE_CARD_TERMINATED;
GPG_SUCCESS ();
}
#endif
struct command
{
uint8_t command;
@@ -1328,13 +1396,16 @@ const struct command cmds[] = {
{ INS_CHANGE_REFERENCE_DATA, cmd_change_password },
{ INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_ACTIVATE_FILE, cmd_activate_file },
#endif
{ 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_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */
{ INS_GET_DATA, cmd_get_data },
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
#if defined(CERTDO_SUPPORT)
@@ -1342,6 +1413,9 @@ const struct command cmds[] = {
#endif
{ INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_TERMINATE_DF, cmd_terminate_df},
#endif
};
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
@@ -1357,9 +1431,22 @@ process_command_apdu (void)
if (i < NUM_CMDS)
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
chopstx_setcancelstate (0);
if (file_selection == FILE_CARD_TERMINATED
&& cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
&& cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE)
GPG_APPLICATION_TERMINATED();
else if (file_selection != FILE_DF_OPENPGP
&& cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
&& cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE
&& cmd != INS_WRITE_BINARY && cmd != INS_UPDATE_BINARY
&& cmd != INS_READ_BINARY)
GPG_NO_RECORD();
else
{
chopstx_setcancelstate (1);
cmds[i].cmd_handler ();
chopstx_setcancelstate (0);
}
}
else
{

View File

@@ -1,4 +1,6 @@
#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)