firmware update keys handling
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 31 May 2012 02:58:14 +0000 (11:58 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 31 May 2012 02:58:14 +0000 (11:58 +0900)
ChangeLog
src/flash.c
src/gnuk.h
src/gnuk.ld.in
src/openpgp.c
src/openpgp.h

index c4115d7..5f9d7fd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2012-05-31  Niibe Yutaka  <gniibe@fsij.org>
 
+       Support "firmware update" keys.
+       * src/flash.c (flash_write_binary): Support update keys.
+       * src/gnuk.h (FILEID_UPDATE_KEY_0, FILEID_UPDATE_KEY_1)
+       (FILEID_UPDATE_KEY_2,FILEID_UPDATE_KEY_3): New.
+       * src/gnuk.ld.in (_updatekey_store): New.
+       * src/openpgp.c (FILE_EF_UPDATE_KEY_0, FILE_EF_UPDATE_KEY_1)
+       (FILE_EF_UPDATE_KEY_2, FILE_EF_UPDATE_KEY_3): New.
+       (gpg_get_firmware_update_key): New.
+       (cmd_read_binary): Support update keys and certificate.
+       (modify_binary): New.
+       (cmd_update_binary, cmd_write_binary): Use modify_binary.
+       (cmd_external_authenticate): Support up to four keys.
+
        Version string of system service is now USB string.
        * src/sys.h (unique_device_id): Define here, not as system
        service.
index 78ebdb1..b12fcfb 100644 (file)
@@ -511,6 +511,11 @@ flash_write_binary (uint8_t file_id, const uint8_t *data,
       maxsize = 6;
       p = &openpgpcard_aid[8];
     }
+  else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
+    {
+      maxsize = KEY_CONTENT_LEN;
+      p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
+    }
 #if defined(CERTDO_SUPPORT)
   else if (file_id == FILEID_CH_CERTIFICATE)
     {
index 7e55465..ebf9aae 100644 (file)
@@ -141,7 +141,11 @@ extern void flash_increment_counter (uint8_t counter_tag_nr);
 extern void flash_reset_counter (uint8_t counter_tag_nr);
 
 #define FILEID_SERIAL_NO       0
-#define FILEID_CH_CERTIFICATE  1
+#define FILEID_UPDATE_KEY_0    1
+#define FILEID_UPDATE_KEY_1    2
+#define FILEID_UPDATE_KEY_2    3
+#define FILEID_UPDATE_KEY_3    4
+#define FILEID_CH_CERTIFICATE  5
 extern int flash_erase_binary (uint8_t file_id);
 extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t len, uint16_t offset);
 
index e87bf1e..1ab53e7 100644 (file)
@@ -159,6 +159,9 @@ SECTIONS
        _keystore_pool = .;
        . += 512*3;
        . = ALIGN(@FLASH_PAGE_SIZE@);
+       _updatekey_store = .;
+       . += 1024;
+       . = ALIGN(@FLASH_PAGE_SIZE@);
     } > flash =0xffffffff
 }
 
index 076f245..3d5785e 100644 (file)
@@ -81,8 +81,12 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
 #define FILE_DF_OPENPGP        1
 #define FILE_MF                2
 #define FILE_EF_DIR    3
-#define FILE_EF_SERIAL 4
-#define FILE_EF_CH_CERTIFICATE  5
+#define FILE_EF_SERIAL_NO      4
+#define FILE_EF_UPDATE_KEY_0   5
+#define FILE_EF_UPDATE_KEY_1   6
+#define FILE_EF_UPDATE_KEY_2   7
+#define FILE_EF_UPDATE_KEY_3   8
+#define FILE_EF_CH_CERTIFICATE 9
 
 static uint8_t file_selection;
 
@@ -484,23 +488,95 @@ cmd_pgp_gakp (void)
     }
 }
 
