diff --git a/src/openpgp/files.c b/src/openpgp/files.c index 6fd335b..4a7f09c 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -39,6 +39,7 @@ 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); +extern int piv_parse_discovery(const file_t *f); uint8_t historical_bytes[] = { 10, 0, @@ -249,10 +250,233 @@ file_t file_entries[] = { /* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, + // ** PIV ** // + /* 57 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 58 */ { .fid = EF_PIV_ATTESTATION, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 59 */ { .fid = EF_PIV_MSCMAP, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 60 */ { .fid = EF_PIV_MSROOTS1, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 61 */ { .fid = EF_PIV_MSROOTS2, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 62 */ { .fid = EF_PIV_MSROOTS3, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 63 */ { .fid = EF_PIV_MSROOTS4, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 64 */ { .fid = EF_PIV_MSROOTS5, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 65 */ { .fid = EF_PIV_KEY_AUTHENTICATION, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 66 */ { .fid = EF_PIV_KEY_CARDMGM, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 67 */ { .fid = EF_PIV_KEY_SIGNATURE, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 68 */ { .fid = EF_PIV_KEY_KEYMGM, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 69 */ { .fid = EF_PIV_KEY_CARDAUTH, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 70 */ { .fid = EF_PIV_KEY_RETIRED1, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 71 */ { .fid = EF_PIV_KEY_RETIRED2, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 72 */ { .fid = EF_PIV_KEY_RETIRED3, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 73 */ { .fid = EF_PIV_KEY_RETIRED4, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 74 */ { .fid = EF_PIV_KEY_RETIRED5, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 75 */ { .fid = EF_PIV_KEY_RETIRED6, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 76 */ { .fid = EF_PIV_KEY_RETIRED7, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 77 */ { .fid = EF_PIV_KEY_RETIRED8, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 78 */ { .fid = EF_PIV_KEY_RETIRED9, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 79 */ { .fid = EF_PIV_KEY_RETIRED10, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 80 */ { .fid = EF_PIV_KEY_RETIRED11, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 81 */ { .fid = EF_PIV_KEY_RETIRED12, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 82 */ { .fid = EF_PIV_KEY_RETIRED12, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 83 */ { .fid = EF_PIV_KEY_RETIRED13, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 84 */ { .fid = EF_PIV_KEY_RETIRED14, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 85 */ { .fid = EF_PIV_KEY_RETIRED15, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 86 */ { .fid = EF_PIV_KEY_RETIRED16, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 87 */ { .fid = EF_PIV_KEY_RETIRED17, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 88 */ { .fid = EF_PIV_KEY_RETIRED18, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 89 */ { .fid = EF_PIV_KEY_RETIRED19, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 90 */ { .fid = EF_PIV_KEY_RETIRED20, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 91 */ { .fid = EF_PIV_KEY_ATTESTATION, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 92 */ { .fid = EF_PIV_CAPABILITY, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 93 */ { .fid = EF_PIV_CHUID, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 94 */ { .fid = EF_PIV_AUTHENTICATION, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 95 */ { .fid = EF_PIV_FINGERPRINTS, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 96 */ { .fid = EF_PIV_SECURITY, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 97 */ { .fid = EF_PIV_FACIAL, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 98 */ { .fid = EF_PIV_PRINTED, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 99 */ { .fid = EF_PIV_SIGNATURE, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 100 */ { .fid = EF_PIV_KEY_MANAGEMENT, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 101 */ { .fid = EF_PIV_CARD_AUTH, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 102 */ { .fid = EF_PIV_DISCOVERY, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) piv_parse_discovery, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 103 */ { .fid = EF_PIV_KEY_HISTORY, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 104 */ { .fid = EF_PIV_IRIS, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 105 */ { .fid = EF_PIV_BITGT, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 106 */ { .fid = EF_PIV_SM_SIGNER, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 107 */ { .fid = EF_PIV_PC_REF_DATA, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 108 */ { .fid = EF_PIV_RETIRED1, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 109 */ { .fid = EF_PIV_RETIRED2, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 110 */ { .fid = EF_PIV_RETIRED3, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 111 */ { .fid = EF_PIV_RETIRED4, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 112 */ { .fid = EF_PIV_RETIRED5, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 113 */ { .fid = EF_PIV_RETIRED6, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 114 */ { .fid = EF_PIV_RETIRED7, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 115 */ { .fid = EF_PIV_RETIRED8, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 116 */ { .fid = EF_PIV_RETIRED9, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 117 */ { .fid = EF_PIV_RETIRED10, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 118 */ { .fid = EF_PIV_RETIRED11, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 119 */ { .fid = EF_PIV_RETIRED12, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 120 */ { .fid = EF_PIV_RETIRED13, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 121 */ { .fid = EF_PIV_RETIRED14, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 122 */ { .fid = EF_PIV_RETIRED15, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 123 */ { .fid = EF_PIV_RETIRED16, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 124 */ { .fid = EF_PIV_RETIRED17, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 125 */ { .fid = EF_PIV_RETIRED18, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 126 */ { .fid = EF_PIV_RETIRED19, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 127 */ { .fid = EF_PIV_RETIRED20, .parent = 0, .name = NULL, + .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 128 */ { .fid = EF_PIV_PIN, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 129 */ { .fid = EF_PIV_PUK, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 130 */ { .fid = EF_META, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, - /* 57 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, + /* 131 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, - /* 58 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, + /* 132 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end }; diff --git a/src/openpgp/files.h b/src/openpgp/files.h index 1918927..207a599 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -81,4 +81,83 @@ #define EF_EXLEN_INFO 0x7f66 //C #define EF_GFM 0x7f74 //C +// PIV + +#define EF_PIV_PIN 0x1184 +#define EF_PIV_PUK 0x1185 + +#define EF_PIV_ADMIN_DATA 0xff00 +#define EF_PIV_ATTESTATION 0xff01 +#define EF_PIV_MSCMAP 0xff10 +#define EF_PIV_MSROOTS1 0xff11 +#define EF_PIV_MSROOTS2 0xff12 +#define EF_PIV_MSROOTS3 0xff13 +#define EF_PIV_MSROOTS4 0xff14 +#define EF_PIV_MSROOTS5 0xff15 + +#define EF_PIV_KEY_AUTHENTICATION 0x009a +#define EF_PIV_KEY_CARDMGM 0x009b +#define EF_PIV_KEY_SIGNATURE 0x009c +#define EF_PIV_KEY_KEYMGM 0x009d +#define EF_PIV_KEY_CARDAUTH 0x009e +#define EF_PIV_KEY_RETIRED1 0x0082 +#define EF_PIV_KEY_RETIRED2 0x0083 +#define EF_PIV_KEY_RETIRED3 0x0084 +#define EF_PIV_KEY_RETIRED4 0x0085 +#define EF_PIV_KEY_RETIRED5 0x0086 +#define EF_PIV_KEY_RETIRED6 0x0087 +#define EF_PIV_KEY_RETIRED7 0x0088 +#define EF_PIV_KEY_RETIRED8 0x0089 +#define EF_PIV_KEY_RETIRED9 0x008a +#define EF_PIV_KEY_RETIRED10 0x008b +#define EF_PIV_KEY_RETIRED11 0x008c +#define EF_PIV_KEY_RETIRED12 0x008d +#define EF_PIV_KEY_RETIRED13 0x008e +#define EF_PIV_KEY_RETIRED14 0x008f +#define EF_PIV_KEY_RETIRED15 0x0090 +#define EF_PIV_KEY_RETIRED16 0x0091 +#define EF_PIV_KEY_RETIRED17 0x0092 +#define EF_PIV_KEY_RETIRED18 0x0096 // It's 0x9e but assigned to EF_SIG_COUNT +#define EF_PIV_KEY_RETIRED19 0x0094 +#define EF_PIV_KEY_RETIRED20 0x0095 +#define EF_PIV_KEY_ATTESTATION 0x00fb // It's 0xf9 but assigned to EF_KDF + +#define EF_PIV_CAPABILITY 0xc107 +#define EF_PIV_CHUID 0xc102 +#define EF_PIV_AUTHENTICATION 0xc105 /* cert for 9a key */ +#define EF_PIV_FINGERPRINTS 0xc103 +#define EF_PIV_SECURITY 0xc106 +#define EF_PIV_FACIAL 0xc108 +#define EF_PIV_PRINTED 0xc109 +#define EF_PIV_SIGNATURE 0xc10a /* cert for 9c key */ +#define EF_PIV_KEY_MANAGEMENT 0xc10b /* cert for 9d key */ +#define EF_PIV_CARD_AUTH 0xc101 /* cert for 9e key */ +#define EF_PIV_DISCOVERY 0x007e +#define EF_PIV_KEY_HISTORY 0xc10c +#define EF_PIV_IRIS 0xc121 +#define EF_PIV_BITGT 0x7f61 +#define EF_PIV_SM_SIGNER 0xc122 +#define EF_PIV_PC_REF_DATA 0xc123 + +#define EF_PIV_RETIRED1 0xc10d +#define EF_PIV_RETIRED2 0xc10e +#define EF_PIV_RETIRED3 0xc10f +#define EF_PIV_RETIRED4 0xc110 +#define EF_PIV_RETIRED5 0xc111 +#define EF_PIV_RETIRED6 0xc112 +#define EF_PIV_RETIRED7 0xc113 +#define EF_PIV_RETIRED8 0xc114 +#define EF_PIV_RETIRED9 0xc115 +#define EF_PIV_RETIRED10 0xc116 +#define EF_PIV_RETIRED11 0xc117 +#define EF_PIV_RETIRED12 0xc118 +#define EF_PIV_RETIRED13 0xc119 +#define EF_PIV_RETIRED14 0xc11a +#define EF_PIV_RETIRED15 0xc11b +#define EF_PIV_RETIRED16 0xc11c +#define EF_PIV_RETIRED17 0xc11d +#define EF_PIV_RETIRED18 0xc11e +#define EF_PIV_RETIRED19 0xc11f +#define EF_PIV_RETIRED20 0xc120 + #endif diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index fb41029..b56734f 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -174,8 +174,32 @@ void scan_files() { memset((char *) ef->data + 12, 0, 4); #endif } - if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) { + bool reset_dek = false; + if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { if (!ef->data) { + printf("DEK is empty\r\n"); + const uint8_t def1[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + const uint8_t def3[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; + + uint8_t def[IV_SIZE + 32 + 32 + 32]; + const uint8_t *dek = random_bytes_get(IV_SIZE + 32); + memcpy(def, dek, IV_SIZE + 32); + memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); + memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); + hash_multi(def1, sizeof(def1), session_pw1); + aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); + memset(session_pw1, 0, sizeof(session_pw1)); + + hash_multi(def3, sizeof(def3), session_pw3); + aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32, 32); + aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); + memset(session_pw3, 0, sizeof(session_pw3)); + flash_write_data_to_file(ef, def, sizeof(def)); + reset_dek = true; + } + } + if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) { + if (!ef->data || reset_dek) { printf("PW1 is empty. Initializing with default password\r\n"); const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; uint8_t dhash[33]; @@ -185,7 +209,7 @@ void scan_files() { } } if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { - if (!ef->data) { + if (!ef->data || reset_dek) { printf("RC is empty. Initializing with default password\r\n"); const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; @@ -196,7 +220,7 @@ void scan_files() { } } if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { - if (!ef->data) { + if (!ef->data || reset_dek) { printf("PW3 is empty. Initializing with default password\r\n"); const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; @@ -220,28 +244,6 @@ void scan_files() { flash_write_data_to_file(ef, def, sizeof(def)); } } - if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { - if (!ef->data) { - printf("DEK is empty\r\n"); - const uint8_t def1[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; - const uint8_t def3[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; - - uint8_t def[IV_SIZE + 32 + 32 + 32]; - const uint8_t *dek = random_bytes_get(IV_SIZE + 32); - memcpy(def, dek, IV_SIZE + 32); - memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); - memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); - hash_multi(def1, sizeof(def1), session_pw1); - aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); - memset(session_pw1, 0, sizeof(session_pw1)); - - hash_multi(def3, sizeof(def3), session_pw3); - aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32, 32); - aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); - memset(session_pw3, 0, sizeof(session_pw3)); - flash_write_data_to_file(ef, def, sizeof(def)); - } - } if ((ef = search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) { if (!ef->data) { printf("UIF SIG is empty. Initializing to default\r\n"); @@ -281,8 +283,10 @@ void scan_files() { low_flash_available(); } +extern bool has_pwpiv; +extern uint8_t session_pwpiv[32]; int load_dek() { - if (!has_pw1 && !has_pw2 && !has_pw3) { + if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) { return CCID_NO_LOGIN; } file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); @@ -299,6 +303,11 @@ int load_dek() { memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32, 32); r = aes_decrypt_cfb_256(session_pw3, dek, dek + IV_SIZE, 32); } + else if (has_pwpiv) { + memcpy(dek, file_get_data(tf), IV_SIZE); + memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32 + 32, 32); + r = aes_decrypt_cfb_256(session_pwpiv, dek, dek + IV_SIZE, 32); + } if (r != 0) { return CCID_EXEC_ERROR; } @@ -578,14 +587,6 @@ int parse_pw_status(const file_t *f, int mode) { return res_APDU_size - init_len; } -#define ALGO_RSA 0x01 -#define ALGO_ECDH 0x12 -#define ALGO_ECDSA 0x13 -#define ALGO_AES 0x70 -#define ALGO_AES_128 0x71 -#define ALGO_AES_192 0x72 -#define ALGO_AES_256 0x74 - #define ALGO_RSA_1K 0 #define ALGO_RSA_2k 1 #define ALGO_RSA_3K 2 @@ -849,13 +850,13 @@ int pin_reset_retries(const file_t *pin, bool force) { if (!pw_status) { return CCID_ERR_FILE_NOT_FOUND; } - uint8_t p[7]; - memcpy(p, file_get_data(pw_status), 7); - uint8_t retries = p[3 + (pin->fid & 0x3)]; + uint8_t p[64]; + memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); + uint8_t retries = p[3 + (pin->fid & 0xf)]; if (retries == 0 && force == false) { //blocked return CCID_ERR_BLOCKED; } - p[3 + (pin->fid & 0x3)] = 3; + p[3 + (pin->fid & 0xf)] = 3; int r = flash_write_data_to_file(pw_status, p, file_get_size(pw_status)); low_flash_available(); return r; @@ -869,19 +870,19 @@ int pin_wrong_retry(const file_t *pin) { if (!pw_status) { return CCID_ERR_FILE_NOT_FOUND; } - uint8_t p[7]; - memcpy(p, file_get_data(pw_status), 7); - if (p[3 + (pin->fid & 0x3)] > 0) { - p[3 + (pin->fid & 0x3)] -= 1; + uint8_t p[64]; + memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); + if (p[3 + (pin->fid & 0xf)] > 0) { + p[3 + (pin->fid & 0xf)] -= 1; int r = flash_write_data_to_file(pw_status, p, file_get_size(pw_status)); if (r != CCID_OK) { return r; } low_flash_available(); - if (p[3 + (pin->fid & 0x3)] == 0) { + if (p[3 + (pin->fid & 0xf)] == 0) { return CCID_ERR_BLOCKED; } - return p[3 + (pin->fid & 0x3)]; + return p[3 + (pin->fid & 0xf)]; } return CCID_ERR_BLOCKED; } @@ -972,7 +973,7 @@ static int cmd_verify() { if (apdu.nc > 0) { return check_pin(pw, apdu.data, apdu.nc); } - uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0x3)); + uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf)); if (retries == 0) { return SW_PIN_BLOCKED(); } diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h index 07a4f94..990af8c 100644 --- a/src/openpgp/openpgp.h +++ b/src/openpgp/openpgp.h @@ -29,4 +29,14 @@ extern bool has_pw1; extern bool has_pw3; +extern int store_keys(void *key_ctx, int type, uint16_t key_id); + +#define ALGO_RSA 0x01 +#define ALGO_ECDH 0x12 +#define ALGO_ECDSA 0x13 +#define ALGO_AES 0x70 +#define ALGO_AES_128 0x71 +#define ALGO_AES_192 0x72 +#define ALGO_AES_256 0x74 + #endif diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c index 2b48376..aa19835 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -19,11 +19,27 @@ #include "files.h" #include "apdu.h" #include "pico_keys.h" +#include "random.h" #include "eac.h" +#include "crypto_utils.h" #include "version.h" +#ifndef ENABLE_EMULATION #include "pico/unique_id.h" +#endif +#include "asn1.h" +#include "mbedtls/ecdsa.h" +#include "mbedtls/rsa.h" +#include "mbedtls/aes.h" +#include "openpgp.h" -extern bool has_pw1; +#define PIV_ALGO_AES128 0x08 +#define PIV_ALGO_AES192 0x0a +#define PIV_ALGO_AES256 0x0c +#define PIV_ALGO_RSA1024 0x06 +#define PIV_ALGO_RSA2048 0x07 +#define PIV_ALGO_ECCP256 0x11 +#define PIV_ALGO_ECCP384 0x14 +#define PIV_ALGO_X25519 0xE1 uint8_t piv_aid[] = { 5, @@ -38,10 +54,145 @@ uint8_t mgmt_aid[] = { 0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 }; -int piv_process_apdu(); +bool has_pwpiv = false; +uint8_t session_pwpiv[32]; +int piv_process_apdu(); +/* +static int piv_generate_key(uint8_t key_ref, uint8_t algo) { + int r = CCID_OK; + if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256) { + size_t ksize = 0; + if (algo == PIV_ALGO_AES128) { + ksize = 16; + } + else if (algo == PIV_ALGO_AES192) { + ksize = 24; + } + else if (algo == PIV_ALGO_AES256) { + ksize = 32; + } + const uint8_t *key = random_bytes_get(ksize); + r = store_keys((uint8_t *)key, ALGO_AES, key_ref); + } + else if (algo == PIV_ALGO_RSA1024 || algo == PIV_ALGO_RSA2048) { + mbedtls_rsa_context rsa; + mbedtls_rsa_init(&rsa); + int exponent = 65537, nlen = 0; + if (algo == PIV_ALGO_RSA1024) { + nlen = 1024; + } + else if (algo == PIV_ALGO_RSA2048) { + nlen = 2048; + } + r = mbedtls_rsa_gen_key(&rsa, random_gen, NULL, nlen, exponent); + if (r != 0) { + mbedtls_rsa_free(&rsa); + return CCID_EXEC_ERROR; + } + r = store_keys(&rsa, ALGO_RSA, key_ref); + mbedtls_rsa_free(&rsa); + } + else if (algo == PIV_ALGO_ECCP256 || algo == PIV_ALGO_ECCP384 || algo == PIV_ALGO_X25519) { + mbedtls_ecdsa_context ecdsa; + mbedtls_ecdsa_init(&ecdsa); + mbedtls_ecp_group_id gid = MBEDTLS_ECP_DP_NONE; + if (algo == PIV_ALGO_ECCP256) { + gid = MBEDTLS_ECP_DP_SECP256R1; + } + else if (algo == PIV_ALGO_ECCP384) { + gid = MBEDTLS_ECP_DP_SECP384R1; + } + else if (algo == PIV_ALGO_X25519) { + gid = MBEDTLS_ECP_DP_CURVE25519; + } + r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, NULL); + if (r != 0) { + mbedtls_ecdsa_free(&ecdsa); + return CCID_EXEC_ERROR; + } + r = store_keys(&ecdsa, ALGO_ECDSA, key_ref); + mbedtls_ecdsa_free(&ecdsa); + } + if (r != CCID_OK) { + return CCID_ERR_NO_MEMORY; + } + uint8_t meta[] = { algo, 0, 0, 1 }; + if ((r = meta_add(key_ref, meta, sizeof(meta))) != CCID_OK) { + return r; + } + low_flash_available(); + return r; +} +*/ static void scan_files() { scan_flash(); + file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); + if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { + if (file_get_size(ef) == 0) { + printf("PW status is empty. Initializing to default\r\n"); + const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 }; + flash_write_data_to_file(ef, def, sizeof(def)); + } + else if (file_get_size(ef) == 7) { + printf("PW status is older. Initializing to default\r\n"); + uint8_t def[9] = { 0 }; + memcpy(def, file_get_data(ef), 7); + def[7] = def[8] = 3; // PIV retries + flash_write_data_to_file(ef, def, sizeof(def)); + } + } + bool reset_dek = false; + if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY)) || true) { + if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE+32*3 || true) { + printf("DEK is empty or older\r\n"); + const uint8_t defpin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + const uint8_t *dek = random_bytes_get(IV_SIZE + 32); + uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; + if (file_get_size(ef) > 0) { + memcpy(def, file_get_data(ef), file_get_size(ef)); + } + else { + memcpy(def, dek, IV_SIZE); + } + memcpy(def + IV_SIZE + 32*3, dek + IV_SIZE, 32); + hash_multi(defpin, sizeof(defpin), session_pwpiv); + aes_encrypt_cfb_256(session_pwpiv, def, def + IV_SIZE + 32*3, 32); + flash_write_data_to_file(ef, def, sizeof(def)); + + has_pwpiv = true; + uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"; + file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY); + flash_write_data_to_file(ef, key, 24); + uint8_t meta[] = { PIV_ALGO_AES192, 0, 0, 1 }; + meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta)); + has_pwpiv = false; + memset(session_pwpiv, 0, sizeof(session_pwpiv)); + + reset_dek = true; + } + } + if ((ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) { + if (!ef->data || reset_dek) { + printf("PIV PIN is empty. Initializing with default password\r\n"); + const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + uint8_t dhash[33]; + dhash[0] = sizeof(def); + double_hash_pin(def, sizeof(def), dhash + 1); + flash_write_data_to_file(ef, dhash, sizeof(dhash)); + } + } + if ((ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) { + if (!ef->data) { + printf("PIV PUK is empty. Initializing with default password\r\n"); + const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; + uint8_t dhash[33]; + dhash[0] = sizeof(def); + double_hash_pin(def, sizeof(def), dhash + 1); + flash_write_data_to_file(ef, dhash, sizeof(dhash)); + } + } + low_flash_available(); } void init_piv() { @@ -111,10 +262,20 @@ static int cmd_select() { return SW_OK(); } +int piv_parse_discovery(const file_t *ef) { + memcpy(res_APDU, "\x7E\x12\x4F\x0B\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00\x5F\x2F\x02\x40\x10", 20); + res_APDU_size = 20; + return res_APDU_size; +} + static int cmd_get_serial() { - pico_unique_board_id_t unique_id; - pico_get_unique_board_id(&unique_id); - memcpy(res_APDU, unique_id.id, 4); +#ifndef ENABLE_EMULATION + pico_unique_board_id_t unique_id; + pico_get_unique_board_id(&unique_id); + memcpy(res_APDU, unique_id.id, 4); +#else + memset(res_APDU, 0, 4); +#endif res_APDU_size = 4; return SW_OK(); } @@ -129,10 +290,7 @@ static int cmd_verify() { return SW_REFERENCE_NOT_FOUND(); } file_t *pw, *pw_status; - uint16_t fid = 0x0; - if (key_ref == 0x80) { - fid = EF_PW1; - } + uint16_t fid = EF_PIV_PIN; if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { return SW_REFERENCE_NOT_FOUND(); } @@ -143,29 +301,199 @@ static int cmd_verify() { return SW_REFERENCE_NOT_FOUND(); } if (apdu.nc > 0) { - return check_pin(pw, apdu.data, apdu.nc); + uint16_t ret = check_pin(pw, apdu.data, apdu.nc); + if (ret == 0x9000) { + has_pwpiv = true; + hash_multi(apdu.data, apdu.nc, session_pwpiv); + } + return ret; //SW already set } - uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0x3)); + uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf)); if (retries == 0) { return SW_PIN_BLOCKED(); } - if ((key_ref == 0x80 && has_pw1)) { + if ((key_ref == 0x80 && has_pwpiv)) { return SW_OK(); } return set_res_sw(0x63, 0xc0 | retries); } +static int cmd_get_data() { + if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { + return SW_INCORRECT_P1P2(); + } + if (apdu.data[0] != 0x5C || (apdu.data[1] & 0x80) || apdu.data[1] >= 4 || apdu.data[1] == 0) { + return SW_WRONG_DATA(); + } + uint32_t fid = apdu.data[2]; + for (uint8_t lt = 1; lt < apdu.data[1]; lt++) { + fid <<= 8; + fid |= apdu.data[2 + lt]; + } + if ((fid & 0xFFFF00) != 0x5FC100 && fid != EF_PIV_BITGT && fid != EF_PIV_DISCOVERY) { + return SW_REFERENCE_NOT_FOUND(); + } + file_t *ef = NULL; + if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) { + uint16_t data_len = 0; + res_APDU_size = 2; // Minimum: TAG+LEN + if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { + data_len = ((int (*)(const file_t *))(ef->data))((const file_t *) ef); + } + else { + if (ef->data) { + data_len = file_get_size(ef); + memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); + } + } + if (data_len > 255) { + memmove(res_APDU + res_APDU_size + 2, res_APDU + res_APDU_size, data_len); + } + else if (data_len > 127) { + memmove(res_APDU + res_APDU_size + 1, res_APDU + res_APDU_size, data_len); + } + res_APDU[0] = 0x53; + res_APDU_size = 1 + format_tlv_len(data_len, res_APDU + 1) + data_len; + } + return SW_OK(); +} + +static int cmd_get_metadata() { + if (P1(apdu) != 0x00) { + return SW_INCORRECT_P1P2(); + } + uint8_t *meta = NULL; + int meta_len = 0; + if ((meta_len = meta_find(P2(apdu), &meta)) <= 0) { + return SW_REFERENCE_NOT_FOUND(); + } + res_APDU[res_APDU_size++] = 0x1; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = meta[0]; + res_APDU[res_APDU_size++] = 0x2; + res_APDU[res_APDU_size++] = 2; + res_APDU[res_APDU_size++] = meta[1]; + res_APDU[res_APDU_size++] = meta[2]; + res_APDU[res_APDU_size++] = 0x3; + res_APDU[res_APDU_size++] = 1; + res_APDU[res_APDU_size++] = meta[3]; + return SW_OK(); +} +uint8_t challenge[16]; +bool has_challenge = false; +static int cmd_authenticate() { + uint8_t algo = P1(apdu), key_ref = P2(apdu); + if (apdu.nc == 0) { + return SW_WRONG_LENGTH(); + } + if (apdu.data[0] != 0x7C) { + return SW_WRONG_DATA(); + } + size_t t7c = 0; + uint8_t *c7c = NULL; + if (!asn1_find_tag(apdu.data, (uint16_t)apdu.nc, 0x7C, &t7c, &c7c) || t7c == 0 || c7c == NULL) { + return SW_WRONG_DATA(); + } + size_t t80 = 0, t81 = 0, t82 = 0; + uint8_t *c80 = NULL, *c81 = NULL, *c82 = NULL; + asn1_find_tag(c7c, t7c, 0x80, &t80, &c80); + asn1_find_tag(c7c, t7c, 0x81, &t81, &c81); + asn1_find_tag(c7c, t7c, 0x82, &t82, &c82); + if (c80) { + if (t80 == 0) { + memcpy(challenge, random_bytes_get(sizeof(challenge)), sizeof(challenge)); + if (algo == PIV_ALGO_AES128 || algo == PIV_ALGO_AES192 || algo == PIV_ALGO_AES256) { + if (key_ref != EF_PIV_KEY_CARDMGM) { + return SW_INCORRECT_P1P2(); + } + file_t *ef_mgm = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); + if (!file_has_data(ef_mgm)) { + return SW_MEMORY_FAILURE(); + } + uint16_t mgm_len = file_get_size(ef_mgm); + if ((algo == PIV_ALGO_AES128 && mgm_len != 16) || (algo == PIV_ALGO_AES192 && mgm_len != 24) || (algo == PIV_ALGO_AES256 && mgm_len != 32)) { + return SW_INCORRECT_P1P2(); + } + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + int r = mbedtls_aes_setkey_enc(&ctx, file_get_data(ef_mgm), mgm_len * 8); + if (r != 0) { + mbedtls_aes_free(&ctx); + return SW_EXEC_ERROR(); + } + res_APDU[res_APDU_size++] = 0x7C; + res_APDU[res_APDU_size++] = 10; + res_APDU[res_APDU_size++] = 0x80; + res_APDU[res_APDU_size++] = 16; + r = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, challenge, res_APDU + res_APDU_size); + res_APDU_size += 16; + mbedtls_aes_free(&ctx); + if (r != 0) { + return SW_EXEC_ERROR(); + } + } + has_challenge = true; + } + else { + if (!has_challenge) { + return SW_COMMAND_NOT_ALLOWED(); + } + if (sizeof(challenge) != t80 || memcmp(c80, challenge, t80) != 0) { + return SW_DATA_INVALID(); + } + if (!c81 || t81 == 0) { + return SW_INCORRECT_PARAMS(); + } + if (key_ref != EF_PIV_KEY_CARDMGM) { + return SW_INCORRECT_P1P2(); + } + file_t *ef_mgm = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); + if (!file_has_data(ef_mgm)) { + return SW_MEMORY_FAILURE(); + } + uint16_t mgm_len = file_get_size(ef_mgm); + if ((algo == PIV_ALGO_AES128 && mgm_len != 16) || (algo == PIV_ALGO_AES192 && mgm_len != 24) || (algo == PIV_ALGO_AES256 && mgm_len != 32)) { + return SW_INCORRECT_P1P2(); + } + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + int r = mbedtls_aes_setkey_enc(&ctx, file_get_data(ef_mgm), mgm_len * 8); + if (r != 0) { + mbedtls_aes_free(&ctx); + return SW_EXEC_ERROR(); + } + res_APDU[res_APDU_size++] = 0x7C; + res_APDU[res_APDU_size++] = 10; + res_APDU[res_APDU_size++] = 0x82; + res_APDU[res_APDU_size++] = 16; + r = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, c81, res_APDU + res_APDU_size); + res_APDU_size += 16; + mbedtls_aes_free(&ctx); + if (r != 0) { + return SW_EXEC_ERROR(); + } + } + } + return SW_OK(); +} + #define INS_VERIFY 0x20 #define INS_VERSION 0xFD #define INS_SELECT 0xA4 #define INS_YK_SERIAL 0xF8 #define INS_VERIFY 0x20 +#define INS_GET_DATA 0xCB +#define INS_GET_METADATA 0xF7 +#define INS_AUTHENTICATE 0x87 static const cmd_t cmds[] = { { INS_VERSION, cmd_version }, { INS_SELECT, cmd_select }, { INS_YK_SERIAL, cmd_get_serial }, { INS_VERIFY, cmd_verify }, + { INS_GET_DATA, cmd_get_data }, + { INS_GET_METADATA, cmd_get_metadata }, + { INS_AUTHENTICATE, cmd_authenticate }, { 0x00, 0x0 } };