diff --git a/ChangeLog b/ChangeLog index 0da0baf..cc9412f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2014-03-31 Niibe Yutaka + + * src/openpgp-do.c (gpg_do_load_prvkey, gpg_do_delete_prvkey) + (gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Follow + the change of PRVKEY_DATA and KEY_DATA. + + * src/flash.c (key_available_at): New. + (flash_init): Initilize KD. + + * src/gnuk.h (struct prvkey_data): Remove member KEY_ADDR. + (struct key_data): Addd member KEY_ADDR. + + * src/openpgp-do.c (gpg_do_keygen): Bug fix. Reset the signature + counter when new key is generated. + + * src/flash.c (flash_key_alloc): Change API, supply KK. + 2014-03-29 Niibe Yutaka * src/ecc-edwards.c (point_double, point_add): Rename. diff --git a/src/flash.c b/src/flash.c index efcb4c9..8d43dad 100644 --- a/src/flash.c +++ b/src/flash.c @@ -63,7 +63,6 @@ #define FLASH_DATA_POOL_HEADER_SIZE 2 #define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2) -#define FLASH_KEYSTORE_SIZE (FLASH_PAGE_SIZE*3) static const uint8_t *data_pool; extern uint8_t _keystore_pool; @@ -78,12 +77,36 @@ const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = { /* Linker set this symbol */ extern uint8_t _data_pool; +static int key_available_at (uint8_t *k) +{ + int i; + uint8_t *p; + + p = k; + for (i = 0; i < KEY_SIZE; i++) + if (*p) + break; + if (p == k + KEY_SIZE) /* It's ZERO. Released key. */ + return 0; + + p = k; + for (i = 0; i < KEY_SIZE; i++) + if (*p != 0xff) + break; + if (p == k + KEY_SIZE) /* It's FULL. Unused key. */ + return 0; + + return 1; +} + const uint8_t * flash_init (void) { uint16_t gen0, gen1; uint16_t *gen0_p = (uint16_t *)&_data_pool; uint16_t *gen1_p = (uint16_t *)(&_data_pool + FLASH_PAGE_SIZE); + uint8_t *p; + int i; /* Check data pool generation and choose the page */ gen0 = *gen0_p; @@ -97,6 +120,23 @@ flash_init (void) else data_pool = &_data_pool; + /* For each key, find its address. */ + p = &_keystore_pool; + for (i = 0; i < 3; i++) + { + uint8_t *k; + + kd[i].key_addr = NULL; + for (k = p; k < k + FLASH_PAGE_SIZE; k += KEY_SIZE) + if (key_available_at (k)) + { + kd[i].key_addr = k; + break; + } + + p += FLASH_PAGE_SIZE; + } + return data_pool + FLASH_DATA_POOL_HEADER_SIZE; } @@ -270,14 +310,16 @@ flash_do_release (const uint8_t *do_data) uint8_t * -flash_key_alloc (void) +flash_key_alloc (enum kind_of_key kk) { - uint8_t *k; + uint8_t *k0, *k; int i; - /* Seek empty keystore. */ - k = &_keystore_pool; - while (k < &_keystore_pool + FLASH_KEYSTORE_SIZE) + /* There is a page for each KK. */ + k0 = &_keystore_pool + (FLASH_PAGE_SIZE * kk); + + /* Seek free space in the page. */ + for (k = k0; k < k0 + FLASH_PAGE_SIZE; k += KEY_SIZE) { const uint32_t *p = (const uint32_t *)k; @@ -287,11 +329,10 @@ flash_key_alloc (void) 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. */ + /* Should not happen as we have enough free space all time, but just + in case. */ return NULL; } diff --git a/src/gnuk.h b/src/gnuk.h index 1e293c0..3f94037 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -120,7 +120,7 @@ enum kind_of_key { 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 uint8_t *flash_key_alloc (enum kind_of_key); 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); @@ -148,9 +148,9 @@ extern uint8_t random_bits_start; #define INITIAL_VECTOR_SIZE 16 #define DATA_ENCRYPTION_KEY_SIZE 16 -/* encrypted data content */ struct key_data { - uint8_t data[KEY_CONTENT_LEN]; /* p and q */ + uint8_t *key_addr; /* Pointer to encrypted data, and public */ + uint8_t data[KEY_CONTENT_LEN]; /* decrypted data content */ }; struct key_data_internal { @@ -159,7 +159,6 @@ struct key_data_internal { }; struct prvkey_data { - const uint8_t *key_addr; /* * IV: Initial Vector */ diff --git a/src/openpgp-do.c b/src/openpgp-do.c index 2e23284..e415140 100644 --- a/src/openpgp-do.c +++ b/src/openpgp-do.c @@ -35,15 +35,6 @@ #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]; @@ -624,7 +615,7 @@ encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data); } -/* Signing, Decryption, and Authentication */ +/* For three keys: Signing, Decryption, and Authentication */ struct key_data kd[3]; static void @@ -679,7 +670,7 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk) void gpg_do_clear_prvkey (enum kind_of_key kk) { - memset ((void *)&kd[kk], 0, sizeof (struct key_data)); + memset (kd[kk].data, 0, KEY_CONTENT_LEN); } @@ -722,12 +713,12 @@ 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 *)fetch_four_bytes (&do_data[1]); + key_addr = kd[kk].key_addr; memcpy (kdi.data, key_addr, KEY_CONTENT_LEN); - iv = do_data+5; + iv = &do_data[1]; memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE); - memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE); + memcpy (dek, iv+16*(who+1), DATA_ENCRYPTION_KEY_SIZE); decrypt_dek (keystring, dek); decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal)); @@ -739,7 +730,7 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring) } memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN); - DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN); + DEBUG_BINARY (kd[kk].data, KEY_CONTENT_LEN); return 1; } @@ -756,10 +747,11 @@ gpg_do_delete_prvkey (enum kind_of_key kk) 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); + key_addr = kd[kk].key_addr; + kd[kk].key_addr = NULL; + flash_key_release (key_addr); if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING) { /* Recover admin keystring DO. */ @@ -869,7 +861,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, } DEBUG_INFO ("Getting keystore address...\r\n"); - key_addr = flash_key_alloc (); + key_addr = flash_key_alloc (kk); if (key_addr == NULL) { if (pubkey_allocated_here) @@ -880,6 +872,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, free (pd); return -1; } + kd[kk].key_addr = key_addr; num_prv_keys++; @@ -950,7 +943,6 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len, return r; } - pd->key_addr = key_addr; memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE); memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE); @@ -1014,7 +1006,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk, memcpy (pd, &do_data[1], sizeof (struct prvkey_data)); - dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE + dek_p = ((uint8_t *)pd) + INITIAL_VECTOR_SIZE + DATA_ENCRYPTION_KEY_SIZE * who_old; memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE); if (who_new == 0) /* Remove */ @@ -1056,6 +1048,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk, return 1; } + +static enum kind_of_key +kkb_to_kk (uint8_t kk_byte) +{ + enum kind_of_key kk; + + if (kk_byte == 0xb6) + kk = GPG_KEY_FOR_SIGNING; + else if (kk_byte == 0xb8) + kk = GPG_KEY_FOR_DECRYPTION; + else /* 0xa4 */ + kk = GPG_KEY_FOR_AUTHENTICATION; + return kk; +} + /* * RSA: * 4d, xx, xx, xx: Extended Header List @@ -1101,20 +1108,15 @@ proc_key_import (const uint8_t *data, int len) else p += 1; - if (*p == 0xb6) + kk = kkb_to_kk (*p); + if (kk == GPG_KEY_FOR_SIGNING) { - kk = GPG_KEY_FOR_SIGNING; ac_reset_pso_cds (); gpg_reset_digital_signature_counter (); } else - { - if (*p == 0xb8) - kk = GPG_KEY_FOR_DECRYPTION; - else /* 0xa4 */ - kk = GPG_KEY_FOR_AUTHENTICATION; - ac_reset_other (); - } + ac_reset_other (); + #if defined(RSA_AUTH) && defined(RSA_SIG) if (len <= 22) @@ -1647,28 +1649,21 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) void gpg_do_public_key (uint8_t kk_byte) { - const uint8_t *do_data; const uint8_t *key_addr; + enum kind_of_key kk; DEBUG_INFO ("Public key\r\n"); DEBUG_BYTE (kk_byte); - if (kk_byte == 0xb6) - do_data = do_ptr[NR_DO_PRVKEY_SIG - NR_DO__FIRST__]; - else if (kk_byte == 0xb8) - do_data = do_ptr[NR_DO_PRVKEY_DEC - NR_DO__FIRST__]; - else /* 0xa4 */ - do_data = do_ptr[NR_DO_PRVKEY_AUT - NR_DO__FIRST__]; - - if (do_data == NULL) + kk = kkb_to_kk (kk_byte); + key_addr = kd[kk].key_addr; + if (key_addr == NULL) { DEBUG_INFO ("none.\r\n"); GPG_NO_RECORD (); return; } - key_addr = (const uint8_t *)fetch_four_bytes (&do_data[1]); - res_p = res_APDU; /* TAG */ @@ -1771,13 +1766,7 @@ gpg_do_keygen (uint8_t kk_byte) DEBUG_INFO ("Keygen\r\n"); DEBUG_BYTE (kk_byte); - if (kk_byte == 0xb6) - kk = GPG_KEY_FOR_SIGNING; - else if (kk_byte == 0xb8) - kk = GPG_KEY_FOR_DECRYPTION; - else /* 0xa4 */ - kk = GPG_KEY_FOR_AUTHENTICATION; - + kk = kkb_to_kk (kk_byte); if (admin_authorized == BY_ADMIN) keystring_admin = keystring_md_pw3; else @@ -1812,6 +1801,7 @@ gpg_do_keygen (uint8_t kk_byte) /* GnuPG expects it's ready for signing. */ /* Don't call ac_reset_pso_cds here, but load the private key */ + gpg_reset_digital_signature_counter (); s2k (NULL, 0, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring); gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring); } diff --git a/src/openpgp.c b/src/openpgp.c index db6c8fe..2b8ca5d 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -843,7 +843,7 @@ cmd_pso (void) else { DEBUG_SHORT (len); - DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN); + DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, KEY_CONTENT_LEN); r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len, &kd[GPG_KEY_FOR_SIGNING]); @@ -884,7 +884,7 @@ cmd_pso (void) else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86) { DEBUG_SHORT (len); - DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN); + DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, KEY_CONTENT_LEN); if (!ac_check_status (AC_OTHER_AUTHORIZED)) { @@ -918,7 +918,7 @@ cmd_pso (void) } -#ifdef RSA_AUTH +#if defined(RSA_AUTH) #define MAX_DIGEST_INFO_LEN 102 /* 40% */ static void cmd_internal_authenticate (void) @@ -962,7 +962,7 @@ cmd_internal_authenticate (void) DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n"); } -#else +#elif defined(ECDSA_AUTH) static void cmd_internal_authenticate (void) { @@ -1006,6 +1006,52 @@ cmd_internal_authenticate (void) DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n"); } +#elif defined(EDDSA_AUTH) +static void +cmd_internal_authenticate (void) +{ + int len = apdu.cmd_apdu_data_len; + int r; + + DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n"); + + if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00) + { + DEBUG_SHORT (len); + + if (!ac_check_status (AC_OTHER_AUTHORIZED)) + { + DEBUG_INFO ("security error."); + GPG_SECURITY_FAILURE (); + return; + } + + if (len > EDDSA_HASH_LEN_MAX) + { + DEBUG_INFO ("wrong hash length."); + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + res_APDU_size = EDDSA_SIGNATURE_LENGTH; + r = eddsa_sign_25519 (apdu.cmd_apdu_data, res_APDU, + &kd[GPG_KEY_FOR_AUTHENTICATION]); + if (r < 0) + GPG_ERROR (); + } + else + { + DEBUG_INFO (" - ??"); + DEBUG_BYTE (P1 (apdu)); + DEBUG_INFO (" - ??"); + DEBUG_BYTE (P2 (apdu)); + GPG_ERROR (); + } + + DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n"); +} +#else +#error "Authentication not defined." #endif #define MBD_OPRATION_WRITE 0