Adding ISO 7816 select procedure.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-02-03 11:27:10 +01:00
parent f7c2c0afaa
commit df1f81c61c

396
openpgp.c
View File

@@ -41,11 +41,6 @@ static queue_t *openpgp_comm;
#define USER_PASSWD_MINLEN 6
#define ADMIN_PASSWD_MINLEN 8
#define CLS(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
#define P1(a) a.cmd_apdu_head[2]
#define P2(a) a.cmd_apdu_head[3]
#define INS_VERIFY 0x20
#define INS_CHANGE_REFERENCE_DATA 0x24
#define INS_PSO 0x2a
@@ -57,6 +52,7 @@ static queue_t *openpgp_comm;
#define INS_INTERNAL_AUTHENTICATE 0x88
#define INS_SELECT_FILE 0xa4
#define INS_READ_BINARY 0xb0
#define INS_READ_BINARY_ODD 0xb1
#define INS_GET_DATA 0xca
#define INS_WRITE_BINARY 0xd0
#define INS_UPDATE_BINARY 0xd6
@@ -84,10 +80,10 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
0x00, 0x00 /* PIN status: OK, PIN blocked?: No */
};
void
set_res_sw (uint8_t sw1, uint8_t sw2)
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2)
{
apdu.sw = (sw1 << 8) | sw2;
apdu.sw = (sw1 << 8) | sw2;
return make_uint16_t(sw1, sw2);
}
#define FILE_NONE 0
@@ -100,32 +96,181 @@ 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_DF_SC_HSM 10
#define FILE_CARD_TERMINATED 255
uint8_t file_selection;
#define FILE_TYPE_UNKNOWN 0x00
#define FILE_TYPE_DF 0x04
#define FILE_TYPE_INTERNAL_EF 0x03
#define FILE_TYPE_WORKING_EF 0x01
#define FILE_TYPE_BSO 0x10
static void
gpg_init (void)
/* EF structures */
#define FILE_EF_UNKNOWN 0x00
#define FILE_EF_TRANSPARENT 0x01
#define FILE_EF_LINEAR_FIXED 0x02
#define FILE_EF_LINEAR_FIXED_TLV 0x03
#define FILE_EF_LINEAR_VARIABLE 0x04
#define FILE_EF_LINEAR_VARIABLE_TLV 0x05
#define FILE_EF_CYCLIC 0x06
#define FILE_EF_CYCLIC_TLV 0x07
typedef struct pkcs15_entry
{
const uint8_t *flash_do_start;
const uint8_t *flash_do_end;
const uint16_t fid;
const uint8_t parent; //entry number in the whole table!!
const uint8_t *name;
const uint8_t type;
const uint8_t *data; //should include 2 bytes len at begining
const uint8_t ef_structure;
} pkcs15_entry_t;
flash_do_storage_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_key_storage_init ();
multicore_lockout_victim_init();
//puts FCI in the RAPDU
void process_fci(const pkcs15_entry_t *pe) {
uint8_t *p = res_APDU;
uint8_t buf[64];
res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0x6f;
res_APDU[res_APDU_size++] = 0x00; //computed later
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 2;
if (pe->data)
memcpy(res_APDU+res_APDU_size, pe->data, 2);
else
memset(res_APDU+res_APDU_size, 0, 2);
res_APDU_size += 2;
res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size] = 0;
if (pe->type == FILE_TYPE_INTERNAL_EF)
res_APDU[res_APDU_size++] |= 0x08;
else if (pe->type == FILE_TYPE_WORKING_EF)
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
else if (pe->type == FILE_TYPE_DF)
res_APDU[res_APDU_size++] |= 0x38;
res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2;
put_uint16_t(pe->fid, res_APDU+res_APDU_size);
res_APDU_size += 2;
res_APDU[1] = res_APDU_size-2;
}
static void
gpg_fini (void)
const pkcs15_entry_t pkcs15_entries[] = {
{ 0x3f00, 0xff, NULL, FILE_TYPE_DF, NULL, 0 }, // MF
{ 0x2f00, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.DIR
{ 0x2f01, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.ATR
{ 0x2f02, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.GDO
{ 0x5015, 0, NULL, FILE_TYPE_DF, NULL, 0 }, //DF.PKCS15
{ 0x5031, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.ODF
{ 0x5032, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.TokenInfo
{ 0x5033, 0, NULL, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT }, //EF.UnusedSpace
{ 0x0000, 0, openpgpcard_aid, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT },
{ 0x0000, 0, sc_hsm_aid, FILE_TYPE_WORKING_EF, NULL, FILE_EF_TRANSPARENT },
{ 0x0000, 0xff, NULL, FILE_TYPE_UNKNOWN, NULL, 0 } //end
};
const pkcs15_entry_t *MF = &pkcs15_entries[0];
const pkcs15_entry_t *pkcs15_last = &pkcs15_entries[sizeof(pkcs15_entries)/sizeof(pkcs15_entry_t)];
extern const pkcs15_entry_t *search_by_fid(const uint16_t, const pkcs15_entry_t *, const uint8_t);
bool card_terminated = false;
#define SPECIFY_EF 0x1
#define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3
#define MAX_DEPTH 4
bool is_parent(const pkcs15_entry_t *child, const pkcs15_entry_t *parent) {
if (child == parent)
return true;
if (child == MF)
return false;
return is_parent(&pkcs15_entries[child->parent], parent);
}
const pkcs15_entry_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_last; p++) {
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
return p;
}
}
return NULL;
}
const pkcs15_entry_t *search_by_fid(const uint16_t fid, const pkcs15_entry_t *parent, const uint8_t sp) {
for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_last; p++) {
if (p->fid != 0x0000 && p->fid == fid) {
if (!parent || (parent && is_parent(p, parent))) {
if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
return p;
}
}
}
return NULL;
}
uint8_t make_path_buf(const pkcs15_entry_t *pe, uint8_t *buf, uint8_t buflen, const pkcs15_entry_t *top) {
if (!buflen)
return 0;
if (pe == top) //MF or relative DF
return 0;
put_uint16_t(pe->fid, buf);
return make_path_buf(&pkcs15_entries[pe->parent], buf+2, buflen-2, top)+2;
}
uint8_t make_path(const pkcs15_entry_t *pe, const pkcs15_entry_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH*2], *p = path;
put_uint16_t(pe->fid, buf);
uint8_t depth = make_path_buf(&pkcs15_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2;
for (int d = depth-2; d >= 0; d -= 2) {
memcpy(p, buf+d, 2);
p += 2;
}
return depth;
}
const pkcs15_entry_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const pkcs15_entry_t *parent) {
uint8_t path[MAX_DEPTH*2];
if (pathlen > sizeof(path)) {
return NULL;
}
for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_last; p++) {
uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth))
return p;
}
return NULL;
}
uint8_t file_selection;
const pkcs15_entry_t *currentEF = NULL;
const pkcs15_entry_t *currentDF = NULL;
static void gpg_init (void)
{
ac_fini ();
const uint8_t *flash_do_start;
const uint8_t *flash_do_end;
flash_do_storage_init (&flash_do_start, &flash_do_end);
if (flash_do_start == NULL)
card_terminated = true;
gpg_data_scan (flash_do_start, flash_do_end);
flash_key_storage_init ();
multicore_lockout_victim_init();
}
static void gpg_fini (void)
{
ac_fini ();
}
#if defined(PINPAD_SUPPORT)
@@ -844,76 +989,86 @@ cmd_read_binary (queue_t *ccid_comm)
return;
}
}
static void
cmd_select_file (queue_t *ccid_comm)
void select_file(const pkcs15_entry_t *pe) {
if (!pe)
{
currentDF = MF;
currentEF = NULL;
}
else if (pe->type & FILE_TYPE_INTERNAL_EF) {
currentEF = pe;
currentDF = &pkcs15_entries[pe->parent];
}
else {
currentDF = pe;
}
}
static uint16_t cmd_select_file (queue_t *ccid_comm)
{
(void)ccid_comm;
if (P1 (apdu) == 4) /* Selection by DF name */
{
DEBUG_INFO (" - select DF by name\r\n");
/* name = D2 76 00 01 24 01 */
if (apdu.cmd_apdu_data_len != 6
|| memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0)
{
DEBUG_SHORT (apdu.cmd_apdu_data_len);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
GPG_NO_FILE ();
return;
}
if (file_selection == FILE_CARD_TERMINATED)
{
GPG_APPLICATION_TERMINATED ();
return;
}
file_selection = FILE_DF_OPENPGP;
/* Behave just like original OpenPGP card. */
GPG_SUCCESS ();
(void)ccid_comm;
uint8_t p1 = P1(apdu);
uint8_t p2 = P2(apdu);
const pkcs15_entry_t *pe = NULL;
uint16_t fid = 0x0;
// Only "first or only occurence" supported
//if ((p2 & 0xF3) != 0x00) {
// return SW_INCORRECT_P1P2();
//}
if (apdu.cmd_apdu_data_len >= 2)
fid = get_uint16_t(apdu.cmd_apdu_data, 0);
if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
if (apdu.cmd_apdu_data_len == 0) {
pe = MF;
ac_fini();
}
else if (apdu.cmd_apdu_data_len == 2) {
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
return GPG_NO_FILE ();
}
}
}
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
{
DEBUG_INFO (" - select 0x2f02 EF\r\n");
/*
* MF.EF-GDO -- Serial number of the card and name of the owner
*/
GPG_SUCCESS ();
file_selection = FILE_EF_SERIAL_NO;
else if (p1 == 0x01) { //Select child DF - DF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) {
return GPG_NO_FILE ();
}
}
else if (apdu.cmd_apdu_data_len == 2
&& apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
{
DEBUG_INFO (" - select ROOT MF\r\n");
if (P2 (apdu) == 0x0c)
{
GPG_SUCCESS ();
}
else
{
int len = sizeof (select_file_TOP_result);
res_APDU_size = len;
memcpy (res_APDU, select_file_TOP_result, len);
res_APDU[2] = (data_objects_number_of_bytes & 0xff);
res_APDU[3] = (data_objects_number_of_bytes >> 8);
GPG_SUCCESS ();
}
file_selection = FILE_MF;
ac_fini (); /* Reset authentication */
else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) {
return GPG_NO_FILE ();
}
}
else
{
DEBUG_INFO (" - select ?? \r\n");
file_selection = FILE_NONE;
GPG_NO_FILE ();
else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
if (apdu.cmd_apdu_data_len != 0)
return GPG_NO_FILE ();
}
else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
if (!(pe = search_by_name(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len))) {
return GPG_NO_FILE ();
}
if (card_terminated) {
return GPG_APPLICATION_TERMINATED ();
}
}
else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, MF))) {
return GPG_NO_FILE ();
}
}
else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier
if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, currentDF))) {
return GPG_NO_FILE ();
}
}
if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
process_fci(pe);
}
else
return SW_INCORRECT_P1P2();
select_file(pe);
return GPG_SUCCESS ();
}
static void
@@ -1471,7 +1626,8 @@ cmd_activate_file (queue_t *ccid_comm)
}
flash_activate ();
file_selection = FILE_DF_OPENPGP;
//file_selection = FILE_DF_OPENPGP;
file_selection = FILE_DF_SC_HSM;
GPG_SUCCESS ();
}
@@ -1483,7 +1639,8 @@ cmd_terminate_df (queue_t *ccid_comm)
uint8_t p2 = P2 (apdu);
(void)ccid_comm;
if (file_selection != FILE_DF_OPENPGP)
//if (file_selection != FILE_DF_OPENPGP)
if (file_selection != FILE_DF_SC_HSM)
{
GPG_NO_RECORD ();
return;
@@ -1546,6 +1703,7 @@ const struct command cmds[] = {
{ INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
{ INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */
{ INS_READ_BINARY_ODD, 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)
@@ -1562,37 +1720,35 @@ const struct command cmds[] = {
static void
process_command_apdu (queue_t *ccid_comm)
{
int i;
uint8_t cmd = INS (apdu);
int i;
uint8_t cmd = INS (apdu);
for (i = 0; i < NUM_CMDS; i++)
if (cmds[i].command == cmd)
break;
if (i < NUM_CMDS)
for (i = 0; i < NUM_CMDS; i++)
if (cmds[i].command == cmd)
break;
DEBUG_BYTE(i);
if (i < NUM_CMDS)
{
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 (ccid_comm);
//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_SC_HSM
&& 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 && cmd != INS_READ_BINARY_ODD)
GPG_NO_RECORD ();
else
{
cmds[i].cmd_handler (ccid_comm);
}
}
else
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd);
GPG_NO_INS ();
DEBUG_INFO (" - ??");
DEBUG_BYTE (cmd);
GPG_NO_INS ();
}
}