diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 7cf63e6..c6a40a1 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -274,24 +274,16 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) { return YKPIV_OK; } -ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ, - const unsigned char *in_data, long in_len, - unsigned char *out_data, unsigned long *out_len, int *sw) { - const unsigned char *in_ptr = in_data; - unsigned long max_out = *out_len; - ykpiv_rc res; +static ykpiv_rc _begin_transaction(ykpiv_state *state) { long rc; - *out_len = 0; - unsigned long active_protocol; + ykpiv_rc res; -BeginTransaction: rc = SCardBeginTransaction(state->card); if((rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) { - res = _reconnect(state); - if(res != YKPIV_OK) { + if((res = _reconnect(state)) != YKPIV_OK) { return res; } - goto BeginTransaction; + return _begin_transaction(state); } if(rc != SCARD_S_SUCCESS) { if(state->verbose) { @@ -299,79 +291,102 @@ BeginTransaction: } return YKPIV_PCSC_ERROR; } - do { - size_t this_size = 0xff; - unsigned char data[261]; - unsigned long recv_len = sizeof(data); - APDU apdu; + return YKPIV_OK; +} - memset(apdu.raw, 0, sizeof(apdu.raw)); - memcpy(apdu.raw, templ, 4); - if(in_ptr + 0xff < in_data + in_len) { - apdu.st.cla = 0x10; - } else { - this_size = (size_t)((in_data + in_len) - in_ptr); - } - if(state->verbose > 2) { - fprintf(stderr, "Going to send %lu bytes in this go.\n", (unsigned long)this_size); - } - apdu.st.lc = this_size; - memcpy(apdu.st.data, in_ptr, this_size); - res = send_data(state, &apdu, data, &recv_len, sw); - if(res != YKPIV_OK) { - return res; - } else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) { - return YKPIV_OK; - } - if(*out_len + recv_len - 2 > max_out) { - if(state->verbose) { - fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.\n", *out_len + recv_len - 2, max_out); - } - return YKPIV_SIZE_ERROR; - } - if(out_data) { - memcpy(out_data, data, recv_len - 2); - out_data += recv_len - 2; - *out_len += recv_len - 2; - } - in_ptr += this_size; - } while(in_ptr < in_data + in_len); - while(*sw >> 8 == 0x61) { - APDU apdu; - unsigned char data[261]; - unsigned long recv_len = sizeof(data); - - if(state->verbose > 2) { - fprintf(stderr, "The card indicates there is %d bytes more data for us.\n", *sw & 0xff); - } - - memset(apdu.raw, 0, sizeof(apdu.raw)); - apdu.st.ins = 0xc0; - res = send_data(state, &apdu, data, &recv_len, sw); - if(res != YKPIV_OK) { - return res; - } else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) { - return YKPIV_OK; - } - if(*out_len + recv_len - 2 > max_out) { - fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.", *out_len + recv_len - 2, max_out); - } - if(out_data) { - memcpy(out_data, data, recv_len - 2); - out_data += recv_len - 2; - *out_len += recv_len - 2; - } - } - rc = SCardEndTransaction(state->card, SCARD_LEAVE_CARD); - if(rc != SCARD_S_SUCCESS) { - if(state->verbose) { - fprintf(stderr, "error: Failed to end pcsc transaction, rc=%08lx\n", rc); - } +static ykpiv_rc _end_transaction(ykpiv_state *state) { + long rc = SCardEndTransaction(state->card, SCARD_LEAVE_CARD); + if(rc != SCARD_S_SUCCESS && state->verbose) { + fprintf(stderr, "error: Failed to end pcsc transaction, rc=%08lx\n", rc); return YKPIV_PCSC_ERROR; } return YKPIV_OK; } +ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ, + const unsigned char *in_data, long in_len, + unsigned char *out_data, unsigned long *out_len, int *sw) { + const unsigned char *in_ptr = in_data; + unsigned long max_out = *out_len; + ykpiv_rc res; + long rc; + *out_len = 0; + + res = _begin_transaction(state); + if (res != YKPIV_OK) { + return res; + } + do { + size_t this_size = 0xff; + unsigned char data[261]; + unsigned long recv_len = sizeof(data); + APDU apdu; + + memset(apdu.raw, 0, sizeof(apdu.raw)); + memcpy(apdu.raw, templ, 4); + if(in_ptr + 0xff < in_data + in_len) { + apdu.st.cla = 0x10; + } else { + this_size = (size_t)((in_data + in_len) - in_ptr); + } + if(state->verbose > 2) { + fprintf(stderr, "Going to send %lu bytes in this go.\n", (unsigned long)this_size); + } + apdu.st.lc = this_size; + memcpy(apdu.st.data, in_ptr, this_size); + res = send_data(state, &apdu, data, &recv_len, sw); + if(res != YKPIV_OK) { + _end_transaction(state); + return res; + } else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) { + _end_transaction(state); + return YKPIV_OK; + } + if(*out_len + recv_len - 2 > max_out) { + if(state->verbose) { + fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.\n", *out_len + recv_len - 2, max_out); + } + _end_transaction(state); + return YKPIV_SIZE_ERROR; + } + if(out_data) { + memcpy(out_data, data, recv_len - 2); + out_data += recv_len - 2; + *out_len += recv_len - 2; + } + in_ptr += this_size; + } while(in_ptr < in_data + in_len); + while(*sw >> 8 == 0x61) { + APDU apdu; + unsigned char data[261]; + unsigned long recv_len = sizeof(data); + + if(state->verbose > 2) { + fprintf(stderr, "The card indicates there is %d bytes more data for us.\n", *sw & 0xff); + } + + memset(apdu.raw, 0, sizeof(apdu.raw)); + apdu.st.ins = 0xc0; + res = send_data(state, &apdu, data, &recv_len, sw); + if(res != YKPIV_OK) { + _end_transaction(state); + return res; + } else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) { + _end_transaction(state); + return YKPIV_OK; + } + if(*out_len + recv_len - 2 > max_out) { + fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.", *out_len + recv_len - 2, max_out); + } + if(out_data) { + memcpy(out_data, data, recv_len - 2); + out_data += recv_len - 2; + *out_len += recv_len - 2; + } + } + return _end_transaction(state); +} + static ykpiv_rc send_data(ykpiv_state *state, APDU *apdu, unsigned char *data, unsigned long *recv_len, int *sw) { long rc;