From 7863290b62e0cfb5b6dbc3a817ffc73aacf928dd Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 5 Nov 2010 16:42:17 +0900 Subject: [PATCH] improve flash memory usage for passwd status and digital signature counter --- ChangeLog | 41 ++++- src/ac.c | 52 ++---- src/flash.c | 193 +++++++++++++++++++--- src/gnuk.h | 127 ++++++++++---- src/gnuk.ld.in | 2 +- src/openpgp-do.c | 418 ++++++++++++++++++++++++++--------------------- src/openpgp.c | 69 +++----- 7 files changed, 574 insertions(+), 328 deletions(-) diff --git a/ChangeLog b/ChangeLog index a789f3c..670daf1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,45 @@ +2010-11-05 NIIBE Yutaka + + * src/flash.c, src/gnuk.ld.in: Rename "Flash DO Pool" to "Flash + Data Pool", because it's not only DO. + * src/gnuk.h, src/opengpg-do.c: Cleanup. + + Digital Signature Counter implementation improvement. + * src/gnuk.h (NR_DO_DS_COUNT): Removed. + (NR_COUNTER_DS, NR_COUNTER_DS_LSB): New. + * src/openpgp-do.c (do_ds_count_initial_value): Removed. + (gpg_do_increment_digital_signature_counter): Removed. + (digital_signature_counter): New variable. + (do_ds_count, gpg_increment_digital_signature_counter): New functions. + (gpg_do_table): Change the entry for GPG_DO_DS_COUNT as DO_PROC_READ. + (gpg_do_table_init): Handle digital_signature_counter. + * src/flash.c (flash_data_pool_allocate, flash_put_data): New. + + Password status implementation improvement. + * src/gnuk.h (PW_STATUS_PW1, PW_STATUS_RC, PW_STATUS_PW3): Removed. + (PW_ERR_PW1, PW_ERR_RC, PW_ERR_PW3): New define. + (NR_COUNTER_123, NR_BOOL_PW1_LIFETIME): New define. + (NR_NONE, NR_EMPTY): New define. + * src/flash.c (flash_bool_clear, flash_bool_write) + (flash_cnt123_get_value, flash_cnt123_increment) + (flash_cnt123_clear): New functions. + * src/openpgp-do.c (do_pw_status_bytes_template): Removed. + (PW_STATUS_BYTES_TEMPLATE, gpg_do_reset_pw_counter): Removed. + (PASSWORD_ERRORS_MAX, PW_LEN_MAX): New define. + (pw1_lifetime_p, pw_err_counter_p): New variables. + (gpg_get_pw1_lifetime): New function. + (gpg_get_pw_err_counter, gpg_passwd_locked, gpg_reset_pw_counter) + (gpg_increment_pw_counter): New functions. + (rw_pw_status): Use pw1_lifetime_p and pw_err_counter_p. + (gpg_do_table_init): Handle NR_COUNTER_123 and NR_BOOL_PW1_LIFETIME. + * src/ac.c (verify_pso_cds, verify_pso_other, verify_admin_0): + Follow the changes. + * src/openpgp.c (cmd_change_password, cmd_reset_user_password) + (cmd_pso, cmd_internal_authenticate): Likewise. + 2010-11-04 NIIBE Yutaka - * src/flash.c (flash_warning): New. + * src/flash.c (flash_warning): New. (flash_do_pool): Added header for DO pool. (flash_do_release): Fill zero. (flash_do_write): Change DO format in flash. diff --git a/src/ac.c b/src/ac.c index 8049842..66ba242 100644 --- a/src/ac.c +++ b/src/ac.c @@ -56,16 +56,16 @@ ac_reset_pso_other (void) auth_status &= ~AC_PSO_OTHER_AUTHORIZED; } +/* + * Verify for "Perform Security Operation : Compute Digital Signature" + */ int verify_pso_cds (const uint8_t *pw, int pw_len) { int r; - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); uint8_t keystring[KEYSTRING_SIZE_PW1]; - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */ + if (gpg_passwd_locked (PW_ERR_PW1)) return 0; DEBUG_INFO ("verify_pso_cds\r\n"); @@ -73,18 +73,13 @@ verify_pso_cds (const uint8_t *pw, int pw_len) keystring[0] = pw_len; sha1 (pw, pw_len, keystring+1); - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring+1)) < 0) { - pwsb[PW_STATUS_PW1]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_PW1); return r; } - else if (pwsb[PW_STATUS_PW1] != 3) - { - pwsb[PW_STATUS_PW1] = 3; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - } + else + gpg_reset_pw_err_counter (PW_ERR_PW1); auth_status |= AC_PSO_CDS_AUTHORIZED; return 1; @@ -93,20 +88,15 @@ verify_pso_cds (const uint8_t *pw, int pw_len) int verify_pso_other (const uint8_t *pw, int pw_len) { - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; const uint8_t *ks_pw1; DEBUG_INFO ("verify_pso_other\r\n"); - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */ + if (gpg_passwd_locked (PW_ERR_PW1)) return 0; - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); - /* - * We check only the length of password string now. + * We check only the length of password string here. * Real check is defered to decrypt/authenticate routines. */ ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1); @@ -114,8 +104,8 @@ verify_pso_other (const uint8_t *pw, int pw_len) || (ks_pw1 != NULL && pw_len == ks_pw1[0])) { /* No problem */ /* - * We don't reset pwsb[PW_STATUS_PW1] here. - * Because password may be wrong. + * We don't call gpg_reset_pw_err_counters here, because + * password may be wrong. */ pw1_keystring[0] = pw_len; sha1 (pw, pw_len, pw1_keystring+1); @@ -124,8 +114,7 @@ verify_pso_other (const uint8_t *pw, int pw_len) } else { - pwsb[PW_STATUS_PW1]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_PW1); return 0; } } @@ -172,11 +161,9 @@ int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) { const uint8_t *pw3_keystring; - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); int pw_len; - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW3] == 0) /* locked */ + if (gpg_passwd_locked (PW_ERR_PW3)) return 0; pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); @@ -185,9 +172,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) int count; uint8_t md[KEYSTRING_MD_SIZE]; const uint8_t *salt; - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); pw_len = pw3_keystring[0]; if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len) goto failure; @@ -199,15 +184,12 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known) if (memcmp (md, &pw3_keystring[1+8+1], KEYSTRING_MD_SIZE) != 0) { failure: - pwsb[PW_STATUS_PW3]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_PW3); return -1; } - else if (pwsb[PW_STATUS_PW3] != 3) - { /* OK, the user is now authenticated */ - pwsb[PW_STATUS_PW3] = 3; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - } + else + /* OK, the user is now authenticated */ + gpg_reset_pw_err_counter (PW_ERR_PW3); } else /* For empty PW3, pass phrase should be OPENPGP_CARD_INITIAL_PW3 */ diff --git a/src/flash.c b/src/flash.c index 193c1a5..b75d1b3 100644 --- a/src/flash.c +++ b/src/flash.c @@ -24,8 +24,9 @@ /* * We assume single DO size is less than 256. * - * NOTE: When we will support "Card holder certificate" - * (which size is larger than 256), it will not be put into DO pool. + * NOTE: When we will support "Card holder certificate" (which size is + * larger than 256), it will not be put into data pool, but will + * be implemented by its own flash page. */ /* @@ -128,15 +129,15 @@ flash_program_halfword (uint32_t addr, uint16_t data) * * 1-KiB align padding * - * 1-KiB DO pool * 3 + * 1-KiB data pool * 3 * * 3-KiB Key store (512-byte (p, q and N) key-store * 6) */ -static const uint8_t *do_pool; +static const uint8_t *data_pool; static const uint8_t *keystore_pool; -static const uint8_t *last_p; +static uint8_t *last_p; static const uint8_t *keystore; const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { @@ -144,7 +145,7 @@ const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { }; /* Linker set this symbol */ -extern uint8_t _do_pool; +extern uint8_t _data_pool; void flash_init (void) @@ -152,7 +153,7 @@ flash_init (void) const uint8_t *p; extern uint8_t _keystore_pool; - do_pool = &_do_pool; + data_pool = &_data_pool; keystore_pool = &_keystore_pool; /* Seek empty keystore */ @@ -166,48 +167,74 @@ flash_init (void) } /* - * DO pool managenent + * Flash data pool managenent * - * DO pool consists of two part: + * Flash data pool consists of two parts: * 2-byte header * contents * - * Format of a DO pool content: + * Flash data pool objects: + * Data Object (DO) (of smart card) + * Internal objects: + * NONE (0x0000) + * 123-counter + * 14-bit counter + * bool object + * + * Format of a Data Object: * NR: 8-bit tag_number * LEN: 8-bit length * DATA: data * LEN * PAD: optional byte for 16-bit alignment */ -#define FLASH_DO_POOL_HEADER_SIZE 2 -#define FLASH_DO_POOL_SIZE 1024*3 -#define FLASH_PAGE_SIZE 1024 +#define FLASH_DATA_POOL_HEADER_SIZE 2 +#define FLASH_DATA_POOL_SIZE (1024*3) +#define FLASH_PAGE_SIZE 1024 const uint8_t * -flash_do_pool (void) +flash_data_pool (void) { - return do_pool + FLASH_DO_POOL_HEADER_SIZE; + return data_pool + FLASH_DATA_POOL_HEADER_SIZE; } void -flash_set_do_pool_last (const uint8_t *p) +flash_set_data_pool_last (const uint8_t *p) { - last_p = p; + last_p = (uint8_t *)p; +} + +static uint8_t * +flash_data_pool_allocate (size_t size) +{ + uint8_t *p = last_p; + + size = (size + 1) & ~1; /* allocation unit is 1-word (2-byte) */ + + if (last_p + size > data_pool - FLASH_DATA_POOL_HEADER_SIZE + FLASH_PAGE_SIZE) + return NULL; /* gc/erase/.../ */ + + last_p += size; + return p; } const uint8_t * flash_do_write (uint8_t nr, const uint8_t *data, int len) { - const uint8_t *p = last_p; + const uint8_t *p; uint16_t hw; uint32_t addr; int i; - if (last_p - do_pool + len + FLASH_DO_POOL_HEADER_SIZE + 2 > FLASH_PAGE_SIZE) - return NULL; /* gc/erase/.../ */ - DEBUG_INFO ("flash DO\r\n"); - addr = (uint32_t)last_p; + p = flash_data_pool_allocate (2 + len); + if (p == NULL) + { + DEBUG_INFO ("flash data pool allocation failure.\r\n"); + return NULL; + } + + addr = (uint32_t)p; hw = nr | (len << 8); if (flash_program_halfword (addr, hw) != FLASH_COMPLETE) return NULL; @@ -229,8 +256,6 @@ flash_do_write (uint8_t nr, const uint8_t *data, int len) addr += 2; } - last_p = (const uint8_t *)addr; - DEBUG_INFO ("flash DO...done\r\n"); return p + 1; } @@ -253,7 +278,7 @@ flash_do_release (const uint8_t *do_data) int len = do_data[0]; /* Don't filling zero for data in code (such as ds_count_initial_value) */ - if (do_data < &_do_pool || do_data > &_do_pool + FLASH_DO_POOL_SIZE) + if (do_data < &_data_pool || do_data > &_data_pool + FLASH_DATA_POOL_SIZE) return; addr += 2; @@ -327,3 +352,121 @@ flash_clear_halfword (uint32_t addr) flash_program_halfword (addr, 0); } + +void +flash_put_data (uint16_t hw) +{ + uint8_t *p; + + p = flash_data_pool_allocate (2); + if (p == NULL) + { + DEBUG_INFO ("data allocation failure.\r\n"); + } + + flash_program_halfword ((uint32_t)p, hw); +} + + +void +flash_bool_clear (const uint8_t **addr_p) +{ + const uint8_t *p; + + if ((p = *addr_p) == NULL) + return; + + flash_program_halfword ((uint32_t)p, 0); + *addr_p = NULL; +} + +const uint8_t * +flash_bool_write (uint8_t nr) +{ + uint8_t *p; + uint16_t hw = nr; + + p = flash_data_pool_allocate (2); + if (p == NULL) + { + DEBUG_INFO ("bool allocation failure.\r\n"); + return NULL; + } + + flash_program_halfword ((uint32_t)p, hw); + return p; +} + + +int +flash_cnt123_get_value (const uint8_t *p) +{ + if (p == NULL) + return 0; + else + { + uint8_t v = *p; + + /* + * After erase, a word in flash memory becomes 0xffff. + * The word can be programmed to any value. + * Then, the word can be programmed to zero. + * + * Thus, we can represent value 1, 2, and 3. + */ + if (v == 0xff) + return 1; + else if (v == 0x00) + return 3; + else + return 2; + } +} + +void +flash_cnt123_increment (uint8_t which, const uint8_t **addr_p) +{ + const uint8_t *p; + uint16_t hw; + + if ((p = *addr_p) == NULL) + { + p = flash_data_pool_allocate (4); + if (p == NULL) + { + DEBUG_INFO ("cnt123 allocation failure.\r\n"); + return; + } + hw = NR_COUNTER_123 | (which << 8); + flash_program_halfword ((uint32_t)p, hw); + *addr_p = p + 2; + } + else + { + uint8_t v = *p; + + if (v == 0) + return; + + if (v == 0xff) + hw = 0xc3c3; + else + hw = 0; + + flash_program_halfword ((uint32_t)p, hw); + } +} + +void +flash_cnt123_clear (const uint8_t **addr_p) +{ + const uint8_t *p; + + if ((p = *addr_p) == NULL) + return; + + flash_program_halfword ((uint32_t)p, 0); + p -= 2; + flash_program_halfword ((uint32_t)p, 0); + *addr_p = NULL; +} diff --git a/src/gnuk.h b/src/gnuk.h index d021eec..12c20a7 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -51,6 +51,13 @@ extern int res_APDU_size; #define AC_NEVER 0x80 #define AC_ALWAYS 0xFF +#define PW_ERR_PW1 0 +#define PW_ERR_RC 1 +#define PW_ERR_PW3 2 +extern int gpg_passwd_locked (uint8_t which); +extern void gpg_reset_pw_err_counter (uint8_t which); +extern void gpg_increment_pw_err_counter (uint8_t which); + extern int ac_check_status (uint8_t ac_flag); extern int verify_pso_cds (const uint8_t *pw, int pw_len); extern int verify_pso_other (const uint8_t *pw, int pw_len); @@ -63,7 +70,6 @@ extern void ac_reset_pso_other (void); extern void write_res_apdu (const uint8_t *p, int len, uint8_t sw1, uint8_t sw2); - uint16_t data_objects_number_of_bytes; extern int gpg_do_table_init (void); @@ -84,9 +90,11 @@ 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 (const uint8_t *); -extern const uint8_t *flash_do_pool (void); -extern void flash_set_do_pool_last (const uint8_t *p); +extern const uint8_t *flash_data_pool (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); +extern void flash_reset_counter (uint8_t counter_tag_nr); #define KEY_MAGIC_LEN 8 #define KEY_CONTENT_LEN 256 /* p and q */ @@ -165,11 +173,7 @@ extern int gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, in extern const uint8_t *gpg_do_read_simple (uint8_t); extern void gpg_do_write_simple (uint8_t, const uint8_t *, int); -extern void gpg_do_increment_digital_signature_counter (void); - -#define PW_STATUS_PW1 4 -#define PW_STATUS_RC 5 -#define PW_STATUS_PW3 6 +extern void gpg_increment_digital_signature_counter (void); extern void gpg_set_pw3 (const uint8_t *newpw, int newpw_len); @@ -177,30 +181,76 @@ extern void fatal (void) __attribute__ ((noreturn)); extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE]; -#define NR_DO_PRVKEY_SIG 0 -#define NR_DO_PRVKEY_DEC 1 -#define NR_DO_PRVKEY_AUT 2 -#define NR_DO_KEYSTRING_PW1 3 -#define NR_DO_KEYSTRING_RC 4 -#define NR_DO_KEYSTRING_PW3 5 -#define NR_DO_PW_STATUS 6 -#define NR_DO_DS_COUNT 7 -#define NR_DO_SEX 8 -#define NR_DO_FP_SIG 9 -#define NR_DO_FP_DEC 10 -#define NR_DO_FP_AUT 11 -#define NR_DO_CAFP_1 12 -#define NR_DO_CAFP_2 13 -#define NR_DO_CAFP_3 14 -#define NR_DO_KGTIME_SIG 15 -#define NR_DO_KGTIME_DEC 16 -#define NR_DO_KGTIME_AUT 17 -#define NR_DO_LOGIN_DATA 18 -#define NR_DO_URL 19 -#define NR_DO_NAME 20 -#define NR_DO_LANGUAGE 21 -#define NR_DO_CH_CERTIFICATE 22 -#define NR_DO_LAST 23 +/*** Flash memory tag values ***/ +#define NR_NONE 0x00 +/* Data objects */ +/* + * Representation of data object: + * + * <-1 word-> <--len/2 words-> + * <-data content-> + */ +#define NR_DO__FIRST__ 0x01 +#define NR_DO_SEX 0x01 +#define NR_DO_FP_SIG 0x02 +#define NR_DO_FP_DEC 0x03 +#define NR_DO_FP_AUT 0x04 +#define NR_DO_CAFP_1 0x05 +#define NR_DO_CAFP_2 0x06 +#define NR_DO_CAFP_3 0x07 +#define NR_DO_KGTIME_SIG 0x08 +#define NR_DO_KGTIME_DEC 0x09 +#define NR_DO_KGTIME_AUT 0x0a +#define NR_DO_LOGIN_DATA 0x0b +#define NR_DO_URL 0x0c +#define NR_DO_NAME 0x0d +#define NR_DO_LANGUAGE 0x0e +#define NR_DO_PRVKEY_SIG 0x0f +#define NR_DO_PRVKEY_DEC 0x10 +#define NR_DO_PRVKEY_AUT 0x11 +#define NR_DO_KEYSTRING_PW1 0x12 +#define NR_DO_KEYSTRING_RC 0x13 +#define NR_DO_KEYSTRING_PW3 0x14 +#define NR_DO__LAST__ 21 /* == 0x15 */ +/* 14-bit counter for DS: Recorded in flash memory by 1-word (2-byte). */ +/* + * Representation of 14-bit counter: + * 0: 0x8000 + * 1: 0x8001 + * ... + * 16383: 0xbfff + */ +#define NR_COUNTER_DS 0x80 /* ..0xbf */ +/* 10-bit counter for DS: Recorded in flash memory by 1-word (2-byte). */ +/* + * Representation of 10-bit counter: + * 0: 0xc000 + * 1: 0xc001 + * ... + * 1023: 0xc3ff + */ +#define NR_COUNTER_DS_LSB 0xc0 /* ..0xc3 */ +/* 8-bit int or Boolean objects: Recorded in flash memory by 1-word (2-byte) */ +/* + * Representation of Boolean object: + * 0: No record in flash memory + * 1: 0xc?00 + */ +#define NR_BOOL_PW1_LIFETIME 0xf0 +/* + * NR_BOOL_SOMETHING, NR_UINT_SOMETHING could be here... Use 0xf? + */ +/* 123-counters: Recorded in flash memory by 2-word (4-byte). */ +/* + * Representation of 123-counters: + * 0: No record in flash memory + * 1: 0xfe?? 0xffff + * 2: 0xfe?? 0xc3c3 + * 3: 0xfe?? 0x0000 + * where is placed at second byte + */ +#define NR_COUNTER_123 0xfe +#define NR_EMPTY 0xff #define SIZE_PW_STATUS_BYTES 7 @@ -211,8 +261,6 @@ extern void random_bytes_free (const uint8_t *); extern uint32_t hardclock (void); -extern void gpg_do_reset_pw_counter (uint8_t which); - extern void set_led (int); #define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */ @@ -227,4 +275,13 @@ extern uint8_t pw1_keystring[KEYSTRING_SIZE_PW1]; #define OPENPGP_CARD_INITIAL_PW3 "12345678" #endif -const uint8_t openpgpcard_aid[17] __attribute__ ((aligned (1))); +extern const uint8_t openpgpcard_aid[17] __attribute__ ((aligned (1))); + +extern int gpg_get_pw1_lifetime (void); + +extern void flash_bool_clear (const uint8_t **addr_p); +extern const uint8_t *flash_bool_write (uint8_t nr); +extern int flash_cnt123_get_value (const uint8_t *p); +extern void flash_cnt123_increment (uint8_t which, const uint8_t **addr_p); +extern void flash_cnt123_clear (const uint8_t **addr_p); +extern void flash_put_data (uint16_t hw); diff --git a/src/gnuk.ld.in b/src/gnuk.ld.in index f9e989c..c74ce9b 100644 --- a/src/gnuk.ld.in +++ b/src/gnuk.ld.in @@ -122,7 +122,7 @@ SECTIONS .gnuk_flash : ALIGN (1024) { - _do_pool = .; + _data_pool = .; KEEP(*(.gnuk_data)) FILL(0xffffffff); . = ALIGN(1024); diff --git a/src/openpgp-do.c b/src/openpgp-do.c index cfbeaaf..7764632 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -32,6 +32,67 @@ #include "polarssl/aes.h" #include "polarssl/sha1.h" +static uint32_t digital_signature_counter; + +void +gpg_increment_digital_signature_counter (void) +{ + uint16_t hw0, hw1; + + digital_signature_counter++; + digital_signature_counter &= 0x00ffffff; + + if ((digital_signature_counter & 0x03ff) == 0) + { /* carry occurs from l10 to h14 */ + hw0 = NR_COUNTER_DS + | ((digital_signature_counter & 0x00fc0000) >> 18) + | ((digital_signature_counter & 0x0003fc00) >> 2); + hw1 = NR_COUNTER_DS_LSB; + flash_put_data (hw0); + flash_put_data (hw1); + } + else + { + hw1 = NR_COUNTER_DS_LSB + | ((digital_signature_counter & 0x0300) >> 8) + | ((digital_signature_counter & 0x00ff) << 8); + flash_put_data (hw1); + } +} + +#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */ +const uint8_t *pw_err_counter_p[3]; + +static int +gpg_get_pw_err_counter (uint8_t which) +{ + return flash_cnt123_get_value (pw_err_counter_p[which]); +} + +int +gpg_passwd_locked (uint8_t which) +{ + if (gpg_get_pw_err_counter (which) >= PASSWORD_ERRORS_MAX) + return 1; + else + return 0; +} + +void +gpg_reset_pw_err_counter (uint8_t which) +{ + flash_cnt123_clear (&pw_err_counter_p[which]); + if (pw_err_counter_p[which] != NULL) + GPG_MEMORY_FAILURE (); +} + +void +gpg_increment_pw_err_counter (uint8_t which) +{ + flash_cnt123_increment (which, &pw_err_counter_p[which]); +} + + uint16_t data_objects_number_of_bytes; /* @@ -89,21 +150,24 @@ static const uint8_t algorithm_attr[] __attribute__ ((aligned (1))) = { 0x00 /* 0: p&q , 3: CRT with N (not yet supported) */ }; -static const uint8_t do_ds_count_initial_value[] __attribute__ ((aligned (1))) = { - 3, - 0, 0, 0 -}; - -static const uint8_t do_pw_status_bytes_template[] __attribute__ ((aligned (1))) = { - 7, - 0, /* PW1 is valid for single PSO:CDS command */ - 127, 127, 127, /* max length of PW1, RC, and PW3 */ - 3, 0, 3 /* Error counter of PW1, RC, and PW3 */ -}; -#define PW_STATUS_BYTES_TEMPLATE (do_pw_status_bytes_template+1) - -#define SIZE_DIGITAL_SIGNATURE_COUNTER 3 -/* 3-byte binary (big endian) */ +#define PW_LEN_MAX 127 +/* + * Representation of PW1_LIFETIME: + * 0: PW1_LIEFTIME_P == NULL : PW1 is valid for single PSO:CDS command + * 1: PW1_LIEFTIME_P != NULL : PW1 is valid for several PSO:CDS commands + * + * The address in the variable PW1_LIEFTIME_P is used when filling zero + * in flash memory + */ +static const uint8_t *pw1_lifetime_p; +int +gpg_get_pw1_lifetime (void) +{ + if (pw1_lifetime_p == NULL) + return 0; + else + return 1; +} #define SIZE_FINGER_PRINT 20 #define SIZE_KEYGEN_TIME 4 /* RFC4880 */ @@ -130,13 +194,6 @@ static uint8_t *res_p; static void copy_do_1 (uint16_t tag, const uint8_t *do_data, int with_tag); static const struct do_table_entry *get_do_entry (uint16_t tag); -#define GNUK_DO_PRVKEY_SIG 0xff01 -#define GNUK_DO_PRVKEY_DEC 0xff02 -#define GNUK_DO_PRVKEY_AUT 0xff03 -#define GNUK_DO_KEYSTRING_PW1 0xff04 -#define GNUK_DO_KEYSTRING_RC 0xff05 -#define GNUK_DO_KEYSTRING_PW3 0xff06 -#define GNUK_DO_PW_STATUS 0xff07 #define GPG_DO_AID 0x004f #define GPG_DO_NAME 0x005b #define GPG_DO_LOGIN_DATA 0x005e @@ -170,30 +227,13 @@ static const struct do_table_entry *get_do_entry (uint16_t tag); #define GPG_DO_HIST_BYTES 0x5f52 #define GPG_DO_CH_CERTIFICATE 0x7f21 -#define NUM_DO_OBJS 23 -static const uint8_t *do_ptr[NUM_DO_OBJS]; +static const uint8_t *do_ptr[NR_DO__LAST__]; static uint8_t do_tag_to_nr (uint16_t tag) { switch (tag) { - case GNUK_DO_PRVKEY_SIG: - return NR_DO_PRVKEY_SIG; - case GNUK_DO_PRVKEY_DEC: - return NR_DO_PRVKEY_DEC; - case GNUK_DO_PRVKEY_AUT: - return NR_DO_PRVKEY_AUT; - case GNUK_DO_KEYSTRING_PW1: - return NR_DO_KEYSTRING_PW1; - case GNUK_DO_KEYSTRING_RC: - return NR_DO_KEYSTRING_RC; - case GNUK_DO_KEYSTRING_PW3: - return NR_DO_KEYSTRING_PW3; - case GNUK_DO_PW_STATUS: - return NR_DO_PW_STATUS; - case GPG_DO_DS_COUNT: - return NR_DO_DS_COUNT; case GPG_DO_SEX: return NR_DO_SEX; case GPG_DO_FP_SIG: @@ -222,8 +262,6 @@ do_tag_to_nr (uint16_t tag) return NR_DO_NAME; case GPG_DO_LANGUAGE: return NR_DO_LANGUAGE; - case GPG_DO_CH_CERTIFICATE: - return NR_DO_CH_CERTIFICATE; default: fatal (); } @@ -357,51 +395,65 @@ do_kgtime_all (uint16_t tag, int with_tag) return 0; } +static int +do_ds_count (uint16_t tag, int with_tag) +{ + if (with_tag) + { + copy_tag (tag); + *res_p++ = 3; + } + + *res_p++ = (digital_signature_counter >> 16) & 0xff; + *res_p++ = (digital_signature_counter >> 8) & 0xff; + *res_p++ = digital_signature_counter & 0xff; + return 0; +} + static int rw_pw_status (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write) { - const uint8_t *do_data = do_ptr[NR_DO_PW_STATUS]; - if (is_write) { - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; + (void)len; /* Should be SIZE_PW_STATUS_BYTES */ - (void)len; - if (do_data) + /* Only the first byte of DATA is checked */ + if (data[0] == 0) { - memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES); - flash_do_release (do_data); + flash_bool_clear (&pw1_lifetime_p); + if (pw1_lifetime_p == NULL) + GPG_SUCCESS (); + else + GPG_MEMORY_FAILURE(); } else - memcpy (pwsb, PW_STATUS_BYTES_TEMPLATE, SIZE_PW_STATUS_BYTES); - - pwsb[0] = data[0]; - do_ptr[NR_DO_PW_STATUS] - = flash_do_write (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - if (do_ptr[NR_DO_PW_STATUS]) - GPG_SUCCESS (); - else - GPG_MEMORY_FAILURE(); + { + pw1_lifetime_p = flash_bool_write (NR_BOOL_PW1_LIFETIME); + if (pw1_lifetime_p != NULL) + GPG_SUCCESS (); + else + GPG_MEMORY_FAILURE(); + } return 0; } else { - if (do_data) + if (with_tag) { - if (with_tag) - { - copy_tag (tag); - *res_p++ = SIZE_PW_STATUS_BYTES; - } - - memcpy (res_p, &do_data[1], SIZE_PW_STATUS_BYTES); - res_p += SIZE_PW_STATUS_BYTES; - return 1; + copy_tag (tag); + *res_p++ = SIZE_PW_STATUS_BYTES; } - else - return 0; + + *res_p++ = gpg_get_pw1_lifetime (); + *res_p++ = PW_LEN_MAX; + *res_p++ = PW_LEN_MAX; + *res_p++ = PW_LEN_MAX; + *res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_PW1); + *res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_RC); + *res_p++ = PASSWORD_ERRORS_MAX - gpg_get_pw_err_counter (PW_ERR_PW3); + return 1; } } @@ -446,8 +498,7 @@ proc_resetting_code (const uint8_t *data, int len) GPG_SUCCESS (); } - /* Reset RC counter in GNUK_DO_PW_STATUS */ - gpg_do_reset_pw_counter (PW_STATUS_RC); + gpg_reset_pw_err_counter (PW_ERR_RC); } static void @@ -508,7 +559,7 @@ int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring) { uint8_t nr = get_do_ptr_nr_for_kk (kk); - const uint8_t *do_data = do_ptr[nr]; + const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; uint8_t *key_addr; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; @@ -557,7 +608,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, struct prvkey_data *pd; uint8_t *key_addr; const uint8_t *dek; - const uint8_t *do_data = do_ptr[nr]; + const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; const uint8_t *ks_pw1; const uint8_t *ks_rc; @@ -659,7 +710,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, encrypt (keystring, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE); p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); - do_ptr[nr] = p; + do_ptr[nr - NR_DO__FIRST__] = p; if (do_data == NULL) random_bytes_free (dek); @@ -693,7 +744,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk, int who_new, const uint8_t *new_ks) { uint8_t nr = get_do_ptr_nr_for_kk (kk); - const uint8_t *do_data = do_ptr[nr]; + const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; uint8_t dek[DATA_ENCRYPTION_KEY_SIZE]; struct prvkey_data *pd; const uint8_t *p; @@ -715,7 +766,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk, memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE); p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); - do_ptr[nr] = p; + do_ptr[nr - NR_DO__FIRST__] = p; flash_do_release (do_data); free (pd); @@ -752,7 +803,7 @@ proc_key_import (const uint8_t *data, int len) if (len <= 22) { /* Deletion of the key */ uint8_t nr = get_do_ptr_nr_for_kk (kk); - const uint8_t *do_data = do_ptr[nr]; + const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__]; /* Delete the key */ if (do_data) @@ -762,7 +813,7 @@ proc_key_import (const uint8_t *data, int len) flash_key_release (key_addr); flash_do_release (do_data); } - do_ptr[nr] = NULL; + do_ptr[nr - NR_DO__FIRST__] = NULL; if (--num_prv_keys == 0) { @@ -779,7 +830,7 @@ proc_key_import (const uint8_t *data, int len) /* Skip E, 4-byte */ r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_md_pw3); if (r < 0) - GPG_MEMORY_FAILURE(); + GPG_MEMORY_FAILURE (); else GPG_SUCCESS (); } @@ -806,38 +857,29 @@ static const uint16_t const cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT }; static const struct do_table_entry gpg_do_table[] = { - /* Pseudo DO (private): not directly user accessible */ - { GNUK_DO_PRVKEY_SIG, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[0] }, - { GNUK_DO_PRVKEY_DEC, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[1] }, - { GNUK_DO_PRVKEY_AUT, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[2] }, - { GNUK_DO_KEYSTRING_PW1, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[3] }, - { GNUK_DO_KEYSTRING_RC, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[4] }, - { GNUK_DO_KEYSTRING_PW3, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[5] }, - { GNUK_DO_PW_STATUS, DO_VAR, AC_NEVER, AC_NEVER, &do_ptr[6] }, - /* Variable(s): Fixed size, not changeable by user */ - { GPG_DO_DS_COUNT, DO_VAR, AC_ALWAYS, AC_NEVER, &do_ptr[7] }, /* Variables: Fixed size */ - { GPG_DO_SEX, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[8] }, - { GPG_DO_FP_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[9] }, - { GPG_DO_FP_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[10] }, - { GPG_DO_FP_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[11] }, - { GPG_DO_CAFP_1, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] }, - { GPG_DO_CAFP_2, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] }, - { GPG_DO_CAFP_3, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[14] }, - { GPG_DO_KGTIME_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[15] }, - { GPG_DO_KGTIME_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[16] }, - { GPG_DO_KGTIME_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[17] }, + { GPG_DO_SEX, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[0] }, + { GPG_DO_FP_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[1] }, + { GPG_DO_FP_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[2] }, + { GPG_DO_FP_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[3] }, + { GPG_DO_CAFP_1, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[4] }, + { GPG_DO_CAFP_2, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[5] }, + { GPG_DO_CAFP_3, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[6] }, + { GPG_DO_KGTIME_SIG, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[7] }, + { GPG_DO_KGTIME_DEC, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[8] }, + { GPG_DO_KGTIME_AUT, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[9] }, /* Variables: Variable size */ - { GPG_DO_LOGIN_DATA, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[18] }, - { GPG_DO_URL, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[19] }, - { GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[20] }, - { GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[21] }, - { GPG_DO_CH_CERTIFICATE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[22] }, + { GPG_DO_LOGIN_DATA, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[10] }, + { GPG_DO_URL, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[11] }, + { GPG_DO_NAME, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[12] }, + { GPG_DO_LANGUAGE, DO_VAR, AC_ALWAYS, AC_ADMIN_AUTHORIZED, &do_ptr[13] }, /* Pseudo DO READ: calculated */ { GPG_DO_HIST_BYTES, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_hist_bytes }, { GPG_DO_FP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_fp_all }, { GPG_DO_CAFP_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_cafp_all }, { GPG_DO_KGTIME_ALL, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_kgtime_all }, + /* Pseudo DO READ: calculated, not changeable by user */ + { GPG_DO_DS_COUNT, DO_PROC_READ, AC_ALWAYS, AC_NEVER, do_ds_count }, /* Pseudo DO READ/WRITE: calculated */ { GPG_DO_PW_STATUS, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_pw_status }, @@ -854,60 +896,116 @@ gpg_do_table[] = { /* Simple data: write access only */ { GPG_DO_RESETTING_CODE, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED, proc_resetting_code }, - /* Compound data: Write access only*/ + /* Compound data: Write access only */ { GPG_DO_KEY_IMPORT, DO_PROC_WRITE, AC_NEVER, AC_ADMIN_AUTHORIZED, proc_key_import }, + /* Card holder certificate: Not supported yet */ + { GPG_DO_CH_CERTIFICATE, DO_PROC_READWRITE, AC_NEVER, AC_NEVER, NULL }, }; #define NUM_DO_ENTRIES (int)(sizeof (gpg_do_table) / sizeof (struct do_table_entry)) /* - * Initialize DO_PTR reading from Flash ROM + * Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc. */ int gpg_do_table_init (void) { const uint8_t *p, *p_start; int i; + const uint8_t *dsc_h14_p, *dsc_l10_p; + int dsc_h14, dsc_l10; - do_ptr[NR_DO_DS_COUNT] = do_ds_count_initial_value; - do_ptr[NR_DO_PW_STATUS] = do_pw_status_bytes_template; - p_start = flash_do_pool (); + p_start = flash_data_pool (); - /* Traverse DO pool */ + dsc_h14_p = dsc_l10_p = NULL; + 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; + + /* Traverse DO and counters in DO pool */ p = p_start; - while (*p != 0xff) + while (*p != NR_EMPTY) { uint8_t nr = *p++; - uint8_t len = *p; + uint8_t second_byte = *p; - if (len == 0x00) - p++; + if (nr == 0x00 && second_byte == 0x00) + p++; /* Skip released word */ else { - do_ptr[nr] = p; - p += len + 1; + if (nr < 0x80) + { + /* It's Data Object */ + do_ptr[nr - NR_DO__FIRST__] = p; + p += second_byte + 1; - if (((uint32_t)p & 1)) - p++; + if (((uint32_t)p & 1)) + p++; + } + else if (nr >= 0x80 && nr <= 0xbf) + /* Encoded data of Digital Signature Counter: upper 14-bit */ + { + dsc_h14_p = p - 1; + p++; + } + else if (nr >= 0xc0 && nr <= 0xc3) + /* Encoded data of Digital Signature Counter: lower 10-bit */ + { + dsc_l10_p = p - 1; + p++; + } + else + switch (nr) + { + case NR_BOOL_PW1_LIFETIME: + pw1_lifetime_p = p - 1; + p++; + continue; + case NR_COUNTER_123: + if (second_byte <= PW_ERR_PW3) + pw_err_counter_p[second_byte] = ++p; + p += 2; + break; + } } } - flash_set_do_pool_last (p); + flash_set_data_pool_last (p); num_prv_keys = 0; - if (do_ptr[NR_DO_PRVKEY_SIG] != NULL) + if (do_ptr[NR_DO_PRVKEY_SIG - NR_DO__FIRST__] != NULL) num_prv_keys++; - if (do_ptr[NR_DO_PRVKEY_DEC] != NULL) + if (do_ptr[NR_DO_PRVKEY_DEC - NR_DO__FIRST__] != NULL) num_prv_keys++; - if (do_ptr[NR_DO_PRVKEY_AUT] != NULL) + if (do_ptr[NR_DO_PRVKEY_AUT - NR_DO__FIRST__] != NULL) num_prv_keys++; data_objects_number_of_bytes = 0; - for (i = 0; i < NR_DO_LAST; i++) - if (do_ptr[i] != NULL) - data_objects_number_of_bytes += *do_ptr[i]; + for (i = NR_DO__FIRST__; i < NR_DO__LAST__; i++) + if (do_ptr[i - NR_DO__FIRST__] != NULL) + data_objects_number_of_bytes += *do_ptr[i - NR_DO__FIRST__]; + + if (dsc_l10_p == NULL) + dsc_l10 = 0; + else + dsc_l10 = ((*dsc_l10_p - 0xc0) << 8) | *(dsc_l10_p + 1); + + if (dsc_h14_p == NULL) + dsc_h14 = 0; + else + { + dsc_h14 = ((*dsc_h14_p - 0x80) << 8) | *(dsc_h14_p + 1); + if (dsc_l10_p == NULL) + DEBUG_INFO ("something wrong in DSC\r\n"); /* weird??? */ + else if (dsc_l10_p < dsc_h14_p) + /* Possibly, power off during writing dsc_l10 */ + dsc_l10 = 0; + } + + digital_signature_counter = (dsc_h14 << 10) | dsc_l10; return 0; } @@ -1086,7 +1184,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) /* make DO empty */ *do_data_p = NULL; else if (len > 255) - GPG_MEMORY_FAILURE(); + GPG_MEMORY_FAILURE (); else { uint8_t nr = do_tag_to_nr (tag); @@ -1095,7 +1193,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) if (*do_data_p) GPG_SUCCESS (); else - GPG_MEMORY_FAILURE(); + GPG_MEMORY_FAILURE (); } break; } @@ -1131,11 +1229,11 @@ gpg_do_public_key (uint8_t kk_byte) DEBUG_BYTE (kk_byte); if (kk_byte == 0xb6) - do_data = do_ptr[NR_DO_PRVKEY_SIG]; + do_data = do_ptr[NR_DO_PRVKEY_SIG - NR_DO__FIRST__]; else if (kk_byte == 0xb8) - do_data = do_ptr[NR_DO_PRVKEY_DEC]; + do_data = do_ptr[NR_DO_PRVKEY_DEC - NR_DO__FIRST__]; else /* 0xa4 */ - do_data = do_ptr[NR_DO_PRVKEY_AUT]; + do_data = do_ptr[NR_DO_PRVKEY_AUT - NR_DO__FIRST__]; if (do_data == NULL) { @@ -1180,7 +1278,7 @@ gpg_do_read_simple (uint8_t nr) { const uint8_t *do_data; - do_data = do_ptr[nr]; + do_data = do_ptr[nr - NR_DO__FIRST__]; if (do_data == NULL) return NULL; @@ -1192,7 +1290,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) { const uint8_t **do_data_p; - do_data_p = (const uint8_t **)&do_ptr[nr]; + do_data_p = (const uint8_t **)&do_ptr[nr - NR_DO__FIRST__]; if (*do_data_p) flash_do_release (*do_data_p); @@ -1202,7 +1300,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) if (*do_data_p) GPG_SUCCESS (); else - GPG_MEMORY_FAILURE(); + GPG_MEMORY_FAILURE (); } else { @@ -1210,55 +1308,3 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) GPG_SUCCESS (); } } - -void -gpg_do_increment_digital_signature_counter (void) -{ - const uint8_t *do_data; - uint32_t count; - uint8_t count_data[SIZE_DIGITAL_SIGNATURE_COUNTER]; - - do_data = do_ptr[NR_DO_DS_COUNT]; - if (do_data == NULL) /* No object means count 0 */ - count = 0; - else - count = (do_data[1]<<16) | (do_data[2]<<8) | do_data[3]; - - count++; - count_data[0] = (count >> 16) & 0xff; - count_data[1] = (count >> 8) & 0xff; - count_data[2] = count & 0xff; - - if (do_data) - flash_do_release (do_data); - do_ptr[NR_DO_DS_COUNT] = flash_do_write (NR_DO_DS_COUNT, count_data, - SIZE_DIGITAL_SIGNATURE_COUNTER); -} - -void -gpg_do_reset_pw_counter (uint8_t which) -{ - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; - const uint8_t *do_data = do_ptr[NR_DO_PW_STATUS]; - - /* Reset PW1/RC/PW3 counter in GNUK_DO_PW_STATUS */ - if (do_data) - { - memcpy (pwsb, &do_data[1], SIZE_PW_STATUS_BYTES); - if (pwsb[which] == 3) - return; - - pwsb[which] = 3; - flash_do_release (do_data); - } - else - { - memcpy (pwsb, PW_STATUS_BYTES_TEMPLATE, SIZE_PW_STATUS_BYTES); - if (pwsb[which] == 3) - return; - - pwsb[which] = 3; - } - - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); -} diff --git a/src/openpgp.c b/src/openpgp.c index 98ba617..a04af86 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -246,20 +246,20 @@ cmd_change_password (void) { gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); + gpg_reset_pw_err_counter (PW_ERR_PW1); DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n"); } else if (r > 0 && who == BY_USER) { gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); + gpg_reset_pw_err_counter (PW_ERR_PW1); DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n"); } else /* r >= 0 && who == BY_ADMIN */ { DEBUG_INFO ("done.\r\n"); - gpg_do_reset_pw_counter (PW_STATUS_PW3); + gpg_reset_pw_err_counter (PW_ERR_PW3); GPG_SUCCESS (); } } @@ -287,12 +287,10 @@ cmd_reset_user_password (void) if (p1 == 0x00) /* by User with Reseting Code */ { - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC); uint8_t old_ks[KEYSTRING_MD_SIZE]; - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW1] == 0) /* locked */ + if (gpg_passwd_locked (PW_ERR_RC)) { DEBUG_INFO ("blocked.\r\n"); GPG_SECURITY_AUTH_BLOCKED (); @@ -320,29 +318,27 @@ cmd_reset_user_password (void) } else if (r < 0) { - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; - sec_fail: DEBUG_INFO ("failed.\r\n"); - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); - pwsb[PW_STATUS_RC]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_RC); GPG_SECURITY_FAILURE (); } else if (r == 0) { if (memcmp (ks_rc+1, old_ks, KEYSTRING_MD_SIZE) != 0) goto sec_fail; + DEBUG_INFO ("done (no prvkey).\r\n"); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); - DEBUG_INFO ("done (no prvkey).\r\n"); + gpg_reset_pw_err_counter (PW_ERR_RC); + gpg_reset_pw_err_counter (PW_ERR_PW1); } else { DEBUG_INFO ("done.\r\n"); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); + gpg_reset_pw_err_counter (PW_ERR_RC); + gpg_reset_pw_err_counter (PW_ERR_PW1); GPG_SUCCESS (); } } @@ -377,13 +373,13 @@ cmd_reset_user_password (void) DEBUG_INFO ("done (no privkey).\r\n"); gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); + gpg_reset_pw_err_counter (PW_ERR_PW1); } else { DEBUG_INFO ("done.\r\n"); ac_reset_pso_cds (); - gpg_do_reset_pw_counter (PW_STATUS_PW1); + gpg_reset_pw_err_counter (PW_ERR_PW1); GPG_SUCCESS (); } } @@ -567,24 +563,18 @@ cmd_pso (void) } else { /* Success */ - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - - if (pw_status_bytes[0] == 0) + if (gpg_get_pw1_lifetime ()) ac_reset_pso_cds (); - gpg_do_increment_digital_signature_counter (); + gpg_increment_digital_signature_counter (); } } } else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86) { - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; - DEBUG_SHORT (len); - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */ + if (gpg_passwd_locked (PW_ERR_PW1) || !ac_check_status (AC_PSO_OTHER_AUTHORIZED)) { DEBUG_INFO ("security error."); @@ -592,20 +582,16 @@ cmd_pso (void) return; } - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, pw1_keystring + 1)) < 0) { - pwsb[PW_STATUS_PW1]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_PW1); GPG_SECURITY_FAILURE (); return; } - else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */ - { /* Reset counter as it's success now */ - pwsb[PW_STATUS_PW1] = 3; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - } + else + /* Reset counter as it's success now */ + gpg_reset_pw_err_counter (PW_ERR_PW1); ac_reset_pso_other (); @@ -634,8 +620,6 @@ cmd_internal_authenticate (void) int len = cmd_APDU[4]; int data_start = 5; int r; - const uint8_t *pw_status_bytes = gpg_do_read_simple (NR_DO_PW_STATUS); - uint8_t pwsb[SIZE_PW_STATUS_BYTES]; if (len == 0) { @@ -649,8 +633,7 @@ cmd_internal_authenticate (void) { DEBUG_SHORT (len); - if (pw_status_bytes == NULL - || pw_status_bytes[PW_STATUS_PW1] == 0 /* locked */ + if (gpg_passwd_locked (PW_ERR_PW1) || !ac_check_status (AC_PSO_OTHER_AUTHORIZED)) { DEBUG_INFO ("security error."); @@ -658,20 +641,16 @@ cmd_internal_authenticate (void) return; } - memcpy (pwsb, pw_status_bytes, SIZE_PW_STATUS_BYTES); if ((r = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, pw1_keystring + 1)) < 0) { - pwsb[PW_STATUS_PW1]--; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); + gpg_increment_pw_err_counter (PW_ERR_PW1); GPG_SECURITY_FAILURE (); return; } - else if (pwsb[PW_STATUS_PW1] != 3) /* Failure in the past? */ - { /* Reset counter as it's success now */ - pwsb[PW_STATUS_PW1] = 3; - gpg_do_write_simple (NR_DO_PW_STATUS, pwsb, SIZE_PW_STATUS_BYTES); - } + else + /* Reset counter as it's success now */ + gpg_reset_pw_err_counter (PW_ERR_PW1); ac_reset_pso_other ();