+const uint8_t *
+gpg_get_firmware_update_key (uint8_t keyno)
+{
+  extern uint8_t _updatekey_store;
+  const uint8_t *p;
+
+  p = &_updatekey_store + keyno * KEY_CONTENT_LEN;
+  return p;
+}
+
+#ifdef CERTDO_SUPPORT
+#define FILEID_CH_CERTIFICATE_IS_VALID 1
+#else
+#define FILEID_CH_CERTIFICATE_IS_VALID 0
+#endif
+
 static void
 cmd_read_binary (void)
 {
+  int is_short_EF = (P1 (apdu) & 0x80) != 0;
+  uint8_t file_id;
+  const uint8_t *p;
+  uint16_t offset;
+
   DEBUG_INFO (" - Read binary\r\n");
 
-  if (file_selection == FILE_EF_SERIAL)
+  if (is_short_EF)
+    file_id = (P1 (apdu) & 0x1f);
+  else
+    file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
+
+  if ((!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
+      || file_id > FILEID_CH_CERTIFICATE)
+    {
+      GPG_NO_FILE ();
+      return;
+    }
+
+  if (is_short_EF)
     {
-      if (P2 (apdu) >= 6)
-       GPG_BAD_P0_P1 ();
+      file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
+      offset = P2 (apdu);
+    }
+  else
+    offset = (P1 (apdu) << 8) | P2 (apdu);
+
+  if (file_id == FILEID_SERIAL_NO)
+    {
+      if (offset != 0)
+       GPG_BAD_P1_P2 ();
       else
        {
-         gpg_do_get_data (0x004f, 1); /* AID */
-         res_APDU[0] = 0x5a;
+         gpg_do_get_data (0x004f, 1); /* Get AID... */
+         res_APDU[0] = 0x5a; /* ... and overwrite the first byte of data. */
        }
+      return;
     }
-  else
-    GPG_NO_RECORD();
+
+  if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3)
+    {
+      if (offset != 0)
+       GPG_MEMORY_FAILURE ();
+      else
+       {
+         p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0);
+         res_APDU_size = KEY_CONTENT_LEN;
+         memcpy (res_APDU, p, KEY_CONTENT_LEN);
+         GPG_SUCCESS ();
+       }
+    }
+#if defined(CERTDO_SUPPORT)
+  else /* file_id == FILEID_CH_CERTIFICATE */
+    {
+      uint16_t len = 256;
+
+      p = &ch_certificate_start;
+      if (offset >= FLASH_CH_CERTIFICATE_SIZE)
+       GPG_MEMORY_FAILURE ();
+      else
+       {
+         if (offset + len >= FLASH_CH_CERTIFICATE_SIZE)
+           len = FLASH_CH_CERTIFICATE_SIZE - offset;
+
+         res_APDU_size = len;
+         memcpy (res_APDU, p + offset, len);
+         GPG_SUCCESS ();
+       }
+    }
+#endif
 }
 
 static void
@@ -543,7 +619,7 @@ cmd_select_file (void)
        * MF.EF-GDO -- Serial number of the card and name of the owner
        */
       GPG_SUCCESS ();
-      file_selection = FILE_EF_SERIAL;
+      file_selection = FILE_EF_SERIAL_NO;
     }
   else if (apdu.cmd_apdu_data_len == 2
           && apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
@@ -704,17 +780,17 @@ cmd_internal_authenticate (void)
   DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
 }
 
+#define MBD_OPRATION_WRITE  0
+#define MBD_OPRATION_UPDATE 1
 
-#if defined(CERTDO_SUPPORT)
 static void
