26 Commits

Author SHA1 Message Date
Pol Henarejos
994553bfd7 Fix pico build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-02 12:05:49 +02:00
Pol Henarejos
328c3112ac Use ecp keypair calc public instead.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 21:04:15 +02:00
Pol Henarejos
5ce888b75b Use dynamic dependence resolver.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:50:40 +02:00
Pol Henarejos
1ef40f5826 Upgrade PicoKeys SDK
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 18:53:13 +02:00
Pol Henarejos
d9193129c7 Upgrade to v4.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-08 16:29:38 +02:00
Pol Henarejos
402c92ea83 Upgrade Pico Keys SDK 8.6 and MbedTLS v3.6.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 20:04:37 +02:00
Pol Henarejos
ac1e3af410 Fix include.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 19:58:14 +02:00
Pol Henarejos
5a7f1dd781 Migrate to the new PIN KDF system.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-01 16:39:16 +02:00
Pol Henarejos
a0f8d67821 Apply strict build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-09 12:18:18 +01:00
Pol Henarejos
757a000f77 Update pico keys sdk.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 18:05:33 +01:00
Pol Henarejos
4fba684a24 Fix duplicated file entry.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 18:05:20 +01:00
Pol Henarejos
0b7beeec8c Introduce GET BULK DATA to execute GET DATA in multiple DO with a single APDU.
It saves considerable bandwidth since only one APDU/RAPDU are transmitted.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 18:30:50 +01:00
Pol Henarejos
1f037da326 Do no parse flash data as TLV.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:57:59 +01:00
Pol Henarejos
ffbdef14b6 Set rollback globally to avoid incompatibilities.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:50:32 +01:00
Pol Henarejos
ad59aa8c1a Fixed ACL for EF_CHR_CERT.
Fixes #51.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:52:49 +01:00
Pol Henarejos
fcca95715e Fixed a bug allowing to write without PW3.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:52:19 +01:00
Pol Henarejos
704df76499 DO is cleared when no data is provided.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:38:52 +01:00
Pol Henarejos
e6cc190c4f Do not interpret private DO as TLV.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:29:59 +01:00
Pol Henarejos
615737807a Add support for private DO.
Closes #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-17 16:46:03 +01:00
Pol Henarejos
e563bb3379 Fixed pw2 verify persistence.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-17 16:45:49 +01:00
Pol Henarejos
374cff588c Fix secure boot enable.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 16:31:12 +01:00
Pol Henarejos
ca8d81fd20 Fix key rotation. Now also rotates cert & metadata.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 01:32:47 +01:00
Pol Henarejos
5d71e69c1d Do not allow slot move from retired to active.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:52:25 +01:00
Pol Henarejos
75691b6a42 Fix crash when attestating.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:46:58 +01:00
Pol Henarejos
811f33e282 Fix extension set in attestation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:46:26 +01:00
Pol Henarejos
90b62f067d Add support for HIGH/LOW ESP32 LED
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-04 23:47:07 +01:00
32 changed files with 1275 additions and 823 deletions

View File

@@ -17,6 +17,8 @@
cmake_minimum_required(VERSION 3.13) 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_VID 0x2E8A)
set(USB_PID 0x10FF) set(USB_PID 0x10FF)
@@ -46,10 +48,10 @@ endif()
set(USB_ITF_CCID 1) set(USB_ITF_CCID 1)
set(USB_ITF_WCID 1) set(USB_ITF_WCID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake) include(pico-keys-sdk/picokeys_sdk_import.cmake)
if(NOT ESP_PLATFORM) if(NOT ESP_PLATFORM)
set(SOURCES ${PICO_KEYS_SOURCES}) set(SOURCES ${PICOKEYS_SOURCES})
endif() endif()
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
@@ -76,7 +78,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/defs.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/defs.c
) )
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h" 3) SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h")
if(ESP_PLATFORM) if(ESP_PLATFORM)
project(pico_openpgp) project(pico_openpgp)
@@ -88,14 +90,27 @@ set(INCLUDES ${INCLUDES}
if(NOT ESP_PLATFORM) if(NOT ESP_PLATFORM)
target_sources(pico_openpgp PUBLIC ${SOURCES}) target_sources(pico_openpgp PUBLIC ${SOURCES})
target_include_directories(pico_openpgp PUBLIC ${INCLUDES}) 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()
target_compile_options(pico_openpgp PUBLIC set(COMMON_COMPILE_OPTIONS
-Wall -Wall
) )
if(NOT MSVC) target_compile_options(pico_openpgp PRIVATE ${COMMON_COMPILE_OPTIONS})
target_compile_options(pico_openpgp PUBLIC
-Werror picokeys_apply_strict_flags(
SOURCES ${SOURCES}
FILTER_REGEX "/src/openpgp/|/pico-keys-sdk/src/|/pico-keys-sdk/config/"
) )
if(NOT MSVC)
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
if(${COMPILER_COLON} GREATER_EQUAL 0)
target_compile_options(pico_openpgp PRIVATE
-Wno-error=use-after-free
)
endif()
endif() endif()
if(ENABLE_EMULATION) if(ENABLE_EMULATION)
@@ -120,7 +135,7 @@ if(NOT ESP_PLATFORM)
-Wl,--gc-sections -Wl,--gc-sections
) )
endif(APPLE) endif(APPLE)
target_link_libraries(pico_openpgp PRIVATE pico_keys_sdk mbedtls pthread m) target_link_libraries(pico_openpgp PRIVATE picokeys_sdk mbedtls pthread m)
else() else()
pico_add_extra_outputs(${CMAKE_PROJECT_NAME}) pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif() endif()

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="4" VERSION_MAJOR="4"
VERSION_MINOR="4" VERSION_MINOR="6"
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then #if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}" # SUFFIX="${SUFFIX}.${GITHUB_SHA}"

View File

@@ -3,4 +3,7 @@ idf_component_register(
INCLUDE_DIRS . INCLUDE_DIRS .
REQUIRES mbedtls efuse pico-keys-sdk 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) idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -17,6 +17,6 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_activate_file() { int cmd_activate_file(void) {
return SW_OK(); return SW_OK();
} }

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "random.h" #include "random.h"
int cmd_challenge() { int cmd_challenge(void) {
uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne); uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
if (!rb) { if (!rb) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();

View File

@@ -18,13 +18,13 @@
#include "openpgp.h" #include "openpgp.h"
#include "otp.h" #include "otp.h"
int cmd_change_pin() { int cmd_change_pin(void) {
if (P1(apdu) != 0x0) { if (P1(apdu) != 0x0) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
uint16_t fid = 0x1000 | P2(apdu); uint16_t fid = 0x1000 | P2(apdu);
file_t *pw; file_t *pw;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t pin_len = file_get_data(pw)[0]; uint8_t pin_len = file_get_data(pw)[0];
@@ -33,37 +33,38 @@ int cmd_change_pin() {
if (r != 0x9000) { if (r != 0x9000) {
return r; return r;
} }
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (otp_key_1) { uint8_t dhash[34];
for (int i = 0; i < 32; i++) {
dek[IV_SIZE + i] ^= otp_key_1[i];
}
}
uint8_t dhash[33];
dhash[0] = apdu.nc - pin_len; 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_put_data(pw, dhash, sizeof(dhash));
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); if (P2(apdu) == 0x81) {
file_t *tf = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
if (!tf) { if (!tf) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32] = {0}; uint8_t def[DEK_FILE_SIZE];
memcpy(def, file_get_data(tf), file_get_size(tf)); def[0] = 0x3;
if (P2(apdu) == 0x81) { pin_derive_session(apdu.data + pin_len, apdu.nc - pin_len, session_pw1);
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1); encrypt_with_aad(session_pw1, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
memcpy(def + IV_SIZE, dek + IV_SIZE, 32); r = file_put_data(tf, def, sizeof(def));
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
} }
else if (P2(apdu) == 0x83) { else if (P2(apdu) == 0x83) {
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3); file_t *tf = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF);
memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); if (!tf) {
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); return SW_REFERENCE_NOT_FOUND();
} }
file_put_data(tf, def, sizeof(def)); uint8_t def[DEK_FILE_SIZE];
low_flash_available(); 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));
}
flash_commit();
return SW_OK(); return SW_OK();
} }

View File

