/*
* 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>
*
#include "gnuk.h"
#include "sys.h"
-#include "openpgp.h"
+#include "status-code.h"
#include "sha256.h"
#include "random.h"
#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
#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 */
#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 ();
}
cmd_verify (void)
{
int len;
+ uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu);
int r;
const uint8_t *pw;
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;
}
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;
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)
DEBUG_INFO (" - Get Data\r\n");
- if (file_selection != FILE_DF_OPENPGP)
- GPG_NO_RECORD ();
-
gpg_do_get_data (tag, 0);
}
}
+#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;
{ 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)
#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)))
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
{
}
}
-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;