add factory reset support (not-full yet)
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 13 Oct 2016 06:06:19 +0000 (15:06 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 13 Oct 2016 06:06:19 +0000 (15:06 +0900)
src/flash.c
src/gnuk.h
src/openpgp-do.c
src/openpgp.c
src/status-code.h

index 383d645..13021da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
  *
- * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
  *               Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
@@ -75,7 +75,7 @@ static uint8_t *last_p;
 
 /* The first halfword is generation for the data page (little endian) */
 const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
-  0x01, 0x00, 0xff, 0xff
+  0x00, 0x00, 0xff, 0xff
 };
 
 /* Linker set this symbol */
@@ -114,22 +114,51 @@ flash_init (void)
     flash_page_size = 2048;
 
   gen1_p = (uint16_t *)(&_data_pool + flash_page_size);
+  data_pool = &_data_pool;
 
   /* Check data pool generation and choose the page */
   gen0 = *gen0_p;
   gen1 = *gen1_p;
+
+  if (gen0 == 0xffff && gen1 == 0xffff)
+    /* It's terminated.  */
+    return NULL;
+
   if (gen0 == 0xffff)
+    /* Use another page if a page is erased.  */
     data_pool = &_data_pool + flash_page_size;
   else if (gen1 == 0xffff)
+    /* Or use different page if another page is erased.  */
     data_pool = &_data_pool;
-  else if (gen1 > gen0)
+  else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0)
+    /* When both pages have valid header, use newer page.   */
     data_pool = &_data_pool + flash_page_size;
-  else
-    data_pool = &_data_pool;
 
   return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
 }
 
+static uint8_t *flash_key_getpage (enum kind_of_key kk);
+
+void
+flash_terminate (void)
+{
+  int i;
+
+  for (i = 0; i < 3; i++)
+    flash_erase_page ((uint32_t)flash_key_getpage (i));
+  flash_erase_page ((uint32_t)&_data_pool);
+  flash_erase_page ((uint32_t)(&_data_pool + flash_page_size));
+  data_pool = &_data_pool;
+  last_p = &_data_pool + FLASH_DATA_POOL_HEADER_SIZE;
+}
+
+void
+flash_activate (void)
+{
+  flash_program_halfword ((uint32_t)&_data_pool, 0);
+}
+
+
 void
 flash_init_keys (void)
 {
@@ -209,8 +238,12 @@ flash_copying_gc (void)
   generation = *(uint16_t *)src;
   data_pool = dst;
   gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE);
+  if (generation == 0xfffe)
+    generation = 0;
+  else
+    generation++;
+  flash_program_halfword ((uint32_t)dst, generation);
   flash_erase_page ((uint32_t)src);
-  flash_program_halfword ((uint32_t)dst, generation+1);
   return 0;
 }
 
index b74e03f..5586040 100644 (file)
@@ -107,6 +107,7 @@ extern uint16_t data_objects_number_of_bytes;
 
 void gpg_data_scan (const uint8_t *p);
 void gpg_data_copy (const uint8_t *p);
+void gpg_do_terminate (void);
 void gpg_do_get_data (uint16_t tag, int with_tag);
 void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
 void gpg_do_public_key (uint8_t kk_byte);
@@ -138,6 +139,8 @@ int gpg_get_algo_attr (enum kind_of_key kk);
 int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
 
 const uint8_t *flash_init (void);
+void flash_terminate (void);
+void flash_activate (void);
 void flash_init_keys (void);
 void flash_do_release (const uint8_t *);
 const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
index 8546358..be21f29 100644 (file)
@@ -1074,6 +1074,28 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full)
     }
 }
 
+void
+gpg_do_terminate (void)
+{
+  int i;
+
+  for (i = 0; i < 3; i++)
+    kd[i].pubkey = NULL;
+
+  for (i = 0; i < NR_DO__LAST__; i++)
+    do_ptr[i] = NULL;
+
+  num_prv_keys = 0;
+  data_objects_number_of_bytes = 0;
+  digital_signature_counter = 0;
+
+  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;
+  algo_attr_sig_p = algo_attr_dec_p = algo_attr_aut_p = NULL;
+}
+
 static int
 gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
                     int prvkey_len, const uint8_t *keystring_admin,
