Backport minidriver changes
* Port ykpiv_auth_getchallenge and ykpiv_auth_verifyresponse - Commit 8fde607b50b19c57a662c53c6b276b54a78606d8 - Commit 6046b98e477cfef59a590ce2177336d694813e7e - Commit 422cea11745dc67d15039e242ed21ecb5208ae55 - Commit 1d31647e5a27bd2df6bda76512c7d673980f0bec * Rename connect2() and done2() to connect_with_external_card(), etc. * Select applet in ykpiv_change_pin, change_puk, and unblock_pin
This commit is contained in:
@@ -795,6 +795,10 @@ ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (sw == SW_ERR_SECURITY_STATUS) {
|
||||||
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
|
if (state->verbose) { fprintf(stderr, "not authenticated)\n"); }
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
res = YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
if (state->verbose) { fprintf(stderr, "error %x)\n", sw); }
|
if (state->verbose) { fprintf(stderr, "error %x)\n", sw); }
|
||||||
|
|||||||
+143
-31
@@ -167,13 +167,22 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
|||||||
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
|
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
static ykpiv_rc _done_internal(ykpiv_state *state, bool disconnect) {
|
||||||
|
if (disconnect)
|
||||||
ykpiv_disconnect(state);
|
ykpiv_disconnect(state);
|
||||||
_cache_pin(state, NULL, 0);
|
_cache_pin(state, NULL, 0);
|
||||||
_ykpiv_free(state, state);
|
_ykpiv_free(state, state);
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_done_with_external_card(ykpiv_state *state) {
|
||||||
|
return _done_internal(state, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
||||||
|
return _done_internal(state, true);
|
||||||
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
||||||
if(state->card) {
|
if(state->card) {
|
||||||
SCardDisconnect(state->card, SCARD_RESET_CARD);
|
SCardDisconnect(state->card, SCARD_RESET_CARD);
|
||||||
@@ -265,15 +274,19 @@ static ykpiv_rc _connect_internal(ykpiv_state *state, uint64_t context, uint64_t
|
|||||||
state->context = context;
|
state->context = context;
|
||||||
state->card = card;
|
state->card = card;
|
||||||
|
|
||||||
// transact the connect operation
|
/*
|
||||||
|
** Do not select the applet here, as we need to accommodate commands that are
|
||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
** sensitive to re-select (custom apdu/auth). All commands that can handle explicit
|
||||||
res = _ykpiv_ensure_application_selected(state);
|
** selection already check the applet state and select accordingly anyway.
|
||||||
_ykpiv_end_transaction(state);
|
** ykpiv_verify_select is supplied for those who want to select explicitly.
|
||||||
|
**
|
||||||
|
** The applet _is_ selected by ykpiv_connect(), but is not selected when bypassing
|
||||||
|
** it with ykpiv_connect_with_external_card().
|
||||||
|
*/
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_connect_with_card(ykpiv_state *state, uint64_t context, uint64_t card) {
|
ykpiv_rc ykpiv_connect_with_external_card(ykpiv_state *state, uint64_t context, uint64_t card, bool select) {
|
||||||
return _connect_internal(state, context, card);
|
return _connect_internal(state, context, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,8 +326,16 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// at this point, card should not equal state->card, to allow _connect_internal() to determine device type
|
// at this point, card should not equal state->card, to allow _connect_internal() to determine device type
|
||||||
if (!_connect_internal(state, state->context, card)) {
|
if (YKPIV_OK == _connect_internal(state, state->context, card)) {
|
||||||
return YKPIV_OK;
|
/*
|
||||||
|
* Select applet. This is done here instead of in _connect_internal() because
|
||||||
|
* you may not want to select the applet when connecting to a card handle that
|
||||||
|
* was supplied by an external library.
|
||||||
|
*/
|
||||||
|
if (YKPIV_OK != (ret = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
ret = _ykpiv_ensure_application_selected(state);
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -926,7 +947,6 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) {
|
|||||||
if(len > 8) {
|
if(len > 8) {
|
||||||
return YKPIV_SIZE_ERROR;
|
return YKPIV_SIZE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(apdu.raw, 0, sizeof(apdu.raw));
|
memset(apdu.raw, 0, sizeof(apdu.raw));
|
||||||
apdu.st.ins = YKPIV_INS_VERIFY;
|
apdu.st.ins = YKPIV_INS_VERIFY;
|
||||||
apdu.st.p1 = 0x00;
|
apdu.st.p1 = 0x00;
|
||||||
@@ -957,6 +977,19 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select) {
|
||||||
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup;
|
||||||
|
if (force_select) {
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
}
|
||||||
|
res = ykpiv_verify(state, pin, tries);
|
||||||
|
Cleanup:
|
||||||
|
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_get_pin_retries(ykpiv_state *state, int* tries) {
|
ykpiv_rc ykpiv_get_pin_retries(ykpiv_state *state, int* tries) {
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
ykpiv_rc ykrc;
|
ykpiv_rc ykrc;
|
||||||
@@ -1054,21 +1087,47 @@ static ykpiv_rc change_pin_internal(ykpiv_state *state, int action, const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
||||||
ykpiv_rc res = change_pin_internal(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries);
|
ykpiv_rc res = YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
res = change_pin_internal(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries);
|
||||||
if (res == YKPIV_OK && new_pin != NULL) {
|
if (res == YKPIV_OK && new_pin != NULL) {
|
||||||
// Intentionally ignore errors. If the PIN fails to save, it will only
|
// Intentionally ignore errors. If the PIN fails to save, it will only
|
||||||
// be a problem if a reconnect is attempted. Failure deferred until then.
|
// be a problem if a reconnect is attempted. Failure deferred until then.
|
||||||
_cache_pin(state, new_pin, new_pin_len + 1);
|
_cache_pin(state, new_pin, new_pin_len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len, const char * new_puk, size_t new_puk_len, int *tries) {
|
ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t current_puk_len, const char * new_puk, size_t new_puk_len, int *tries) {
|
||||||
return change_pin_internal(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries);
|
ykpiv_rc res = YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
res = change_pin_internal(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
||||||
return change_pin_internal(state, CHREF_ACT_UNBLOCK_PIN, puk, puk_len, new_pin, new_pin_len, tries);
|
ykpiv_rc res = YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
res = change_pin_internal(state, CHREF_ACT_UNBLOCK_PIN, puk, puk_len, new_pin, new_pin_len, tries);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
||||||
@@ -1295,27 +1354,80 @@ ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TREV TODO: remove these, fix minidriver
|
ykpiv_rc ykpiv_auth_getchallenge(ykpiv_state *state, uint8_t *challenge, const size_t challenge_len) {
|
||||||
|
|
||||||
ykpiv_rc ykpiv_done2(ykpiv_state *state, bool disconnect) {
|
|
||||||
// TODO: why is this needed? windows unit tests pass without it
|
|
||||||
if (disconnect)
|
|
||||||
ykpiv_disconnect(state);
|
|
||||||
_cache_pin(state, NULL, 0);
|
|
||||||
_ykpiv_free(state, state);
|
|
||||||
return YKPIV_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select) {
|
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup;
|
APDU apdu = { 0 };
|
||||||
#if 0
|
unsigned char data[261] = { 0 };
|
||||||
// TODO when is this needed? windows unit tests pass without it
|
unsigned long recv_len = sizeof(data);
|
||||||
if (force_select) {
|
int sw = 0;
|
||||||
|
|
||||||
|
if (NULL == state) return YKPIV_GENERIC_ERROR;
|
||||||
|
if (NULL == challenge) return YKPIV_GENERIC_ERROR;
|
||||||
|
if (8 != challenge_len) return YKPIV_SIZE_ERROR;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
/* get a challenge from the card */
|
||||||
|
memset(apdu.raw, 0, sizeof(apdu));
|
||||||
|
apdu.st.ins = YKPIV_INS_AUTHENTICATE;
|
||||||
|
apdu.st.p1 = YKPIV_ALGO_3DES; /* triple des */
|
||||||
|
apdu.st.p2 = YKPIV_KEY_CARDMGM; /* management key */
|
||||||
|
apdu.st.lc = 0x04;
|
||||||
|
apdu.st.data[0] = 0x7c;
|
||||||
|
apdu.st.data[1] = 0x02;
|
||||||
|
apdu.st.data[2] = 0x81; //0x80;
|
||||||
|
if ((res = _send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) {
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
#endif
|
else if (sw != SW_SUCCESS) {
|
||||||
res = ykpiv_verify(state, pin, tries);
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
memcpy(challenge, data + 4, 8);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_auth_verifyresponse(ykpiv_state *state, uint8_t *response, const size_t response_len) {
|
||||||
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
APDU apdu = { 0 };
|
||||||
|
unsigned char data[261] = { 0 };
|
||||||
|
unsigned long recv_len = sizeof(data);
|
||||||
|
int sw = 0;
|
||||||
|
unsigned char *dataptr = apdu.st.data;
|
||||||
|
|
||||||
|
if (NULL == state) return YKPIV_GENERIC_ERROR;
|
||||||
|
if (NULL == response) return YKPIV_GENERIC_ERROR;
|
||||||
|
if (8 != response_len) return YKPIV_SIZE_ERROR;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
/* note: do not select the applet here, as it resets the challenge state */
|
||||||
|
|
||||||
|
/* send the response to the card and a challenge of our own. */
|
||||||
|
recv_len = sizeof(data);
|
||||||
|
memset(apdu.raw, 0, sizeof(apdu));
|
||||||
|
apdu.st.ins = YKPIV_INS_AUTHENTICATE;
|
||||||
|
apdu.st.p1 = YKPIV_ALGO_3DES; /* triple des */
|
||||||
|
apdu.st.p2 = YKPIV_KEY_CARDMGM; /* management key */
|
||||||
|
*dataptr++ = 0x7c;
|
||||||
|
*dataptr++ = 0x0a; /* 2 + 8 */
|
||||||
|
*dataptr++ = 0x82;
|
||||||
|
*dataptr++ = 8;
|
||||||
|
memcpy(dataptr, response, response_len);
|
||||||
|
dataptr += 8;
|
||||||
|
apdu.st.lc = (unsigned char)(dataptr - apdu.st.data);
|
||||||
|
if ((res = _send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) {
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
else if (sw != SW_SUCCESS) {
|
||||||
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
|
|||||||
+2
-4
@@ -499,10 +499,8 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
uint32_t ykpiv_util_slot_object(uint8_t slot);
|
uint32_t ykpiv_util_slot_object(uint8_t slot);
|
||||||
|
|
||||||
ykpiv_rc ykpiv_connect_with_card(ykpiv_state *state, uint64_t context, uint64_t card);
|
ykpiv_rc ykpiv_connect_with_exteral_card(ykpiv_state *state, uint64_t context, uint64_t card, bool select);
|
||||||
|
ykpiv_rc ykpiv_done_with_external_card(ykpiv_state *state);
|
||||||
// TREV TODO: remove
|
|
||||||
ykpiv_rc ykpiv_done2(ykpiv_state *state, bool disconnect);
|
|
||||||
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select);
|
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
Reference in New Issue
Block a user