Fix issue #116
This commit is contained in:
+94
-79
@@ -274,24 +274,16 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
|
|||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
static ykpiv_rc _begin_transaction(ykpiv_state *state) {
|
||||||
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;
|
long rc;
|
||||||
*out_len = 0;
|
ykpiv_rc res;
|
||||||
unsigned long active_protocol;
|
|
||||||
|
|
||||||
BeginTransaction:
|
|
||||||
rc = SCardBeginTransaction(state->card);
|
rc = SCardBeginTransaction(state->card);
|
||||||
if((rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) {
|
if((rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) {
|
||||||
res = _reconnect(state);
|
if((res = _reconnect(state)) != YKPIV_OK) {
|
||||||
if(res != YKPIV_OK) {
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
goto BeginTransaction;
|
return _begin_transaction(state);
|
||||||
}
|
}
|
||||||
if(rc != SCARD_S_SUCCESS) {
|
if(rc != SCARD_S_SUCCESS) {
|
||||||
if(state->verbose) {
|
if(state->verbose) {
|
||||||
@@ -299,79 +291,102 @@ BeginTransaction:
|
|||||||
}
|
}
|
||||||
return YKPIV_PCSC_ERROR;
|
return YKPIV_PCSC_ERROR;
|
||||||
}
|
}
|
||||||
do {
|
return YKPIV_OK;
|
||||||
size_t this_size = 0xff;
|
}
|
||||||
unsigned char data[261];
|
|
||||||
unsigned long recv_len = sizeof(data);
|
|
||||||
APDU apdu;
|
|
||||||
|
|
||||||
memset(apdu.raw, 0, sizeof(apdu.raw));
|
static ykpiv_rc _end_transaction(ykpiv_state *state) {
|
||||||
memcpy(apdu.raw, templ, 4);
|
long rc = SCardEndTransaction(state->card, SCARD_LEAVE_CARD);
|
||||||
if(in_ptr + 0xff < in_data + in_len) {
|
if(rc != SCARD_S_SUCCESS && state->verbose) {
|
||||||
apdu.st.cla = 0x10;
|
fprintf(stderr, "error: Failed to end pcsc transaction, rc=%08lx\n", rc);
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
return YKPIV_PCSC_ERROR;
|
return YKPIV_PCSC_ERROR;
|
||||||
}
|
}
|
||||||
return YKPIV_OK;
|
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,
|
static ykpiv_rc send_data(ykpiv_state *state, APDU *apdu,
|
||||||
unsigned char *data, unsigned long *recv_len, int *sw) {
|
unsigned char *data, unsigned long *recv_len, int *sw) {
|
||||||
long rc;
|
long rc;
|
||||||
|
|||||||
Reference in New Issue
Block a user