@@ -1549,7 +1571,7 @@ gpg_data_scan (const uint8_t *p_start)
 
   /* Traverse DO, counters, etc. in DATA pool */
   p = p_start;
-  while (*p != NR_EMPTY)
+  while (p && *p != NR_EMPTY)
     {
       uint8_t nr = *p++;
       uint8_t second_byte = *p;
index 4d62297..b4b9f40 100644 (file)
@@ -48,6 +48,7 @@ static struct eventflag *openpgp_comm;
 #define INS_CHANGE_REFERENCE_DATA              0x24
 #define INS_PSO                                        0x2a
 #define INS_RESET_RETRY_COUNTER                        0x2c
+#define INS_ACTIVATE_FILE                      0x44
 #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR   0x47
 #define INS_EXTERNAL_AUTHENTICATE              0x82
 #define INS_GET_CHALLENGE                      0x84
@@ -59,6 +60,7 @@ static struct eventflag *openpgp_comm;
 #define INS_UPDATE_BINARY                      0xd6
 #define INS_PUT_DATA                           0xda
 #define INS_PUT_DATA_ODD                       0xdb    /* For key import */
+#define INS_TERMINATE_DF                       0xe6
 
 static const uint8_t *challenge; /* Random bytes */
 
@@ -96,6 +98,8 @@ set_res_sw (uint8_t sw1, uint8_t sw2)
 #define FILE_EF_UPDATE_KEY_2   7
 #define FILE_EF_UPDATE_KEY_3   8
 #define FILE_EF_CH_CERTIFICATE 9
+#define FILE_CARD_TERMINATED_OPENPGP   254
+#define FILE_CARD_TERMINATED   255
 
 static uint8_t file_selection;
 
@@ -104,10 +108,15 @@ gpg_init (void)
 {
   const uint8_t *flash_data_start;
 
-  file_selection = FILE_NONE;
+  flash_init_keys ();
   flash_data_start = flash_init ();
+
+  if (flash_data_start == NULL)
+    file_selection = FILE_CARD_TERMINATED;
+  else
+    file_selection = FILE_NONE;
+
   gpg_data_scan (flash_data_start);
-  flash_init_keys ();
 }
 
 static void
@@ -616,9 +625,6 @@ cmd_put_data (void)
 
   DEBUG_INFO (" - PUT DATA\r\n");
 
-  if (file_selection != FILE_DF_OPENPGP)
-    GPG_NO_RECORD();
-
   tag = ((P1 (apdu)<<8) | P2 (apdu));
   len = apdu.cmd_apdu_data_len;
   data = apdu.cmd_apdu_data;
@@ -751,6 +757,13 @@ cmd_select_file (void)
          return;
        }
 
+      if (file_selection == FILE_CARD_TERMINATED)
+       {
+         file_selection = FILE_CARD_TERMINATED_OPENPGP;
+         GPG_APPLICATION_TERMINATED();
+         return;
+       }
+
       file_selection = FILE_DF_OPENPGP;
       if ((P2 (apdu) & 0x0c) == 0x0c)  /* No FCI */
        GPG_SUCCESS ();
@@ -813,9 +826,6 @@ cmd_get_data (void)
 
   DEBUG_INFO (" - Get Data\r\n");
 
-  if (file_selection != FILE_DF_OPENPGP)
-    GPG_NO_RECORD ();
-
   gpg_do_get_data (tag, 0);
 }
 
@@ -1317,6 +1327,64 @@ cmd_get_challenge (void)
 }
 
 
+#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
+static void
+cmd_activate_file (void)
+{
+  if (file_selection != FILE_CARD_TERMINATED_OPENPGP)
+    {
+      GPG_NO_RECORD();
+      return;
+    }
+
+  flash_activate ();
+  file_selection = FILE_DF_OPENPGP;
+  GPG_SUCCESS ();
+}
+
+static void
+cmd_terminate_df (void)
+{
+  uint8_t p1 = P1 (apdu);
+  uint8_t p2 = P2 (apdu);
+
+  if (file_selection != FILE_DF_OPENPGP)
+    {
+      GPG_NO_RECORD();
+      return;
+    }
+
+  if (p1 != 0 || p2 != 0)
+    {
+      GPG_BAD_P1_P2();
+      return;
+    }
+
+  if (apdu.cmd_apdu_data_len != 0)
+    {
+      GPG_WRONG_LENGTH();
+      return;
+    }
+
+
+  if (!ac_check_status (AC_ADMIN_AUTHORIZED) && !gpg_pw_locked (PW_ERR_PW3))
+    {
+      /* Only allow the case admin authorized, or, admin pass is locked.  */
+      GPG_SECURITY_FAILURE();
+      return;
+    }
+
+  ac_reset_admin ();
+  ac_reset_pso_cds ();
+  ac_reset_other ();
+  gpg_do_terminate ();
+  flash_terminate ();
+  file_selection = FILE_CARD_TERMINATED;
+  GPG_SUCCESS ();
+}
+#endif
+
+
 struct command
 {
   uint8_t command;
@@ -1328,13 +1396,16 @@ const struct command cmds[] = {
   { INS_CHANGE_REFERENCE_DATA, cmd_change_password },
   { INS_PSO, cmd_pso },
   { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
+#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
+  { INS_ACTIVATE_FILE, cmd_activate_file },
+#endif
   { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
   { INS_EXTERNAL_AUTHENTICATE,             /* Not in OpenPGP card protocol */
     cmd_external_authenticate },
   { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
   { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
   { INS_SELECT_FILE, cmd_select_file },
-  { INS_READ_BINARY, cmd_read_binary },
+  { INS_READ_BINARY, cmd_read_binary },     /* Not in OpenPGP card protocol */
   { INS_GET_DATA, cmd_get_data },
   { INS_WRITE_BINARY, cmd_write_binary},    /* Not in OpenPGP card protocol */
 #if defined(CERTDO_SUPPORT)
@@ -1342,6 +1413,9 @@ const struct command cmds[] = {
 #endif
   { INS_PUT_DATA, cmd_put_data },
   { INS_PUT_DATA_ODD, cmd_put_data },
+#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
+  { INS_TERMINATE_DF, cmd_terminate_df},
+#endif
 };
 #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
 
@@ -1357,9 +1431,22 @@ process_command_apdu (void)
 
   if (i < NUM_CMDS)
     {
-      chopstx_setcancelstate (1);
-      cmds[i].cmd_handler ();
-      chopstx_setcancelstate (0);
+      if (file_selection == FILE_CARD_TERMINATED
+         && cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
+         && cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE)
+       GPG_APPLICATION_TERMINATED();
+      else if (file_selection != FILE_DF_OPENPGP
+              && cmd != INS_SELECT_FILE && cmd != INS_ACTIVATE_FILE
+              && cmd != INS_GET_CHALLENGE && cmd != INS_EXTERNAL_AUTHENTICATE
+              && cmd != INS_WRITE_BINARY && cmd != INS_UPDATE_BINARY
+              && cmd != INS_READ_BINARY)
+       GPG_NO_RECORD();
+      else
+       {
+         chopstx_setcancelstate (1);
+         cmds[i].cmd_handler ();
+         chopstx_setcancelstate (0);
+       }
     }
   else
     {
index b8693b9..537d56c 100644 (file)
@@ -1,4 +1,6 @@
+#define GPG_APPLICATION_TERMINATED()   set_res_sw (0x62, 0x85)
 #define GPG_MEMORY_FAILURE()           set_res_sw (0x65, 0x81)
+#define GPG_WRONG_LENGTH()             set_res_sw (0x67, 0x00)
 #define GPG_SECURITY_FAILURE()         set_res_sw (0x69, 0x82)
 #define GPG_SECURITY_AUTH_BLOCKED()    set_res_sw (0x69, 0x83)
 #define GPG_CONDITION_NOT_SATISFIED()  set_res_sw (0x69, 0x85)