diff --git a/lib/ykpiv.c b/lib/ykpiv.c index cf8d22c2..e1102361 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -2205,3 +2205,33 @@ static ykpiv_rc _ykpiv_auth_deauthenticate(ykpiv_state *state) { return res; } + +//static bool check_version(ykpiv_state *state, uint8_t major, uint8_t minor) { +// return state->ver.major > major || (state->ver.major == major && state->ver.minor >= minor); +//} + +// if to_slot is set to 0xff, the key will be deleted +ykpiv_rc ykpiv_move_key(ykpiv_state *state, const unsigned char from_slot, const unsigned char to_slot) { +// if(!check_version(state, 5, 7)) { +// DBG("Move key operation available with firmware version 5.7.0 or higher"); +// return YKPIV_NOT_SUPPORTED; +// } + ykpiv_rc res = YKPIV_OK; + unsigned char data[256] = {0}; + unsigned long recv_len = sizeof(data); + int sw = 0; + unsigned char adpu[] = {0, YKPIV_INS_MOVE_KEY, to_slot, from_slot}; + DBG("Moving key from slot %x to slot %x", from_slot, to_slot); + + if ((res = _ykpiv_transfer_data(state, adpu, NULL, 0, data, &recv_len, &sw)) != YKPIV_OK) { + return res; + } + res = ykpiv_translate_sw(sw); + if (res != YKPIV_OK) { + DBG("Failed to move key"); + } else { + DBG("Key moved from slot %x to %x", from_slot, to_slot); + } + + return res; +} diff --git a/lib/ykpiv.h b/lib/ykpiv.h index bcf3c4f3..cf9ed87b 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -138,6 +138,8 @@ extern "C" ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len); ykpiv_rc ykpiv_get_metadata(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len); + ykpiv_rc ykpiv_move_key(ykpiv_state *state, const unsigned char from_slot, const unsigned char to_slot); + /** * Return the number of PIN attempts remaining before PIN is locked. * @@ -708,6 +710,7 @@ extern "C" #define YKPIV_INS_AUTHENTICATE 0x87 #define YKPIV_INS_GET_DATA 0xcb #define YKPIV_INS_PUT_DATA 0xdb +#define YKPIV_INS_MOVE_KEY 0xf6 #define YKPIV_INS_SELECT_APPLICATION 0xa4 #define YKPIV_INS_GET_RESPONSE_APDU 0xc0 diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 0c47120e..3f634fc2 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -33,11 +33,19 @@ option "action" a "Action to take" values="version","generate","set-mgm-key", "request-certificate","verify-pin","change-pin","change-puk","unblock-pin", "selfsign-certificate","delete-certificate","read-certificate","status", "test-signature","test-decipher","list-readers","set-ccc","write-object", - "read-object","attest" enum multiple + "read-object","attest", "move-key", "delete-key" enum multiple text " Multiple actions may be given at once and will be executed in order for example --action=verify-pin --action=request-certificate\n" option "slot" s "What key slot to operate on" values="9a","9c","9d","9e","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95","f9" enum optional +text " + 9a is for PIV Authentication + 9c is for Digital Signature (PIN always checked) + 9d is for Key Management + 9e is for Card Authentication (PIN never checked) + 82-95 is for Retired Key Management + f9 is for Attestation\n" +option "to-slot" - "What slot to move an existing key to" values="9a","9c","9d","9e","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95","f9" enum optional text " 9a is for PIV Authentication 9c is for Digital Signature (PIN always checked) diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 4baf8094..aacd3098 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -240,6 +240,19 @@ static EVP_PKEY* wrap_public_key(ykpiv_state *state, int algorithm, EVP_PKEY *pu } #endif +static bool move_key(ykpiv_state *state, int from_slot, int to_slot) { + bool ret = false; + ykpiv_rc res; + + res = ykpiv_move_key(state, (uint8_t) (from_slot & 0xFF), (uint8_t) (to_slot & 0xFF)); + if (res != YKPIV_OK) { + fprintf(stderr, "Failed to move key.\n"); + } else { + ret = true; + } + return ret; +} + static bool generate_key(ykpiv_state *state, enum enum_slot slot, enum enum_algorithm algorithm, const char *output_file_name, enum enum_key_format key_format, enum enum_pin_policy pin_policy, @@ -2201,6 +2214,7 @@ int main(int argc, char *argv[]) { case action_arg_testMINUS_signature: case action_arg_testMINUS_decipher: case action_arg_attest: + case action_arg_deleteMINUS_key: if(args_info.slot_arg == slot__NULL) { fprintf(stderr, "The '%s' action needs a slot (-s) to operate on.\n", cmdline_parser_action_values[action]); @@ -2208,6 +2222,14 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } break; + case action_arg_moveMINUS_key: + if(args_info.slot_arg == slot__NULL || args_info.to_slot_arg == to_slot__NULL) { + fprintf(stderr, "The '%s' action needs both a slot (-s) to operate on and a --to-slot to move the key to.\n", + cmdline_parser_action_values[action]); + cmdline_parser_free(&args_info); + return EXIT_FAILURE; + } + break; case action_arg_pinMINUS_retries: if(!args_info.pin_retries_given || !args_info.puk_retries_given) { fprintf(stderr, "The '%s' action needs both --pin-retries and --puk-retries arguments.\n", @@ -2296,6 +2318,8 @@ int main(int argc, char *argv[]) { case action_arg_setMINUS_ccc: case action_arg_deleteMINUS_certificate: case action_arg_writeMINUS_object: + case action_arg_moveMINUS_key: + case action_arg_deleteMINUS_key: if(!authed) { if(verbosity) { fprintf(stderr, "Authenticating since action '%s' needs that.\n", cmdline_parser_action_values[action]); @@ -2588,6 +2612,23 @@ int main(int argc, char *argv[]) { ret = EXIT_FAILURE; } break; + case action_arg_moveMINUS_key: { + int from_slot = get_slot_hex(args_info.slot_arg); + int to_slot = get_slot_hex((enum enum_slot) args_info.to_slot_arg); + if (move_key(state, from_slot, to_slot) == false) { + ret = EXIT_FAILURE; + } else { + fprintf(stderr, "Successfully moved key.\n"); + } + break; + } + case action_arg_deleteMINUS_key: + if(move_key(state, get_slot_hex(args_info.slot_arg), 0xFF) == false) { + ret = EXIT_FAILURE; + } else { + fprintf(stderr, "Successfully deleted key.\n"); + } + break; case action__NULL: default: fprintf(stderr, "Wrong action. %d.\n", action);