-cmd_update_binary (void)
+modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
 {
-  int len = apdu.cmd_apdu_data_len;
+  uint8_t file_id;
   uint16_t offset;
+  int is_short_EF = (p1 & 0x80) != 0;
   int r;
 
-  DEBUG_INFO (" - UPDATE BINARY\r\n");
-
   if (!ac_check_status (AC_ADMIN_AUTHORIZED))
     {
       DEBUG_INFO ("security error.");
@@ -722,98 +798,52 @@ cmd_update_binary (void)
       return;
     }
 
-  if ((P1 (apdu) & 0x80))
-    if ((P1 (apdu) & 0x7f) == FILEID_CH_CERTIFICATE)
-      {
-       file_selection = FILE_EF_CH_CERTIFICATE;
-       r = flash_erase_binary (FILEID_CH_CERTIFICATE);
-       if (r < 0)
-         {
-           DEBUG_INFO ("memory error.\r\n");
-           GPG_MEMORY_FAILURE ();
-           return;
-         }
-
-       offset = 0;
-      }
-    else
-      {
-       GPG_NO_FILE ();
-       return;
-      }
+  if (is_short_EF)
+    file_id = (p1 & 0x1f);
   else
-    {
-      if (file_selection != FILE_EF_CH_CERTIFICATE)
-       {
-         GPG_COMMAND_NOT_ALLOWED ();
-         return;
-       }
+    file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO;
 
-      offset = (P1 (apdu) << 8) | P2 (apdu);
+  if (!FILEID_CH_CERTIFICATE_IS_VALID && file_id == FILEID_CH_CERTIFICATE)
+    {
+      GPG_NO_FILE ();
+      return;
     }
 
-  DEBUG_SHORT (len);
-  DEBUG_SHORT (offset);
-
-  r = flash_write_binary (FILEID_CH_CERTIFICATE,
-                         apdu.cmd_apdu_data, len, offset);
-  if (r < 0)
+  if (op == MBD_OPRATION_UPDATE && file_id != FILEID_CH_CERTIFICATE)
     {
-      DEBUG_INFO ("memory error.\r\n");
-      GPG_MEMORY_FAILURE ();
+      GPG_CONDITION_NOT_SATISFIED ();
       return;
     }
 
-  GPG_SUCCESS ();
-  DEBUG_INFO ("UPDATE BINARY done.\r\n");
-}
-#endif
-
-
-static void
-cmd_write_binary (void)
-{
-  int len = apdu.cmd_apdu_data_len;
-  uint16_t offset;
-  int r;
-
-  DEBUG_INFO (" - WRITE BINARY\r\n");
-
-  if (!ac_check_status (AC_ADMIN_AUTHORIZED))
+  if (file_id > FILEID_CH_CERTIFICATE)
     {
-      DEBUG_INFO ("security error.");
-      GPG_SECURITY_FAILURE ();
+      GPG_NO_FILE ();
       return;
     }
 
-  if ((P1 (apdu) & 0x80))
-    if ((P1 (apdu) & 0x7f) <= FILEID_CH_CERTIFICATE)
-      {
-       file_selection = FILE_EF_SERIAL + (P1 (apdu) & 0x7f);
-       offset = 0;
-      }
-    else
-      {
-       GPG_NO_FILE ();
-       return;
-      }
-  else
+  if (is_short_EF)
     {
-      if (file_selection != FILE_EF_SERIAL
-         && file_selection != FILE_EF_CH_CERTIFICATE)
+      file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
+      offset = p2;
+
+      if (op == MBD_OPRATION_UPDATE)
        {
-         GPG_COMMAND_NOT_ALLOWED ();
-         return;
+         r = flash_erase_binary (file_id);
+         if (r < 0)
+           {
+             DEBUG_INFO ("memory error.\r\n");
+             GPG_MEMORY_FAILURE ();
+             return;
+           }
        }
-
-      offset = (P1 (apdu) << 8) | P2 (apdu);
     }
+  else
+    offset = (p1 << 8) | p2;
 
   DEBUG_SHORT (len);
   DEBUG_SHORT (offset);
 
-  r = flash_write_binary (file_selection - FILE_EF_SERIAL,
-                         apdu.cmd_apdu_data, len, offset);
+  r = flash_write_binary (file_id, apdu.cmd_apdu_data, len, offset);
   if (r < 0)
     {
       DEBUG_INFO ("memory error.\r\n");
@@ -822,6 +852,29 @@ cmd_write_binary (void)
     }
 
   GPG_SUCCESS ();
+}
+
+
+#if defined(CERTDO_SUPPORT)
+static void
+cmd_update_binary (void)
+{
+  int len = apdu.cmd_apdu_data_len;
+
+  DEBUG_INFO (" - UPDATE BINARY\r\n");
+  modify_binary (MBD_OPRATION_UPDATE, P1 (apdu), P2 (apdu), len);
+  DEBUG_INFO ("UPDATE BINARY done.\r\n");
+}
+#endif
+
+
+static void
+cmd_write_binary (void)
+{
+  int len = apdu.cmd_apdu_data_len;
+
+  DEBUG_INFO (" - WRITE BINARY\r\n");
+  modify_binary (MBD_OPRATION_WRITE, P1 (apdu), P2 (apdu), len);
   DEBUG_INFO ("WRITE BINARY done.\r\n");
 }
 
@@ -837,14 +890,16 @@ cmd_external_authenticate (void)
 
   DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
 
-  if (keyno > 2)
+  if (keyno > 4)
     {
       GPG_CONDITION_NOT_SATISFIED ();
       return;
     }
 
   pubkey = gpg_get_firmware_update_key (keyno);
-  if (pubkey == NULL || len != 256)
+  if (len != 256
+      || (pubkey[0] == 0xff && pubkey[1] == 0xff) /* not registered */
+      || (pubkey[0] == 0x00 && pubkey[1] == 0x00) /* removed */)
     {
       GPG_CONDITION_NOT_SATISFIED ();
       return;
index b92c2c8..b8693b9 100644 (file)
@@ -6,7 +6,7 @@
 #define GPG_FUNCTION_NOT_SUPPORTED()   set_res_sw (0x6a, 0x81)
 #define GPG_NO_FILE()                  set_res_sw (0x6a, 0x82)
 #define GPG_NO_RECORD()                        set_res_sw (0x6a, 0x88)
-#define GPG_BAD_P0_P1()                        set_res_sw (0x6b, 0x00)
+#define GPG_BAD_P1_P2()                        set_res_sw (0x6b, 0x00)
 #define GPG_NO_INS()                   set_res_sw (0x6d, 0x00)
 #define GPG_ERROR()                    set_res_sw (0x6f, 0x00)
 #define GPG_SUCCESS()                  set_res_sw (0x90, 0x00)