diff --git a/CMakeLists.txt b/CMakeLists.txt index 49b0567..9910399 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c - ${CMAKE_CURRENT_LIST_DIR}/src/hsm/hash_utils.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c @@ -119,7 +119,7 @@ pico_add_extra_outputs(pico_hsm) #target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1) -target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id) +target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc) # #project(flash_nuke C CXX ASM) diff --git a/build_pico_hsm.sh b/build_pico_hsm.sh index 10d4875..037ee77 100755 --- a/build_pico_hsm.sh +++ b/build_pico_hsm.sh @@ -1,7 +1,7 @@ #!/bin/bash VERSION_MAJOR="1" -VERSION_MINOR="8" +VERSION_MINOR="10" rm -rf release/* cd build_release diff --git a/patch_vidpid.sh b/patch_vidpid.sh index 0262343..dc1f379 100755 --- a/patch_vidpid.sh +++ b/patch_vidpid.sh @@ -18,7 +18,7 @@ # VERSION_MAJOR="1" -VERSION_MINOR="8" +VERSION_MINOR="0A" echo "----------------------------" echo "VID/PID patcher for Pico HSM" diff --git a/src/fs/file.c b/src/fs/file.c index 39d0fea..ad2af10 100644 --- a/src/fs/file.c +++ b/src/fs/file.c @@ -99,15 +99,16 @@ file_t file_entries[] = { /* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN) /* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN) /* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK - /* 16 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs - /* 17 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs - /* 18 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs - /* 19 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs - /* 20 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs - /* 21 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs - ///* 22 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - /* 23 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - /* 24 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end + /* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options + /* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs + /* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs + /* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs + /* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs + /* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs + /* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs + ///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end }; const file_t *MF = &file_entries[0]; diff --git a/src/fs/file.h b/src/fs/file.h index c87db66..5b4175f 100644 --- a/src/fs/file.h +++ b/src/fs/file.h @@ -60,6 +60,7 @@ #define EF_AODFS 0x6043 #define EF_DODFS 0x6044 #define EF_SKDFS 0x6045 +#define EF_DEVOPS 0x100E #define MAX_DEPTH 4 diff --git a/src/hsm/hash_utils.c b/src/hsm/crypto_utils.c similarity index 99% rename from src/hsm/hash_utils.c rename to src/hsm/crypto_utils.c index 9a665df..4df1811 100644 --- a/src/hsm/hash_utils.c +++ b/src/hsm/crypto_utils.c @@ -19,7 +19,7 @@ #include "mbedtls/md.h" #include "mbedtls/sha256.h" #include "mbedtls/aes.h" -#include "hash_utils.h" +#include "crypto_utils.h" #include "sc_hsm.h" #include "libopensc/card-sc-hsm.h" diff --git a/src/hsm/hash_utils.h b/src/hsm/crypto_utils.h similarity index 97% rename from src/hsm/hash_utils.h rename to src/hsm/crypto_utils.h index c411812..3b686c1 100644 --- a/src/hsm/hash_utils.h +++ b/src/hsm/crypto_utils.h @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#ifndef _HASH_UTILS_H_ -#define _HASH_UTILS_H_ +#ifndef _CRYPTO_UTILS_H_ +#define _CRYPTO_UTILS_H_ #include "stdlib.h" #include "pico/stdlib.h" diff --git a/src/hsm/dkek.c b/src/hsm/dkek.c index 0cd5f06..cd89c65 100644 --- a/src/hsm/dkek.c +++ b/src/hsm/dkek.c @@ -20,7 +20,7 @@ #include "stdlib.h" #include "pico/stdlib.h" #include "dkek.h" -#include "hash_utils.h" +#include "crypto_utils.h" #include "random.h" #include "sc_hsm.h" #include "mbedtls/md.h" @@ -88,6 +88,7 @@ int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes hash256(dkek+IV_SIZE, 32, hsh); release_dkek(); memcpy(kcv, hsh, 8); + return HSM_OK; } int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes diff --git a/src/hsm/hsm2040.c b/src/hsm/hsm2040.c index 72b0a46..228b1d5 100644 --- a/src/hsm/hsm2040.c +++ b/src/hsm/hsm2040.c @@ -33,6 +33,7 @@ #include "pico/multicore.h" #include "random.h" #include "hsm2040.h" +#include "hardware/rtc.h" extern void do_flash(); extern void low_flash_init(); @@ -1628,6 +1629,7 @@ int main(void) gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); #endif #endif + led_off_all(); @@ -1638,6 +1640,8 @@ int main(void) random_init(); low_flash_init(); + + rtc_init(); while (1) { diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index c0a12f9..21c6ee6 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -30,8 +30,9 @@ #include "mbedtls/hkdf.h" #include "version.h" #include "cvcerts.h" -#include "hash_utils.h" +#include "crypto_utils.h" #include "dkek.h" +#include "hardware/rtc.h" const uint8_t sc_hsm_aid[] = { 11, @@ -92,6 +93,14 @@ void select_file(file_t *pe) { //sc_hsm_unload(); //reset auth status } } + +uint16_t get_device_options() { + file_t *ef = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF); + if (ef && ef->data) + return (file_read_uint8(ef->data+2) << 8) | file_read_uint8(ef->data+3); + return 0x0; +} + static int cmd_select() { uint8_t p1 = P1(apdu); uint8_t p2 = P2(apdu); @@ -171,8 +180,9 @@ static int cmd_select() { if (pe == file_sc_hsm) { res_APDU[res_APDU_size++] = 0x85; res_APDU[res_APDU_size++] = 4; - res_APDU[res_APDU_size++] = 0xff; //options - res_APDU[res_APDU_size++] = 0xff; + uint16_t opts = get_device_options(); + res_APDU[res_APDU_size++] = opts & 0xff; + res_APDU[res_APDU_size++] = opts >> 8; res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR; res_APDU[res_APDU_size++] = HSM_VERSION_MINOR; res_APDU[1] = res_APDU_size-2; @@ -400,11 +410,12 @@ int pin_wrong_retry(const file_t *pin) { int check_pin(const file_t *pin, const uint8_t *data, size_t len) { if (!pin) - return SW_FILE_NOT_FOUND(); + return SW_REFERENCE_NOT_FOUND(); if (!pin->data) { return SW_REFERENCE_NOT_FOUND(); } isUserAuthenticated = false; + has_session_pin = has_session_sopin = false; uint8_t dhash[32]; double_hash_pin(data, len, dhash); if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len @@ -422,7 +433,10 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { return SW_MEMORY_FAILURE(); isUserAuthenticated = true; hash_multi(data, len, session_pin); - has_session_pin = true; + if (pin == file_pin1) + has_session_pin = true; + else if (pin == file_sopin) + has_session_sopin = true; return SW_OK(); } @@ -434,46 +448,94 @@ static int cmd_verify() { return SW_WRONG_P1P2(); uint8_t qualifier = p2&0x1f; if (p2 == 0x81) { //UserPin + uint16_t opts = get_device_options(); + if (opts & HSM_OPT_TRANSPORT_PIN) + return SW_DATA_INVALID(); + if (file_read_uint8(file_pin1->data+2) == 0) //not initialized + return SW_REFERENCE_NOT_FOUND(); if (apdu.cmd_apdu_data_len > 0) { return check_pin(file_pin1, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); } if (file_read_uint8(file_retries_pin1->data+2) == 0) return SW_PIN_BLOCKED(); + if (has_session_pin) + return SW_OK(); return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_pin1->data+2)); } else if (p2 == 0x88) { //SOPin + if (file_read_uint8(file_sopin->data+2) == 0) //not initialized + return SW_REFERENCE_NOT_FOUND(); if (apdu.cmd_apdu_data_len > 0) { return check_pin(file_sopin, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); } if (file_read_uint8(file_retries_sopin->data+2) == 0) return SW_PIN_BLOCKED(); + if (has_session_sopin) + return SW_OK(); return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2)); } return SW_REFERENCE_NOT_FOUND(); } static int cmd_reset_retry() { - if (P1(apdu) == 0x0) { - if (P2(apdu) == 0x81) { - if (!file_sopin || !file_pin1) { - return SW_FILE_NOT_FOUND(); - } - if (!file_sopin->data) { - return SW_REFERENCE_NOT_FOUND(); - } + if (P2(apdu) != 0x81) + return SW_REFERENCE_NOT_FOUND(); + if (!file_sopin || !file_pin1) { + return SW_FILE_NOT_FOUND(); + } + if (!file_sopin->data) { + return SW_REFERENCE_NOT_FOUND(); + } + uint16_t opts = get_device_options(); + if (!(opts & HSM_OPT_RRC)) + return SW_COMMAND_NOT_ALLOWED(); + if (P1(apdu) == 0x0 || P1(apdu) == 0x2) { + int newpin_len = 0; + if (P1(apdu) == 0x0) { + if (apdu.cmd_apdu_data_len <= 8) + return SW_WRONG_LENGTH(); uint16_t r = check_pin(file_sopin, apdu.cmd_apdu_data, 8); if (r != 0x9000) return r; - uint8_t dhash[33]; - dhash[0] = apdu.cmd_apdu_data_len-8; - double_hash_pin(apdu.cmd_apdu_data+8, apdu.cmd_apdu_data_len-8, dhash+1); - flash_write_data_to_file(file_pin1, dhash, sizeof(dhash)); - if (pin_reset_retries(file_pin1, true) != HSM_OK) - return SW_MEMORY_FAILURE(); - low_flash_available(); - return SW_OK(); + newpin_len = apdu.cmd_apdu_data_len-8; } + else if (P1(apdu) == 0x2) { + if (!has_session_sopin) + return SW_CONDITIONS_NOT_SATISFIED(); + if (apdu.cmd_apdu_data_len > 16) + return SW_WRONG_LENGTH(); + newpin_len = apdu.cmd_apdu_data_len; + } + uint8_t dhash[33]; + dhash[0] = newpin_len; + double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1); + flash_write_data_to_file(file_pin1, dhash, sizeof(dhash)); + if (pin_reset_retries(file_pin1, true) != HSM_OK) + return SW_MEMORY_FAILURE(); + low_flash_available(); + return SW_OK(); } + else if (P1(apdu) == 0x1 || P1(apdu) == 0x3) { + if (!(opts & HSM_OPT_RRC_RESET_ONLY)) + return SW_COMMAND_NOT_ALLOWED(); + if (P1(apdu) == 0x1) { + if (apdu.cmd_apdu_data_len != 8) + return SW_WRONG_LENGTH(); + uint16_t r = check_pin(file_sopin, apdu.cmd_apdu_data, 8); + if (r != 0x9000) + return r; + } + else if (P1(apdu) == 0x3) { + if (!has_session_sopin) + return SW_CONDITIONS_NOT_SATISFIED(); + if (apdu.cmd_apdu_data_len != 0) + return SW_WRONG_LENGTH(); + } + if (pin_reset_retries(file_pin1, true) != HSM_OK) + return SW_MEMORY_FAILURE(); + return SW_OK(); + } + return SW_INCORRECT_P1P2(); } static int cmd_challenge() { @@ -503,6 +565,8 @@ static int cmd_initialize() { uint8_t tag = *p++; uint8_t tag_len = *p++; if (tag == 0x80) { //options + file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF); + flash_write_data_to_file(tf, p, tag_len); } else if (tag == 0x81) { //user pin if (file_pin1 && file_pin1->data) { @@ -581,6 +645,7 @@ static int cmd_import_dkek() { } } + memset(res_APDU,0,10); res_APDU[0] = dkeks; res_APDU[1] = dkeks-current_dkeks; dkek_kcv(res_APDU+2); @@ -1036,7 +1101,7 @@ static int cmd_delete_file() { if (apdu.cmd_apdu_data_len == 0) { ef = currentEF; if (!(ef = search_dynamic_file(ef->fid))) - return SW_FILE_INVALID(); + return SW_FILE_NOT_FOUND(); } else { uint16_t fid = (apdu.cmd_apdu_data[0] << 8) | apdu.cmd_apdu_data[1]; @@ -1649,6 +1714,24 @@ static int cmd_derive_asym() { return SW_OK(); } +static int cmd_datetime() { + if (P1(apdu) != 0x0 || P2(apdu) != 0x0) + return SW_INCORRECT_P1P2(); + if (apdu.cmd_apdu_data_len != 8) + return SW_WRONG_LENGTH(); + datetime_t dt; + dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]); + dt.month = apdu.cmd_apdu_data[2]; + dt.day = apdu.cmd_apdu_data[3]; + dt.dotw = apdu.cmd_apdu_data[4]; + dt.hour = apdu.cmd_apdu_data[5]; + dt.min = apdu.cmd_apdu_data[6]; + dt.sec = apdu.cmd_apdu_data[7]; + if (!rtc_set_datetime(&dt)) + return SW_WRONG_DATA(); + return SW_OK(); +} + typedef struct cmd { uint8_t ins; @@ -1670,6 +1753,7 @@ typedef struct cmd #define INS_DERIVE_ASYM 0x76 #define INS_CIPHER_SYM 0x78 #define INS_CHALLENGE 0x84 +#define INS_DATETIME 0x88 #define INS_SELECT_FILE 0xA4 #define INS_READ_BINARY 0xB0 #define INS_READ_BINARY_ODD 0xB1 @@ -1697,6 +1781,7 @@ static const cmd_t cmds[] = { { INS_DECRYPT_ASYM, cmd_decrypt_asym }, { INS_CIPHER_SYM, cmd_cipher_sym }, { INS_DERIVE_ASYM, cmd_derive_asym }, + { INS_DATETIME, cmd_datetime }, { 0x00, 0x0} }; diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index c2a4f9f..6ac44f1 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -26,7 +26,6 @@ extern const uint8_t sc_hsm_aid[]; #define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00) #define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00) -#define SW_PIN_BLOCKED() set_res_sw (0x63, 0x00) #define SW_EXEC_ERROR() set_res_sw (0x64, 0x00) #define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81) #define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00) @@ -34,7 +33,7 @@ extern const uint8_t sc_hsm_aid[]; #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81) #define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82) #define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) -#define SW_FILE_INVALID() set_res_sw (0x69, 0x83) +#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83) #define SW_DATA_INVALID() set_res_sw (0x69, 0x84) #define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85) #define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) diff --git a/src/hsm/version.h b/src/hsm/version.h index 5534f9c..5340f9d 100644 --- a/src/hsm/version.h +++ b/src/hsm/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define HSM_VERSION 0x0108 +#define HSM_VERSION 0x010A #define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff) #define HSM_VERSION_MINOR (HSM_VERSION & 0xff)