@@ -20,19 +20,29 @@
extern bool is_gpg; extern bool is_gpg;
int cmd_get_data() { int cmd_get_data(void) {
if (apdu.nc > 0) { if (apdu.nc > 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
file_t *ef; file_t *ef;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { if (fid == EF_PRIV_DO_3) {
if (!has_pw2 && !has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected }
else if (fid == EF_PRIV_DO_4) {
if (!has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
}
else if (!file_authenticate_action(ef, ACL_OP_READ_SEARCH)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (currentEF && currentEF->fid == fid) { // previously selected same EF
ef = currentEF; ef = currentEF;
} }
else { else {
@@ -44,6 +54,7 @@ int cmd_get_data() {
} }
uint16_t fids[] = { 1, fid }; uint16_t fids[] = { 1, fid };
uint16_t data_len = parse_do(fids, 1); uint16_t data_len = parse_do(fids, 1);
if (!(ef->type & FILE_DATA_FLASH)) {
uint8_t *p = NULL; uint8_t *p = NULL;
uint16_t tg = 0; uint16_t tg = 0;
uint16_t tg_len = 0; uint16_t tg_len = 0;
@@ -63,6 +74,7 @@ int cmd_get_data() {
res_APDU_size -= dec; res_APDU_size -= dec;
} }
} }
}
if (is_gpg == false) { if (is_gpg == false) {
uint8_t off = 2; uint8_t off = 2;
if (P1(apdu) > 0x0) { if (P1(apdu) > 0x0) {
@@ -103,7 +115,7 @@ int cmd_get_data() {
return SW_OK(); return SW_OK();
} }
int cmd_get_next_data() { int cmd_get_next_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
if (apdu.nc > 0) { if (apdu.nc > 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -112,19 +124,26 @@ int cmd_get_next_data() {
return SW_RECORD_NOT_FOUND(); return SW_RECORD_NOT_FOUND();
} }
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0)) { if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0)) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
select_file(ef); select_file(ef);
return cmd_get_data(); return cmd_get_data();
} }
int cmd_get_bulk_data(void) {
if (apdu.nc < 3) {
return SW_WRONG_LENGTH();
}
return bulk_cmd(cmd_get_data);
}

View File

@@ -18,14 +18,12 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "random.h" #include "random.h"
#include "do.h" #include "do.h"
uint16_t tag_len(uint8_t **data) { static uint16_t tag_len(uint8_t **data) {
size_t len = *(*data)++; size_t len = *(*data)++;
if (len == 0x82) { if (len == 0x82) {
len = *(*data)++ << 8; len = *(*data)++ << 8;
@@ -37,7 +35,7 @@ uint16_t tag_len(uint8_t **data) {
return len; return len;
} }
int cmd_import_data() { int cmd_import_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
@@ -67,10 +65,10 @@ int cmd_import_data() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
start++; start++;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
start += (*start + 1); start += (*start + 1);
@@ -101,7 +99,7 @@ int cmd_import_data() {
} }
} }
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -152,7 +150,7 @@ int cmd_import_data() {
r = store_keys(&rsa, ALGO_RSA, fid, true); r = store_keys(&rsa, ALGO_RSA, fid, true);
make_rsa_response(&rsa); make_rsa_response(&rsa);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -177,15 +175,7 @@ int cmd_import_data() {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
#ifdef MBEDTLS_EDDSA_C r = mbedtls_ecp_keypair_calc_public(&ecdsa, random_fill_iterator, NULL);
if (ecdsa.grp.id == MBEDTLS_ECP_DP_ED25519) {
r = mbedtls_ecp_point_edwards(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, random_gen, NULL);
}
else
#endif
{
r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL);
}
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -193,7 +183,7 @@ int cmd_import_data() {
r = store_keys(&ecdsa, ALGO_ECDSA, fid, true); r = store_keys(&ecdsa, ALGO_ECDSA, fid, true);
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -203,12 +193,12 @@ int cmd_import_data() {
if (fid == EF_PK_SIG) { if (fid == EF_PK_SIG) {
reset_sig_count(); reset_sig_count();
} }
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *pbef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!pbef) { if (!pbef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
r = file_put_data(pbef, res_APDU, res_APDU_size); r = file_put_data(pbef, res_APDU, res_APDU_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU_size = 0; //make_*_response sets a response. we need to overwrite res_APDU_size = 0; //make_*_response sets a response. we need to overwrite

View File

@@ -18,14 +18,14 @@
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
int cmd_internal_aut() { int cmd_internal_aut(void) {
if (P1(apdu) != 0x00 || P2(apdu) != 0x00) { if (P1(apdu) != 0x00 || P2(apdu) != 0x00) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
if (!has_pw3 && !has_pw2) { if (!has_pw3 && !has_pw2) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
file_t *algo_ef = search_by_fid(algo_aut, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(algo_aut, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -33,19 +33,19 @@ int cmd_internal_aut() {
if (algo_ef && algo_ef->data) { if (algo_ef && algo_ef->data) {
algo = file_get_data(algo_ef); algo = file_get_data(algo_ef);
} }
file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(pk_aut, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (wait_button_pressed_fid(EF_UIF_AUT) == true) { if (wait_button_pressed_fid(EF_UIF_AUT) == true) {
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
} }
int r = PICOKEY_OK; int r = PICOKEYS_OK;
if (algo[0] == ALGO_RSA) { if (algo[0] == ALGO_RSA) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef, true); r = load_private_key_rsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -61,7 +61,7 @@ int cmd_internal_aut() {
mbedtls_ecp_keypair ctx; mbedtls_ecp_keypair ctx;
mbedtls_ecp_keypair_init(&ctx); mbedtls_ecp_keypair_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef, true); r = load_private_key_ecdsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ctx); mbedtls_ecp_keypair_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }

View File

@@ -15,11 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
#include "random.h" #include "random.h"
int cmd_keypair_gen() { int cmd_keypair_gen(void) {
if (P2(apdu) != 0x0) { if (P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -31,7 +32,7 @@ int cmd_keypair_gen() {
} }
uint16_t fid = 0x0; uint16_t fid = 0x0;
int r = PICOKEY_OK; int r = PICOKEYS_OK;
if (apdu.data[0] == 0xB6) { if (apdu.data[0] == 0xB6) {
fid = EF_PK_SIG; fid = EF_PK_SIG;
} }
@@ -45,7 +46,7 @@ int cmd_keypair_gen() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -63,8 +64,7 @@ int cmd_keypair_gen() {
// return SW_FUNC_NOT_SUPPORTED(); // return SW_FUNC_NOT_SUPPORTED();
mbedtls_rsa_context rsa; mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa); mbedtls_rsa_init(&rsa);
uint8_t index = 0; r = mbedtls_rsa_gen_key(&rsa, random_fill_iterator, NULL, nlen, exponent);
r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -72,7 +72,7 @@ int cmd_keypair_gen() {
r = store_keys(&rsa, ALGO_RSA, fid, true); r = store_keys(&rsa, ALGO_RSA, fid, true);
make_rsa_response(&rsa); make_rsa_response(&rsa);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -84,8 +84,7 @@ int cmd_keypair_gen() {
} }
mbedtls_ecp_keypair ecdsa; mbedtls_ecp_keypair ecdsa;
mbedtls_ecp_keypair_init(&ecdsa); mbedtls_ecp_keypair_init(&ecdsa);
uint8_t index = 0; r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_fill_iterator, NULL);
r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index);
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -93,19 +92,19 @@ int cmd_keypair_gen() {
r = store_keys(&ecdsa, algo[0], fid, true); r = store_keys(&ecdsa, algo[0], fid, true);
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
else { else {
return SW_FUNC_NOT_SUPPORTED(); return SW_FUNC_NOT_SUPPORTED();
} }
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *pbef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!pbef) { if (!pbef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
r = file_put_data(pbef, res_APDU, res_APDU_size); r = file_put_data(pbef, res_APDU, res_APDU_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (fid == EF_PK_SIG) { if (fid == EF_PK_SIG) {
@@ -119,14 +118,14 @@ int cmd_keypair_gen() {
memcpy(aes_key, random_bytes_get(key_size), key_size); memcpy(aes_key, random_bytes_get(key_size), key_size);
r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true); r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true);
/* if storing the key fails, we silently continue */ /* if storing the key fails, we silently continue */
//if (r != PICOKEY_OK) //if (r != PICOKEYS_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
} }
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
else if (P1(apdu) == 0x81) { //read else if (P1(apdu) == 0x81) { //read
file_t *ef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_mse() { int cmd_mse(void) {
if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) { if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }

View File

@@ -18,8 +18,6 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
@@ -27,7 +25,7 @@
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/asn1.h" #include "mbedtls/asn1.h"
int cmd_pso() { int cmd_pso(void) {
uint16_t algo_fid = 0x0, pk_fid = 0x0; uint16_t algo_fid = 0x0, pk_fid = 0x0;
bool is_aes = false; bool is_aes = false;
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
@@ -47,7 +45,7 @@ int cmd_pso() {
else { else {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(algo_fid, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -62,35 +60,35 @@ int cmd_pso() {
is_aes = true; is_aes = true;
} }
} }
file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(pk_fid, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) { if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
} }
int r = PICOKEY_OK; int r = PICOKEYS_OK;
int key_size = file_get_size(ef); size_t key_size = file_get_size(ef);
if (is_aes) { if (is_aes) {
uint8_t aes_key[32]; uint8_t aes_key[32];
r = load_aes_key(aes_key, ef); r = load_aes_key(aes_key, ef);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher
r = aes_decrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1); r = aes_decrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
memcpy(res_APDU, apdu.data + 1, apdu.nc - 1); memcpy(res_APDU, apdu.data + 1, apdu.nc - 1);
res_APDU_size = apdu.nc - 1; res_APDU_size = apdu.nc - 1;
} }
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher
r = aes_encrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data, apdu.nc); r = aes_encrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc);
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU[0] = 0x2; res_APDU[0] = 0x2;
@@ -103,7 +101,7 @@ int cmd_pso() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef, true); r = load_private_key_rsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -123,13 +121,7 @@ int cmd_pso() {
memset(apdu.data + apdu.nc, 0, key_size - apdu.nc); memset(apdu.data + apdu.nc, 0, key_size - apdu.nc);
} }
size_t olen = 0; size_t olen = 0;
r = mbedtls_rsa_pkcs1_decrypt(&ctx, r = mbedtls_rsa_pkcs1_decrypt(&ctx, random_fill_iterator, NULL, &olen, apdu.data + 1, res_APDU, key_size);
random_gen,
NULL,
&olen,
apdu.data + 1,
res_APDU,
key_size);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (r != 0) { if (r != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -142,7 +134,7 @@ int cmd_pso() {
mbedtls_ecp_keypair ctx; mbedtls_ecp_keypair ctx;
mbedtls_ecp_keypair_init(&ctx); mbedtls_ecp_keypair_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef, true); r = load_private_key_ecdsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ctx); mbedtls_ecp_keypair_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -195,12 +187,7 @@ int cmd_pso() {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
size_t olen = 0; size_t olen = 0;
r = mbedtls_ecdh_calc_secret(&ctx, r = mbedtls_ecdh_calc_secret(&ctx, &olen, res_APDU, MBEDTLS_ECP_MAX_BYTES, random_fill_iterator, NULL);
&olen,
res_APDU,
MBEDTLS_ECP_MAX_BYTES,
random_gen,
NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdh_free(&ctx); mbedtls_ecdh_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_put_data() { int cmd_put_data(void) {
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
file_t *ef; file_t *ef;
if (fid == EF_RESET_CODE) { if (fid == EF_RESET_CODE) {
@@ -26,49 +26,61 @@ int cmd_put_data() {
else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) { else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
fid |= 0x1000; fid |= 0x1000;
} }
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if ((fid == EF_PRIV_DO_1 || fid == EF_PRIV_DO_3) && (!has_pw2 && !has_pw3)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (!(fid == EF_PRIV_DO_1 || fid == EF_PRIV_DO_3) && !has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (fid == EF_PW_STATUS) { if (fid == EF_PW_STATUS) {
fid = EF_PW_PRIV; fid = EF_PW_PRIV;
apdu.nc = 4; //we silently ommit the reset parameters apdu.nc = 4; //we silently ommit the reset parameters
} }
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected if (currentEF && currentEF->fid == fid) { // previously selected same EF
ef = currentEF; ef = currentEF;
} }
if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) { if (ef->type & FILE_DATA_FLASH) {
int r = 0; int r = 0;
if (apdu.nc > 0) {
if (fid == EF_RC) { if (fid == EF_RC) {
has_rc = false; has_rc = false;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = apdu.nc; dhash[0] = apdu.nc;
double_hash_pin(apdu.data, apdu.nc, dhash + 1); dhash[1] = 0x1; // Format
r = file_put_data(ef, dhash, sizeof(dhash)); 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); file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) { if (!tf) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32];
memcpy(def, file_get_data(tf), file_get_size(tf)); uint8_t def[DEK_FILE_SIZE];
hash_multi(apdu.data, apdu.nc, session_rc); def[0] = 0x3;
memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); pin_derive_session(apdu.data, apdu.nc, session_rc);
aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32); encrypt_with_aad(session_rc, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
r = file_put_data(tf, def, sizeof(def)); r = file_put_data(tf, def, sizeof(def));
} }
else { else {
r = file_put_data(ef, apdu.data, apdu.nc); r = file_put_data(ef, apdu.data, apdu.nc);
} }
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
low_flash_available(); flash_commit();
}
else {
file_delete(ef);
}
} }
return SW_OK(); return SW_OK();
} }

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "otp.h" #include "otp.h"
int cmd_reset_retry() { int cmd_reset_retry(void) {
if (P2(apdu) != 0x81) { if (P2(apdu) != 0x81) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -26,12 +26,12 @@ int cmd_reset_retry() {
int newpin_len = 0; int newpin_len = 0;
file_t *pw = NULL; file_t *pw = NULL;
has_pw1 = false; has_pw1 = false;
if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(EF_PW1, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (P1(apdu) == 0x0) { if (P1(apdu) == 0x0) {
file_t *rc; file_t *rc;
if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) { if (!(rc = file_search_by_fid(EF_RC, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t pin_len = file_get_data(rc)[0]; uint8_t pin_len = file_get_data(rc)[0];
@@ -44,7 +44,7 @@ int cmd_reset_retry() {
} }
newpin_len = apdu.nc - pin_len; newpin_len = apdu.nc - pin_len;
has_rc = true; 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; has_pw1 = has_pw3 = false;
isUserAuthenticated = false; isUserAuthenticated = false;
} }
@@ -55,34 +55,29 @@ int cmd_reset_retry() {
newpin_len = apdu.nc; newpin_len = apdu.nc;
} }
int r = 0; int r = 0;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); file_t *tf = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
if (!tf) { if (!tf) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (otp_key_1) { uint8_t def[DEK_FILE_SIZE];
for (int i = 0; i < 32; i++) { def[0] = 0x03;
dek[IV_SIZE + i] ^= otp_key_1[i]; 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);
}
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);
r = file_put_data(tf, def, sizeof(def)); r = file_put_data(tf, def, sizeof(def));
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = newpin_len; 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)); file_put_data(pw, dhash, sizeof(dhash));
if (pin_reset_retries(pw, true) != PICOKEY_OK) { if (pin_reset_retries(pw, true) != PICOKEYS_OK) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
low_flash_available(); flash_commit();
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
return SW_OK(); return SW_OK();

View File

@@ -17,14 +17,14 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_select() { int cmd_select(void) {
uint8_t p1 = P1(apdu); uint8_t p1 = P1(apdu);
uint8_t p2 = P2(apdu); uint8_t p2 = P2(apdu);
file_t *pe = NULL; file_t *pe = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (apdu.nc >= 2) { if (apdu.nc >= 2) {
fid = get_uint16_t_be(apdu.data); fid = get_uint16_be(apdu.data);
} }
if (!pe) { if (!pe) {
@@ -34,18 +34,18 @@ int cmd_select() {
//ac_fini(); //ac_fini();
} }
else if (apdu.nc == 2) { else if (apdu.nc == 2) {
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { if (!(pe = file_search_by_fid(fid, NULL, SPECIFY_ANY))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
} }
else if (p1 == 0x01) { //Select child DF - DF identifier else if (p1 == 0x01) { //Select child DF - DF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) { if (!(pe = file_search_by_fid(fid, currentDF, SPECIFY_DF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
else if (p1 == 0x02) { //Select EF under the current DF - EF identifier else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) { if (!(pe = file_search_by_fid(fid, currentDF, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
@@ -55,7 +55,7 @@ int cmd_select() {
} }
} }
else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
if (!(pe = search_by_name(apdu.data, apdu.nc))) { if (!(pe = file_search_by_name(apdu.data, apdu.nc))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (card_terminated) { if (card_terminated) {
@@ -63,19 +63,19 @@ int cmd_select() {
} }
} }
else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
if (!(pe = search_by_path(apdu.data, apdu.nc, MF))) { if (!(pe = file_search_by_path(apdu.data, apdu.nc, MF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier
if (!(pe = search_by_path(apdu.data, apdu.nc, currentDF))) { if (!(pe = file_search_by_path(apdu.data, apdu.nc, currentDF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
} }
if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) { if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
if ((p2 & 0xfc) == 0x04) { if ((p2 & 0xfc) == 0x04) {
process_fci(pe, 0); file_process_fci(pe, 0);
} }
} }
else { else {

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_select_data() { int cmd_select_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (P2(apdu) != 0x4) { if (P2(apdu) != 0x4) {
@@ -26,7 +26,7 @@ int cmd_select_data() {
if (apdu.data[0] != 0x60) { if (apdu.data[0] != 0x60) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
if (apdu.nc != apdu.data[1] + 2 || apdu.nc < 5) { if (apdu.nc != (uint32_t) apdu.data[1] + 2u || apdu.nc < 5u) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
if (apdu.data[2] != 0x5C) { if (apdu.data[2] != 0x5C) {
@@ -38,15 +38,15 @@ int cmd_select_data() {
else { else {
fid = apdu.data[4]; fid = apdu.data[4];
} }
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
fid &= ~0x6000; //Now get private DO fid &= ~0x6000; //Now get private DO
fid += P1(apdu); fid += P1(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
select_file(ef); select_file(ef);

View File

@@ -17,12 +17,12 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_terminate_df() { int cmd_terminate_df(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *retries; file_t *retries;
if (!(retries = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(retries = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!has_pw3 && *(file_get_data(retries) + 6) > 0) { if (!has_pw3 && *(file_get_data(retries) + 6) > 0) {
@@ -31,7 +31,7 @@ int cmd_terminate_df() {
if (apdu.nc != 0) { if (apdu.nc != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
initialize_flash(true); file_initialize_flash(true);
scan_files_openpgp(); scan_files_openpgp();
return SW_OK(); return SW_OK();
} }

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_verify() { int cmd_verify(void) {
uint8_t p1 = P1(apdu); uint8_t p1 = P1(apdu);
uint8_t p2 = P2(apdu); uint8_t p2 = P2(apdu);
@@ -44,10 +44,10 @@ int cmd_verify() {
fid = EF_PW1; fid = EF_PW1;
} }
file_t *pw, *pw_status; file_t *pw, *pw_status;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw)[0] == 0) { //not initialized if (file_get_data(pw)[0] == 0) { //not initialized

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "version.h" #include "version.h"
int cmd_version_openpgp() { int cmd_version_openpgp(void) {
res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR; res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR; res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0x0; res_APDU[res_APDU_size++] = 0x0;

View File

@@ -18,14 +18,30 @@
#include "openpgp.h" #include "openpgp.h"
#include "asn1.h" #include "asn1.h"
int parse_trium(uint16_t fid, uint8_t num, size_t size);
int parse_ch_data(const file_t *f, int mode);
int parse_sec_tpl(const file_t *f, int mode);
int parse_ch_cert(const file_t *f, int mode);
int parse_fp(const file_t *f, int mode);
int parse_cafp(const file_t *f, int mode);
int parse_ts(const file_t *f, int mode);
int parse_keyinfo(const file_t *f, int mode);
int parse_pw_status(const file_t *f, int mode);
int parse_algo(const uint8_t *algo, uint16_t tag);
int parse_algoinfo(const file_t *f, int mode);
int parse_app_data(const file_t *f, int mode);
int parse_discrete_do(const file_t *f, int mode);
int parse_do(uint16_t *fids, int mode) { int parse_do(uint16_t *fids, int mode) {
int len = 0; int len = 0;
file_t *ef; file_t *ef;
for (int i = 0; i < fids[0]; i++) { for (int i = 0; i < fids[0]; i++) {
if ((ef = search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) { if ((ef = file_search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
uint16_t data_len; uint16_t data_len;
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, mode); int (*file_data_func)(const file_t *, int) = NULL;
memcpy(&file_data_func, &ef->data, sizeof(file_data_func));
data_len = file_data_func(ef, mode);
} }
else { else {
data_len = file_get_size(ef); data_len = file_get_size(ef);
@@ -55,7 +71,7 @@ int parse_do(uint16_t *fids, int mode) {
int parse_trium(uint16_t fid, uint8_t num, size_t size) { int parse_trium(uint16_t fid, uint8_t num, size_t size) {
for (uint8_t i = 0; i < num; i++) { for (uint8_t i = 0; i < num; i++) {
file_t *ef; file_t *ef;
if ((ef = search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) { if ((ef = file_search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
uint16_t data_len = file_get_size(ef); uint16_t data_len = file_get_size(ef);
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
res_APDU_size += data_len; res_APDU_size += data_len;
@@ -69,6 +85,7 @@ int parse_trium(uint16_t fid, uint8_t num, size_t size) {
} }
int parse_ch_data(const file_t *f, int mode) { int parse_ch_data(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
3, 3,
EF_CH_NAME, EF_LANG_PREF, EF_SEX, EF_CH_NAME, EF_LANG_PREF, EF_SEX,
@@ -85,9 +102,11 @@ int parse_ch_data(const file_t *f, int mode) {
} }
int parse_sec_tpl(const file_t *f, int mode) { int parse_sec_tpl(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff; res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
res_APDU[res_APDU_size++] = 5; res_APDU[res_APDU_size++] = 5;
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff; res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
res_APDU[res_APDU_size++] = 3; res_APDU[res_APDU_size++] = 3;
@@ -98,34 +117,44 @@ int parse_sec_tpl(const file_t *f, int mode) {
} }
int parse_ch_cert(const file_t *f, int mode) { int parse_ch_cert(const file_t *f, int mode) {
(void) f;
(void) mode;
return 0; return 0;
} }
int parse_fp(const file_t *f, int mode) { int parse_fp(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_FP & 0xff; res_APDU[res_APDU_size++] = EF_FP & 0xff;
res_APDU[res_APDU_size++] = 60; res_APDU[res_APDU_size++] = 60;
return parse_trium(EF_FP_SIG, 3, 20) + 2; return parse_trium(EF_FP_SIG, 3, 20) + 2;
} }
int parse_cafp(const file_t *f, int mode) { int parse_cafp(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_CA_FP & 0xff; res_APDU[res_APDU_size++] = EF_CA_FP & 0xff;
res_APDU[res_APDU_size++] = 60; res_APDU[res_APDU_size++] = 60;
return parse_trium(EF_FP_CA1, 3, 20) + 2; return parse_trium(EF_FP_CA1, 3, 20) + 2;
} }
int parse_ts(const file_t *f, int mode) { int parse_ts(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff; res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff;
res_APDU[res_APDU_size++] = 12; res_APDU[res_APDU_size++] = 12;
return parse_trium(EF_TS_SIG, 3, 4) + 2; return parse_trium(EF_TS_SIG, 3, 4) + 2;
} }
int parse_keyinfo(const file_t *f, int mode) { int parse_keyinfo(const file_t *f, int mode) {
(void) f;
(void) mode;
int init_len = res_APDU_size; int init_len = res_APDU_size;
if (res_APDU_size > 0) { if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff; res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff;
res_APDU[res_APDU_size++] = 6; res_APDU[res_APDU_size++] = 6;
} }
file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -134,7 +163,7 @@ int parse_keyinfo(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
ef = search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -143,7 +172,7 @@ int parse_keyinfo(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
ef = search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x02; res_APDU[res_APDU_size++] = 0x02;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -155,13 +184,15 @@ int parse_keyinfo(const file_t *f, int mode) {
} }
int parse_pw_status(const file_t *f, int mode) { int parse_pw_status(const file_t *f, int mode) {
(void) f;
(void) mode;
file_t *ef; file_t *ef;
int init_len = res_APDU_size; int init_len = res_APDU_size;
if (res_APDU_size > 0) { if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff; res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff;
res_APDU[res_APDU_size++] = 7; res_APDU[res_APDU_size++] = 7;
} }
ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
if (ef && ef->data) { if (ef && ef->data) {
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7); memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
res_APDU_size += 7; res_APDU_size += 7;
@@ -278,6 +309,7 @@ int parse_algo(const uint8_t *algo, uint16_t tag) {
} }
int parse_algoinfo(const file_t *f, int mode) { int parse_algoinfo(const file_t *f, int mode) {
(void) mode;
int datalen = 0; int datalen = 0;
if (f->fid == EF_ALGO_INFO) { if (f->fid == EF_ALGO_INFO) {
res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff; res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff;
@@ -337,7 +369,7 @@ int parse_algoinfo(const file_t *f, int mode) {
else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) { else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) {
uint16_t fid = 0x1000 | f->fid; uint16_t fid = 0x1000 | f->fid;
file_t *ef; file_t *ef;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) {
datalen += parse_algo(algorithm_attr_rsa2k, f->fid); datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
} }
else { else {
@@ -356,6 +388,7 @@ int parse_algoinfo(const file_t *f, int mode) {
} }
int parse_app_data(const file_t *f, int mode) { int parse_app_data(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
6, 6,
EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO
@@ -372,6 +405,7 @@ int parse_app_data(const file_t *f, int mode) {
} }
int parse_discrete_do(const file_t *f, int mode) { int parse_discrete_do(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
11, 11,
EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL, EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL,

View File

@@ -20,13 +20,6 @@
extern const uint8_t openpgp_aid[]; extern const uint8_t openpgp_aid[];
extern const uint8_t openpgp_aid_full[]; 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_ch_data(const file_t *f, int mode);
extern int parse_sec_tpl(const file_t *f, int mode); extern int parse_sec_tpl(const file_t *f, int mode);
extern int parse_ch_cert(const file_t *f, int mode); extern int parse_ch_cert(const file_t *f, int mode);
@@ -55,12 +48,12 @@ uint8_t historical_bytes[] = {
uint8_t extended_capabilities[] = { uint8_t extended_capabilities[] = {
10, 0, 10, 0,
0x77, /* 0x7f, /*
* No Secure Messaging supported * No Secure Messaging supported
* GET CHALLENGE supported * GET CHALLENGE supported
* Key import supported * Key import supported
* PW status byte can be put * PW status byte can be put
* No private_use_DO * private_use_DO
* Algorithm attrs are changable * Algorithm attrs are changable
* ENC/DEC with AES * ENC/DEC with AES
* KDF-DO available * KDF-DO available
@@ -68,7 +61,7 @@ uint8_t extended_capabilities[] = {
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, 128, /* Max size of GET CHALLENGE */ 0x00, 128, /* Max size of GET CHALLENGE */
0x08, 0x00, /* max. length of cardholder certificate (2KiB) */ 0x08, 0x00, /* max. length of cardholder certificate (2KiB) */
0x00, 0xff, 0x08, 0x00, /* max. length of private DO (2KiB) */
0x00, 0x1 0x00, 0x1
}; };
@@ -114,7 +107,7 @@ file_t file_entries[] = {
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 10 */ { .fid = EF_CH_CERT, .parent = 0, .name = NULL, /* 10 */ { .fid = EF_CH_CERT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) parse_ch_cert, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) parse_ch_cert,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, /* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,
.data = exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .data = exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, /* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,
@@ -250,236 +243,263 @@ file_t file_entries[] = {
/* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL, /* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
// ** PIV ** // /* 57 */ { .fid = EF_DEK_PW1, .parent = 0, .name = NULL,
/* 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, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 131 */ { .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, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 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 },
/* 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 },
/* 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 },
/* 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 },
/* 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 },
/* 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 },
/* 132 */ { .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 }, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 133 */ { .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 .ef_structure = 0, .acl = ACL_NONE } //end
}; };

View File

@@ -36,6 +36,10 @@
#define EF_PB_DEC 0x10d5 #define EF_PB_DEC 0x10d5
#define EF_PB_AUT 0x10d6 #define EF_PB_AUT 0x10d6
#define EF_DEK 0x1099 #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_1 0x1f21
#define EF_CH_2 0x1f22 #define EF_CH_2 0x1f22
#define EF_CH_3 0x1f23 #define EF_CH_3 0x1f23
@@ -163,4 +167,11 @@
#define EF_DEV_CONF 0x1122 #define EF_DEV_CONF 0x1122
#define EF_PRIV_DO_1 0x0101
#define EF_PRIV_DO_2 0x0102
#define EF_PRIV_DO_3 0x0103
#define EF_PRIV_DO_4 0x0104
extern const file_t *file_openpgp;
#endif #endif

View File

@@ -15,7 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include <stdio.h>
#include "picokeys.h"
#include "serial.h"
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
#include "files.h" #include "files.h"
@@ -24,16 +26,16 @@
bool is_gpg = true; bool is_gpg = true;
int man_process_apdu(); static int man_process_apdu(void);
int man_unload(); static int man_unload(void);
const uint8_t man_aid[] = { const uint8_t man_aid[] = {
8, 8,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
}; };
extern void init_piv(); extern void init_piv(void);
int man_select(app_t *a, uint8_t force) { static int man_select(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = man_process_apdu; a->process_apdu = man_process_apdu;
a->unload = man_unload; a->unload = man_unload;
@@ -42,19 +44,19 @@ int man_select(app_t *a, uint8_t force) {
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
init_piv(); init_piv();
is_gpg = false; is_gpg = false;
return PICOKEY_OK; return PICOKEYS_OK;
} }
INITIALIZER( man_ctor ) { INITIALIZER( man_ctor ) {
register_app(man_select, man_aid); register_app(man_select, man_aid);
} }
int man_unload() { static int man_unload(void) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
bool cap_supported(uint16_t cap) { bool cap_supported(uint16_t cap) {
file_t *ef = search_dynamic_file(EF_DEV_CONF); file_t *ef = file_search(EF_DEV_CONF);
if (file_has_data(ef)) { if (file_has_data(ef)) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
@@ -74,8 +76,8 @@ bool cap_supported(uint16_t cap) {
return true; return true;
} }
int man_get_config() { int man_get_config(void) {
file_t *ef = search_dynamic_file(EF_DEV_CONF); file_t *ef = file_search(EF_DEV_CONF);
res_APDU_size = 0; res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0; // Overall length. Filled later res_APDU[res_APDU_size++] = 0; // Overall length. Filled later
res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED; res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED;
@@ -118,18 +120,18 @@ int man_get_config() {
return 0; return 0;
} }
int cmd_read_config() { static int cmd_read_config(void) {
man_get_config(); man_get_config();
return SW_OK(); return SW_OK();
} }
int cmd_write_config() { static int cmd_write_config(void) {
if (apdu.data[0] != apdu.nc - 1) { if (apdu.data[0] != apdu.nc - 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = file_new(EF_DEV_CONF); file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, apdu.nc - 1); file_put_data(ef, apdu.data + 1, apdu.nc - 1);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
@@ -142,7 +144,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int man_process_apdu() { static int man_process_apdu(void) {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -50,6 +50,6 @@
#define FLAG_EJECT 0x80 #define FLAG_EJECT 0x80
extern bool cap_supported(uint16_t cap); extern bool cap_supported(uint16_t cap);
extern int man_get_config(); extern int man_get_config(void);
#endif //_MANAGEMENT_H #endif //_MANAGEMENT_H

View File

@@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "serial.h"
#include "version.h" #include "version.h"
#include "random.h" #include "random.h"
#include "eac.h" #include "eac.h"
@@ -41,7 +41,7 @@ bool has_rc = false;
uint8_t session_pw1[32]; uint8_t session_pw1[32];
uint8_t session_rc[32]; uint8_t session_rc[32];
uint8_t session_pw3[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; 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[] = { uint8_t openpgp_aid[] = {
@@ -61,20 +61,22 @@ char atr_openpgp[] = {
0x60, 0x00, 0x90, 0x00, 0x1c 0x60, 0x00, 0x90, 0x00, 0x1c
}; };
int openpgp_process_apdu(); int openpgp_process_apdu(void);
extern uint32_t board_button_read(void); extern uint32_t board_button_read(void);
bool wait_button_pressed_fid(uint16_t fid) { bool wait_button_pressed_fid(uint16_t fid) {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
file_t *ef = search_by_fid(fid, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_ANY);
if (ef && ef->data && file_get_data(ef)[0] > 0) { if (ef && ef->data && file_get_data(ef)[0] > 0) {
queue_try_add(&card_to_usb_q, &val); queue_try_add(&card_to_usb_q, &val);
do { do {
queue_remove_blocking(&usb_to_card_q, &val); queue_remove_blocking(&usb_to_card_q, &val);
}while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); }while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
} }
#else
(void) fid;
#endif #endif
return val == EV_BUTTON_TIMEOUT; return val == EV_BUTTON_TIMEOUT;
} }
@@ -97,25 +99,28 @@ void select_file(file_t *pe) {
} }
} }
void scan_files_openpgp() { void scan_files_openpgp(void) {
scan_flash(); file_scan_flash();
file_t *ef; file_t *ef;
if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) {
ef->data = openpgp_aid_full; ef->data = openpgp_aid_full;
memcpy(ef->data + 12, pico_serial.id, 4); memcpy(ef->data + 12, pico_serial.id, 4);
} }
bool reset_dek = false; bool reset_dek = false;
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { bool bootstrap_legacy = false;
if (!ef->data) { file_t *ef_dek = file_search_by_fid(EF_DEK, NULL, SPECIFY_ANY), *ef_dek_pw1 = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_ANY), *ef_dek_rc = file_search_by_fid(EF_DEK_RC, NULL, SPECIFY_ANY), *ef_dek_pw3 = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_ANY);
printf("DEK is empty\r\n"); if (!file_has_data(ef_dek_pw1) && !file_has_data(ef_dek_rc) && !file_has_data(ef_dek_pw3) && !file_has_data(ef_dek)) {
const uint8_t def1[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; 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 }; 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]; uint8_t def[IV_SIZE + 32 + 32 + 32];
const uint8_t *dek = random_bytes_get(IV_SIZE + 32); memcpy(def, random_dek, IV_SIZE + 32);
memcpy(def, dek, IV_SIZE + 32); memcpy(def + IV_SIZE + 32, random_dek + IV_SIZE, 32);
memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); memcpy(def + IV_SIZE + 32 + 32, random_dek + IV_SIZE, 32);
memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32);
hash_multi(def1, sizeof(def1), session_pw1); hash_multi(def1, sizeof(def1), session_pw1);
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
memset(session_pw1, 0, sizeof(session_pw1)); memset(session_pw1, 0, sizeof(session_pw1));
@@ -124,145 +129,228 @@ void scan_files_openpgp() {
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32, 32); 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); aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32);
memset(session_pw3, 0, sizeof(session_pw3)); memset(session_pw3, 0, sizeof(session_pw3));
file_put_data(ef, def, sizeof(def)); 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; reset_dek = true;
} }
} if ((ef = file_search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) {
if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PW1 is empty. Initializing with default password\r\n"); printf("PW1 is empty. Initializing with default password\r\n");
const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
uint8_t dhash[33]; uint8_t dhash[34];
if (bootstrap_legacy) {
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
double_hash_pin(def, sizeof(def), dhash + 1); 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)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { }
if ((ef = file_search_by_fid(EF_RC, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("RC is empty. Initializing with default password\r\n"); printf("RC is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
uint8_t dhash[33]; uint8_t dhash[34];
if (bootstrap_legacy) {
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
double_hash_pin(def, sizeof(def), dhash + 1); 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)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { }
if ((ef = file_search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PW3 is empty. Initializing with default password\r\n"); printf("PW3 is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
uint8_t dhash[33]; uint8_t dhash[34];
if (bootstrap_legacy) {
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
double_hash_pin(def, sizeof(def), dhash + 1); 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)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) { }
if ((ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("SigCount is empty. Initializing to zero\r\n"); printf("SigCount is empty. Initializing to zero\r\n");
const uint8_t def[3] = { 0 }; const uint8_t def[3] = { 0 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PW status is empty. Initializing to default\r\n"); printf("PW status is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3 }; const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF SIG is empty. Initializing to default\r\n"); printf("UIF SIG is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF DEC is empty. Initializing to default\r\n"); printf("UIF DEC is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF AUT is empty. Initializing to default\r\n"); printf("UIF AUT is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("KDF is empty. Initializing to default\r\n"); printf("KDF is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x81, 0x1, 0x0 }; const uint8_t def[] = { 0x81, 0x1, 0x0 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_SEX, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_SEX, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("Sex is empty. Initializing to default\r\n"); printf("Sex is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x30 }; const uint8_t def[] = { 0x30 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PW retries is empty. Initializing to default\r\n"); printf("PW retries is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 3, 3, 3 }; const uint8_t def[] = { 0x1, 3, 3, 3 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
low_flash_available(); flash_commit();
} }
void release_dek() { static void release_dek(void) {
memset(dek, 0, sizeof(dek)); memset(dek, 0, sizeof(dek));
} }
extern bool has_pwpiv; extern bool has_pwpiv;
extern uint8_t session_pwpiv[32]; extern uint8_t session_pwpiv[32];
int load_dek() { int load_dek(void) {
if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) { if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) {
return PICOKEY_NO_LOGIN; return PICOKEYS_NO_LOGIN;
} }
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); int r = PICOKEYS_OK;
if (!tf) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
int r = PICOKEY_OK;
if (has_pw1 || has_pw2) { if (has_pw1 || has_pw2) {
file_t *ef_dek_pw1 = file_search(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 PICOKEYS_ERR_NULL_PARAM;
}
}
else {
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
memcpy(dek, file_get_data(tf), IV_SIZE + 32); memcpy(dek, file_get_data(tf), IV_SIZE + 32);
r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32); r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32);
} }
}
else if (has_pw3) { else if (has_pw3) {
file_t *ef_dek_pw3 = file_search(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 PICOKEYS_ERR_NULL_PARAM;
}
}
else {
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
memcpy(dek, file_get_data(tf), IV_SIZE); memcpy(dek, file_get_data(tf), IV_SIZE);
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32, 32); 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); r = aes_decrypt_cfb_256(session_pw3, dek, dek + IV_SIZE, 32);
} }
}
else if (has_pwpiv) { else if (has_pwpiv) {
file_t *ef_dek_pwpiv = file_search(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 PICOKEYS_ERR_NULL_PARAM;
}
}
else {
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
memcpy(dek, file_get_data(tf), IV_SIZE); memcpy(dek, file_get_data(tf), IV_SIZE);
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32 + 32, 32); 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); r = aes_decrypt_cfb_256(session_pwpiv, dek, dek + IV_SIZE, 32);
} }
}
if (r != 0) { if (r != 0) {
release_dek(); release_dek();
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (otp_key_1) { return PICOKEYS_OK;
for (int i = 0; i < 32; i++) {
dek[IV_SIZE + i] ^= otp_key_1[i];
}
}
return PICOKEY_OK;
} }
int dek_encrypt(uint8_t *data, size_t len) { int dek_encrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return r; return r;
} }
r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len); r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len);
@@ -272,7 +360,7 @@ int dek_encrypt(uint8_t *data, size_t len) {
int dek_decrypt(uint8_t *data, size_t len) { int dek_decrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return r; return r;
} }
r = aes_decrypt_cfb_256(dek + IV_SIZE, dek, data, len); r = aes_decrypt_cfb_256(dek + IV_SIZE, dek, data, len);
@@ -280,9 +368,9 @@ int dek_decrypt(uint8_t *data, size_t len) {
return r; return r;
} }
void init_openpgp() { static void init_openpgp(void) {
isUserAuthenticated = false; isUserAuthenticated = false;
has_pw1 = has_pw3 = false; has_pw1 = has_pw2 = has_pw3 = false;
algo_dec = EF_ALGO_PRIV2; algo_dec = EF_ALGO_PRIV2;
algo_aut = EF_ALGO_PRIV3; algo_aut = EF_ALGO_PRIV3;
pk_dec = EF_PK_DEC; pk_dec = EF_PK_DEC;
@@ -291,18 +379,18 @@ void init_openpgp() {
//cmd_select(); //cmd_select();
} }
int openpgp_unload() { static int openpgp_unload(void) {
isUserAuthenticated = false; isUserAuthenticated = false;
has_pw1 = has_pw3 = false; has_pw1 = has_pw2 = has_pw3 = false;
algo_dec = EF_ALGO_PRIV2; algo_dec = EF_ALGO_PRIV2;
algo_aut = EF_ALGO_PRIV3; algo_aut = EF_ALGO_PRIV3;
pk_dec = EF_PK_DEC; pk_dec = EF_PK_DEC;
pk_aut = EF_PK_AUT; pk_aut = EF_PK_AUT;
return PICOKEY_OK; return PICOKEYS_OK;
} }
extern char __StackLimit; extern char __StackLimit;
int heapLeft() { static int heapLeft(void) {
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
char *p = malloc(256); // try to avoid undue fragmentation char *p = malloc(256); // try to avoid undue fragmentation
int left = &__StackLimit - p; int left = &__StackLimit - p;
@@ -313,12 +401,12 @@ int heapLeft() {
return left; return left;
} }
int openpgp_select_aid(app_t *a, uint8_t force) { static int openpgp_select_aid(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = openpgp_process_apdu; a->process_apdu = openpgp_process_apdu;
a->unload = openpgp_unload; a->unload = openpgp_unload;
init_openpgp(); init_openpgp();
process_fci(file_openpgp, 1); file_process_fci(file_openpgp, 1);
memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4); memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4);
res_APDU_size += 4; res_APDU_size += 4;
int heap_left = heapLeft(); int heap_left = heapLeft();
@@ -328,94 +416,170 @@ int openpgp_select_aid(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = ((heap_left >> 0) & 0xff); res_APDU[res_APDU_size++] = ((heap_left >> 0) & 0xff);
res_APDU[1] += 8; res_APDU[1] += 8;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEY_OK; return PICOKEYS_OK;
} }
INITIALIZER( openpgp_ctor ) { INITIALIZER( openpgp_ctor ) {
ccid_atr = (uint8_t *) atr_openpgp;
register_app(openpgp_select_aid, openpgp_aid); register_app(openpgp_select_aid, openpgp_aid);
} }
int set_atr(void) {
ccid_atr = (uint8_t *) atr_openpgp;
return 0;
}
int pin_reset_retries(const file_t *pin, bool force) { int pin_reset_retries(const file_t *pin, bool force) {
if (!pin) { if (!pin) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
file_t *pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF); file_t *pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF);
file_t *pw_retries = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF); file_t *pw_retries = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF);
if (!pw_status || !pw_retries) { if (!pw_status || !pw_retries) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
if (3 + (pin->fid & 0xf) >= file_get_size(pw_status) || (pin->fid & 0xf) >= file_get_size(pw_retries)) { if (3 + (pin->fid & 0xf) >= file_get_size(pw_status) || (pin->fid & 0xf) >= file_get_size(pw_retries)) {
return PICOKEY_ERR_MEMORY_FATAL; return PICOKEYS_ERR_MEMORY_FATAL;
} }
uint8_t p[64]; uint8_t p[64];
memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); memcpy(p, file_get_data(pw_status), file_get_size(pw_status));
uint8_t retries = p[3 + (pin->fid & 0xf)]; uint8_t retries = p[3 + (pin->fid & 0xf)];
if (retries == 0 && force == false) { //blocked if (retries == 0 && force == false) { //blocked
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
uint8_t max_retries = file_get_data(pw_retries)[(pin->fid & 0xf)]; uint8_t max_retries = file_get_data(pw_retries)[(pin->fid & 0xf)];
p[3 + (pin->fid & 0xf)] = max_retries; p[3 + (pin->fid & 0xf)] = max_retries;
int r = file_put_data(pw_status, p, file_get_size(pw_status)); int r = file_put_data(pw_status, p, file_get_size(pw_status));
low_flash_available(); flash_commit();
return r; return r;
} }
int pin_wrong_retry(const file_t *pin) { static int pin_wrong_retry(const file_t *pin) {
if (!pin) { if (!pin) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
file_t *pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF); file_t *pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF);
if (!pw_status) { if (!pw_status) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t p[64]; uint8_t p[64];
memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); memcpy(p, file_get_data(pw_status), file_get_size(pw_status));
if (p[3 + (pin->fid & 0xf)] > 0) { if (p[3 + (pin->fid & 0xf)] > 0) {
p[3 + (pin->fid & 0xf)] -= 1; p[3 + (pin->fid & 0xf)] -= 1;
int r = file_put_data(pw_status, p, file_get_size(pw_status)); int r = file_put_data(pw_status, p, file_get_size(pw_status));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
low_flash_available(); flash_commit();
if (p[3 + (pin->fid & 0xf)] == 0) { if (p[3 + (pin->fid & 0xf)] == 0) {
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
return p[3 + (pin->fid & 0xf)]; return p[3 + (pin->fid & 0xf)];
} }
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
int check_pin(const file_t *pin, const uint8_t *data, size_t len) { int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
if (!pin) { if (!file_has_data(pin)) {
return SW_REFERENCE_NOT_FOUND();
}
if (!pin->data) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
isUserAuthenticated = false; isUserAuthenticated = false;
//has_pw1 = has_pw3 = false; //has_pw1 = has_pw3 = false;
uint8_t dhash[32]; uint8_t dhash[32], off = 2;
if (file_get_size(pin) == 33) {
off = 1;
double_hash_pin(data, len, dhash); double_hash_pin(data, len, dhash);
if (sizeof(dhash) != file_get_size(pin) - 1) { //1 byte for pin len }
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(); 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; int retries;
if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) { if ((retries = pin_wrong_retry(pin)) < PICOKEYS_OK) {
return SW_PIN_BLOCKED(); return SW_PIN_BLOCKED();
} }
return set_res_sw(0x63, 0xc0 | retries); return set_res_sw(0x63, 0xc0 | retries);
} }
int r = pin_reset_retries(pin, false); int r = pin_reset_retries(pin, false);
if (r == PICOKEY_ERR_BLOCKED) { if (r == PICOKEYS_ERR_BLOCKED) {
return SW_PIN_BLOCKED(); return SW_PIN_BLOCKED();
} }
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_MEMORY_FAILURE(); 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 != PICOKEYS_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 = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
}
else if (has_pw3) {
ef_dek_pw = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF);
}
else if (has_pwpiv) {
ef_dek_pw = file_search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_EF);
}
if (!ef_dek_pw) {
return PICOKEYS_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 = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!ef_dek) {
return PICOKEYS_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));
flash_commit();
}
has_pw1 = has_pw2 = has_pw3 = false;
}
isUserAuthenticated = true; isUserAuthenticated = true;
if (pin->fid == EF_PW1) { if (pin->fid == EF_PW1) {
if (P2(apdu) == 0x81) { if (P2(apdu) == 0x81) {
@@ -424,51 +588,51 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
else { else {
has_pw2 = true; has_pw2 = true;
} }
hash_multi(data, len, session_pw1); pin_derive_session(data, len, session_pw1);
} }
else if (pin->fid == EF_PW3) { else if (pin->fid == EF_PW3) {
has_pw3 = true; has_pw3 = true;
hash_multi(data, len, session_pw3); pin_derive_session(data, len, session_pw3);
} }
return SW_OK(); return SW_OK();
} }
int inc_sig_count() { int inc_sig_count(void) {
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw_status)[0] == 0) { if (file_get_data(pw_status)[0] == 0) {
has_pw1 = false; has_pw1 = false;
} }
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (!ef || !ef->data) { if (!ef || !ef->data) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t *p = file_get_data(ef); uint8_t *p = file_get_data(ef);
uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2]; uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2];
counter++; counter++;
uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff }; uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff };
int r = file_put_data(ef, q, sizeof(q)); int r = file_put_data(ef, q, sizeof(q));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int reset_sig_count() { int reset_sig_count(void) {
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (!ef || !ef->data) { if (!ef || !ef->data) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t q[3] = { 0 }; uint8_t q[3] = { 0 };
int r = file_put_data(ef, q, sizeof(q)); int r = file_put_data(ef, q, sizeof(q));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) { int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
@@ -476,13 +640,13 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
uint8_t kdata[4096 / 8]; //worst uint8_t kdata[4096 / 8]; //worst
//if (!has_pw3) //if (!has_pw3)
// return PICOKEY_NO_LOGIN; // return PICOKEYS_NO_LOGIN;
//file_t *pw3 = search_by_fid(EF_PW3, NULL, SPECIFY_EF); //file_t *pw3 = file_search_by_fid(EF_PW3, NULL, SPECIFY_EF);
//if (!pw3) //if (!pw3)
// return PICOKEY_ERR_FILE_NOT_FOUND; // return PICOKEYS_ERR_FILE_NOT_FOUND;
file_t *ef = search_by_fid(key_id, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(key_id, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
if (type == ALGO_RSA) { if (type == ALGO_RSA) {
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) key_ctx; mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) key_ctx;
@@ -511,19 +675,19 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
} }
if (use_kek) { if (use_kek) {
r = dek_encrypt(kdata, key_size); r = dek_encrypt(kdata, key_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
} }
//r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size); //r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size);
//if (r != PICOKEY_OK) //if (r != PICOKEYS_OK)
// return r; // return r;
r = file_put_data(ef, kdata, key_size); r = file_put_data(ef, kdata, key_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) { int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) {
@@ -531,33 +695,33 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) {
uint8_t kdata[4096 / 8]; uint8_t kdata[4096 / 8];
memcpy(kdata, file_get_data(fkey), key_size); memcpy(kdata, file_get_data(fkey), key_size);
if (use_dek && dek_decrypt(kdata, key_size) != 0) { if (use_dek && dek_decrypt(kdata, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) { if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) { if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) { if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) { if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_rsa_complete(ctx) != 0) { if (mbedtls_rsa_complete(ctx) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_rsa_check_privkey(ctx) != 0) { if (mbedtls_rsa_check_privkey(ctx) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) { int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) {
@@ -565,38 +729,30 @@ int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek)
uint8_t kdata[67]; //Worst case, 521 bit + 1byte uint8_t kdata[67]; //Worst case, 521 bit + 1byte
memcpy(kdata, file_get_data(fkey), key_size); memcpy(kdata, file_get_data(fkey), key_size);
if (use_dek && dek_decrypt(kdata, key_size) != 0) { if (use_dek && dek_decrypt(kdata, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
mbedtls_ecp_group_id gid = kdata[0]; mbedtls_ecp_group_id gid = kdata[0];
int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1); int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1);
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(ctx); mbedtls_ecp_keypair_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
mbedtls_platform_zeroize(kdata, sizeof(kdata)); mbedtls_platform_zeroize(kdata, sizeof(kdata));
#ifdef MBEDTLS_EDDSA_C r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL);
if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) {
r = mbedtls_ecp_point_edwards(&ctx->grp, &ctx->Q, &ctx->d, random_gen, NULL);
}
else
#endif
{
r = mbedtls_ecp_mul(&ctx->grp, &ctx->Q, &ctx->d, &ctx->grp.G, random_gen, NULL);
}
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(ctx); mbedtls_ecp_keypair_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_aes_key(uint8_t *aes_key, file_t *fkey) { int load_aes_key(uint8_t *aes_key, file_t *fkey) {
int key_size = file_get_size(fkey); int key_size = file_get_size(fkey);
memcpy(aes_key, file_get_data(fkey), key_size); memcpy(aes_key, file_get_data(fkey), key_size);
if (dek_decrypt(aes_key, key_size) != 0) { if (dek_decrypt(aes_key, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) { mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) {
@@ -643,25 +799,20 @@ void make_rsa_response(mbedtls_rsa_context *rsa) {
res_APDU_size = 5; res_APDU_size = 5;
res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
put_uint16_t_be(mbedtls_mpi_size(&rsa->N), res_APDU + res_APDU_size); res_APDU_size += 2; put_uint16_be(mbedtls_mpi_size(&rsa->N), res_APDU + res_APDU_size); res_APDU_size += 2;
mbedtls_mpi_write_binary(&rsa->N, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->N)); mbedtls_mpi_write_binary(&rsa->N, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->N));
res_APDU_size += mbedtls_mpi_size(&rsa->N); res_APDU_size += mbedtls_mpi_size(&rsa->N);
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = mbedtls_mpi_size(&rsa->E) & 0xff; res_APDU[res_APDU_size++] = mbedtls_mpi_size(&rsa->E) & 0xff;
mbedtls_mpi_write_binary(&rsa->E, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->E)); mbedtls_mpi_write_binary(&rsa->E, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->E));
res_APDU_size += mbedtls_mpi_size(&rsa->E); res_APDU_size += mbedtls_mpi_size(&rsa->E);
put_uint16_t_be(res_APDU_size - 5, res_APDU + 3); put_uint16_be(res_APDU_size - 5, res_APDU + 3);
} }
void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) { void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN]; uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN];
size_t plen = 0; size_t plen = 0;
mbedtls_ecp_point_write_binary(&ecdsa->grp, mbedtls_ecp_point_write_binary(&ecdsa->grp, &ecdsa->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt));
&ecdsa->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&plen,
pt,
sizeof(pt));
res_APDU[res_APDU_size++] = 0x7f; res_APDU[res_APDU_size++] = 0x7f;
res_APDU[res_APDU_size++] = 0x49; res_APDU[res_APDU_size++] = 0x49;
if (plen >= 128) { if (plen >= 128) {
@@ -677,17 +828,13 @@ void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
res_APDU_size += plen; res_APDU_size += plen;
} }
int rsa_sign(mbedtls_rsa_context *ctx, int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) {
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; uint8_t *d = (uint8_t *) data, *end = d + data_len, *hsh = NULL;
size_t seq_len = 0, hash_len = 0; size_t seq_len = 0, hash_len = 0;
int key_size = ctx->len, r = 0; size_t key_size = ctx->len;
int r = 0;
mbedtls_md_type_t md = MBEDTLS_MD_NONE; mbedtls_md_type_t md = MBEDTLS_MD_NONE;
if (mbedtls_asn1_get_tag(&d, end, &seq_len, if (mbedtls_asn1_get_tag(&d, end, &seq_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) {
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) {
mbedtls_asn1_buf mdb; mbedtls_asn1_buf mdb;
r = mbedtls_asn1_get_alg_null(&d, end, &mdb); r = mbedtls_asn1_get_alg_null(&d, end, &mdb);
if (r == 0) { if (r == 0) {
@@ -734,11 +881,11 @@ int rsa_sign(mbedtls_rsa_context *ctx,
if (data_len < key_size) { //needs padding if (data_len < key_size) { //needs padding
memset((uint8_t *) data + data_len, 0, key_size - data_len); memset((uint8_t *) data + data_len, 0, key_size - data_len);
} }
r = mbedtls_rsa_private(ctx, random_gen, NULL, data, out); r = mbedtls_rsa_private(ctx, random_fill_iterator, NULL, data, out);
} }
else { else {
uint8_t *signature = (uint8_t *) calloc(key_size, sizeof(uint8_t)); uint8_t *signature = (uint8_t *) calloc(key_size, sizeof(uint8_t));
r = mbedtls_rsa_pkcs1_sign(ctx, random_gen, NULL, md, hash_len, hsh, signature); r = mbedtls_rsa_pkcs1_sign(ctx, random_fill_iterator, NULL, md, hash_len, hsh, signature);
memcpy(out, signature, key_size); memcpy(out, signature, key_size);
free(signature); free(signature);
} }
@@ -746,16 +893,12 @@ int rsa_sign(mbedtls_rsa_context *ctx,
return r; return r;
} }
int ecdsa_sign(mbedtls_ecp_keypair *ctx, int ecdsa_sign(mbedtls_ecp_keypair *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) {
const uint8_t *data,
size_t data_len,
uint8_t *out,
size_t *out_len) {
int r = 0; int r = 0;
#ifdef MBEDTLS_EDDSA_C #ifdef MBEDTLS_EDDSA_C
if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) { if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) {
r = mbedtls_eddsa_write_signature(ctx, data, data_len, out, 114, out_len, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL); r = mbedtls_eddsa_write_signature(ctx, data, data_len, out, 114, out_len, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL);
} }
else else
#endif #endif
@@ -763,7 +906,7 @@ int ecdsa_sign(mbedtls_ecp_keypair *ctx,
mbedtls_mpi ri, si; mbedtls_mpi ri, si;
mbedtls_mpi_init(&ri); mbedtls_mpi_init(&ri);
mbedtls_mpi_init(&si); mbedtls_mpi_init(&si);
r = mbedtls_ecdsa_sign(&ctx->grp, &ri, &si, &ctx->d, data, data_len, random_gen, NULL); r = mbedtls_ecdsa_sign(&ctx->grp, &ri, &si, &ctx->d, data, data_len, random_fill_iterator, NULL);
if (r == 0) { if (r == 0) {
size_t plen = (ctx->grp.nbits + 7) / 8; size_t plen = (ctx->grp.nbits + 7) / 8;
mbedtls_mpi_write_binary(&ri, out, plen); mbedtls_mpi_write_binary(&ri, out, plen);
@@ -776,24 +919,6 @@ int ecdsa_sign(mbedtls_ecp_keypair *ctx,
return r; return r;
} }
extern int cmd_select();
extern int cmd_get_data();
extern int cmd_get_next_data();
extern int cmd_put_data();
extern int cmd_verify();
extern int cmd_select_data();
extern int cmd_version_openpgp();
extern int cmd_import_data();
extern int cmd_change_pin();
extern int cmd_mse();
extern int cmd_internal_aut();
extern int cmd_challenge();
extern int cmd_activate_file();
extern int cmd_terminate_df();
extern int cmd_pso();
extern int cmd_keypair_gen();
extern int cmd_reset_retry();
#define INS_VERIFY 0x20 #define INS_VERIFY 0x20
#define INS_MSE 0x22 #define INS_MSE 0x22
#define INS_CHANGE_PIN 0x24 #define INS_CHANGE_PIN 0x24
@@ -807,6 +932,7 @@ extern int cmd_reset_retry();
#define INS_SELECT_DATA 0xA5 #define INS_SELECT_DATA 0xA5
#define INS_GET_DATA 0xCA #define INS_GET_DATA 0xCA
#define INS_GET_NEXT_DATA 0xCC #define INS_GET_NEXT_DATA 0xCC
#define INS_GET_BULK_DATA 0xCE
#define INS_PUT_DATA 0xDA #define INS_PUT_DATA 0xDA
#define INS_IMPORT_DATA 0xDB #define INS_IMPORT_DATA 0xDB
#define INS_TERMINATE_DF 0xE6 #define INS_TERMINATE_DF 0xE6
@@ -830,10 +956,11 @@ static const cmd_t cmds[] = {
{ INS_VERSION, cmd_version_openpgp }, { INS_VERSION, cmd_version_openpgp },
{ INS_SELECT_DATA, cmd_select_data }, { INS_SELECT_DATA, cmd_select_data },
{ INS_GET_NEXT_DATA, cmd_get_next_data }, { INS_GET_NEXT_DATA, cmd_get_next_data },
{ 0x00, 0x0 } { INS_GET_BULK_DATA, cmd_get_bulk_data },
{ 0x00, NULL }
}; };
int openpgp_process_apdu() { int openpgp_process_apdu(void) {
sm_unwrap(); sm_unwrap();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {

View File

@@ -23,7 +23,7 @@
#include <pico/stdlib.h> #include <pico/stdlib.h>
#endif #endif
#include "pico_keys.h" #include "picokeys.h"
#include "apdu.h" #include "apdu.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
@@ -67,16 +67,41 @@ extern int pin_reset_retries(const file_t *pin, bool force);
extern void select_file(file_t *pe); extern void select_file(file_t *pe);
extern int parse_do(uint16_t *fids, int mode); extern int parse_do(uint16_t *fids, int mode);
extern int load_dek(); extern int load_dek(void);
extern int check_pin(const file_t *pin, const uint8_t *data, size_t len); extern int check_pin(const file_t *pin, const uint8_t *data, size_t len);
extern mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len); extern mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len);
extern int reset_sig_count(); extern int reset_sig_count(void);
extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut; extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut;
extern bool wait_button_pressed_fid(uint16_t fid); extern bool wait_button_pressed_fid(uint16_t fid);
extern void scan_files_openpgp(); extern void scan_files_openpgp(void);
extern int load_aes_key(uint8_t *aes_key, file_t *fkey); extern int load_aes_key(uint8_t *aes_key, file_t *fkey);
extern int inc_sig_count(); extern int inc_sig_count(void);
extern int dek_encrypt(uint8_t *data, size_t len); extern int dek_encrypt(uint8_t *data, size_t len);
extern int dek_decrypt(uint8_t *data, size_t len); extern int dek_decrypt(uint8_t *data, size_t len);
int cmd_select(void);
int cmd_get_data(void);
int cmd_get_next_data(void);
int cmd_put_data(void);
int cmd_verify(void);
int cmd_select_data(void);
int cmd_version_openpgp(void);
int cmd_import_data(void);
int cmd_change_pin(void);
int cmd_mse(void);
int cmd_internal_aut(void);
int cmd_challenge(void);
int cmd_activate_file(void);
int cmd_terminate_df(void);
int cmd_pso(void);
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 #endif

View File

@@ -15,15 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "pico_keys.h" #include "picokeys.h"
#include "serial.h"
#include "random.h" #include "random.h"
#include "eac.h" #include "eac.h"
#include "crypto_utils.h" #include "crypto_utils.h"
@@ -76,9 +76,11 @@ uint8_t yk_aid[] = {
bool has_pwpiv = false; bool has_pwpiv = false;
uint8_t session_pwpiv[32]; uint8_t session_pwpiv[32];
int piv_process_apdu(); int piv_process_apdu(void);
void init_piv(void);
int piv_parse_discovery(const file_t *ef);
static int get_serial() { static int get_serial(void) {
uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3]; uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3];
return serial; return serial;
} }
@@ -89,7 +91,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3); mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3);
mbedtls_x509write_crt_set_validity(&ctx, "20240325000000", "20741231235959"); mbedtls_x509write_crt_set_validity(&ctx, "20240325000000", "20741231235959");
uint8_t serial[20]; uint8_t serial[20];
random_gen(NULL, serial, sizeof(serial)); random_fill_buffer(serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial)); mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context skey, ikey; mbedtls_pk_context skey, ikey;
mbedtls_ecdsa_context actx; // attestation key mbedtls_ecdsa_context actx; // attestation key
@@ -108,7 +110,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Attestation %X", slot); sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Attestation %X", slot);
mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname); mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname);
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot F9"); mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot F9");
file_t *ef_key = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_EF);
mbedtls_ecdsa_init(&actx); mbedtls_ecdsa_init(&actx);
load_private_key_ecdsa(&actx, ef_key, false); load_private_key_ecdsa(&actx, ef_key, false);
mbedtls_pk_setup(&ikey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); mbedtls_pk_setup(&ikey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
@@ -116,15 +118,15 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
mbedtls_x509write_crt_set_issuer_key(&ctx, &ikey); mbedtls_x509write_crt_set_issuer_key(&ctx, &ikey);
uint8_t ver[] = {PIV_VERSION_MAJOR, PIV_VERSION_MINOR, 0}; uint8_t ver[] = {PIV_VERSION_MAJOR, PIV_VERSION_MINOR, 0};
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x03", 10, 0, ver, sizeof(ver)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x03", 10, 0, ver, sizeof(ver));
uint32_t serial = get_serial(); uint32_t device_serial = get_serial();
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x07", 10, 0, (const uint8_t *)&serial, sizeof(serial)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x07", 10, 0, (const uint8_t *)&device_serial, sizeof(device_serial));
int meta_len = 0; int meta_len = 0;
uint8_t *meta; uint8_t *meta;
if ((meta_len = meta_find(slot, &meta)) >= 0) { if ((meta_len = meta_find(slot, &meta)) >= 0) {
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x08", 10, 0, &meta[1], 2); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x08", 10, 0, &meta[1], 2);
} }
uint8_t v = 1; uint8_t v = 1;
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x09", 10, 0, &v, sizeof(serial)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x09", 10, 0, &v, sizeof(v));
} }
else { else {
uint8_t wslot = slot; uint8_t wslot = slot;
@@ -153,10 +155,8 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
} }
mbedtls_x509write_crt_set_subject_key_identifier(&ctx); mbedtls_x509write_crt_set_subject_key_identifier(&ctx);
mbedtls_x509write_crt_set_authority_key_identifier(&ctx); mbedtls_x509write_crt_set_authority_key_identifier(&ctx);
mbedtls_x509write_crt_set_key_usage(&ctx, mbedtls_x509write_crt_set_key_usage(&ctx, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN);
MBEDTLS_X509_KU_DIGITAL_SIGNATURE | int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_fill_iterator, NULL);
MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL);
/* skey cannot be freed, as it is freed later */ /* skey cannot be freed, as it is freed later */
if (attestation) { if (attestation) {
mbedtls_ecdsa_free(&actx); mbedtls_ecdsa_free(&actx);
@@ -165,10 +165,10 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
return ret; return ret;
} }
static void scan_files_piv() { static void scan_files_piv(void) {
scan_flash(); file_scan_flash();
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF);
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
if (file_get_size(ef) == 0) { if (file_get_size(ef) == 0) {
printf("PW status is empty. Initializing to default\r\n"); printf("PW status is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 }; const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 };
@@ -182,7 +182,7 @@ static void scan_files_piv() {
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) {
if (file_get_size(ef) == 0) { if (file_get_size(ef) == 0) {
printf("PW retries is empty. Initializing to default\r\n"); printf("PW retries is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 3, 3, 3, 3, 3 }; const uint8_t def[] = { 0x1, 3, 3, 3, 3, 3 };
@@ -197,83 +197,77 @@ static void scan_files_piv() {
} }
} }
bool reset_dek = false; bool reset_dek = false;
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_ANY)) && !file_has_data(ef)) {
if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE+32*3) { printf("DEK PIV is empty or older\r\n");
printf("DEK is empty or older\r\n"); const uint8_t defpin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
const uint8_t defpin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; const uint8_t *random_dek = random_bytes_get(IV_SIZE + 32);
const uint8_t *dek = random_bytes_get(IV_SIZE + 32);
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; uint8_t def[DEK_FILE_SIZE];
if (file_get_size(ef) > 0) { def[0] = 0x3; // Format
memcpy(def, file_get_data(ef), file_get_size(ef));
} pin_derive_session(defpin, sizeof(defpin), session_pwpiv);
else { encrypt_with_aad(session_pwpiv, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
memcpy(def, dek, IV_SIZE); mbedtls_platform_zeroize(session_pwpiv, sizeof(session_pwpiv));
}
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);
file_put_data(ef, def, sizeof(def)); file_put_data(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"; 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); file_t *ef_cardmgm = file_search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY);
file_put_data(ef, key, 24); file_put_data(ef_cardmgm, key, 24);
uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS }; uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS };
meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta)); meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta));
has_pwpiv = false;
memset(session_pwpiv, 0, sizeof(session_pwpiv));
reset_dek = true; reset_dek = true;
} }
} if ((ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) {
if ((ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PIV PIN is empty. Initializing with default password\r\n"); printf("PIV PIN is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; 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); 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)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PIV PUK is empty. Initializing with default password\r\n"); printf("PIV PUK is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; 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); 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)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("ATTESTATION key is empty. Initializing with random one\r\n"); printf("ATTESTATION key is empty. Initializing with random one\r\n");
mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa); mbedtls_ecdsa_init(&ecdsa);
int r = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP384R1, random_gen, NULL); int r = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP384R1, random_fill_iterator, NULL);
r = store_keys(&ecdsa, ALGO_ECDSA, EF_PIV_KEY_ATTESTATION, false); r = store_keys(&ecdsa, ALGO_ECDSA, EF_PIV_KEY_ATTESTATION, false);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&ecdsa, PIV_ALGO_ECCP384, EF_PIV_KEY_ATTESTATION, false, cert, sizeof(cert)); r = x509_create_cert(&ecdsa, PIV_ALGO_ECCP384, EF_PIV_KEY_ATTESTATION, false, cert, sizeof(cert));
ef = search_by_fid(EF_PIV_ATTESTATION, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_ATTESTATION, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
} }
} }
low_flash_available(); flash_commit();
} }
void init_piv() { void init_piv(void) {
scan_files_piv(); scan_files_piv();
has_pwpiv = false; has_pwpiv = false;
// cmd_select(); // cmd_select();
} }
int piv_unload() { static int piv_unload(void) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
void select_piv_aid() { static void select_piv_aid(void) {
res_APDU[res_APDU_size++] = 0x61; res_APDU[res_APDU_size++] = 0x61;
res_APDU[res_APDU_size++] = 0; //filled later res_APDU[res_APDU_size++] = 0; //filled later
res_APDU[res_APDU_size++] = 0x4F; res_APDU[res_APDU_size++] = 0x4F;
@@ -300,13 +294,13 @@ void select_piv_aid() {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
int piv_select_aid(app_t *a, uint8_t force) { static int piv_select_aid(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = piv_process_apdu; a->process_apdu = piv_process_apdu;
a->unload = piv_unload; a->unload = piv_unload;
init_piv(); init_piv();
select_piv_aid(); select_piv_aid();
return PICOKEY_OK; return PICOKEYS_OK;
} }
INITIALIZER( piv_ctor ) { INITIALIZER( piv_ctor ) {
@@ -314,14 +308,14 @@ INITIALIZER( piv_ctor ) {
register_app(piv_select_aid, yk_aid); register_app(piv_select_aid, yk_aid);
} }
static int cmd_version() { static int cmd_version(void) {
res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR; res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PIV_VERSION_MINOR; res_APDU[res_APDU_size++] = PIV_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0x0; res_APDU[res_APDU_size++] = 0x0;
return SW_OK(); return SW_OK();
} }
static int cmd_select() { static int cmd_piv_select(void) {
if (P2(apdu) != 0x1) { if (P2(apdu) != 0x1) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
@@ -332,12 +326,13 @@ static int cmd_select() {
} }
int piv_parse_discovery(const file_t *ef) { int piv_parse_discovery(const file_t *ef) {
(void) 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); 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; res_APDU_size = 20;
return res_APDU_size; return res_APDU_size;
} }
static int cmd_get_serial() { static int cmd_get_serial(void) {
uint32_t serial = get_serial(); uint32_t serial = get_serial();
res_APDU[res_APDU_size++] = serial >> 24; res_APDU[res_APDU_size++] = serial >> 24;
res_APDU[res_APDU_size++] = serial >> 16; res_APDU[res_APDU_size++] = serial >> 16;
@@ -346,8 +341,7 @@ static int cmd_get_serial() {
return SW_OK(); return SW_OK();
} }
extern int check_pin(const file_t *pin, const uint8_t *data, size_t len); static int cmd_piv_verify(void) {
static int cmd_verify() {
uint8_t key_ref = P2(apdu); uint8_t key_ref = P2(apdu);
if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) { if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -357,10 +351,10 @@ static int cmd_verify() {
} }
file_t *pw, *pw_status; file_t *pw, *pw_status;
uint16_t fid = EF_PIV_PIN; uint16_t fid = EF_PIV_PIN;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw)[0] == 0) { //not initialized if (file_get_data(pw)[0] == 0) { //not initialized
@@ -384,7 +378,7 @@ static int cmd_verify() {
return set_res_sw(0x63, 0xc0 | retries); return set_res_sw(0x63, 0xc0 | retries);
} }
static int cmd_get_data() { static int cmd_piv_get_data(void) {
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -400,11 +394,13 @@ static int cmd_get_data() {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
} }
file_t *ef = NULL; file_t *ef = NULL;
if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) { if ((ef = file_search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) {
uint16_t data_len = 0; uint16_t data_len = 0;
res_APDU_size = 2; // Minimum: TAG+LEN res_APDU_size = 2; // Minimum: TAG+LEN
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
data_len = ((int (*)(const file_t *))(ef->data))((const file_t *) ef); int (*file_data_func)(const file_t *) = NULL;
memcpy(&file_data_func, &ef->data, sizeof(file_data_func));
data_len = file_data_func(ef);
} }
else { else {
if (ef->data) { if (ef->data) {
@@ -430,7 +426,7 @@ static int cmd_get_data() {
return SW_OK(); return SW_OK();
} }
static int cmd_get_metadata() { static int cmd_get_metadata(void) {
if (P1(apdu) != 0x00) { if (P1(apdu) != 0x00) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -442,7 +438,7 @@ static int cmd_get_metadata() {
else if (key_ref == 0x81) { else if (key_ref == 0x81) {
key_ref = EF_PIV_PUK; key_ref = EF_PIV_PUK;
} }
file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -470,13 +466,13 @@ static int cmd_get_metadata() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
int r = load_private_key_rsa(&ctx, ef_key, false); int r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
put_uint16_t_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2; put_uint16_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2;
mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N)); mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N));
res_APDU_size += mbedtls_mpi_size(&ctx.N); res_APDU_size += mbedtls_mpi_size(&ctx.N);
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
@@ -489,7 +485,7 @@ static int cmd_get_metadata() {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
int r = load_private_key_ecdsa(&ctx, ef_key, false); int r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -529,26 +525,27 @@ static int cmd_get_metadata() {
uint8_t dhash[32]; uint8_t dhash[32];
int32_t eq = 0; int32_t eq = 0;
if (key_ref == EF_PIV_PIN) { 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); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
} }
else if (key_ref == EF_PIV_PUK) { 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); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
} }
else if (key_ref == EF_PIV_KEY_CARDMGM) { 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++] = 0x5;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = eq == 0; res_APDU[res_APDU_size++] = eq == 0;
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) { if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) {
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf)); uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf));
if (!(pw_status = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf)); uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf));
@@ -563,7 +560,7 @@ static int cmd_get_metadata() {
uint8_t challenge[16]; uint8_t challenge[16];
bool has_challenge = false; bool has_challenge = false;
bool has_mgm = false; bool has_mgm = false;
static int cmd_authenticate() { static int cmd_authenticate(void) {
uint8_t algo = P1(apdu), key_ref = P2(apdu); uint8_t algo = P1(apdu), key_ref = P2(apdu);
if (apdu.nc == 0) { if (apdu.nc == 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -575,7 +572,7 @@ static int cmd_authenticate() {
if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) { if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_mgm = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_mgm)) { if (!file_has_data(ef_mgm)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -617,7 +614,7 @@ static int cmd_authenticate() {
if (key_ref != EF_PIV_KEY_CARDMGM) { if (key_ref != EF_PIV_KEY_CARDMGM) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_mgm = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_mgm)) { if (!file_has_data(ef_mgm)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -684,7 +681,7 @@ static int cmd_authenticate() {
has_challenge = true; has_challenge = true;
} }
else { else {
file_t *ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -692,7 +689,7 @@ static int cmd_authenticate() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
int r = load_private_key_rsa(&ctx, ef_key, false); int r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -705,7 +702,7 @@ static int cmd_authenticate() {
memcpy(res_APDU, "\x7C\x82\x00\x00\x82\x82\x00\x00", 8); memcpy(res_APDU, "\x7C\x82\x00\x00\x82\x82\x00\x00", 8);
res_APDU_size = 8; res_APDU_size = 8;
} }
r = mbedtls_rsa_private(&ctx, random_gen, NULL, a81.data, res_APDU + res_APDU_size); r = mbedtls_rsa_private(&ctx, random_fill_iterator, NULL, a81.data, res_APDU + res_APDU_size);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (algo == PIV_ALGO_RSA1024) { if (algo == PIV_ALGO_RSA1024) {
res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 1] = olen;
@@ -726,14 +723,14 @@ static int cmd_authenticate() {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
int r = load_private_key_ecdsa(&ctx, ef_key, false); int r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
memcpy(res_APDU, "\x7C\x00\x82\x00", 4); memcpy(res_APDU, "\x7C\x00\x82\x00", 4);
res_APDU_size = 4; res_APDU_size = 4;
r = mbedtls_ecdsa_write_signature(&ctx, algo == PIV_ALGO_ECCP256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384, a81.data, a81.len, res_APDU + res_APDU_size, MBEDTLS_ECDSA_MAX_LEN, &olen, random_gen, NULL); r = mbedtls_ecdsa_write_signature(&ctx, algo == PIV_ALGO_ECCP256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384, a81.data, a81.len, res_APDU + res_APDU_size, MBEDTLS_ECDSA_MAX_LEN, &olen, random_fill_iterator, NULL);
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 1] = olen;
res_APDU[res_APDU_size - 3] = olen + 2; res_APDU[res_APDU_size - 3] = olen + 2;
@@ -797,7 +794,7 @@ static int cmd_authenticate() {
if (chal_len != a82.len) { if (chal_len != a82.len) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -840,7 +837,7 @@ static int cmd_authenticate() {
return SW_OK(); return SW_OK();
} }
static int cmd_asym_keygen() { static int cmd_asym_keygen(void) {
uint8_t key_ref = P2(apdu); uint8_t key_ref = P2(apdu);
if (apdu.nc == 0) { if (apdu.nc == 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -895,7 +892,7 @@ static int cmd_asym_keygen() {
if (asn1_len(&a81)) { if (asn1_len(&a81)) {
exponent = (int)asn1_get_uint(&a81); exponent = (int)asn1_get_uint(&a81);
} }
int r = mbedtls_rsa_gen_key(&rsa, random_gen, NULL, nlen, exponent); int r = mbedtls_rsa_gen_key(&rsa, random_fill_iterator, NULL, nlen, exponent);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -903,11 +900,11 @@ static int cmd_asym_keygen() {
make_rsa_response(&rsa); make_rsa_response(&rsa);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&rsa, a80.data[0], key_ref, false, cert, sizeof(cert)); r = x509_create_cert(&rsa, a80.data[0], key_ref, false, cert, sizeof(cert));
file_t *ef = search_by_fid(key_cert, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_cert, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -916,7 +913,7 @@ static int cmd_asym_keygen() {
mbedtls_ecp_group_id gid = a80.data[0] == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1; mbedtls_ecp_group_id gid = a80.data[0] == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1;
mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa); mbedtls_ecdsa_init(&ecdsa);
int r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, NULL); int r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -924,11 +921,11 @@ static int cmd_asym_keygen() {
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&ecdsa, a80.data[0], key_ref, false, cert, sizeof(cert)); r = x509_create_cert(&ecdsa, a80.data[0], key_ref, false, cert, sizeof(cert));
file_t *ef = search_by_fid(key_cert, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_cert, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false);
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -943,11 +940,11 @@ static int cmd_asym_keygen() {
} }
uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED}; uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED};
meta_add(key_ref, meta, sizeof(meta)); meta_add(key_ref, meta, sizeof(meta));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_put_data() { static int cmd_piv_put_data(void) {
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -961,7 +958,7 @@ static int cmd_put_data() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
uint16_t fid = (a5c.data[1] << 8 | a5c.data[2]); uint16_t fid = (a5c.data[1] << 8 | a5c.data[2]);
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -971,12 +968,12 @@ static int cmd_put_data() {
else { else {
flash_clear_file(ef); flash_clear_file(ef);
} }
low_flash_available(); flash_commit();
} }
return SW_OK(); return SW_OK();
} }
static int cmd_set_mgmkey() { static int cmd_set_mgmkey(void) {
if (P1(apdu) != 0xFF) { if (P1(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -997,7 +994,7 @@ static int cmd_set_mgmkey() {
if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) { if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = search_by_fid(key_ref, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_ref, NULL, SPECIFY_ANY);
file_put_data(ef, apdu.data + 3, pinlen); file_put_data(ef, apdu.data + 3, pinlen);
uint8_t *meta = NULL, new_meta[4]; uint8_t *meta = NULL, new_meta[4];
int meta_len = 0; int meta_len = 0;
@@ -1008,11 +1005,11 @@ static int cmd_set_mgmkey() {
new_meta[0] = algo; new_meta[0] = algo;
new_meta[2] = touch; new_meta[2] = touch;
meta_add(key_ref, new_meta, sizeof(new_meta)); meta_add(key_ref, new_meta, sizeof(new_meta));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_move_key() { static int cmd_move_key(void) {
if (apdu.nc != 0) { if (apdu.nc != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
@@ -1020,6 +1017,9 @@ static int cmd_move_key() {
if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) { if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (IS_RETIRED(from) && IS_ACTIVE(to)) {
return SW_INCORRECT_P1P2();
}
if (from == 0x93) { if (from == 0x93) {
from = EF_PIV_KEY_RETIRED18; from = EF_PIV_KEY_RETIRED18;
} }
@@ -1027,23 +1027,99 @@ static int cmd_move_key() {
to = EF_PIV_KEY_RETIRED18; to = EF_PIV_KEY_RETIRED18;
} }
file_t *efs, *efd; file_t *efs, *efd;
if (!(efs = search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) { if (!(efs = file_search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = file_search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
} }
uint16_t cert_from_fid = 0;
uint16_t cert_to_fid = 0;
if (from == EF_PIV_KEY_AUTHENTICATION) {
cert_from_fid = EF_PIV_AUTHENTICATION;
}
else if (from == EF_PIV_KEY_SIGNATURE) {
cert_from_fid = EF_PIV_SIGNATURE;
}
else if (from == EF_PIV_KEY_KEYMGM) {
cert_from_fid = EF_PIV_KEY_MANAGEMENT;
}
else if (from == EF_PIV_KEY_CARDAUTH) {
cert_from_fid = EF_PIV_CARD_AUTH;
}
else if (from == EF_PIV_KEY_RETIRED18) {
cert_from_fid = EF_PIV_RETIRED18;
}
else {
cert_from_fid = from + 0xC08B;
}
if (to != 0xFF) {
if (to == EF_PIV_KEY_AUTHENTICATION) {
cert_to_fid = EF_PIV_AUTHENTICATION;
}
else if (to == EF_PIV_KEY_SIGNATURE) {
cert_to_fid = EF_PIV_SIGNATURE;
}
else if (to == EF_PIV_KEY_KEYMGM) {
cert_to_fid = EF_PIV_KEY_MANAGEMENT;
}
else if (to == EF_PIV_KEY_CARDAUTH) {
cert_to_fid = EF_PIV_CARD_AUTH;
}
else if (to == EF_PIV_KEY_RETIRED18) {
cert_to_fid = EF_PIV_RETIRED18;
}
else {
cert_to_fid = to + 0xC08B;
}
}
if (to != 0xFF) { if (to != 0xFF) {
file_put_data(efd, file_get_data(efs), file_get_size(efs)); file_put_data(efd, file_get_data(efs), file_get_size(efs));
} }
file_t *ef_cert_from = file_search_by_fid(cert_from_fid, NULL, SPECIFY_EF);
if (to != 0xFF) {
file_t *ef_cert_to = file_search_by_fid(cert_to_fid, NULL, SPECIFY_EF);
if (!ef_cert_to) {
return SW_FILE_NOT_FOUND();
}
if (file_has_data(ef_cert_from)) {
file_put_data(ef_cert_to, file_get_data(ef_cert_from), file_get_size(ef_cert_from));
}
else {
flash_clear_file(ef_cert_to);
}
}
if (ef_cert_from) {
flash_clear_file(ef_cert_from);
}
uint8_t *meta_src = NULL;
int meta_len = meta_find(from, &meta_src);
if (to != 0xFF) {
if (meta_len > 0 && meta_src != NULL) {
uint8_t *meta_copy = (uint8_t *)calloc(1, (size_t)meta_len);
if (!meta_copy) {
return SW_MEMORY_FAILURE();
}
memcpy(meta_copy, meta_src, (size_t)meta_len);
meta_add(to, meta_copy, (uint16_t)meta_len);
free(meta_copy);
}
else {
meta_delete(to);
}
}
meta_delete(from);
flash_clear_file(efs); flash_clear_file(efs);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_change_pin() { static int cmd_piv_change_pin(void) {
uint8_t pin_ref = P2(apdu); uint8_t pin_ref = P2(apdu);
if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) { if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef = search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1052,19 +1128,21 @@ static int cmd_change_pin() {
if (ret != 0x9000) { if (ret != 0x9000) {
return ret; return ret;
} }
uint8_t dhash[33];
uint8_t dhash[34];
dhash[0] = pin_len; 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)); file_put_data(ef, dhash, sizeof(dhash));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_reset_retry() { static int cmd_piv_reset_retry(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x80) { if (P1(apdu) != 0x0 || P2(apdu) != 0x80) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1073,18 +1151,19 @@ static int cmd_reset_retry() {
if (ret != 0x9000) { if (ret != 0x9000) {
return ret; return ret;
} }
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = pin_len; dhash[0] = pin_len;
double_hash_pin(apdu.data + puk_data[0], pin_len, dhash + 1); dhash[1] = 0x1; // Format
ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); pin_derive_verifier(apdu.data + puk_data[0], pin_len, dhash + 2);
ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_set_retries() { static int cmd_set_retries(void) {
file_t *ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1095,31 +1174,34 @@ static int cmd_set_retries() {
file_put_data(ef, tmp, file_get_size(ef)); file_put_data(ef, tmp, file_get_size(ef));
free(tmp); free(tmp);
ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY);
const uint8_t def_pin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; 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); 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)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY);
const uint8_t def_puk[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; const uint8_t def_puk[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38};
dhash[0] = sizeof(def_puk); 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)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_reset() { static int cmd_reset(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)))
{ {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -1127,13 +1209,13 @@ static int cmd_reset() {
if (retPIN != 0 || retPUK != 0) { if (retPIN != 0 || retPUK != 0) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
initialize_flash(true); file_initialize_flash(true);
low_flash_available(); flash_commit();
init_piv(); init_piv();
return SW_OK(); return SW_OK();
} }
static int cmd_attestation() { static int cmd_attestation(void) {
uint8_t key_ref = P1(apdu); uint8_t key_ref = P1(apdu);
if (P2(apdu) != 0x00) { if (P2(apdu) != 0x00) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -1144,7 +1226,7 @@ static int cmd_attestation() {
file_t *ef_key = NULL; file_t *ef_key = NULL;
int meta_len = 0; int meta_len = 0;
uint8_t *meta = NULL; uint8_t *meta = NULL;
if (!(ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) { if (!(ef_key = file_search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if ((meta_len = meta_find(key_ref, &meta)) <= 0) { if ((meta_len = meta_find(key_ref, &meta)) <= 0) {
@@ -1154,26 +1236,27 @@ static int cmd_attestation() {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
int r = 0; int r = 0;
uint8_t abuf[2048];
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) { if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef_key, false); r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); r = x509_create_cert(&ctx, meta[0], key_ref, true, abuf, sizeof(abuf));
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
} }
else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) { else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef_key, false); r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); r = x509_create_cert(&ctx, meta[0], key_ref, true, abuf, sizeof(abuf));
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
} }
else { else {
@@ -1182,12 +1265,12 @@ static int cmd_attestation() {
if (r <= 0) { if (r <= 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
memmove(res_APDU, res_APDU + 2048 - r, r); memcpy(res_APDU, abuf + sizeof(abuf) - r, r);
res_APDU_size = r; res_APDU_size = r;
return SW_OK(); return SW_OK();
} }
static int cmd_import_asym() { static int cmd_import_asym(void) {
uint8_t algo = P1(apdu), key_ref = P2(apdu); uint8_t algo = P1(apdu), key_ref = P2(apdu);
if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) { if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -1252,12 +1335,12 @@ static int cmd_import_asym() {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL); r = mbedtls_ecp_keypair_calc_public(&ecdsa, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = mbedtls_ecp_check_pub_priv(&ecdsa, &ecdsa, random_gen, NULL); r = mbedtls_ecp_check_pub_priv(&ecdsa, &ecdsa, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -1301,18 +1384,18 @@ static int cmd_import_asym() {
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_VERSION, cmd_version }, { INS_VERSION, cmd_version },
{ INS_SELECT, cmd_select }, { INS_SELECT, cmd_piv_select },
{ INS_YK_SERIAL, cmd_get_serial }, { INS_YK_SERIAL, cmd_get_serial },
{ INS_VERIFY, cmd_verify }, { INS_VERIFY, cmd_piv_verify },
{ INS_GET_DATA, cmd_get_data }, { INS_GET_DATA, cmd_piv_get_data },
{ INS_GET_METADATA, cmd_get_metadata }, { INS_GET_METADATA, cmd_get_metadata },
{ INS_AUTHENTICATE, cmd_authenticate }, { INS_AUTHENTICATE, cmd_authenticate },
{ INS_ASYM_KEYGEN, cmd_asym_keygen }, { INS_ASYM_KEYGEN, cmd_asym_keygen },
{ INS_PUT_DATA, cmd_put_data }, { INS_PUT_DATA, cmd_piv_put_data },
{ INS_SET_MGMKEY, cmd_set_mgmkey }, { INS_SET_MGMKEY, cmd_set_mgmkey },
{ INS_MOVE_KEY, cmd_move_key }, { INS_MOVE_KEY, cmd_move_key },
{ INS_CHANGE_PIN, cmd_change_pin }, { INS_CHANGE_PIN, cmd_piv_change_pin },
{ INS_RESET_RETRY, cmd_reset_retry }, { INS_RESET_RETRY, cmd_piv_reset_retry },
{ INS_SET_RETRIES, cmd_set_retries }, { INS_SET_RETRIES, cmd_set_retries },
{ INS_RESET, cmd_reset }, { INS_RESET, cmd_reset },
{ INS_ATTESTATION, cmd_attestation }, { INS_ATTESTATION, cmd_attestation },
@@ -1320,7 +1403,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int piv_process_apdu() { int piv_process_apdu(void) {
sm_unwrap(); sm_unwrap();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {

View File

@@ -29,7 +29,7 @@
#define PIV_VERSION_MINOR (PIV_VERSION & 0xff) #define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
#define PIPGP_VERSION 0x0404 #define PIPGP_VERSION 0x0406
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff) #define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff) #define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)

View File

@@ -3,5 +3,5 @@
source tests/docker_env.sh source tests/docker_env.sh
#run_in_docker rm -rf CMakeFiles #run_in_docker rm -rf CMakeFiles
run_in_docker mkdir -p build_in_docker 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} run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}

View File

@@ -201,7 +201,7 @@ def test_extended_capabilities(card):
pytest.skip("Yubikey returns 6B00 when no key") pytest.skip("Yubikey returns 6B00 when no key")
else: else:
a = get_data_object(card, 0xc0) a = get_data_object(card, 0xc0)
assert a == None or match(b'[\x70\x74\x75\x77]\x00\x00.[\x00\x08]\x00\x00\xff[\x00\x01][\x00\x01]', a) assert a == None or match(b'[\x70\x7F\x75\x77]\x00\x00.[\x00\x08]\x00\x08\x00[\x00\x01][\x00\x01]', a)
def test_key_attributes_1(card): def test_key_attributes_1(card):
if card.is_yubikey: if card.is_yubikey:

View File

@@ -28,6 +28,26 @@ from card_const import *
from constants_for_test import * from constants_for_test import *
import pytest import pytest
PRIVATE_DO_0101 = (0x01, 0x01)
PRIVATE_DO_0102 = (0x01, 0x02)
PRIVATE_DO_0103 = (0x01, 0x03)
PRIVATE_DO_0104 = (0x01, 0x04)
def _assert_sw(e, sw_list):
sw = e.args[0]
assert sw in sw_list
def _expect_security_error(callable_):
try:
callable_()
except ValueError as e:
_assert_sw(e, ["6982", "6985"])
return
assert False
class Test_Card_Personalize_Card_2(object): class Test_Card_Personalize_Card_2(object):
def test_verify_pw3_0(self, card): def test_verify_pw3_0(self, card):
v = card.verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
@@ -202,3 +222,112 @@ class Test_Card_Personalize_Card_2(object):
def test_verify_pw3_2(self, card): def test_verify_pw3_2(self, card):
v = card.verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
assert v assert v
def test_private_do_0101_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_pw3_ok")
assert r
def test_private_do_0101_write_fail_with_pw1_81(self, card):
card.cmd_select_openpgp()
v = card.verify(1, PW1_TEST4)
assert v
_expect_security_error(
lambda: card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_pw1_81")
)
def test_private_do_0101_write_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
r = card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_ok")
assert r
def test_private_do_0101_read_always(self, card):
card.cmd_select_openpgp()
data = get_data_object(card, 0x0101)
assert data == b"priv0101_ok" or data == b"priv0101_pw3_ok"
def test_private_do_0102_write_fail_with_pw1(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
_expect_security_error(
lambda: card.cmd_put_data(PRIVATE_DO_0102[0], PRIVATE_DO_0102[1], b"priv0102_pw1")
)
def test_private_do_0102_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0102[0], PRIVATE_DO_0102[1], b"priv0102_ok")
assert r
def test_private_do_0102_read_always(self, card):
card.cmd_select_openpgp()
data = get_data_object(card, 0x0102)
assert data == b"priv0102_ok"
def test_private_do_0103_read_fail_without_auth(self, card):
card.cmd_select_openpgp()
_expect_security_error(lambda: get_data_object(card, 0x0103))
def test_private_do_0103_read_fail_with_pw1_81(self, card):
card.cmd_select_openpgp()
v = card.verify(1, PW1_TEST4)
assert v
_expect_security_error(lambda: get_data_object(card, 0x0103))
def test_private_do_0103_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0103[0], PRIVATE_DO_0103[1], b"priv0103_pw3_ok")
assert r
def test_private_do_0103_read_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
data = get_data_object(card, 0x0103)
assert data == b"priv0103_pw3_ok"
def test_private_do_0103_write_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
r = card.cmd_put_data(PRIVATE_DO_0103[0], PRIVATE_DO_0103[1], b"priv0103_ok")
assert r
def test_private_do_0103_read_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
data = get_data_object(card, 0x0103)
assert data == b"priv0103_ok"
def test_private_do_0104_read_fail_without_auth(self, card):
card.cmd_select_openpgp()
_expect_security_error(lambda: get_data_object(card, 0x0104))
def test_private_do_0104_read_fail_with_pw1(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
_expect_security_error(lambda: get_data_object(card, 0x0104))
def test_private_do_0104_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0104[0], PRIVATE_DO_0104[1], b"priv0104_ok")
assert r
def test_private_do_0104_read_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
data = get_data_object(card, 0x0104)
assert data == b"priv0104_ok"