From c05d87996836ffd8955262806d39c5dbdc53e899 Mon Sep 17 00:00:00 2001 From: emersonl Date: Thu, 25 May 2017 21:38:08 -0700 Subject: [PATCH] Fix issue #88 and #102 --- lib/internal.h | 1 + lib/ykpiv.c | 112 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/lib/internal.h b/lib/internal.h index 218d7ee..d05436c 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -49,6 +49,7 @@ struct ykpiv_state { SCARDCONTEXT context; SCARDHANDLE card; int verbose; + char *pin; }; union u_APDU { diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 96a5a90..7cf63e6 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -102,6 +102,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) { return YKPIV_MEMORY_ERROR; } memset(s, 0, sizeof(ykpiv_state)); + s->pin = NULL; s->verbose = verbose; s->context = SCARD_E_INVALID_HANDLE; *state = s; @@ -110,6 +111,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) { ykpiv_rc ykpiv_done(ykpiv_state *state) { ykpiv_disconnect(state); + free(state->pin); free(state); return YKPIV_OK; } @@ -128,6 +130,34 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) { return YKPIV_OK; } +static ykpiv_rc _select_application(ykpiv_state *state) { + APDU apdu; + unsigned char data[0xff]; + unsigned long recv_len = sizeof(data); + int sw; + ykpiv_rc res; + + memset(apdu.raw, 0, sizeof(apdu)); + apdu.st.ins = 0xa4; + apdu.st.p1 = 0x04; + apdu.st.lc = sizeof(aid); + memcpy(apdu.st.data, aid, sizeof(aid)); + + if((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) { + if(state->verbose) { + fprintf(stderr, "Failed communicating with card: '%s'\n", ykpiv_strerror(res)); + } + return res; + } else if(sw == SW_SUCCESS) { + return YKPIV_OK; + } else { + if(state->verbose) { + fprintf(stderr, "Failed selecting application: %04x\n", sw); + } + return YKPIV_GENERIC_ERROR; + } +} + ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) { unsigned long active_protocol; char reader_buf[2048]; @@ -154,40 +184,15 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) { } rc = SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &state->card, &active_protocol); - if(rc != SCARD_S_SUCCESS) - { + if(rc != SCARD_S_SUCCESS) { if(state->verbose) { fprintf(stderr, "SCardConnect failed, rc=%08lx\n", rc); } continue; } - - { - APDU apdu; - unsigned char data[0xff]; - unsigned long recv_len = sizeof(data); - int sw; - ykpiv_rc res; - - memset(apdu.raw, 0, sizeof(apdu)); - apdu.st.ins = 0xa4; - apdu.st.p1 = 0x04; - apdu.st.lc = sizeof(aid); - memcpy(apdu.st.data, aid, sizeof(aid)); - - if((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) { - if(state->verbose) { - fprintf(stderr, "Failed communicating with card: '%s'\n", ykpiv_strerror(res)); - } - continue; - } else if(sw == SW_SUCCESS) { - return YKPIV_OK; - } else { - if(state->verbose) { - fprintf(stderr, "Failed selecting application: %04x\n", sw); - } - } - } + if (_select_application(state) != YKPIV_OK) + continue; + return YKPIV_OK; } if(*reader_ptr == '\0') { @@ -202,6 +207,30 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) { return YKPIV_GENERIC_ERROR; } +static ykpiv_rc _reconnect(ykpiv_state *state) { + unsigned long active_protocol; + long rc; + ykpiv_rc res; + int tries; + + if(state->verbose) { + fprintf(stderr, "trying to reconnect to current reader.\n"); + } + rc = SCardReconnect(state->card, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &active_protocol); + if(rc != SCARD_S_SUCCESS) { + if(state->verbose) { + fprintf(stderr, "SCardReconnect failed, rc=%08lx\n", rc); + } + return YKPIV_PCSC_ERROR; + } + if ((res = _select_application(state)) != YKPIV_OK) + return res; + if (state->pin) + return ykpiv_verify(state, state->pin, &tries); + return YKPIV_OK; +} + ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) { unsigned long num_readers = 0; long rc; @@ -231,8 +260,7 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) { } rc = SCardListReaders(state->context, NULL, readers, &num_readers); - if (rc != SCARD_S_SUCCESS) - { + if (rc != SCARD_S_SUCCESS) { if(state->verbose) { fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc); } @@ -254,8 +282,17 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ, ykpiv_rc res; long rc; *out_len = 0; + unsigned long active_protocol; +BeginTransaction: rc = SCardBeginTransaction(state->card); + if((rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) { + res = _reconnect(state); + if(res != YKPIV_OK) { + return res; + } + goto BeginTransaction; + } if(rc != SCARD_S_SUCCESS) { if(state->verbose) { fprintf(stderr, "error: Failed to begin pcsc transaction, rc=%08lx\n", rc); @@ -704,6 +741,11 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) { if((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) { return res; } else if(sw == SW_SUCCESS) { + if (pin) { + free(state->pin); + state->pin = malloc(len * sizeof(char) + 1); + strcpy(state->pin, pin); + } return YKPIV_OK; } else if((sw >> 8) == 0x63) { *tries = (sw & 0xf); @@ -767,7 +809,13 @@ 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) { - return _change_pin_internal(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries); + ykpiv_rc 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) { + free(state->pin); + state->pin = malloc(new_pin_len * sizeof(char) + 1); + strcpy(state->pin, new_pin); + } + 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) {