diff --git a/pico-ccid b/pico-ccid index 16f23df..cddc3b2 160000 --- a/pico-ccid +++ b/pico-ccid @@ -1 +1 @@ -Subproject commit 16f23dfa6c458e027910d17b0ca0fa35e715cf9b +Subproject commit cddc3b2dec36a9e37145a2897d6735cbcf8a7384 diff --git a/src/openpgp/files.c b/src/openpgp/files.c index 6ef7814..bee84d8 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -30,7 +30,6 @@ extern const uint8_t openpgp_aid_full[]; 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); @@ -39,50 +38,100 @@ 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); +extern int parse_pw_status(const file_t *f, int mode); + +uint8_t historical_bytes[] = { + 10, 0, + 0x00, + 0x31, 0x84, /* Full DF name, GET DATA, MF */ + 0x73, + 0x80, 0x01, 0xC0, /* Full DF name */ + /* 1-byte */ + /* Command chaining, No extended Lc and Le */ + 0x00, + 0x90, 0x00 /* Status info */ +}; + +uint8_t extended_capabilities[] = { + 10, 0, + 0x74, /* + * No Secure Messaging supported + * GET CHALLENGE supported + * Key import supported + * PW status byte can be put + * No private_use_DO + * Algorithm attrs are changable + * No DEC with AES + * KDF-DO available + */ + 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ + 0x00, 128, /* Max size of GET CHALLENGE */ + 0x08, 0x00, /* max. length of cardholder certificate (2KiB) */ + 0x00, 0xff, + 0x00, 0x1 +}; + +uint8_t feature_mngmnt[] = { + 3, 0, + 0x81, 0x01, 0x20, +}; + +uint8_t exlen_info[] = { + 8,0, + 0x2, 0x2, 0x07, 0xff, + 0x2, 0x2, 0x08, 0x00, +}; file_t file_entries[] = { /* 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 }, + /* 1 */ { .fid = EF_FULL_AID, .parent = 0, .name = openpgp_aid_full, .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 }, + /* 7 */ { .fid = EF_HIST_BYTES, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = historical_bytes, .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 }, + /* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = feature_mngmnt, .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 }, + /* 14 */ { .fid = EF_EXT_CAP, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = extended_capabilities, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 15 */ { .fid = EF_ALGO_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_algoinfo, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 16 */ { .fid = EF_ALGO_DEC, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_algoinfo, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 17 */ { .fid = EF_ALGO_AUT, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_algoinfo, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 18 */ { .fid = EF_PW_STATUS, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *)parse_pw_status, .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 }, + /* 20 */ { .fid = EF_FP_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 }, + /* 24 */ { .fid = EF_FP_CA1, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 }, + /* 28 */ { .fid = EF_TS_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 32 */ { .fid = EF_UIF_SIG, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 | FILE_DATA_FLASH, .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 + /* 39 */ { .fid = EF_PW1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + /* 40 */ { .fid = EF_RC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + /* 41 */ { .fid = EF_PW3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + /* 42 */ { .fid = EF_PW1_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + /* 43 */ { .fid = EF_RC_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + /* 44 */ { .fid = EF_PW3_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, //PIN (PIN1) + + /* 45 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, + /* 46 */ { .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 f31ffa6..ad2ce0e 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -21,6 +21,13 @@ #include "file.h" +#define EF_PW1 0x1081 +#define EF_RC 0x1082 +#define EF_PW3 0x1083 +#define EF_PW1_RETRIES 0x1084 +#define EF_RC_RETRIES 0x1085 +#define EF_PW3_RETRIES 0x1086 + #define EF_EXT_HEADER 0x004d //C #define EF_FULL_AID 0x004f //S #define EF_CH_NAME 0x005b //S diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index 2834f5f..fb262b9 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -129,17 +129,65 @@ static int cmd_select() { } void scan_files() { + scan_flash(); 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); } + if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) { + if (!ef->data) { + TU_LOG1("PW1 is empty. Initializing with default password\r\n"); + const uint8_t empty[33] = { 0 }; + flash_write_data_to_file(ef, empty, sizeof(empty)); + + ef = search_by_fid(EF_PW1_RETRIES, NULL, SPECIFY_ANY); + if (ef && !ef->data) { + const uint8_t retries = 3; + flash_write_data_to_file(ef, &retries, sizeof(retries)); + } + } + } + if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { + if (!ef->data) { + TU_LOG1("RC is empty. Initializing with default password\r\n"); + const uint8_t empty[33] = { 0 }; + flash_write_data_to_file(ef, empty, sizeof(empty)); + + ef = search_by_fid(EF_RC_RETRIES, NULL, SPECIFY_ANY); + if (ef && !ef->data) { + const uint8_t retries = 3; + flash_write_data_to_file(ef, &retries, sizeof(retries)); + } + } + } + if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { + if (!ef->data) { + TU_LOG1("PW3 is empty. Initializing with default password\r\n"); + const uint8_t empty[33] = { 0 }; + flash_write_data_to_file(ef, empty, sizeof(empty)); + + ef = search_by_fid(EF_PW3_RETRIES, NULL, SPECIFY_ANY); + if (ef && !ef->data) { + const uint8_t retries = 3; + flash_write_data_to_file(ef, &retries, sizeof(retries)); + } + } + } + if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) { + if (!ef->data) { + TU_LOG1("SigCount is empty. Initializing to zero\r\n"); + const uint8_t def[3] = { 0 }; + flash_write_data_to_file(ef, def, sizeof(def)); + } + } + low_flash_available(); } void init_openpgp() { isUserAuthenticated = false; scan_files(); - cmd_select(); + //cmd_select(); } int openpgp_unload() { @@ -167,13 +215,17 @@ 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) { + printf("FID %x\r\n",fids[i+1]); + if ((ef = search_by_fid(fids[i+1], NULL, SPECIFY_EF))) { 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); + data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *)ef, mode); } else { - data_len = file_read_uint16(ef->data); + if (ef->data) + data_len = file_read_uint16(ef->data); + else + data_len = 0; if (mode == 1) { if (fids[0] > 1) { if (fids[i+1] < 0x0100) { @@ -183,9 +235,10 @@ int parse_do(uint16_t *fids, int mode) { 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); + res_APDU_size += format_tlv_len(data_len, res_APDU+res_APDU_size); } - memcpy(res_APDU+res_APDU_size, file_read(ef->data+2), data_len); + if (ef->data) + memcpy(res_APDU+res_APDU_size, file_read(ef->data+2), data_len); res_APDU_size += data_len; } } @@ -214,61 +267,223 @@ int parse_trium(uint16_t fid, uint8_t num, size_t size) { int parse_ch_data(const file_t *f, int mode) { uint16_t fids[] = { 3, - EF_CH_NAME, EF_LANG_PREF, EF_SEX + EF_CH_NAME, EF_LANG_PREF, EF_SEX, }; - return parse_do(fids, mode); + res_APDU[res_APDU_size++] = EF_CH_DATA & 0xff; + res_APDU[res_APDU_size++] = 0x82; + uint8_t *lp = res_APDU+res_APDU_size; + res_APDU_size += 2; + uint16_t data_len = parse_do(fids, mode); + uint16_t lpdif = res_APDU+res_APDU_size-lp-2; + *lp++ = lpdif >> 8; + *lp++ = lpdif & 0xff; + return lpdif+4; } int parse_sec_tpl(const file_t *f, int mode) { - + res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff; + res_APDU[res_APDU_size++] = 5; + file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); + if (ef && ef->data) { + res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff; + res_APDU[res_APDU_size++] = 3; + memcpy(res_APDU+res_APDU_size, file_read(ef->data+2), 3); + res_APDU_size += 3; + } + return 5+2; } 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) { - + return 0; } int parse_fp(const file_t *f, int mode) { + res_APDU[res_APDU_size++] = EF_FP & 0xff; + res_APDU[res_APDU_size++] = 60; return parse_trium(EF_FP_SIG, 3, 20); } int parse_cafp(const file_t *f, int mode) { + res_APDU[res_APDU_size++] = EF_CA_FP & 0xff; + res_APDU[res_APDU_size++] = 60; return parse_trium(EF_FP_CA1, 3, 20); } int parse_ts(const file_t *f, int mode) { + res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff; + res_APDU[res_APDU_size++] = 12; return parse_trium(EF_TS_SIG, 3, 4); } int parse_keyinfo(const file_t *f, int mode) { + int init_len = res_APDU_size; + if (res_APDU_size > 0) { + res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff; + res_APDU[res_APDU_size++] = 6; + } + res_APDU[res_APDU_size++] = 0x00; + res_APDU[res_APDU_size++] = 0x00; + res_APDU[res_APDU_size++] = 0x01; + res_APDU[res_APDU_size++] = 0x00; + + res_APDU[res_APDU_size++] = 0x02; + res_APDU[res_APDU_size++] = 0x00; + return res_APDU_size-init_len; +} + +int parse_pw_status(const file_t *f, int mode) { + file_t *ef; + int init_len = res_APDU_size; + if (res_APDU_size > 0) { + res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff; + res_APDU[res_APDU_size++] = 7; + } + res_APDU[res_APDU_size++] = 0x1; + res_APDU[res_APDU_size++] = 127; + res_APDU[res_APDU_size++] = 127; + res_APDU[res_APDU_size++] = 127; + ef = search_by_fid(EF_PW1_RETRIES, NULL, SPECIFY_ANY); + if (ef && ef->data) { + res_APDU[res_APDU_size++] = file_read_uint8(ef->data+2); + } + ef = search_by_fid(EF_RC_RETRIES, NULL, SPECIFY_ANY); + if (ef && ef->data) { + res_APDU[res_APDU_size++] = file_read_uint8(ef->data+2); + } + ef = search_by_fid(EF_PW3_RETRIES, NULL, SPECIFY_ANY); + if (ef && ef->data) { + res_APDU[res_APDU_size++] = file_read_uint8(ef->data+2); + } + return res_APDU_size-init_len; +} + +#define ALGO_RSA 0x01 +#define ALGO_ECDH 0x12 +#define ALGO_ECDSA 0x13 +#define ALGO_EDDSA 0x16 + +static const uint8_t algorithm_attr_ed448[] = { + 4, + ALGO_EDDSA, + /* OID of Ed448 */ + 0x2b, 0x65, 0x71 +}; + +static const uint8_t algorithm_attr_x448[] = { + 4, + ALGO_ECDH, + /* OID of X448 */ + 0x2b, 0x65, 0x6f +}; + +static const uint8_t algorithm_attr_rsa2k[] = { + 6, + ALGO_RSA, + 0x08, 0x00, /* Length modulus (in bit): 2048 */ + 0x00, 0x20, /* Length exponent (in bit): 32 */ + 0x00 /* 0: Acceptable format is: P and Q */ +}; + +static const uint8_t algorithm_attr_rsa4k[] = { + 6, + ALGO_RSA, + 0x10, 0x00, /* Length modulus (in bit): 4096 */ + 0x00, 0x20, /* Length exponent (in bit): 32 */ + 0x00 /* 0: Acceptable format is: P and Q */ +}; + +static const uint8_t algorithm_attr_p256k1[] = { + 6, + ALGO_ECDSA, + 0x2b, 0x81, 0x04, 0x00, 0x0a /* OID of curve secp256k1 */ +}; + +static const uint8_t algorithm_attr_ed25519[] = { + 10, + ALGO_EDDSA, + /* OID of the curve Ed25519 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 +}; + +static const uint8_t algorithm_attr_cv25519[] = { + 11, + ALGO_ECDH, + /* OID of the curve Curve25519 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 +}; + +int parse_algo(const uint8_t *algo, uint16_t tag) { + res_APDU[res_APDU_size++] = tag & 0xff; + memcpy(res_APDU+res_APDU_size, algo, algo[0]+1); + res_APDU_size += algo[0]+1; + return algo[0]+2; } int parse_algoinfo(const file_t *f, int mode) { - + uint8_t *lp = NULL; + uint8_t datalen = 0; + if (f->fid == EF_ALGO_INFO) { + res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff; + uint8_t *lp = res_APDU+res_APDU_size; + res_APDU_size++; + } + if (f->fid == EF_ALGO_INFO || f->fid == EF_ALGO_SIG) { + datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_SIG); + datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_SIG); + datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_SIG); + datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_SIG); + datalen += parse_algo(algorithm_attr_ed448, EF_ALGO_SIG); + } + if (f->fid == EF_ALGO_INFO || f->fid == EF_ALGO_DEC) { + datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_DEC); + datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_DEC); + datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_DEC); + datalen += parse_algo(algorithm_attr_cv25519, EF_ALGO_DEC); + datalen += parse_algo(algorithm_attr_x448, EF_ALGO_DEC); + } + if (f->fid == EF_ALGO_INFO || f->fid == EF_ALGO_AUT) { + datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_AUT); + datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_AUT); + datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_AUT); + datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_AUT); + datalen += parse_algo(algorithm_attr_ed448, EF_ALGO_AUT); + } + if (lp) + *lp = res_APDU+res_APDU_size-lp-1; + return lp ? *lp+2 : datalen; } 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 + 6, + EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO }; - return parse_do(fids, mode); + res_APDU[res_APDU_size++] = EF_APP_DATA & 0xff; + res_APDU[res_APDU_size++] = 0x82; + uint8_t *lp = res_APDU+res_APDU_size; + res_APDU_size += 2; + uint16_t data_len = parse_do(fids, mode); + uint16_t lpdif = res_APDU+res_APDU_size-lp-2; + *lp++ = lpdif >> 8; + *lp++ = lpdif & 0xff; + return lpdif+4; } 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 + 8, + 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); + res_APDU[res_APDU_size++] = EF_DISCRETE_DO & 0xff; + res_APDU[res_APDU_size++] = 0x82; + uint8_t *lp = res_APDU+res_APDU_size; + res_APDU_size += 2; + uint16_t data_len = parse_do(fids, mode); + uint16_t lpdif = res_APDU+res_APDU_size-lp-2; + *lp++ = lpdif >> 8; + *lp++ = lpdif & 0xff; + return lpdif+4; } @@ -288,7 +503,6 @@ static int cmd_get_data() { if (apdu.expected_res_size > data_len) apdu.expected_res_size = data_len; } - return SW_OK(); } diff --git a/src/openpgp/version.h b/src/openpgp/version.h index ff791f8..c53ae74 100644 --- a/src/openpgp/version.h +++ b/src/openpgp/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define OPGP_VERSION 0x0100 +#define OPGP_VERSION 0x0304 #define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff) #define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)