@@ -49,6 +49,7 @@ struct ykpiv_state {
|
|||||||
SCARDCONTEXT context;
|
SCARDCONTEXT context;
|
||||||
SCARDHANDLE card;
|
SCARDHANDLE card;
|
||||||
int verbose;
|
int verbose;
|
||||||
|
char *pin;
|
||||||
};
|
};
|
||||||
|
|
||||||
union u_APDU {
|
union u_APDU {
|
||||||
|
|||||||
+80
-32
@@ -102,6 +102,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
|||||||
return YKPIV_MEMORY_ERROR;
|
return YKPIV_MEMORY_ERROR;
|
||||||
}
|
}
|
||||||
memset(s, 0, sizeof(ykpiv_state));
|
memset(s, 0, sizeof(ykpiv_state));
|
||||||
|
s->pin = NULL;
|
||||||
s->verbose = verbose;
|
s->verbose = verbose;
|
||||||
s->context = SCARD_E_INVALID_HANDLE;
|
s->context = SCARD_E_INVALID_HANDLE;
|
||||||
*state = s;
|
*state = s;
|
||||||
@@ -110,6 +111,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
|||||||
|
|
||||||
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
||||||
ykpiv_disconnect(state);
|
ykpiv_disconnect(state);
|
||||||
|
free(state->pin);
|
||||||
free(state);
|
free(state);
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
@@ -128,6 +130,34 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
|||||||
return YKPIV_OK;
|
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) {
|
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
||||||
unsigned long active_protocol;
|
unsigned long active_protocol;
|
||||||
char reader_buf[2048];
|
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,
|
rc = SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED,
|
||||||
SCARD_PROTOCOL_T1, &state->card, &active_protocol);
|
SCARD_PROTOCOL_T1, &state->card, &active_protocol);
|
||||||
if(rc != SCARD_S_SUCCESS)
|
if(rc != SCARD_S_SUCCESS) {
|
||||||
{
|
|
||||||
if(state->verbose) {
|
if(state->verbose) {
|
||||||
fprintf(stderr, "SCardConnect failed, rc=%08lx\n", rc);
|
fprintf(stderr, "SCardConnect failed, rc=%08lx\n", rc);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (_select_application(state) != YKPIV_OK)
|
||||||
{
|
continue;
|
||||||
APDU apdu;
|
return YKPIV_OK;
|
||||||
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(*reader_ptr == '\0') {
|
if(*reader_ptr == '\0') {
|
||||||
@@ -202,6 +207,30 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
|||||||
return YKPIV_GENERIC_ERROR;
|
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) {
|
ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
|
||||||
unsigned long num_readers = 0;
|
unsigned long num_readers = 0;
|
||||||
long rc;
|
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);
|
rc = SCardListReaders(state->context, NULL, readers, &num_readers);
|
||||||
if (rc != SCARD_S_SUCCESS)
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
{
|
|
||||||
if(state->verbose) {
|
if(state->verbose) {
|
||||||
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
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;
|
ykpiv_rc res;
|
||||||
long rc;
|
long rc;
|
||||||
*out_len = 0;
|
*out_len = 0;
|
||||||
|
unsigned long active_protocol;
|
||||||
|
|
||||||
|
BeginTransaction:
|
||||||
rc = SCardBeginTransaction(state->card);
|
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(rc != SCARD_S_SUCCESS) {
|
||||||
if(state->verbose) {
|
if(state->verbose) {
|
||||||
fprintf(stderr, "error: Failed to begin pcsc transaction, rc=%08lx\n", rc);
|
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) {
|
if((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) {
|
||||||
return res;
|
return res;
|
||||||
} else if(sw == SW_SUCCESS) {
|
} else if(sw == SW_SUCCESS) {
|
||||||
|
if (pin) {
|
||||||
|
free(state->pin);
|
||||||
|
state->pin = malloc(len * sizeof(char) + 1);
|
||||||
|
strcpy(state->pin, pin);
|
||||||
|
}
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
} else if((sw >> 8) == 0x63) {
|
} else if((sw >> 8) == 0x63) {
|
||||||
*tries = (sw & 0xf);
|
*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) {
|
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) {
|
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user