From e4ecbc413dfe279081dd2c7d8282e1d11c87505a Mon Sep 17 00:00:00 2001 From: Aveen Ismail Date: Wed, 4 Dec 2024 15:48:11 +0100 Subject: [PATCH] Add support for global device reset --- lib/ykpiv.c | 26 ++++++++++++++++++++++++++ lib/ykpiv.h | 3 +++ tool/cmdline.ggo | 1 + tool/yubico-piv-tool.c | 33 +++++++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 21344489..2537387a 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -2371,3 +2371,29 @@ ykpiv_rc ykpiv_auth_get_verified(ykpiv_state* state) { ykpiv_rc ykpiv_auth_verify(ykpiv_state* state, uint8_t* pin, size_t* p_pin_len, int *tries, bool force_select, bool bio, bool verify_spin) { return _ykpiv_verify_select(state, pin, p_pin_len, tries, force_select, bio, verify_spin); } + +ykpiv_rc ykpiv_global_reset(ykpiv_state *state) { + ykpiv_rc res = YKPIV_OK; + unsigned char mgm_templ[] = {0x00, YKPIV_INS_SELECT_APPLICATION, 0x04, 0x00}; + unsigned char recv[256] = {0}; + unsigned long recv_len = sizeof(recv); + int sw = 0; + if ((res = _ykpiv_transfer_data(state, mgm_templ, mgmt_aid, sizeof(mgmt_aid), recv, &recv_len, &sw)) < YKPIV_OK) { + return res; + } + res = ykpiv_translate_sw_ex(__FUNCTION__, sw); + if (res != YKPIV_OK) { + DBG("Failed selecting mgmt/yk application"); + return res; + } + + unsigned char reset_templ[] = {0, MGM_INS_GLOBAL_RESET, 0, 0}; + recv_len = 0; + sw = 0; + res = ykpiv_transfer_data(state, reset_templ, NULL, 0, NULL, &recv_len, &sw); + if(res != YKPIV_OK) { + return res; + } + return ykpiv_translate_sw_ex(__FUNCTION__, sw); + +} \ No newline at end of file diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 02c024c4..a8077c97 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -142,6 +142,7 @@ extern "C" bool is_version_compatible(ykpiv_state *state, uint8_t major, uint8_t minor, uint8_t patch); ykpiv_rc ykpiv_move_key(ykpiv_state *state, const unsigned char from_slot, const unsigned char to_slot); + ykpiv_rc ykpiv_global_reset(ykpiv_state *state); /** * Return the number of PIN attempts remaining before PIN is locked. @@ -745,6 +746,8 @@ extern "C" #define YKPIV_INS_GET_SERIAL 0xf8 #define YKPIV_INS_GET_METADATA 0xf7 +#define MGM_INS_GLOBAL_RESET 0x1f + #define YKPIV_PINPOLICY_TAG 0xaa #define YKPIV_PINPOLICY_DEFAULT 0 #define YKPIV_PINPOLICY_NEVER 1 diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 7fe347f5..bf17aaa0 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -62,6 +62,7 @@ option "input" i "Filename to use as input, - for stdin" string optional default option "output" o "Filename to use as output, - for stdout" string optional default="-" option "key-format" K "Format of the key being read/written" values="PEM","PKCS12","GZIP","DER","SSH" enum optional default="PEM" option "compress" - "Compress a large certificate using GZIP before import" flag off +option "global" - "Reset the whole device over all protocols" flag off option "password" p "Password for decryption of private key file, if omitted password will be asked for" string optional option "subject" S "The subject to use for certificate request" string optional text " diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 9fc0d650..7aba6a50 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -443,8 +443,32 @@ static bool generate_key(ykpiv_state *state, enum enum_slot slot, return ret; } -static bool reset(ykpiv_state *state) { - return ykpiv_util_reset(state) == YKPIV_OK; +static bool reset(ykpiv_state *state, bool global) { + if(!global) { + if(ykpiv_util_reset(state) != YKPIV_OK) { + fprintf(stderr, "Reset failed, are pincodes blocked?\n"); + return false; + } + } else { + fprintf(stderr, "ALL of the data, including PIV data, in the YubiKey will be deleted. The action cannot be reversed!\n\nType 'y' to proceed: "); + char resp = fgetc(stdin); + if(resp == 'y') { + ykpiv_rc rc = ykpiv_global_reset(state); + if(rc != YKPIV_OK) { + if(rc == YKPIV_NOT_SUPPORTED) { + fprintf(stderr, "Global reset not supported on this YubiKey. Please refer to reset commands for specific applications instead\n"); + } else { + fprintf(stderr, "Reset failed\n"); + } + return false; + } + } else { + fprintf(stderr, "Global reset operation aborted\n"); + return true; + } + } + fprintf(stderr, "Successfully reset the application.\n"); + return true; } static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries, int verbose) { @@ -2687,11 +2711,8 @@ int main(int argc, char *argv[]) { } break; case action_arg_reset: - if(reset(state) == false) { - fprintf(stderr, "Reset failed, are pincodes blocked?\n"); + if(!reset(state, args_info.global_given)) { ret = EXIT_FAILURE; - } else { - fprintf(stderr, "Successfully reset the application.\n"); } break; case action_arg_pinMINUS_retries: