docker: source checking container
[gnuk/gnuk.git] / src / openpgp.c
index 83d269b..5b788b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * openpgp.c -- OpenPGP card protocol support
  *
- * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
  *               Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
@@ -31,7 +31,7 @@
 
 #include "gnuk.h"
 #include "sys.h"
-#include "openpgp.h"
+#include "status-code.h"
 #include "sha256.h"
 #include "random.h"
 
@@ -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,17 +98,25 @@ 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;
+uint8_t file_selection;
 
 static void
 gpg_init (void)
 {
-  const uint8_t *flash_data_start;
+  const uint8_t *flash_do_start;
+  const uint8_t *flash_do_end;
 
-  file_selection = FILE_NONE;
-  flash_data_start = flash_init ();
-  gpg_data_scan (flash_data_start);
+  flash_init (&flash_do_start, &flash_do_end);
+
+  if (flash_do_start == NULL)
+    file_selection = FILE_CARD_TERMINATED;
+  else
+    file_selection = FILE_NONE;
+
+  gpg_data_scan (flash_do_start, flash_do_end);
   flash_init_keys ();
 }
 
@@ -138,6 +148,7 @@ static void
 cmd_verify (void)
 {
   int len;
+  uint8_t p1 = P1 (apdu);
   uint8_t p2 = P2 (apdu);
   int r;
   const uint8_t *pw;
@@ -149,22 +160,36 @@ cmd_verify (void)
   pw = apdu.cmd_apdu_data;
 
   if (len == 0)
-    {                          /* This is to examine status.  */
-      if (p2 == 0x81)
-       r = ac_check_status (AC_PSO_CDS_AUTHORIZED);
-      else if (p2 == 0x82)
-       r = ac_check_status (AC_OTHER_AUTHORIZED);
-      else
-       r = ac_check_status (AC_ADMIN_AUTHORIZED);
+    {
+      if (p1 == 0)
+       {                       /* This is to examine status.  */
+         if (p2 == 0x81)
+           r = ac_check_status (AC_PSO_CDS_AUTHORIZED);
+         else if (p2 == 0x82)
+           r = ac_check_status (AC_OTHER_AUTHORIZED);
+         else
+           r = ac_check_status (AC_ADMIN_AUTHORIZED);
 
-      if (r)
-       GPG_SUCCESS (); /* If authentication done already, return success.  */
-      else
-       {                /* If not, return retry counter, encoded.  */
-         r = gpg_pw_get_retry_counter (p2);
-         set_res_sw (0x63, 0xc0 | (r&0x0f));
+         if (r)
+           GPG_SUCCESS ();     /* If authentication done already, return success.  */
+         else
+           {            /* If not, return retry counter, encoded.  */
+             r = gpg_pw_get_retry_counter (p2);
+             set_res_sw (0x63, 0xc0 | (r&0x0f));
+           }
        }
-
+      else if (p1 == 0xff)
+       {                       /* Reset the status.  */
+         if (p2 == 0x81)
+           ac_reset_pso_cds ();
+         else if (p2 == 0x82)
+           ac_reset_other ();
+         else
+           ac_reset_admin ();
+         GPG_SUCCESS ();
+       }
+      else
+       GPG_BAD_P1_P2 ();
       return;
     }
 
@@ -601,9 +626,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;
@@ -736,19 +758,17 @@ cmd_select_file (void)
          return;
        }
 
-      file_selection = FILE_DF_OPENPGP;
-      if ((P2 (apdu) & 0x0c) == 0x0c)  /* No FCI */
-       GPG_SUCCESS ();
-      else
+      if (file_selection == FILE_CARD_TERMINATED)
        {
-         gpg_do_get_data (0x004f, 1); /* AID */
-         memmove (res_APDU+2, res_APDU, res_APDU_size);
-         res_APDU[0] = 0x6f;
-         res_APDU[1] = 0x12;
-         res_APDU[2] = 0x84;   /* overwrite: DF name */
-         res_APDU_size += 2;
-         GPG_SUCCESS ();
+         file_selection = FILE_CARD_TERMINATED_OPENPGP;
+         GPG_APPLICATION_TERMINATED();
+         return;
        }
+
+      file_selection = FILE_DF_OPENPGP;
+
+      /* Behave just like original OpenPGP card.  */
+      GPG_SUCCESS ();
     }
   else if (apdu.cmd_apdu_data_len == 2
           && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
@@ -798,9 +818,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);
 }
 
@@ -1302,6 +1319,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;
@@ -1313,13 +1388,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)
@@ -1327,6 +1405,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)))
 
@@ -1342,9 +1423,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
     {
@@ -1354,23 +1448,10 @@ process_command_apdu (void)
     }
 }
 
-static void * card_thread (chopstx_t thd, struct eventflag *ccid_comm);
-
-void * __attribute__ ((naked))
+void *
 openpgp_card_thread (void *arg)
 {
-  chopstx_t thd;
-
-  asm ("mov    %0, sp" : "=r" (thd));
-  return card_thread (thd, (struct eventflag *)arg);
-}
-
-chopstx_t openpgp_card_thd;
-
-static void * __attribute__ ((noinline))
-card_thread (chopstx_t thd, struct eventflag *ccid_comm)
-{
-  openpgp_card_thd = thd;
+  struct eventflag *ccid_comm = (struct eventflag *)arg;
 
   openpgp_comm = ccid_comm + 1;