flash private key handling.
authorNIIBE Yutaka <gniibe@fsij.org>
Mon, 31 Mar 2014 05:46:16 +0000 (14:46 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Mon, 31 Mar 2014 06:23:37 +0000 (15:23 +0900)
ChangeLog
src/flash.c
src/gnuk.h
src/openpgp-do.c
src/openpgp.c

index 0da0baf..cc9412f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2014-03-31  Niibe Yutaka  <gniibe@fsij.org>
+
+       * 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  <gniibe@fsij.org>
 
        * src/ecc-edwards.c (point_double, point_add): Rename.
index efcb4c9..8d43dad 100644 (file)
@@ -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;
 }
 
index 1e293c0..3f94037 100644 (file)
@@ -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
    */
index 2e23284..e415140 100644 (file)
 #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);
     }
index db6c8fe..2b8ca5d 100644 (file)
@@ -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