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 {
|
||||
res = YKPIV_GENERIC_ERROR;
|
||||
if (state->verbose) { fprintf(stderr, "error %x)\n", sw); }
|
||||
|
||||
+145
-33
@@ -167,13 +167,22 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
||||
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
||||
ykpiv_disconnect(state);
|
||||
static ykpiv_rc _done_internal(ykpiv_state *state, bool disconnect) {
|
||||
if (disconnect)
|
||||
ykpiv_disconnect(state);
|
||||
_cache_pin(state, NULL, 0);
|
||||
_ykpiv_free(state, state);
|
||||
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) {
|
||||
if(state->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->card = card;
|
||||
|
||||
// transact the connect operation
|
||||
|
||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||
res = _ykpiv_ensure_application_selected(state);
|
||||
_ykpiv_end_transaction(state);
|
||||
/*
|
||||
** Do not select the applet here, as we need to accommodate commands that are
|
||||
** sensitive to re-select (custom apdu/auth). All commands that can handle explicit
|
||||
** selection already check the applet state and select accordingly anyway.
|
||||
** 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
if (!_connect_internal(state, state->context, card)) {
|
||||
return YKPIV_OK;
|
||||
if (YKPIV_OK == _connect_internal(state, state->context, card)) {
|
||||
/*
|
||||
* 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) {
|
||||
return YKPIV_SIZE_ERROR;
|
||||
}
|
||||
|
||||
memset(apdu.raw, 0, sizeof(apdu.raw));
|
||||
apdu.st.ins = YKPIV_INS_VERIFY;
|
||||
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 res;
|
||||
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 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) {
|
||||
// Intentionally ignore errors. If the PIN fails to save, it will only
|
||||
// be a problem if a reconnect is attempted. Failure deferred until then.
|
||||
_cache_pin(state, new_pin, new_pin_len + 1);
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
_ykpiv_end_transaction(state);
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
@@ -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_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 ykpiv_auth_getchallenge(ykpiv_state *state, uint8_t *challenge, const size_t challenge_len) {
|
||||
ykpiv_rc res = YKPIV_OK;
|
||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) goto Cleanup;
|
||||
#if 0
|
||||
// TODO when is this needed? windows unit tests pass without it
|
||||
if (force_select) {
|
||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||
APDU apdu = { 0 };
|
||||
unsigned char data[261] = { 0 };
|
||||
unsigned long recv_len = sizeof(data);
|
||||
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;
|
||||
|
||||
/* 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
|
||||
res = ykpiv_verify(state, pin, tries);
|
||||
else if (sw != SW_SUCCESS) {
|
||||
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:
|
||||
|
||||
_ykpiv_end_transaction(state);
|
||||
|
||||
+2
-4
@@ -499,10 +499,8 @@ extern "C"
|
||||
*/
|
||||
uint32_t ykpiv_util_slot_object(uint8_t slot);
|
||||
|
||||
ykpiv_rc ykpiv_connect_with_card(ykpiv_state *state, uint64_t context, uint64_t card);
|
||||
|
||||
// TREV TODO: remove
|
||||
ykpiv_rc ykpiv_done2(ykpiv_state *state, bool disconnect);
|
||||
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);
|
||||
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user