From 5a7f1dd7815b993f156d6d1c65752fbb799ae491 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 1 Apr 2026 16:39:16 +0200 Subject: [PATCH] Migrate to the new PIN KDF system. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 5 + pico-keys-sdk | 2 +- src/openpgp/CMakeLists.txt | 3 + src/openpgp/cmd_change_pin.c | 41 +-- src/openpgp/cmd_put_data.c | 17 +- src/openpgp/cmd_reset_retry.c | 23 +- src/openpgp/files.c | 473 +++++++++++++++++----------------- src/openpgp/files.h | 4 + src/openpgp/openpgp.c | 300 +++++++++++++++------ src/openpgp/openpgp.h | 6 + src/openpgp/piv.c | 81 +++--- tests/build-in-docker.sh | 2 +- 12 files changed, 561 insertions(+), 396 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 168b4f9..a5171d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ cmake_minimum_required(VERSION 3.13) +option(OPENPGP_TEST_INIT_LEGACY_PIN "Bootstrap legacy PIN/DEK format for migration tests" OFF) + set(USB_VID 0x2E8A) set(USB_PID 0x10FF) @@ -88,6 +90,9 @@ set(INCLUDES ${INCLUDES} if(NOT ESP_PLATFORM) target_sources(pico_openpgp PUBLIC ${SOURCES}) target_include_directories(pico_openpgp PUBLIC ${INCLUDES}) + if(OPENPGP_TEST_INIT_LEGACY_PIN) + target_compile_definitions(pico_openpgp PRIVATE OPENPGP_TEST_INIT_LEGACY_PIN=1) + endif() set(COMMON_COMPILE_OPTIONS -Wall diff --git a/pico-keys-sdk b/pico-keys-sdk index 8aad7bd..f76bc63 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 8aad7bdef9103f0c2abb4ececffa29928d489403 +Subproject commit f76bc631d2c7d469cb3752333daddb05f783739e diff --git a/src/openpgp/CMakeLists.txt b/src/openpgp/CMakeLists.txt index b5a83a6..81bd76c 100644 --- a/src/openpgp/CMakeLists.txt +++ b/src/openpgp/CMakeLists.txt @@ -3,4 +3,7 @@ idf_component_register( INCLUDE_DIRS . REQUIRES mbedtls efuse pico-keys-sdk ) +if(OPENPGP_TEST_INIT_LEGACY_PIN) + target_compile_definitions(${COMPONENT_LIB} PRIVATE OPENPGP_TEST_INIT_LEGACY_PIN=1) +endif() idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) diff --git a/src/openpgp/cmd_change_pin.c b/src/openpgp/cmd_change_pin.c index c29bf68..16cef6f 100644 --- a/src/openpgp/cmd_change_pin.c +++ b/src/openpgp/cmd_change_pin.c @@ -37,33 +37,34 @@ int cmd_change_pin(void) { return SW_EXEC_ERROR(); } - if (otp_key_1) { - for (int i = 0; i < 32; i++) { - dek[IV_SIZE + i] ^= otp_key_1[i]; - } - } - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = apdu.nc - pin_len; - double_hash_pin(apdu.data + pin_len, apdu.nc - pin_len, dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(apdu.data + pin_len, apdu.nc - pin_len, dhash + 2); file_put_data(pw, dhash, sizeof(dhash)); - file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); - if (!tf) { - return SW_REFERENCE_NOT_FOUND(); - } - uint8_t def[IV_SIZE + 32 + 32 + 32 + 32] = {0}; - memcpy(def, file_get_data(tf), file_get_size(tf)); if (P2(apdu) == 0x81) { - hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1); - memcpy(def + IV_SIZE, dek + IV_SIZE, 32); - aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); + file_t *tf = search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF); + if (!tf) { + return SW_REFERENCE_NOT_FOUND(); + } + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x3; + pin_derive_session(apdu.data + pin_len, apdu.nc - pin_len, session_pw1); + encrypt_with_aad(session_pw1, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); + r = file_put_data(tf, def, sizeof(def)); } else if (P2(apdu) == 0x83) { - hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3); - memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); - aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); + file_t *tf = search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF); + if (!tf) { + return SW_REFERENCE_NOT_FOUND(); + } + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x3; + pin_derive_session(apdu.data + pin_len, apdu.nc - pin_len, session_pw3); + encrypt_with_aad(session_pw3, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); + r = file_put_data(tf, def, sizeof(def)); } - file_put_data(tf, def, sizeof(def)); low_flash_available(); return SW_OK(); } diff --git a/src/openpgp/cmd_put_data.c b/src/openpgp/cmd_put_data.c index 3767766..13b6595 100644 --- a/src/openpgp/cmd_put_data.c +++ b/src/openpgp/cmd_put_data.c @@ -53,20 +53,21 @@ int cmd_put_data(void) { if ((r = load_dek()) != PICOKEY_OK) { return SW_EXEC_ERROR(); } - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = apdu.nc; - double_hash_pin(apdu.data, apdu.nc, dhash + 1); - r = file_put_data(ef, dhash, sizeof(dhash)); + dhash[1] = 0x1; // Format + pin_derive_verifier(apdu.data, apdu.nc, dhash + 2); + file_put_data(ef, dhash, sizeof(dhash)); file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); if (!tf) { return SW_REFERENCE_NOT_FOUND(); } - uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; - memcpy(def, file_get_data(tf), file_get_size(tf)); - hash_multi(apdu.data, apdu.nc, session_rc); - memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); - aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32); + + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x3; + pin_derive_session(apdu.data, apdu.nc, session_rc); + encrypt_with_aad(session_rc, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); r = file_put_data(tf, def, sizeof(def)); } else { diff --git a/src/openpgp/cmd_reset_retry.c b/src/openpgp/cmd_reset_retry.c index 4f4b2f9..9f21285 100644 --- a/src/openpgp/cmd_reset_retry.c +++ b/src/openpgp/cmd_reset_retry.c @@ -44,7 +44,7 @@ int cmd_reset_retry(void) { } newpin_len = apdu.nc - pin_len; has_rc = true; - hash_multi(apdu.data, pin_len, session_rc); + pin_derive_session(apdu.data, pin_len, session_rc); has_pw1 = has_pw3 = false; isUserAuthenticated = false; } @@ -58,25 +58,20 @@ int cmd_reset_retry(void) { if ((r = load_dek()) != PICOKEY_OK) { return SW_EXEC_ERROR(); } - file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); + file_t *tf = search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF); if (!tf) { return SW_REFERENCE_NOT_FOUND(); } - if (otp_key_1) { - for (int i = 0; i < 32; i++) { - dek[IV_SIZE + i] ^= otp_key_1[i]; - } - } - uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; - memcpy(def, file_get_data(tf), file_get_size(tf)); - hash_multi(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pw1); - memcpy(def + IV_SIZE, dek + IV_SIZE, 32); - aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x03; + pin_derive_session(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pw1); + encrypt_with_aad(session_pw1, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); r = file_put_data(tf, def, sizeof(def)); - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = newpin_len; - double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 2); file_put_data(pw, dhash, sizeof(dhash)); if (pin_reset_retries(pw, true) != PICOKEY_OK) { return SW_MEMORY_FAILURE(); diff --git a/src/openpgp/files.c b/src/openpgp/files.c index 2eca01d..e4f8b51 100644 --- a/src/openpgp/files.c +++ b/src/openpgp/files.c @@ -20,13 +20,6 @@ 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); @@ -250,251 +243,263 @@ 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_RETIRED13, .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_RETIRED14, .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_RETIRED15, .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_RETIRED16, .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_RETIRED17, .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_RETIRED18, .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_RETIRED19, .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_RETIRED20, .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_ATTESTATION, .parent = 0, .name = NULL, - .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, - .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, - /* 91 */ { .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 }, - /* 92 */ { .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 }, - /* 93 */ { .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 }, - /* 94 */ { .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 }, - /* 95 */ { .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 }, - /* 96 */ { .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 }, - /* 97 */ { .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 }, - /* 98 */ { .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 }, - /* 99 */ { .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 }, - /* 100 */ { .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 }, - /* 101 */ { .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 }, - /* 102 */ { .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 }, - /* 103 */ { .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 }, - /* 104 */ { .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 }, - /* 105 */ { .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 }, - /* 106 */ { .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 }, - /* 107 */ { .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 }, - /* 108 */ { .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 }, - /* 109 */ { .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 }, - /* 110 */ { .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 }, - /* 111 */ { .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 }, - /* 112 */ { .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 }, - /* 113 */ { .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 }, - /* 114 */ { .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 }, - /* 115 */ { .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 }, - /* 116 */ { .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 }, - /* 117 */ { .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 }, - /* 118 */ { .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 }, - /* 119 */ { .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 }, - /* 120 */ { .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 }, - /* 121 */ { .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 }, - /* 122 */ { .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 }, - /* 123 */ { .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 }, - /* 124 */ { .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 }, - /* 125 */ { .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 }, - /* 126 */ { .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 }, - /* 127 */ { .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 }, - /* 128 */ { .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 }, - /* 129 */ { .fid = EF_META, .parent = 0, .name = NULL, + /* 57 */ { .fid = EF_DEK_PW1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, - /* 130 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL, + /* 58 */ { .fid = EF_DEK_RC, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, + /* 59 */ { .fid = EF_DEK_PW3, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, + // ** PIV ** // + /* 60 */ { .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 }, - /* 131 */ { .fid = EF_PRIV_DO_1, .parent = 0, .name = NULL, + /* 61 */ { .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 }, - /* 132 */ { .fid = EF_PRIV_DO_2, .parent = 0, .name = NULL, + /* 62 */ { .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 }, - /* 133 */ { .fid = EF_PRIV_DO_3, .parent = 0, .name = NULL, + /* 63 */ { .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 }, + /* 64 */ { .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 }, + /* 65 */ { .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 }, + /* 66 */ { .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 }, + /* 67 */ { .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 }, + /* 68 */ { .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 }, + /* 69 */ { .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 }, + /* 70 */ { .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 }, + /* 71 */ { .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 }, + /* 72 */ { .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 }, + /* 73 */ { .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 }, + /* 74 */ { .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 }, + /* 75 */ { .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 }, + /* 76 */ { .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 }, + /* 77 */ { .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 }, + /* 78 */ { .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 }, + /* 79 */ { .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 }, + /* 80 */ { .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 }, + /* 81 */ { .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 }, + /* 82 */ { .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 }, + /* 83 */ { .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 }, + /* 84 */ { .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 }, + /* 85 */ { .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 }, + /* 86 */ { .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 }, + /* 87 */ { .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 }, + /* 88 */ { .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 }, + /* 89 */ { .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 }, + /* 90 */ { .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 }, + /* 91 */ { .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 }, + /* 92 */ { .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 }, + /* 93 */ { .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 }, - /* 134 */ { .fid = EF_PRIV_DO_4, .parent = 0, .name = NULL, + /* 94 */ { .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 }, + /* 95 */ { .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 }, + /* 96 */ { .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 }, + /* 97 */ { .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 }, + /* 98 */ { .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 }, + /* 99 */ { .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 }, + /* 100 */ { .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 }, + /* 101 */ { .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 }, + /* 102 */ { .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 }, + /* 103 */ { .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 }, + /* 104 */ { .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 }, + /* 105 */ { .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 }, + /* 106 */ { .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 }, + /* 107 */ { .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 }, + /* 108 */ { .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 }, + /* 109 */ { .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 }, + /* 110 */ { .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 }, + /* 111 */ { .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 }, + /* 112 */ { .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 }, + /* 113 */ { .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 }, + /* 114 */ { .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 }, + /* 115 */ { .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 }, + /* 116 */ { .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 }, + /* 117 */ { .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 }, + /* 118 */ { .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 }, + /* 119 */ { .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 }, + /* 120 */ { .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 }, + /* 121 */ { .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 }, + /* 122 */ { .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 }, + /* 123 */ { .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 }, + /* 124 */ { .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 }, + /* 125 */ { .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 }, + /* 126 */ { .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 }, + /* 127 */ { .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 }, + /* 128 */ { .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 }, + /* 129 */ { .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 }, + /* 130 */ { .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 }, - /* 135 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL, + /* 131 */ { .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 }, + /* 132 */ { .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 }, + /* 133 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, - /* 136 */ { .fid = EF_PW_STATUS, .parent = 0, .name = NULL, + /* 134 */ { .fid = EF_PRIV_DO_1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 135 */ { .fid = EF_PRIV_DO_2, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 136 */ { .fid = EF_PRIV_DO_3, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 137 */ { .fid = EF_PRIV_DO_4, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP }, + /* 138 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 139 */ { .fid = EF_PW_STATUS, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, + /* 140 */ { .fid = EF_DEK_PWPIV, .parent = 0, .name = NULL, + .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, + .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, - /* 137 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, + /* 141 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, - /* 138 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, + /* 142 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end }; diff --git a/src/openpgp/files.h b/src/openpgp/files.h index 629a161..ffa3211 100644 --- a/src/openpgp/files.h +++ b/src/openpgp/files.h @@ -36,6 +36,10 @@ #define EF_PB_DEC 0x10d5 #define EF_PB_AUT 0x10d6 #define EF_DEK 0x1099 +#define EF_DEK_PW1 0x109a +#define EF_DEK_RC 0x109b +#define EF_DEK_PW3 0x109c +#define EF_DEK_PWPIV 0x109d #define EF_CH_1 0x1f21 #define EF_CH_2 0x1f22 #define EF_CH_3 0x1f23 diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c index 2b36c02..3f591d2 100644 --- a/src/openpgp/openpgp.c +++ b/src/openpgp/openpgp.c @@ -41,7 +41,7 @@ bool has_rc = false; uint8_t session_pw1[32]; uint8_t session_rc[32]; uint8_t session_pw3[32]; -uint8_t dek[IV_SIZE + 32]; +uint8_t dek[DEK_SIZE]; uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC, pk_aut = EF_PK_AUT; uint8_t openpgp_aid[] = { @@ -107,37 +107,64 @@ void scan_files_openpgp(void) { memcpy(ef->data + 12, pico_serial.id, 4); } 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 }; + bool bootstrap_legacy = false; + file_t *ef_dek = search_by_fid(EF_DEK, NULL, SPECIFY_ANY), *ef_dek_pw1 = search_by_fid(EF_DEK_PW1, NULL, SPECIFY_ANY), *ef_dek_rc = search_by_fid(EF_DEK_RC, NULL, SPECIFY_ANY), *ef_dek_pw3 = search_by_fid(EF_DEK_PW3, NULL, SPECIFY_ANY); + if (!file_has_data(ef_dek_pw1) && !file_has_data(ef_dek_rc) && !file_has_data(ef_dek_pw3) && !file_has_data(ef_dek)) { + printf("DEK are empty\r\n"); + const uint8_t *random_dek = random_bytes_get(DEK_SIZE); + const uint8_t def1[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36}; + const uint8_t def3[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; +#ifdef OPENPGP_TEST_INIT_LEGACY_PIN + /* Test hook: bootstrap legacy PIN+DEK format to validate runtime migration paths. */ - uint8_t def[IV_SIZE + 32 + 32 + 32]; - const uint8_t *random_dek = random_bytes_get(IV_SIZE + 32); - memcpy(def, random_dek, IV_SIZE + 32); - memcpy(def + IV_SIZE + 32, random_dek + IV_SIZE, 32); - memcpy(def + IV_SIZE + 32 + 32, random_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)); + uint8_t def[IV_SIZE + 32 + 32 + 32]; + memcpy(def, random_dek, IV_SIZE + 32); + memcpy(def + IV_SIZE + 32, random_dek + IV_SIZE, 32); + memcpy(def + IV_SIZE + 32 + 32, random_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)); - file_put_data(ef, def, sizeof(def)); - reset_dek = true; - } + 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)); + file_put_data(ef_dek, def, sizeof(def)); + bootstrap_legacy = true; +#else + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x3; // Format + + pin_derive_session(def1, sizeof(def1), session_pw1); + encrypt_with_aad(session_pw1, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); + mbedtls_platform_zeroize(session_pw1, sizeof(session_pw1)); + file_put_data(ef_dek_pw1, def, sizeof(def)); + + pin_derive_session(def3, sizeof(def3), session_pw3); + encrypt_with_aad(session_pw3, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); + mbedtls_platform_zeroize(session_pw3, sizeof(session_pw3)); + file_put_data(ef_dek_rc, def, sizeof(def)); + file_put_data(ef_dek_pw3, def, sizeof(def)); +#endif + + 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]; - dhash[0] = sizeof(def); - double_hash_pin(def, sizeof(def), dhash + 1); - file_put_data(ef, dhash, sizeof(dhash)); + uint8_t dhash[34]; + if (bootstrap_legacy) { + dhash[0] = sizeof(def); + double_hash_pin(def, sizeof(def), dhash + 1); + file_put_data(ef, dhash, 33); + } + else { + dhash[0] = sizeof(def); + dhash[1] = 0x1; // Format + pin_derive_verifier(def, sizeof(def), dhash + 2); + file_put_data(ef, dhash, sizeof(dhash)); + } } } if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { @@ -145,10 +172,18 @@ void scan_files_openpgp(void) { printf("RC 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); - file_put_data(ef, dhash, sizeof(dhash)); + uint8_t dhash[34]; + if (bootstrap_legacy) { + dhash[0] = sizeof(def); + double_hash_pin(def, sizeof(def), dhash + 1); + file_put_data(ef, dhash, 33); + } + else { + dhash[0] = sizeof(def); + dhash[1] = 0x1; // Format + pin_derive_verifier(def, sizeof(def), dhash + 2); + file_put_data(ef, dhash, sizeof(dhash)); + } } } if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { @@ -156,10 +191,18 @@ void scan_files_openpgp(void) { printf("PW3 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); - file_put_data(ef, dhash, sizeof(dhash)); + uint8_t dhash[34]; + if (bootstrap_legacy) { + dhash[0] = sizeof(def); + double_hash_pin(def, sizeof(def), dhash + 1); + file_put_data(ef, dhash, 33); + } + else { + dhash[0] = sizeof(def); + dhash[1] = 0x1; // Format + pin_derive_verifier(def, sizeof(def), dhash + 2); + file_put_data(ef, dhash, sizeof(dhash)); + } } } if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) { @@ -231,34 +274,77 @@ int load_dek(void) { if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) { return PICOKEY_NO_LOGIN; } - file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); - if (!tf) { - return PICOKEY_ERR_FILE_NOT_FOUND; - } int r = PICOKEY_OK; + if (has_pw1 || has_pw2) { - memcpy(dek, file_get_data(tf), IV_SIZE + 32); - r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32); + file_t *ef_dek_pw1 = search_file(EF_DEK_PW1); + if (file_has_data(ef_dek_pw1)) { + uint8_t *ef_data = file_get_data(ef_dek_pw1); + if (ef_data[0] == 0x3) { // Format + r = decrypt_with_aad(session_pw1, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek); + } + else { + return PICOKEY_ERR_NULL_PARAM; + } + } + else { + file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); + if (!tf) { + return PICOKEY_ERR_FILE_NOT_FOUND; + } + + memcpy(dek, file_get_data(tf), IV_SIZE + 32); + r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32); + } } else if (has_pw3) { - memcpy(dek, file_get_data(tf), IV_SIZE); - 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); + file_t *ef_dek_pw3 = search_file(EF_DEK_PW3); + if (file_has_data(ef_dek_pw3)) { + uint8_t *ef_data = file_get_data(ef_dek_pw3); + if (ef_data[0] == 0x3) { // Format + r = decrypt_with_aad(session_pw3, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek); + } + else { + return PICOKEY_ERR_NULL_PARAM; + } + } + else { + file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); + if (!tf) { + return PICOKEY_ERR_FILE_NOT_FOUND; + } + + memcpy(dek, file_get_data(tf), IV_SIZE); + 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); + file_t *ef_dek_pwpiv = search_file(EF_DEK_PWPIV); + if (file_has_data(ef_dek_pwpiv)) { + uint8_t *ef_data = file_get_data(ef_dek_pwpiv); + if (ef_data[0] == 0x3) { // Format + r = decrypt_with_aad(session_pwpiv, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek); + } + else { + return PICOKEY_ERR_NULL_PARAM; + } + } + else { + file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); + if (!tf) { + return PICOKEY_ERR_FILE_NOT_FOUND; + } + + 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) { release_dek(); return PICOKEY_EXEC_ERROR; } - if (otp_key_1) { - for (int i = 0; i < 32; i++) { - dek[IV_SIZE + i] ^= otp_key_1[i]; - } - } return PICOKEY_OK; } @@ -389,21 +475,24 @@ static int pin_wrong_retry(const file_t *pin) { } int check_pin(const file_t *pin, const uint8_t *data, size_t len) { - if (!pin) { - return SW_REFERENCE_NOT_FOUND(); - } - if (!pin->data) { + if (!file_has_data(pin)) { return SW_REFERENCE_NOT_FOUND(); } isUserAuthenticated = false; //has_pw1 = has_pw3 = false; - uint8_t dhash[32]; - double_hash_pin(data, len, dhash); - if (sizeof(dhash) != file_get_size(pin) - 1) { //1 byte for pin len + uint8_t dhash[32], off = 2; + if (file_get_size(pin) == 33) { + off = 1; + double_hash_pin(data, len, dhash); + } + else { + pin_derive_verifier(data, len, dhash); + } + if (sizeof(dhash) != file_get_size(pin) - off) { //1 byte for pin len and 1 byte for format return SW_CONDITIONS_NOT_SATISFIED(); } - if (memcmp(file_get_data(pin) + 1, dhash, sizeof(dhash)) != 0) { + if (memcmp(file_get_data(pin) + off, dhash, sizeof(dhash)) != 0) { int retries; if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) { return SW_PIN_BLOCKED(); @@ -418,6 +507,75 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { if (r != PICOKEY_OK) { return SW_MEMORY_FAILURE(); } + if (off == 1) { + uint8_t pin_data[34], *pin_sp = NULL; + pin_data[0] = len; + pin_data[1] = 0x1; // Format + pin_derive_verifier(data, len, pin_data + 2); + file_put_data((file_t *)pin, pin_data, sizeof(pin_data)); + has_pw1 = has_pw2 = has_pw3 = false; + + if (pin->fid == EF_PW1) { + if (P2(apdu) == 0x81) { + has_pw1 = true; + } + else { + has_pw2 = true; + } + pin_sp = session_pw1; + } + else if (pin->fid == EF_PW3) { + has_pw3 = true; + pin_sp = session_pw3; + } + else if (pin->fid == EF_PIV_PIN) { + has_pwpiv = true; + pin_sp = session_pwpiv; + } + if (pin_sp) { + hash_multi(data, len, pin_sp); + r = load_dek(); + if (r != PICOKEY_OK) { + return SW_EXEC_ERROR(); + } + uint8_t old_data[DEK_FILE_SIZE_OLD], ef_data[DEK_FILE_SIZE]; + file_t *ef_dek_pw = NULL; + if (has_pw1 || has_pw2) { + ef_dek_pw = search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF); + } + else if (has_pw3) { + ef_dek_pw = search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF); + } + else if (has_pwpiv) { + ef_dek_pw = search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_EF); + } + if (!ef_dek_pw) { + return PICOKEY_ERR_FILE_NOT_FOUND; + } + ef_data[0] = 0x3; // Format + pin_derive_session(data, len, pin_sp); + encrypt_with_aad(pin_sp, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, ef_data + 1); + file_put_data(ef_dek_pw, ef_data, sizeof(ef_data)); + + file_t *ef_dek = search_by_fid(EF_DEK, NULL, SPECIFY_EF); + if (!ef_dek) { + return PICOKEY_ERR_FILE_NOT_FOUND; + } + memcpy(old_data, file_get_data(ef_dek), sizeof(old_data)); + if (has_pw1 || has_pw2) { + memset(old_data + IV_SIZE, 0, 32); + } + else if (has_pw3) { + memset(old_data + IV_SIZE + 32 + 32, 0, 32); + } + else if (has_pwpiv) { + memset(old_data + IV_SIZE + 32 + 32 + 32, 0, 32); + } + file_put_data(ef_dek, old_data, sizeof(old_data)); + low_flash_available(); + } + has_pw1 = has_pw2 = has_pw3 = false; + } isUserAuthenticated = true; if (pin->fid == EF_PW1) { if (P2(apdu) == 0x81) { @@ -426,11 +584,11 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { else { has_pw2 = true; } - hash_multi(data, len, session_pw1); + pin_derive_session(data, len, session_pw1); } else if (pin->fid == EF_PW3) { has_pw3 = true; - hash_multi(data, len, session_pw3); + pin_derive_session(data, len, session_pw3); } return SW_OK(); } @@ -658,12 +816,7 @@ void make_rsa_response(mbedtls_rsa_context *rsa) { void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) { uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN]; size_t plen = 0; - mbedtls_ecp_point_write_binary(&ecdsa->grp, - &ecdsa->Q, - MBEDTLS_ECP_PF_UNCOMPRESSED, - &plen, - pt, - sizeof(pt)); + mbedtls_ecp_point_write_binary(&ecdsa->grp, &ecdsa->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt)); res_APDU[res_APDU_size++] = 0x7f; res_APDU[res_APDU_size++] = 0x49; if (plen >= 128) { @@ -679,18 +832,13 @@ void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) { res_APDU_size += plen; } -int rsa_sign(mbedtls_rsa_context *ctx, - const uint8_t *data, - size_t data_len, - uint8_t *out, - size_t *out_len) { +int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) { uint8_t *d = (uint8_t *) data, *end = d + data_len, *hsh = NULL; size_t seq_len = 0, hash_len = 0; size_t key_size = ctx->len; int r = 0; mbedtls_md_type_t md = MBEDTLS_MD_NONE; - if (mbedtls_asn1_get_tag(&d, end, &seq_len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) { + if (mbedtls_asn1_get_tag(&d, end, &seq_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) { mbedtls_asn1_buf mdb; r = mbedtls_asn1_get_alg_null(&d, end, &mdb); if (r == 0) { @@ -749,11 +897,7 @@ int rsa_sign(mbedtls_rsa_context *ctx, return r; } -int ecdsa_sign(mbedtls_ecp_keypair *ctx, - const uint8_t *data, - size_t data_len, - uint8_t *out, - size_t *out_len) { +int ecdsa_sign(mbedtls_ecp_keypair *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) { int r = 0; #ifdef MBEDTLS_EDDSA_C diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h index 79e39b3..0486f0c 100644 --- a/src/openpgp/openpgp.h +++ b/src/openpgp/openpgp.h @@ -98,4 +98,10 @@ int cmd_keypair_gen(void); int cmd_reset_retry(void); int cmd_get_bulk_data(void); +#define DEK_SIZE (IV_SIZE + 32) +#define DEK_AAD_SIZE (PIN_KDF_SIZE(DEK_SIZE)) +#define DEK_FILE_SIZE (1 + DEK_AAD_SIZE) + +#define DEK_FILE_SIZE_OLD (IV_SIZE + 32 + 32 + 32 + 32) + #endif diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c index 2004067..350c480 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -197,42 +197,35 @@ static void scan_files_piv(void) { } } bool reset_dek = false; - if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { - if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE+32*3) { - printf("DEK is empty or older\r\n"); - const uint8_t defpin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; - const uint8_t *random_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, random_dek, IV_SIZE); - } - memcpy(def + IV_SIZE + 32*3, random_dek + IV_SIZE, 32); - hash_multi(defpin, sizeof(defpin), session_pwpiv); - aes_encrypt_cfb_256(session_pwpiv, def, def + IV_SIZE + 32*3, 32); - file_put_data(ef, def, sizeof(def)); + if ((ef = search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_ANY)) && !file_has_data(ef)) { + printf("DEK PIV is empty or older\r\n"); + const uint8_t defpin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; + const uint8_t *random_dek = random_bytes_get(IV_SIZE + 32); - 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_cardmgm = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY); - file_put_data(ef_cardmgm, key, 24); - uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS }; - meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta)); - has_pwpiv = false; - memset(session_pwpiv, 0, sizeof(session_pwpiv)); + uint8_t def[DEK_FILE_SIZE]; + def[0] = 0x3; // Format - reset_dek = true; - } + pin_derive_session(defpin, sizeof(defpin), session_pwpiv); + encrypt_with_aad(session_pwpiv, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1); + mbedtls_platform_zeroize(session_pwpiv, sizeof(session_pwpiv)); + file_put_data(ef, def, sizeof(def)); + + 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_cardmgm = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY); + file_put_data(ef_cardmgm, key, 24); + uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS }; + meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta)); + + 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[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = sizeof(def); - double_hash_pin(def, sizeof(def), dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(def, sizeof(def), dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); } } @@ -240,9 +233,10 @@ static void scan_files_piv(void) { 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]; + uint8_t dhash[34]; dhash[0] = sizeof(def); - double_hash_pin(def, sizeof(def), dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(def, sizeof(def), dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); } } @@ -531,15 +525,16 @@ static int cmd_get_metadata(void) { uint8_t dhash[32]; int32_t eq = 0; if (key_ref == EF_PIV_PIN) { - double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash); + pin_derive_verifier((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); } else if (key_ref == EF_PIV_PUK) { - double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash); + pin_derive_verifier((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); } else if (key_ref == EF_PIV_KEY_CARDMGM) { - eq = memcmp("\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_get_data(ef_key), file_get_size(ef_key)); + pin_derive_verifier((const 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", 24, dhash); + eq = memcmp(dhash, file_get_data(ef_key), file_get_size(ef_key)); } res_APDU[res_APDU_size++] = 0x5; res_APDU[res_APDU_size++] = 1; @@ -1133,9 +1128,11 @@ static int cmd_piv_change_pin(void) { if (ret != 0x9000) { return ret; } - uint8_t dhash[33]; + + uint8_t dhash[34]; dhash[0] = pin_len; - double_hash_pin(apdu.data + pin_data[0], pin_len, dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(apdu.data + pin_data[0], pin_len, dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); low_flash_available(); return SW_OK(); @@ -1154,9 +1151,10 @@ static int cmd_piv_reset_retry(void) { if (ret != 0x9000) { return ret; } - uint8_t dhash[33]; + uint8_t dhash[34]; dhash[0] = pin_len; - double_hash_pin(apdu.data + puk_data[0], pin_len, dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(apdu.data + puk_data[0], pin_len, dhash + 2); ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); file_put_data(ef, dhash, sizeof(dhash)); pin_reset_retries(ef, true); @@ -1178,16 +1176,19 @@ static int cmd_set_retries(void) { ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); const uint8_t def_pin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; - uint8_t dhash[33]; + + uint8_t dhash[34]; dhash[0] = sizeof(def_pin); - double_hash_pin(def_pin, sizeof(def_pin), dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(def_pin, sizeof(def_pin), dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); pin_reset_retries(ef, true); ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); const uint8_t def_puk[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; dhash[0] = sizeof(def_puk); - double_hash_pin(def_puk, sizeof(def_puk), dhash + 1); + dhash[1] = 0x1; // Format + pin_derive_verifier(def_puk, sizeof(def_puk), dhash + 2); file_put_data(ef, dhash, sizeof(dhash)); pin_reset_retries(ef, true); diff --git a/tests/build-in-docker.sh b/tests/build-in-docker.sh index 79c31f1..2813475 100755 --- a/tests/build-in-docker.sh +++ b/tests/build-in-docker.sh @@ -3,5 +3,5 @@ source tests/docker_env.sh #run_in_docker rm -rf CMakeFiles run_in_docker mkdir -p build_in_docker -run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 .. +run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 -DOPENPGP_TEST_INIT_LEGACY_PIN=ON .. run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}