Reorganization of file structure.

At this moment I disabled openpgp/gnuk due to missing deep tests.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-03-07 23:37:10 +01:00
parent bad954a2c4
commit 7988083d6b
57 changed files with 48 additions and 684 deletions

449
src/fs/file.c Normal file
View File

@@ -0,0 +1,449 @@
#include "file.h"
#include "tusb.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include "libopensc/card-sc-hsm.h"
#include <string.h>
extern const uintptr_t end_data_pool;
extern const uintptr_t start_data_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_word (uintptr_t addr, uint32_t data);
extern int flash_program_uintptr (uintptr_t addr, uintptr_t data);
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t flash_read_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern void low_flash_available();
//puts FCI in the RAPDU
void process_fci(const file_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) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
res_APDU[res_APDU_size++] = len & 0xff;
}
else {
res_APDU[res_APDU_size++] = pe->data[1];
res_APDU[res_APDU_size++] = pe->data[0];
}
}
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;
}
const uint8_t cvca[] = {
0x6A, 0x01,
0x7f, 0x21, 0x82, 0x01, 0x65, 0x7f, 0x4e, 0x82, 0x01, 0x2d, 0x5f,
0x29, 0x01, 0x00, 0x42, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x49, 0x81,
0xdd, 0x06, 0x0a, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x02, 0x02, 0x02,
0x02, 0x03, 0x81, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x18, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x83,
0x18, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7, 0x0f, 0xa7,
0xe9, 0xab, 0x72, 0x24, 0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1,
0x46, 0xb9, 0xb1, 0x84, 0x31, 0x04, 0x18, 0x8d, 0xa8, 0x0e, 0xb0,
0x30, 0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00,
0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12, 0x07, 0x19, 0x2b,
0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11, 0x85,
0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x99, 0xde, 0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4,
0xd2, 0x28, 0x31, 0x86, 0x31, 0x04, 0x4d, 0x28, 0x34, 0x67, 0xb5,
0x43, 0xfd, 0x84, 0x22, 0x09, 0xbd, 0xd2, 0xd6, 0x26, 0x27, 0x2d,
0x53, 0xa7, 0xdf, 0x52, 0x8f, 0xc2, 0xde, 0x7c, 0x9a, 0xcd, 0x1f,
0xf2, 0x10, 0x42, 0x7c, 0x13, 0x44, 0x03, 0xb0, 0xa5, 0xdf, 0x8a,
0xd4, 0x59, 0xd1, 0x86, 0x4b, 0xde, 0x33, 0xb1, 0x60, 0x17, 0x87,
0x01, 0x01, 0x5f, 0x20, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x4c, 0x12,
0x06, 0x09, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x01, 0x02, 0x02,
0x53, 0x05, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x25, 0x06, 0x02,
0x02, 0x00, 0x02, 0x01, 0x09, 0x5f, 0x24, 0x06, 0x03, 0x00, 0x01,
0x02, 0x03, 0x01, 0x5f, 0x37, 0x30, 0x26, 0x2d, 0x6f, 0xa6, 0xd0,
0x52, 0x01, 0xf1, 0x41, 0x1e, 0xe9, 0x33, 0x29, 0x19, 0x42, 0x42,
0x9b, 0xb0, 0xeb, 0xf7, 0x46, 0x20, 0xcb, 0x81, 0xfe, 0xda, 0xd7,
0xab, 0x2b, 0xdc, 0xa7, 0x38, 0xf4, 0xc8, 0xec, 0x4c, 0x66, 0xb4,
0x0a, 0x2d, 0x16, 0xfb, 0xf3, 0x79, 0xe9, 0x93, 0xc8, 0x25
};
const uint8_t token_info[] = {
0x28, 0x00, //litle endian
0x30, 0x26, 0x2, 0x1, 0x1, 0x4, 0x4, 0xd, 0x0, 0x0, 0x0, 0xc, 0xd, 0x50, 0x6f, 0x6c, 0x20, 0x48, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x6a, 0x6f, 0x73, 0x80, 0x8, 0x48, 0x53, 0x4d, 0x20, 0x32, 0x30, 0x34, 0x30, 0x3, 0x2, 0x4, 0xf0
};
extern const uint8_t sc_hsm_aid[];
extern int parse_token_info(const file_t *f, int mode);
file_t file_entries[] = {
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
/* 16 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
/* 17 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
/* 18 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
/* 19 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
/* 20 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
/* 21 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
///* 22 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 23 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 24 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
};
const file_t *MF = &file_entries[0];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
file_t *file_pin1 = NULL;
file_t *file_retries_pin1 = NULL;
file_t *file_sopin = NULL;
file_t *file_retries_sopin = NULL;
#define MAX_DYNAMIC_FILES 64
uint16_t dynamic_files = 0;
file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent)
return true;
if (child == MF)
return false;
return is_parent(&file_entries[child->parent], parent);
}
file_t *get_parent(file_t *f) {
return &file_entries[f->parent];
}
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
return p;
}
}
return NULL;
}
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
for (file_t *p = file_entries; p != file_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 file_t *pe, uint8_t *buf, uint8_t buflen, const file_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(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
}
uint8_t make_path(const file_t *pe, const file_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(&file_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;
}
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
uint8_t path[MAX_DEPTH*2];
if (pathlen > sizeof(path)) {
return NULL;
}
for (file_t *p = file_entries; p != file_last; p++) {
uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
return p;
}
return NULL;
}
file_t *currentEF = NULL;
file_t *currentDF = NULL;
const file_t *selected_applet = NULL;
bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op];
if (acl == 0x0)
return true;
else if (acl == 0xff)
return false;
else if (acl == 0x90 || acl & 0x9F == 0x10) {
// PIN required.
if(isUserAuthenticated) {
return true;
}
else {
return false;
}
}
return false;
}
#include "libopensc/pkcs15.h"
void initialize_chain(file_chain_t **chain) {
file_chain_t *next;
for (file_chain_t *f = *chain; f; f = next) {
next = f->next;
free(f);
}
*chain = NULL;
}
void initialize_flash(bool hard) {
if (hard) {
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
low_flash_available();
}
for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
f->data = NULL;
}
dynamic_files = 0;
}
void scan_flash() {
initialize_flash(false); //soft initialization
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
{
printf("First initialization (or corrupted!)\r\n");
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
}
printf("SCAN\r\n");
uintptr_t base = flash_read_uintptr(end_data_pool);
for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) {
if (base == 0x0) //all is empty
break;
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t));
printf("scan fid %x\r\n",fid);
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) {
file = file_new(fid);
if ((fid & 0xff00) == (KEY_PREFIX << 8)) {
//add_file_to_chain(file, &ef_kf);
}
else if ((fid & 0xff00) == (PRKD_PREFIX << 8)) {
//add_file_to_chain(file, &ef_prkdf);
}
else if ((fid & 0xff00) == (CD_PREFIX << 8)) {
//add_file_to_chain(file, &ef_cdf);
}
else if ((fid & 0xff00) == (EE_CERTIFICATE_PREFIX << 8)) {
//add_file_to_chain(file, &ef_pukdf);
}
else {
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
continue;
}
}
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uint16_t));
if (flash_read_uintptr(base) == 0x0) {
break;
}
}
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
if (file_pin1) {
if (!file_pin1->data) {
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
}
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
if (file_sopin) {
if (!file_sopin->data) {
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
}
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
if (file_retries_pin1) {
if (!file_retries_pin1->data) {
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
}
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
if (file_retries_sopin) {
if (!file_retries_sopin->data) {
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
file_t *tf = NULL;
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
}
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
low_flash_available();
}
uint8_t *file_read(const uint8_t *addr) {
return flash_read((uintptr_t)addr);
}
uint16_t file_read_uint16(const uint8_t *addr) {
return flash_read_uint16((uintptr_t)addr);
}
uint8_t file_read_uint8(const uint8_t *addr) {
return flash_read_uint8((uintptr_t)addr);
}
file_t *search_dynamic_file(uint16_t fid) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid)
return &dynamic_file[i];
}
return NULL;
}
int delete_dynamic_file(file_t *f) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) {
for (int j = i+1; j < dynamic_files; j++)
memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
dynamic_files--;
return HSM_OK;
}
}
return HSM_ERR_FILE_NOT_FOUND;
}
file_t *file_new(uint16_t fid) {
file_t *f;
if ((f = search_dynamic_file(fid)))
return f;
if (dynamic_files == MAX_DYNAMIC_FILES)
return NULL;
f = &dynamic_file[dynamic_files];
dynamic_files++;
file_t file = {
.fid = fid,
.parent = 5,
.name = NULL,
.type = FILE_TYPE_WORKING_EF,
.ef_structure = FILE_EF_TRANSPARENT,
.data = NULL,
.acl = {0}
};
memcpy(f, &file, sizeof(file_t));
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
return f;
}
file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) {
if (search_file_chain(file->fid, *chain))
return NULL;
file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t));
fc->file = file;
fc->next = *chain;
*chain = fc;
return fc;
}
file_t *search_file_chain(uint16_t fid, file_chain_t *chain) {
for (file_chain_t *fc = chain; fc; fc = fc->next) {
if (fid == fc->file->fid) {
return fc->file;
}
}
return NULL;
}

105
src/fs/file.h Normal file
View File

@@ -0,0 +1,105 @@
#ifndef _FILE_H_
#define _FILE_H_
#include <stdlib.h>
#include "pico/stdlib.h"
#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
#define FILE_PERSISTENT 0x20
#define FILE_DATA_FLASH 0x40
#define FILE_DATA_FUNC 0x80
/* 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
#define ACL_OP_DELETE_SELF 0x00
#define ACL_OP_CREATE_DF 0x01
#define ACL_OP_CREATE_EF 0x02
#define ACL_OP_DELETE_CHILD 0x03
#define ACL_OP_WRITE 0x04
#define ACL_OP_UPDATE_ERASE 0x05
#define ACL_OP_READ_SEARCH 0x06
#define SPECIFY_EF 0x1
#define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3
#define EF_DKEK 0x108F
#define EF_PRKDFS 0x6040
#define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define MAX_DEPTH 4
typedef struct file
{
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 ef_structure;
uint8_t *data; //should include 2 bytes len at begining
const uint8_t acl[7];
} __attribute__((packed)) file_t;
typedef struct file_chain
{
file_t *file;
struct file_chain *next;
} file_chain_t;
extern file_t *currentEF;
extern file_t *currentDF;
extern const file_t *selected_applet;
extern const file_t *MF;
extern const file_t *file_last;
extern const file_t *file_openpgp;
extern const file_t *file_sc_hsm;
extern bool card_terminated;
extern file_t *file_pin1;
extern file_t *file_retries_pin1;
extern file_t *file_sopin;
extern file_t *file_retries_sopin;
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe);
extern void scan_flash();
extern void initialize_flash(bool);
extern file_t file_entries[];
extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const uint8_t *addr);
extern file_t *file_new(uint16_t);
file_t *get_parent(file_t *f);
extern uint16_t dynamic_files;
extern file_t dynamic_file[];
extern file_t *search_dynamic_file(uint16_t);
extern int delete_dynamic_file(file_t *f);
extern file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain);
extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain);
extern bool isUserAuthenticated;
#endif

125
src/fs/flash.c Normal file
View File

@@ -0,0 +1,125 @@
#include <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hsm2040.h"
#include "tusb.h"
#include "file.h"
#include "sc_hsm.h"
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
//To avoid possible future allocations, data region starts at the begining of flash and goes upwards to the center region
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE; //This is a fixed value. DO NOT CHANGE
#define FLASH_ADDR_DATA_STORAGE_START start_data_pool
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_uintptr(uintptr_t, uintptr_t);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern void low_flash_available();
/*
* Flash data pool managenent
*
* Flash data pool consists of two parts:
* 2-byte header
* contents
*
* Flash data pool objects:
* Data Object (DO) (of smart card)
* Internal objects:
* NONE (0x0000)
* 123-counter
* 14-bit counter
* bool object
* small enum
*
* Format of a Data Object:
* NR: 8-bit tag_number
* LEN: 8-bit length
* DATA: data * LEN
* PAD: optional byte for 16-bit alignment
*/
uintptr_t allocate_free_addr(uint16_t size) {
if (size > FLASH_SECTOR_SIZE)
return 0x0; //ERROR
size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t); //len+len size+next address+fid
uintptr_t next_base = 0x0;
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
uintptr_t potential_addr = base-real_size;
next_base = flash_read_uintptr(base);
//printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
if (next_base == 0x0) { //we are at the end
//now we check if we fit in the current sector
if (addr_alg <= potential_addr) //it fits in the current sector
{
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg-real_size;
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
return 0x0;
}
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked)
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
flash_program_uintptr(potential_addr, next_base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
}
return 0x0; //probably never reached
}
int flash_clear_file(file_t *file) {
uintptr_t prev_addr = (uintptr_t)(file->data+flash_read_uint16((uintptr_t)file->data)+sizeof(uint16_t));
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t));
uintptr_t next_addr = flash_read_uintptr(base_addr);
//printf("nc %x %x %x\r\n",prev_addr,base_addr,next_addr);
flash_program_uintptr(prev_addr, next_addr);
flash_program_halfword((uintptr_t)file->data, 0);
return 0;
}
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
if (!file)
return HSM_ERR_NULL_PARAM;
if (len > FLASH_SECTOR_SIZE)
return HSM_ERR_NO_MEMORY;
if (file->data) { //already in flash
uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data);
if (len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}
else { //we clear the old file
flash_clear_file(file);
}
}
uintptr_t new_addr = allocate_free_addr(len);
//printf("na %x\r\n",new_addr);
if (new_addr == 0x0)
return HSM_ERR_NO_MEMORY;
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t); //next addr+fid
flash_program_halfword(new_addr+sizeof(uintptr_t), file->fid);
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}

