diff --git a/src/openpgp/files.c b/src/openpgp/files.c index cef4281..6ef7814 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -18,10 +18,71 @@ #include "files.h" extern const uint8_t openpgp_aid[]; +extern const uint8_t openpgp_aid_full[]; + +#define ACL_NONE {0xff,0xff,0xff,0xff,0xff,0xff,0xff} +#define ACL_ALL {0} +#define ACL_RO {0xff,0xff,0xff,0xff,0xff,0xff,0x00} +#define ACL_RW {0xff,0xff,0xff,0xff,0x00,0x00,0x00} +#define ACL_R_WP {0xff,0xff,0xff,0xff,0x90,0x90,0x00} +#define ACL_WP {0xff,0xff,0xff,0xff,0x90,0x90,0xff} + +extern int parse_ch_data(const file_t *f, int mode); +extern int parse_sec_tpl(const file_t *f, int mode); +extern int parse_ch_cert(const file_t *f, int mode); +extern int parse_exlen_info(const file_t *f, int mode); +extern int parse_gfm(const file_t *f, int mode); +extern int parse_fp(const file_t *f, int mode); +extern int parse_cafp(const file_t *f, int mode); +extern int parse_ts(const file_t *f, int mode); +extern int parse_keyinfo(const file_t *f, int mode); +extern int parse_algoinfo(const file_t *f, int mode); +extern int parse_app_data(const file_t *f, int mode); +extern int parse_discrete_do(const file_t *f, int mode); file_t file_entries[] = { - { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - /* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end + /* 0 */ { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = ACL_NONE }, // MF + /* 1 */ { .fid = EF_FULL_AID, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = (uint8_t *)openpgp_aid_full, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 2 */ { .fid = EF_CH_NAME, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 3 */ { .fid = EF_LOGIN_DATA, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 4 */ { .fid = EF_LANG_PREF, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 5 */ { .fid = EF_SEX, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 6 */ { .fid = EF_URI_URL, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 7 */ { .fid = EF_HIST_BYTES, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 8 */ { .fid = EF_CH_DATA, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_ch_data, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 9 */ { .fid = EF_SEC_TPL, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_sec_tpl, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 10 */ { .fid = EF_CH_CERT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_ch_cert, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_gfm, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 13 */ { .fid = EF_SIG_COUNT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 14 */ { .fid = EF_EXT_CAP, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 15 */ { .fid = EF_ALGO_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 16 */ { .fid = EF_ALGO_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 17 */ { .fid = EF_ALGO_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 18 */ { .fid = EF_PW_STATUS, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 19 */ { .fid = EF_FP, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_fp, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 20 */ { .fid = EF_FP_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 21 */ { .fid = EF_FP_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 22 */ { .fid = EF_FP_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 23 */ { .fid = EF_CA_FP, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_cafp, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 24 */ { .fid = EF_FP_CA1, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 25 */ { .fid = EF_FP_CA2, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 26 */ { .fid = EF_FP_CA3, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 27 */ { .fid = EF_TS_ALL, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_ts, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 28 */ { .fid = EF_TS_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 29 */ { .fid = EF_TS_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 30 */ { .fid = EF_TS_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 31 */ { .fid = EF_RESET_CODE, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 32 */ { .fid = EF_UIF_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 33 */ { .fid = EF_UIF_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 34 */ { .fid = EF_UIF_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 35 */ { .fid = EF_KEY_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_keyinfo, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 36 */ { .fid = EF_ALGO_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_algoinfo, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 37 */ { .fid = EF_APP_DATA, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_app_data, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 38 */ { .fid = EF_DISCRETE_DO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_discrete_do, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + + /* 39 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 40 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end }; const file_t *MF = &file_entries[0]; diff --git a/src/openpgp/files.h b/src/openpgp/files.h index cd8cd16..f31ffa6 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -21,4 +21,44 @@ #include "file.h" +#define EF_EXT_HEADER 0x004d //C +#define EF_FULL_AID 0x004f //S +#define EF_CH_NAME 0x005b //S +#define EF_LOGIN_DATA 0x005e //S +#define EF_CH_DATA 0x0065 //C +#define EF_APP_DATA 0x006e //C +#define EF_DISCRETE_DO 0x0073 //C +#define EF_SEC_TPL 0x007a //C +#define EF_SIG_COUNT 0x0093 //S +#define EF_EXT_CAP 0x00c0 //S +#define EF_ALGO_SIG 0x00c1 //S +#define EF_ALGO_DEC 0x00c2 //S +#define EF_ALGO_AUT 0x00c3 //S +#define EF_PW_STATUS 0x00c4 //S +#define EF_FP 0x00c5 //S +#define EF_CA_FP 0x00c6 //S +#define EF_FP_SIG 0x00c7 //S +#define EF_FP_DEC 0x00c8 //S +#define EF_FP_AUT 0x00c9 //S +#define EF_FP_CA1 0x00ca //S +#define EF_FP_CA2 0x00cb //S +#define EF_FP_CA3 0x00cc //S +#define EF_TS_ALL 0x00cd //S +#define EF_TS_SIG 0x00ce //S +#define EF_TS_DEC 0x00cf //S +#define EF_TS_AUT 0x00d0 //S +#define EF_RESET_CODE 0x00d3 //S +#define EF_UIF_SIG 0x00d6 //S +#define EF_UIF_DEC 0x00d7 //S +#define EF_UIF_AUT 0x00d8 //S +#define EF_KEY_INFO 0x00de //S +#define EF_ALGO_INFO 0x00fa //C +#define EF_LANG_PREF 0x5f2d //S +#define EF_SEX 0x5f35 //S +#define EF_URI_URL 0x5f50 //S +#define EF_HIST_BYTES 0x5f52 //S +#define EF_CH_CERT 0x7f21 //C +#define EF_EXLEN_INFO 0x7f66 //C +#define EF_GFM 0x7f74 //C + #endif diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index a557afe..2834f5f 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -17,11 +17,18 @@ #include "openpgp.h" #include "version.h" +#include "files.h" #include "eac.h" -const uint8_t openpgp_aid[] = { +uint8_t openpgp_aid[] = { 6, - 0xD2,0x76,0x00,0x01,0x24,0x01 + 0xD2,0x76,0x00,0x01,0x24,0x01, +}; + +uint8_t openpgp_aid_full[] = { + 16,00, + 0xD2,0x76,0x00,0x01,0x24,0x01, + OPGP_VERSION_MAJOR,OPGP_VERSION_MINOR,0xff,0xfe,0xff,0xff,0xff,0xff,0x00,0x00 }; char atr_openpgp[] = { @@ -121,8 +128,17 @@ static int cmd_select() { return SW_OK (); } +void scan_files() { + file_t *ef; + if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) { + ef->data = openpgp_aid_full; + pico_get_unique_board_id_string(ef->data+12, 4); + } +} + void init_openpgp() { isUserAuthenticated = false; + scan_files(); cmd_select(); } @@ -132,11 +148,7 @@ int openpgp_unload() { } app_t *openpgp_select_aid(app_t *a) { - printf("AIDS \r\n"); - DEBUG_PAYLOAD(apdu.cmd_apdu_data,apdu.cmd_apdu_data_len); - DEBUG_PAYLOAD(openpgp_aid+1,openpgp_aid[0]); - if (!memcmp(apdu.cmd_apdu_data, openpgp_aid+1, MIN(apdu.cmd_apdu_data_len,openpgp_aid[0]))) { - printf("SELECTING OPENPGP\r\n"); + if (!memcmp(apdu.cmd_apdu_data, openpgp_aid+1, openpgp_aid[0])) { a->aid = openpgp_aid; a->process_apdu = openpgp_process_apdu; a->unload = openpgp_unload; @@ -151,13 +163,147 @@ void __attribute__ ((constructor)) openpgp_ctor() { register_app(openpgp_select_aid); } +int parse_do(uint16_t *fids, int mode) { + int len = 0; + file_t *ef; + for (int i = 0; i < fids[0]; i++) { + if ((ef = search_by_fid(fids[i+1], NULL, SPECIFY_EF)) && ef->data) { + uint16_t data_len; + if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { + data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *)ef, 1); + } + else { + data_len = file_read_uint16(ef->data); + if (mode == 1) { + if (fids[0] > 1) { + if (fids[i+1] < 0x0100) { + res_APDU[res_APDU_size++] = fids[i+1] & 0xff; + } + else { + res_APDU[res_APDU_size++] = fids[i+1] >> 8; + res_APDU[res_APDU_size++] = fids[i+1] & 0xff; + } + res_APDU_size += format_tlv_len(data_len, res_APDU); + } + memcpy(res_APDU+res_APDU_size, file_read(ef->data+2), data_len); + res_APDU_size += data_len; + } + } + len += data_len; + } + } + return len; +} + +int parse_trium(uint16_t fid, uint8_t num, size_t size) { + for (uint8_t i = 0; i < num; i++) { + file_t *ef; + if ((ef = search_by_fid(fid+i, NULL, SPECIFY_EF)) && ef->data) { + uint16_t data_len = file_read_uint16(ef->data); + memcpy(res_APDU+res_APDU_size, file_read(ef->data+2), data_len); + res_APDU_size += data_len; + } + else { + memset(res_APDU+res_APDU_size, 0, size); + res_APDU_size += size; + } + } + return num*size; +} + +int parse_ch_data(const file_t *f, int mode) { + uint16_t fids[] = { + 3, + EF_CH_NAME, EF_LANG_PREF, EF_SEX + }; + return parse_do(fids, mode); +} + +int parse_sec_tpl(const file_t *f, int mode) { + +} + +int parse_ch_cert(const file_t *f, int mode) { + +} + +int parse_exlen_info(const file_t *f, int mode) { + +} + +int parse_gfm(const file_t *f, int mode) { + +} + +int parse_fp(const file_t *f, int mode) { + return parse_trium(EF_FP_SIG, 3, 20); +} + +int parse_cafp(const file_t *f, int mode) { + return parse_trium(EF_FP_CA1, 3, 20); +} + +int parse_ts(const file_t *f, int mode) { + return parse_trium(EF_TS_SIG, 3, 4); +} + +int parse_keyinfo(const file_t *f, int mode) { + +} + +int parse_algoinfo(const file_t *f, int mode) { + +} + +int parse_app_data(const file_t *f, int mode) { + uint16_t fids[] = { + 5, + EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO + }; + return parse_do(fids, mode); +} + +int parse_discrete_do(const file_t *f, int mode) { + uint16_t fids[] = { + 11, + EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL, EF_UIF_SIG, EF_UIF_DEC, EF_UIF_AUT + }; + return parse_do(fids, mode); +} + + +static int cmd_get_data() { + if (apdu.cmd_apdu_data_len > 0) + return SW_WRONG_LENGTH(); + uint16_t fid = (P1(apdu) << 8) | P2(apdu); + file_t *ef; + if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) + return SW_FILE_NOT_FOUND(); + if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { + return SW_SECURITY_STATUS_NOT_SATISFIED(); + } + if (ef->data) { + uint16_t fids[] = {1,fid}; + uint16_t data_len = parse_do(fids, 1); + if (apdu.expected_res_size > data_len) + apdu.expected_res_size = data_len; + } + + return SW_OK(); +} + typedef struct cmd { uint8_t ins; int (*cmd_handler)(); } cmd_t; +#define INS_SELECT 0xA4 +#define INS_GET_DATA 0xCA + static const cmd_t cmds[] = { + { INS_GET_DATA, cmd_get_data }, + { INS_SELECT, cmd_select }, { 0x00, 0x0} };