Fix applet selection for whole public API.
This commit is contained in:
@@ -183,6 +183,8 @@ int _ykpiv_get_length(const unsigned char *buffer, size_t *len);
|
|||||||
void* _ykpiv_alloc(ykpiv_state *state, size_t size);
|
void* _ykpiv_alloc(ykpiv_state *state, size_t size);
|
||||||
void* _ykpiv_realloc(ykpiv_state *state, void *address, size_t size);
|
void* _ykpiv_realloc(ykpiv_state *state, void *address, size_t size);
|
||||||
void _ykpiv_free(ykpiv_state *state, void *data);
|
void _ykpiv_free(ykpiv_state *state, void *data);
|
||||||
|
ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id, unsigned char *indata, size_t len);
|
||||||
|
ykpiv_rc _ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-20
@@ -103,7 +103,7 @@ ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid) {
|
|||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
res = ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, (unsigned long *)&len);
|
res = _ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, (unsigned long *)&len);
|
||||||
if (YKPIV_OK == res) {
|
if (YKPIV_OK == res) {
|
||||||
if (len != sizeof(CHUID_TMPL)) {
|
if (len != sizeof(CHUID_TMPL)) {
|
||||||
res = YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
@@ -143,7 +143,7 @@ ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) {
|
|||||||
memcpy(buf + CHUID_GUID_OFFS, id, sizeof(id));
|
memcpy(buf + CHUID_GUID_OFFS, id, sizeof(id));
|
||||||
len = sizeof(CHUID_TMPL);
|
len = sizeof(CHUID_TMPL);
|
||||||
|
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_CHUID, buf, len);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_CHUID, buf, len);
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc) {
|
|||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
res = ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, (unsigned long *)&len);
|
res = _ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, (unsigned long *)&len);
|
||||||
if (YKPIV_OK == res) {
|
if (YKPIV_OK == res) {
|
||||||
if (len != sizeof(CCC_TMPL)) {
|
if (len != sizeof(CCC_TMPL)) {
|
||||||
res = YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
@@ -200,7 +200,7 @@ ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc) {
|
|||||||
len = sizeof(CCC_TMPL);
|
len = sizeof(CCC_TMPL);
|
||||||
memcpy(buf, CCC_TMPL, len);
|
memcpy(buf, CCC_TMPL, len);
|
||||||
memcpy(buf + CCC_ID_OFFS, id, YKPIV_CCCID_SIZE);
|
memcpy(buf + CCC_ID_OFFS, id, YKPIV_CCCID_SIZE);
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY, buf, len);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY, buf, len);
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
@@ -452,7 +452,7 @@ ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers
|
|||||||
*containers = 0;
|
*containers = 0;
|
||||||
*n_containers = 0;
|
*n_containers = 0;
|
||||||
|
|
||||||
if (YKPIV_OK == (res = ykpiv_fetch_object(state, YKPIV_OBJ_MSCMAP, buf, (unsigned long*)&cbBuf))) {
|
if (YKPIV_OK == (res = _ykpiv_fetch_object(state, YKPIV_OBJ_MSCMAP, buf, (unsigned long*)&cbBuf))) {
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
|
|
||||||
// check that object contents are at least large enough to read the header
|
// check that object contents are at least large enough to read the header
|
||||||
@@ -509,7 +509,7 @@ ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers
|
|||||||
res = YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, NULL, 0);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
@@ -531,7 +531,7 @@ ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers
|
|||||||
offset += data_len;
|
offset += data_len;
|
||||||
|
|
||||||
// write onto device
|
// write onto device
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, buf, offset);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP, buf, offset);
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
|
||||||
@@ -567,7 +567,7 @@ ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *dat
|
|||||||
for (object_id = YKPIV_OBJ_MSROOTS1; object_id <= YKPIV_OBJ_MSROOTS5; object_id++) {
|
for (object_id = YKPIV_OBJ_MSROOTS1; object_id <= YKPIV_OBJ_MSROOTS5; object_id++) {
|
||||||
cbBuf = sizeof(buf);
|
cbBuf = sizeof(buf);
|
||||||
|
|
||||||
if (YKPIV_OK != (res = ykpiv_fetch_object(state, object_id, buf, (unsigned long*)&cbBuf))) {
|
if (YKPIV_OK != (res = _ykpiv_fetch_object(state, object_id, buf, (unsigned long*)&cbBuf))) {
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,7 +654,7 @@ ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data
|
|||||||
else {
|
else {
|
||||||
// it should be sufficient to just delete the first object, though
|
// it should be sufficient to just delete the first object, though
|
||||||
// to be complete we should erase all of the MSROOTS objects
|
// to be complete we should erase all of the MSROOTS objects
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1, NULL, 0);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
@@ -680,7 +680,7 @@ ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data
|
|||||||
offset += data_chunk;
|
offset += data_chunk;
|
||||||
|
|
||||||
// write onto device
|
// write onto device
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1 + i, buf, offset);
|
res = _ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1 + i, buf, offset);
|
||||||
|
|
||||||
if (YKPIV_OK != res) {
|
if (YKPIV_OK != res) {
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
@@ -1284,7 +1284,6 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len) {
|
static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len) {
|
||||||
// TREV TODO: should this select application?
|
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
uint8_t *ptr = NULL;
|
uint8_t *ptr = NULL;
|
||||||
int object_id = ykpiv_util_slot_object(slot);
|
int object_id = ykpiv_util_slot_object(slot);
|
||||||
@@ -1292,7 +1291,7 @@ static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf
|
|||||||
|
|
||||||
if (-1 == object_id) return YKPIV_INVALID_OBJECT;
|
if (-1 == object_id) return YKPIV_INVALID_OBJECT;
|
||||||
|
|
||||||
if (YKPIV_OK == (res = ykpiv_fetch_object(state, object_id, buf, (unsigned long*)buf_len))) {
|
if (YKPIV_OK == (res = _ykpiv_fetch_object(state, object_id, buf, (unsigned long*)buf_len))) {
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
|
|
||||||
// check that object contents are at least large enough to read the tag
|
// check that object contents are at least large enough to read the tag
|
||||||
@@ -1324,7 +1323,6 @@ static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo) {
|
static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo) {
|
||||||
// TREV TODO: should this select application?
|
|
||||||
uint8_t buf[CB_OBJ_MAX];
|
uint8_t buf[CB_OBJ_MAX];
|
||||||
size_t cbBuf = sizeof(buf);
|
size_t cbBuf = sizeof(buf);
|
||||||
int object_id = ykpiv_util_slot_object(slot);
|
int object_id = ykpiv_util_slot_object(slot);
|
||||||
@@ -1342,7 +1340,7 @@ static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *da
|
|||||||
return YKPIV_GENERIC_ERROR;
|
return YKPIV_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ykpiv_save_object(state, object_id, NULL, 0);
|
return _ykpiv_save_object(state, object_id, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode certificate data for storage
|
// encode certificate data for storage
|
||||||
@@ -1366,7 +1364,7 @@ static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *da
|
|||||||
buf[offset++] = 00;
|
buf[offset++] = 00;
|
||||||
|
|
||||||
// write onto device
|
// write onto device
|
||||||
return ykpiv_save_object(state, object_id, buf, offset);
|
return _ykpiv_save_object(state, object_id, buf, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1524,7 +1522,6 @@ static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_da
|
|||||||
** To read from protected data, the pin must be verified prior to calling this function.
|
** To read from protected data, the pin must be verified prior to calling this function.
|
||||||
*/
|
*/
|
||||||
static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, size_t* pcb_data) {
|
static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, size_t* pcb_data) {
|
||||||
// TREV TODO: should this select application?
|
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
uint8_t *p_temp = NULL;
|
uint8_t *p_temp = NULL;
|
||||||
size_t cb_temp = 0;
|
size_t cb_temp = 0;
|
||||||
@@ -1541,7 +1538,7 @@ static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, s
|
|||||||
cb_temp = *pcb_data;
|
cb_temp = *pcb_data;
|
||||||
*pcb_data = 0;
|
*pcb_data = 0;
|
||||||
|
|
||||||
if (YKPIV_OK != (res = ykpiv_fetch_object(state, obj_id, data, (unsigned long*)&cb_temp))) {
|
if (YKPIV_OK != (res = _ykpiv_fetch_object(state, obj_id, data, (unsigned long*)&cb_temp))) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1573,7 +1570,6 @@ static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, s
|
|||||||
** To write protected data, the pin must be verified prior to calling this function.
|
** To write protected data, the pin must be verified prior to calling this function.
|
||||||
*/
|
*/
|
||||||
static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data, size_t cb_data) {
|
static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data, size_t cb_data) {
|
||||||
// TREV TODO: should this select application?
|
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
uint8_t buf[CB_OBJ_MAX] = { 0 };
|
uint8_t buf[CB_OBJ_MAX] = { 0 };
|
||||||
uint8_t *pTemp = buf;
|
uint8_t *pTemp = buf;
|
||||||
@@ -1591,7 +1587,7 @@ static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data,
|
|||||||
|
|
||||||
if (!data || (0 == cb_data)) {
|
if (!data || (0 == cb_data)) {
|
||||||
// deleting metadata
|
// deleting metadata
|
||||||
res = ykpiv_save_object(state, obj_id, NULL, 0);
|
res = _ykpiv_save_object(state, obj_id, NULL, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*pTemp++ = tag;
|
*pTemp++ = tag;
|
||||||
@@ -1600,7 +1596,7 @@ static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data,
|
|||||||
memcpy(pTemp, data, cb_data);
|
memcpy(pTemp, data, cb_data);
|
||||||
pTemp += cb_data;
|
pTemp += cb_data;
|
||||||
|
|
||||||
res = ykpiv_save_object(state, obj_id, buf, pTemp - buf);
|
res = _ykpiv_save_object(state, obj_id, buf, pTemp - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
+122
-57
@@ -167,7 +167,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
|||||||
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
|
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _done_internal(ykpiv_state *state, bool disconnect) {
|
static ykpiv_rc _ykpiv_done(ykpiv_state *state, bool disconnect) {
|
||||||
if (disconnect)
|
if (disconnect)
|
||||||
ykpiv_disconnect(state);
|
ykpiv_disconnect(state);
|
||||||
_cache_pin(state, NULL, 0);
|
_cache_pin(state, NULL, 0);
|
||||||
@@ -176,11 +176,11 @@ static ykpiv_rc _done_internal(ykpiv_state *state, bool disconnect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_done_with_external_card(ykpiv_state *state) {
|
ykpiv_rc ykpiv_done_with_external_card(ykpiv_state *state) {
|
||||||
return _done_internal(state, false);
|
return _ykpiv_done(state, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
ykpiv_rc ykpiv_done(ykpiv_state *state) {
|
||||||
return _done_internal(state, true);
|
return _ykpiv_done(state, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
||||||
@@ -244,7 +244,7 @@ ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _connect_internal(ykpiv_state *state, uint64_t context, uint64_t card) {
|
static ykpiv_rc _ykpiv_connect(ykpiv_state *state, uint64_t context, uint64_t card) {
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
|
||||||
if (NULL == state) {
|
if (NULL == state) {
|
||||||
@@ -287,7 +287,7 @@ static ykpiv_rc _connect_internal(ykpiv_state *state, uint64_t context, uint64_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_connect_with_external_card(ykpiv_state *state, uint64_t context, uint64_t card, bool select) {
|
ykpiv_rc ykpiv_connect_with_external_card(ykpiv_state *state, uint64_t context, uint64_t card, bool select) {
|
||||||
return _connect_internal(state, context, card);
|
return _ykpiv_connect(state, context, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
||||||
@@ -325,10 +325,10 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point, card should not equal state->card, to allow _connect_internal() to determine device type
|
// at this point, card should not equal state->card, to allow _ykpiv_connect() to determine device type
|
||||||
if (YKPIV_OK == _connect_internal(state, state->context, card)) {
|
if (YKPIV_OK == _ykpiv_connect(state, state->context, card)) {
|
||||||
/*
|
/*
|
||||||
* Select applet. This is done here instead of in _connect_internal() because
|
* Select applet. This is done here instead of in _ykpiv_connect() because
|
||||||
* you may not want to select the applet when connecting to a card handle that
|
* you may not want to select the applet when connecting to a card handle that
|
||||||
* was supplied by an external library.
|
* was supplied by an external library.
|
||||||
*/
|
*/
|
||||||
@@ -457,10 +457,7 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
|||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
*out_len = 0;
|
*out_len = 0;
|
||||||
|
|
||||||
res = _ykpiv_begin_transaction(state);
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (res != YKPIV_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
size_t this_size = 0xff;
|
size_t this_size = 0xff;
|
||||||
unsigned char data[261];
|
unsigned char data[261];
|
||||||
@@ -481,17 +478,16 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
|||||||
memcpy(apdu.st.data, in_ptr, this_size);
|
memcpy(apdu.st.data, in_ptr, this_size);
|
||||||
res = _send_data(state, &apdu, data, &recv_len, sw);
|
res = _send_data(state, &apdu, data, &recv_len, sw);
|
||||||
if(res != YKPIV_OK) {
|
if(res != YKPIV_OK) {
|
||||||
_ykpiv_end_transaction(state);
|
goto Cleanup;
|
||||||
return res;
|
|
||||||
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
|
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
|
||||||
return _ykpiv_end_transaction(state);
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
if(*out_len + recv_len - 2 > max_out) {
|
if(*out_len + recv_len - 2 > max_out) {
|
||||||
if(state->verbose) {
|
if(state->verbose) {
|
||||||
fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.\n", *out_len + recv_len - 2, max_out);
|
fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.\n", *out_len + recv_len - 2, max_out);
|
||||||
}
|
}
|
||||||
_ykpiv_end_transaction(state);
|
res = YKPIV_SIZE_ERROR;
|
||||||
return YKPIV_SIZE_ERROR;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
if(out_data) {
|
if(out_data) {
|
||||||
memcpy(out_data, data, recv_len - 2);
|
memcpy(out_data, data, recv_len - 2);
|
||||||
@@ -513,10 +509,9 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
|||||||
apdu.st.ins = 0xc0;
|
apdu.st.ins = 0xc0;
|
||||||
res = _send_data(state, &apdu, data, &recv_len, sw);
|
res = _send_data(state, &apdu, data, &recv_len, sw);
|
||||||
if(res != YKPIV_OK) {
|
if(res != YKPIV_OK) {
|
||||||
_ykpiv_end_transaction(state);
|
goto Cleanup;
|
||||||
return res;
|
|
||||||
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
|
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
|
||||||
return _ykpiv_end_transaction(state);
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
if(*out_len + recv_len - 2 > max_out) {
|
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);
|
fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.", *out_len + recv_len - 2, max_out);
|
||||||
@@ -527,7 +522,9 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
|||||||
*out_len += recv_len - 2;
|
*out_len += recv_len - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _ykpiv_end_transaction(state);
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _send_data(ykpiv_state *state, APDU *apdu,
|
static ykpiv_rc _send_data(ykpiv_state *state, APDU *apdu,
|
||||||
@@ -573,6 +570,9 @@ ykpiv_rc ykpiv_authenticate(ykpiv_state *state, unsigned const char *key) {
|
|||||||
|
|
||||||
if (NULL == state) return YKPIV_GENERIC_ERROR;
|
if (NULL == state) return 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;
|
||||||
|
|
||||||
if (NULL == key) {
|
if (NULL == key) {
|
||||||
/* use the derived mgm key to authenticate, if it hasn't been derived, use default */
|
/* use the derived mgm key to authenticate, if it hasn't been derived, use default */
|
||||||
key = (unsigned const char*)YKPIV_MGM_DEFAULT;
|
key = (unsigned const char*)YKPIV_MGM_DEFAULT;
|
||||||
@@ -662,6 +662,7 @@ Cleanup:
|
|||||||
des_destroy_key(mgm_key);
|
des_destroy_key(mgm_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,13 +677,17 @@ ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, con
|
|||||||
int sw;
|
int sw;
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
if (yk_des_is_weak_key(new_key, DES_LEN_3DES)) {
|
if (yk_des_is_weak_key(new_key, DES_LEN_3DES)) {
|
||||||
if (state->verbose) {
|
if (state->verbose) {
|
||||||
fprintf(stderr, "Won't set new key '");
|
fprintf(stderr, "Won't set new key '");
|
||||||
dump_hex(new_key, DES_LEN_3DES);
|
dump_hex(new_key, DES_LEN_3DES);
|
||||||
fprintf(stderr, "' since it's weak (with odd parity).\n");
|
fprintf(stderr, "' since it's weak (with odd parity).\n");
|
||||||
}
|
}
|
||||||
return YKPIV_KEY_ERROR;
|
res = YKPIV_KEY_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(apdu.raw, 0, sizeof(apdu));
|
memset(apdu.raw, 0, sizeof(apdu));
|
||||||
@@ -695,7 +700,8 @@ ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, con
|
|||||||
apdu.st.p2 = 0xfe;
|
apdu.st.p2 = 0xfe;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
apdu.st.lc = DES_LEN_3DES + 3;
|
apdu.st.lc = DES_LEN_3DES + 3;
|
||||||
@@ -705,13 +711,16 @@ ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, con
|
|||||||
memcpy(apdu.st.data + 3, new_key, DES_LEN_3DES);
|
memcpy(apdu.st.data + 3, new_key, DES_LEN_3DES);
|
||||||
|
|
||||||
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;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
else if (sw == SW_SUCCESS) {
|
else if (sw == SW_SUCCESS) {
|
||||||
return YKPIV_OK;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
return YKPIV_GENERIC_ERROR;
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char hex_translate[] = "0123456789abcdef";
|
static char hex_translate[] = "0123456789abcdef";
|
||||||
@@ -857,7 +866,6 @@ ykpiv_rc ykpiv_sign_data(ykpiv_state *state,
|
|||||||
if (NULL == state) return YKPIV_GENERIC_ERROR;
|
if (NULL == state) return YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
// TREV TODO: clean up selections
|
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
res = _general_authenticate(state, raw_in, in_len, sign_out, out_len,
|
res = _general_authenticate(state, raw_in, in_len, sign_out, out_len,
|
||||||
@@ -894,19 +902,27 @@ ykpiv_rc ykpiv_get_version(ykpiv_state *state, char *version, size_t len) {
|
|||||||
int sw;
|
int sw;
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
memset(apdu.raw, 0, sizeof(apdu));
|
memset(apdu.raw, 0, sizeof(apdu));
|
||||||
apdu.st.ins = YKPIV_INS_GET_VERSION;
|
apdu.st.ins = YKPIV_INS_GET_VERSION;
|
||||||
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;
|
goto Cleanup;
|
||||||
} else if(sw == SW_SUCCESS) {
|
} else if(sw == SW_SUCCESS) {
|
||||||
int result = snprintf(version, len, "%d.%d.%d", data[0], data[1], data[2]);
|
int result = snprintf(version, len, "%d.%d.%d", data[0], data[1], data[2]);
|
||||||
if(result < 0) {
|
if(result < 0) {
|
||||||
return YKPIV_SIZE_ERROR;
|
res = YKPIV_SIZE_ERROR;
|
||||||
}
|
}
|
||||||
return YKPIV_OK;
|
goto Cleanup;
|
||||||
} else {
|
} else {
|
||||||
return YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc _cache_pin(ykpiv_state *state, const char *pin, size_t len) {
|
static ykpiv_rc _cache_pin(ykpiv_state *state, const char *pin, size_t len) {
|
||||||
@@ -1027,21 +1043,28 @@ ykpiv_rc ykpiv_set_pin_retries(ykpiv_state *state, int pin_tries, int puk_tries)
|
|||||||
templ[2] = (unsigned char)pin_tries;
|
templ[2] = (unsigned char)pin_tries;
|
||||||
templ[3] = (unsigned char)puk_tries;
|
templ[3] = (unsigned char)puk_tries;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
res = ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw);
|
res = ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw);
|
||||||
if (YKPIV_OK == res) {
|
if (YKPIV_OK == res) {
|
||||||
if (SW_SUCCESS == sw) {
|
if (SW_SUCCESS == sw) {
|
||||||
return YKPIV_OK;
|
// success, fall through
|
||||||
} else if (sw == SW_ERR_AUTH_BLOCKED) {
|
} else if (sw == SW_ERR_AUTH_BLOCKED) {
|
||||||
return YKPIV_AUTHENTICATION_ERROR;
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
} else if (sw == SW_ERR_SECURITY_STATUS) {
|
} else if (sw == SW_ERR_SECURITY_STATUS) {
|
||||||
return YKPIV_AUTHENTICATION_ERROR;
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
|
} else {
|
||||||
|
res = YKPIV_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
return YKPIV_GENERIC_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ykpiv_rc change_pin_internal(ykpiv_state *state, int action, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
static ykpiv_rc _ykpiv_change_pin(ykpiv_state *state, int action, const char * current_pin, size_t current_pin_len, const char * new_pin, size_t new_pin_len, int *tries) {
|
||||||
int sw;
|
int sw;
|
||||||
unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80};
|
unsigned char templ[] = {0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80};
|
||||||
unsigned char indata[0x10];
|
unsigned char indata[0x10];
|
||||||
@@ -1093,7 +1116,7 @@ ykpiv_rc ykpiv_change_pin(ykpiv_state *state, const char * current_pin, size_t c
|
|||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
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);
|
res = _ykpiv_change_pin(state, CHREF_ACT_CHANGE_PIN, current_pin, current_pin_len, new_pin, new_pin_len, tries);
|
||||||
if (res == YKPIV_OK && new_pin != NULL) {
|
if (res == YKPIV_OK && new_pin != NULL) {
|
||||||
// Intentionally ignore errors. If the PIN fails to save, it will only
|
// Intentionally ignore errors. If the PIN fails to save, it will only
|
||||||
// be a problem if a reconnect is attempted. Failure deferred until then.
|
// be a problem if a reconnect is attempted. Failure deferred until then.
|
||||||
@@ -1111,7 +1134,7 @@ ykpiv_rc ykpiv_change_puk(ykpiv_state *state, const char * current_puk, size_t c
|
|||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
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);
|
res = _ykpiv_change_pin(state, CHREF_ACT_CHANGE_PUK, current_puk, current_puk_len, new_puk, new_puk_len, tries);
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
@@ -1124,7 +1147,7 @@ ykpiv_rc ykpiv_unblock_pin(ykpiv_state *state, const char * puk, size_t puk_len,
|
|||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
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);
|
res = _ykpiv_change_pin(state, CHREF_ACT_UNBLOCK_PIN, puk, puk_len, new_pin, new_pin_len, tries);
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
@@ -1133,6 +1156,20 @@ Cleanup:
|
|||||||
|
|
||||||
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
||||||
unsigned char *data, unsigned long *len) {
|
unsigned char *data, unsigned long *len) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
res = _ykpiv_fetch_object(state, object_id, data, len);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_rc _ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
||||||
|
unsigned char *data, unsigned long *len) {
|
||||||
int sw;
|
int sw;
|
||||||
unsigned char indata[5];
|
unsigned char indata[5];
|
||||||
unsigned char *inptr = indata;
|
unsigned char *inptr = indata;
|
||||||
@@ -1165,9 +1202,21 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
|||||||
|
|
||||||
ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
|
ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
|
||||||
unsigned char *indata, size_t len) {
|
unsigned char *indata, size_t len) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
// TREV TODO: buffer sizes different in minidriver
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
unsigned char data[3072];
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
res = _ykpiv_save_object(state, object_id, indata, len);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id,
|
||||||
|
unsigned char *indata, size_t len) {
|
||||||
|
unsigned char data[CB_BUF_MAX];
|
||||||
unsigned char *dataptr = data;
|
unsigned char *dataptr = data;
|
||||||
unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff};
|
unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff};
|
||||||
int sw;
|
int sw;
|
||||||
@@ -1224,6 +1273,7 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
|
|||||||
unsigned char n_params;
|
unsigned char n_params;
|
||||||
int i;
|
int i;
|
||||||
int param_tag;
|
int param_tag;
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
if (state == NULL)
|
if (state == NULL)
|
||||||
return YKPIV_GENERIC_ERROR;
|
return YKPIV_GENERIC_ERROR;
|
||||||
@@ -1320,17 +1370,23 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
|
|||||||
*in_ptr++ = touch_policy;
|
*in_ptr++ = touch_policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw) != YKPIV_OK)
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
return YKPIV_GENERIC_ERROR;
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
if (sw == SW_ERR_SECURITY_STATUS)
|
if ((res = ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw)) != YKPIV_OK) {
|
||||||
return YKPIV_AUTHENTICATION_ERROR;
|
goto Cleanup;
|
||||||
|
}
|
||||||
if (sw != SW_SUCCESS)
|
if (SW_SUCCESS != sw) {
|
||||||
return YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
if (sw == SW_ERR_SECURITY_STATUS) {
|
||||||
return YKPIV_OK;
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
|
}
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len) {
|
ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len) {
|
||||||
@@ -1342,19 +1398,28 @@ ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char
|
|||||||
if (state == NULL || data == NULL || data_len == NULL) {
|
if (state == NULL || data == NULL || data_len == NULL) {
|
||||||
return YKPIV_ARGUMENT_ERROR;
|
return YKPIV_ARGUMENT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
if ((res = ykpiv_transfer_data(state, templ, NULL, 0, data, data_len, &sw)) != YKPIV_OK) {
|
if ((res = ykpiv_transfer_data(state, templ, NULL, 0, data, data_len, &sw)) != YKPIV_OK) {
|
||||||
return res;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
else if(SW_SUCCESS != sw) {
|
if (SW_SUCCESS != sw) {
|
||||||
if (sw == SW_ERR_NOT_SUPPORTED) {
|
res = YKPIV_GENERIC_ERROR;
|
||||||
return YKPIV_NOT_SUPPORTED;
|
if (SW_ERR_NOT_SUPPORTED == sw) {
|
||||||
|
res = YKPIV_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
return YKPIV_GENERIC_ERROR;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
if (data[0] != 0x30) {
|
if (data[0] != 0x30) {
|
||||||
return YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
return YKPIV_OK;
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user