242
src/fs/low_flash.c Normal file
View File

@@ -0,0 +1,242 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "pico/multicore.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include <string.h>
#define TOTAL_FLASH_PAGES 4
typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE];
uintptr_t address;
bool ready;
bool erase;
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
} page_flash_t;
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash;
static semaphore_t sem_wait;
static uint8_t ready_pages = 0;
bool flash_available = false;
static bool locked_out = false;
//this function has to be called from the core 0
void do_flash()
{
if (mutex_try_enter(&mtx_flash, NULL) == true)
{
if (locked_out == true && flash_available == true && ready_pages > 0)
{
//printf(" DO_FLASH AVAILABLE\r\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if (flash_pages[r].ready == true)
{
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts (ints);
while (multicore_lockout_end_timeout_us(1000) == false);
//printf("WRITEN %X !\r\n",flash_pages[r].address);
flash_pages[r].ready = false;
ready_pages--;
}
else if (flash_pages[r].erase == true)
{
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING\r\n");
flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
while (multicore_lockout_end_timeout_us(1000) == false);
flash_pages[r].erase = false;
ready_pages--;
}
}
flash_available = false;
if (ready_pages != 0) {
DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES");
}
}
mutex_exit(&mtx_flash);
}
sem_release(&sem_wait);
}
//this function has to be called from the core 0
void low_flash_init()
{
mutex_init(&mtx_flash);
sem_init(&sem_wait, 0, 1);
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
}
void low_flash_init_core1() {
mutex_enter_blocking(&mtx_flash);
multicore_lockout_victim_init();
locked_out = true;
mutex_exit(&mtx_flash);
}
void wait_flash_finish() {
sem_acquire_blocking(&sem_wait); //blocks until released
//wake up
sem_acquire_blocking(&sem_wait); //decrease permits
}
void low_flash_available()
{
mutex_enter_blocking(&mtx_flash);
flash_available = true;
mutex_exit(&mtx_flash);
}
page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
{
p = &flash_pages[r];
if (!flash_pages[r].ready && !flash_pages[r].erase)
{
memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
ready_pages++;
p->address = addr_alg;
p->ready = true;
}
return p;
}
}
return NULL;
}
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
if (!data || len == 0)
return HSM_ERR_NULL_PARAM;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr)))
{
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash);
return HSM_ERR_MEMORY_FATAL;
}
memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
//printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr);
mutex_exit(&mtx_flash);
return HSM_OK;
}
int flash_program_halfword (uintptr_t addr, uint16_t data)
{
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
}
int flash_program_word (uintptr_t addr, uint32_t data)
{
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
}
int flash_program_uintptr (uintptr_t addr, uintptr_t data)
{
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
}
uint8_t *flash_read(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
//mutex_enter_blocking(&mtx_flash);
if (ready_pages > 0) {
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
//mutex_exit(&mtx_flash);
return v;
}
}
}
uint8_t *v = (uint8_t *)addr;
//mutex_exit(&mtx_flash);
return v;
}
uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uintptr_t v = 0x0;
for (int i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t)p[i]<<(8*i);
}
return v;
}
uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uint16_t v = 0x0;
for (int i = 0; i < sizeof(uint16_t); i++) {
v |= p[i]<<(8*i);
}
return v;
}
uint8_t flash_read_uint8(uintptr_t addr) {
return *flash_read(addr);
}
int flash_erase_page (uintptr_t addr, size_t page_size)
{
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr)))
{
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash);
return HSM_ERR_MEMORY_FATAL;
}
p->erase = true;
p->ready = false;
p->page_size = page_size;
mutex_exit(&mtx_flash);
return HSM_OK;
}
bool flash_check_blank (const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++)
if (*p != 0xff)
return false;
return true;
}