improve key store handling (for overriding)

This commit is contained in:
NIIBE Yutaka
2013-10-24 12:01:50 +09:00
parent 65035f5151
commit 40f2725158
5 changed files with 91 additions and 29 deletions

View File

@@ -1,3 +1,16 @@
2013-10-24 Niibe Yutaka <gniibe@fsij.org>
* src/gnuk.ld.in (.gnuk_flash): Three pages for three keys.
* src/flash.c (FLASH_KEYSTORE_SIZE): Likewise.
(flash_keystore_release): Remove.
(flash_key_fill_zero_as_released)
(flash_check_all_other_keys_released, flash_key_release): New.
(flash_init, flash_key_alloc): New method to handle free space.
* src/openpgp-do.c (fetch_four_bytes): New.
(gpg_do_load_prvkey, gpg_do_delete_prvkey, gpg_do_public_key): Use
fetch_four_bytes.
(gpg_do_delete_prvkey): Call flash_key_release.
2013-10-23 Niibe Yutaka <gniibe@fsij.org>
* test/features/010_setup_passphrase.feature

View File

@@ -57,19 +57,18 @@
* _data_pool
* <two pages>
* _keystore_pool
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
* three flash pages for keystore (single: 512-byte (p, q and N))
*/
#define KEY_SIZE 512 /* P, Q and N */
#define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3)
#define FLASH_KEYSTORE_SIZE (FLASH_PAGE_SIZE*3)
static const uint8_t *data_pool;
extern uint8_t _keystore_pool;
static uint8_t *last_p;
static const uint8_t *keystore;
/* The first halfword is generation for the data page (little endian) */
const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
@@ -82,7 +81,6 @@ extern uint8_t _data_pool;
const uint8_t *
flash_init (void)
{
const uint8_t *p;
uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)&_data_pool;
uint16_t *gen1_p = (uint16_t *)(&_data_pool + FLASH_PAGE_SIZE);
@@ -99,13 +97,6 @@ flash_init (void)
else
data_pool = &_data_pool;
/* Seek empty keystore */
p = &_keystore_pool;
while (*p != 0xff || *(p+1) != 0xff)
p += KEY_SIZE;
keystore = p;
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
}
@@ -277,16 +268,31 @@ flash_do_release (const uint8_t *do_data)
flash_warning ("fill-zero tag_nr failure");
}
uint8_t *
flash_key_alloc (void)
{
uint8_t *k = (uint8_t *)keystore;
uint8_t *k;
int i;
if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
return NULL;
/* Seek empty keystore. */
k = &_keystore_pool;
while (k < &_keystore_pool + FLASH_KEYSTORE_SIZE)
{
const uint32_t *p = (const uint32_t *)k;
keystore += KEY_SIZE;
return k;
for (i = 0; i < KEY_SIZE/4; i++)
if (p[i] != 0xffffffff)
break;
if (i == KEY_SIZE/4) /* Yes, it's empty. */
return k;
k += KEY_SIZE;
}
/* Should not happen as we have enough space, but just in case. */
return NULL;
}
int
@@ -317,16 +323,44 @@ flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
return 0;
}
void
flash_keystore_release (void)
static int
flash_check_all_other_keys_released (const uint8_t *key_addr)
{
flash_erase_page ((uint32_t)&_keystore_pool);
#if FLASH_KEYSTORE_SIZE > FLASH_PAGE_SIZE
flash_erase_page ((uint32_t)&_keystore_pool + FLASH_PAGE_SIZE);
#endif
keystore = &_keystore_pool;
uint32_t start = (uint32_t)key_addr & ~(FLASH_PAGE_SIZE - 1);
const uint32_t *p = (const uint32_t *)start;
while (p < (const uint32_t *)(start + FLASH_PAGE_SIZE))
if (p == (const uint32_t *)key_addr)
p += KEY_SIZE/4;
else
if (*p)
return 0;
else
p++;
return 1;
}
static void
flash_key_fill_zero_as_released (uint8_t *key_addr)
{
int i;
uint32_t addr = (uint32_t)key_addr;
for (i = 0; i < KEY_SIZE/2; i++)
flash_program_halfword (addr + i*2, 0);
}
void
flash_key_release (uint8_t *key_addr)
{
if (flash_check_all_other_keys_released (key_addr))
flash_erase_page (((uint32_t)key_addr & ~(FLASH_PAGE_SIZE - 1)));
else
flash_key_fill_zero_as_released (key_addr);
}
void
flash_clear_halfword (uint32_t addr)
{

View File

@@ -111,9 +111,9 @@ extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
extern uint8_t *flash_key_alloc (void);
extern void flash_key_release (uint8_t *);
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
const uint8_t *pubkey, int pubkey_len);
extern void flash_keystore_release (void);
extern void flash_set_data_pool_last (const uint8_t *p);
extern void flash_clear_halfword (uint32_t addr);
extern void flash_increment_counter (uint8_t counter_tag_nr);

View File

@@ -167,7 +167,11 @@ SECTIONS
. = ALIGN(@FLASH_PAGE_SIZE@);
. += @FLASH_PAGE_SIZE@;
_keystore_pool = .;
. += 512*3;
. += 512;
. = ALIGN(@FLASH_PAGE_SIZE@);
. += 512;
. = ALIGN(@FLASH_PAGE_SIZE@);
. += 512;
. = ALIGN(@FLASH_PAGE_SIZE@);
_updatekey_store = .;
. += 1024;

View File

@@ -35,6 +35,16 @@
#include "polarssl/config.h"
#include "polarssl/aes.h"
/* Handles possible unaligned access. */
static uint32_t
fetch_four_bytes (const void *addr)
{
const uint8_t *p = (const uint8_t *)addr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3];
@@ -705,7 +715,7 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
if (do_data == NULL)
return 0;
key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */
key_addr = (const uint8_t *)fetch_four_bytes (&do_data[1]);
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
iv = do_data+5;
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
@@ -734,10 +744,13 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
uint8_t *key_addr;
if (do_data == NULL)
return;
key_addr = (uint8_t *)fetch_four_bytes (&do_data[1]);
flash_key_release (key_addr);
do_ptr[nr - NR_DO__FIRST__] = NULL;
flash_do_release (do_data);
@@ -758,8 +771,6 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
if (--num_prv_keys == 0)
{
flash_keystore_release ();
/* Delete PW1 and RC if any. */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
@@ -1591,7 +1602,7 @@ gpg_do_public_key (uint8_t kk_byte)
return;
}
key_addr = *(const uint8_t **)&do_data[1];
key_addr = (const uint8_t *)fetch_four_bytes (&do_data[1]);
res_p = res_APDU;