Merge branch 'pr-165'

This commit is contained in:
Klas Lindfors
2018-09-21 10:34:09 +02:00
8 changed files with 396 additions and 163 deletions
+4 -3
View File
@@ -33,9 +33,9 @@ AC_CONFIG_MACRO_DIR([m4])
# Interfaces changed/added/removed: CURRENT++ REVISION=0
# Interfaces added: AGE++
# Interfaces removed: AGE=0
AC_SUBST([LT_CURRENT], 5)
AC_SUBST([LT_REVISION], 5)
AC_SUBST([LT_AGE], 4)
AC_SUBST([LT_CURRENT], 6)
AC_SUBST([LT_REVISION], 0)
AC_SUBST([LT_AGE], 5)
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AM_SILENT_RULES([yes])
@@ -224,6 +224,7 @@ if test "$gl_gcc_warnings" = yes; then
nw="$nw -Wconversion" # Too many warnings for now
nw="$nw -Wsuggest-attribute=pure" # Is it worth using attributes?
nw="$nw -Wsuggest-attribute=const" # Is it worth using attributes?
nw="$nw -Waggregate-return" # returning structs shouldn't be a problem
gl_MANYWARN_ALL_GCC([ws])
gl_MANYWARN_COMPLEMENT(ws, [$ws], [$nw])
+16 -3
View File
@@ -304,8 +304,11 @@ des_rc des_encrypt(des_key* key, const unsigned char* in, const size_t inlen, un
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
/* openssl returns void */
DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 1);
#pragma GCC diagnostic pop
#endif
@@ -336,8 +339,11 @@ des_rc des_decrypt(des_key* key, const unsigned char* in, const size_t inlen, un
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
/* openssl returns void */
DES_ecb3_encrypt((const_DES_cblock*)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 0);
#pragma GCC diagnostic pop
#endif
@@ -400,7 +406,12 @@ bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key) {
return false;
#else
(void)cb_key; /* unused */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
return DES_is_weak_key((const_DES_cblock *)key);
#pragma GCC diagnostic pop
#endif
}
@@ -431,7 +442,7 @@ prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req) {
return rc;
}
pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_password, const unsigned char* salt, const size_t cb_salt, unsigned long long iterations, unsigned char* key, const size_t cb_key) {
pkcs5_rc pkcs5_pbkdf2_sha1(const uint8_t* password, const size_t cb_password, const uint8_t* salt, const size_t cb_salt, uint64_t iterations, const uint8_t* key, const size_t cb_key) {
pkcs5_rc rc = PKCS5_OK;
#ifdef _WINDOWS
@@ -459,8 +470,11 @@ pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_passwo
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
/* for some reason openssl always returns 1 for PBKDF2 */
PKCS5_PBKDF2_HMAC_SHA1((const char*)password, cb_password, salt, cb_salt, iterations, cb_key, key);
PKCS5_PBKDF2_HMAC_SHA1((const char*)password, cb_password, salt, cb_salt, iterations, cb_key, (unsigned char*)key);
#pragma GCC diagnostic pop
#endif
@@ -491,7 +505,6 @@ setting_bool_t _get_bool_config(const char *sz_setting) {
#ifdef _WIN32
HKEY hKey = 0;
DWORD dwErr = 0;
DWORD dwValue = 0;
DWORD dwType = 0;
DWORD cbValue = sizeof(dwValue);
+12 -7
View File
@@ -178,21 +178,20 @@ union u_APDU {
typedef union u_APDU APDU;
typedef struct des_key des_key;
extern unsigned const char aid[];
des_rc des_import_key(const int type, const unsigned char* keyraw, const size_t keyrawlen, des_key** key);
des_rc des_destroy_key(des_key* key);
des_rc des_encrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen);
des_rc des_decrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen);
pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_password, const unsigned char* salt, const size_t cb_salt, unsigned long long iterations, unsigned char* key, const size_t cb_key);
pkcs5_rc pkcs5_pbkdf2_sha1(const uint8_t* password, const size_t cb_password, const uint8_t* salt, const size_t cb_salt, uint64_t iterations, const uint8_t* key, const size_t cb_key);
bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key);
prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req);
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state);
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state);
ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state);
int _ykpiv_set_length(unsigned char *buffer, size_t length);
int _ykpiv_get_length(const unsigned char *buffer, size_t *len);
ykpiv_rc _ykpiv_select_application(ykpiv_state *state);
unsigned int _ykpiv_set_length(unsigned char *buffer, size_t length);
unsigned int _ykpiv_get_length(const unsigned char *buffer, size_t *len);
void* _ykpiv_alloc(ykpiv_state *state, size_t size);
void* _ykpiv_realloc(ykpiv_state *state, void *address, size_t size);
@@ -200,8 +199,14 @@ 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);
ykpiv_rc _send_data(ykpiv_state *state, APDU *apdu, unsigned char *data, uint32_t *recv_len, int *sw);
ykpiv_rc _ykpiv_get_version(ykpiv_state *state, ykpiv_version_t *p_version);
ykpiv_rc _ykpiv_util_get_serial(ykpiv_state *state, uint32_t *p_serial, bool f_force);
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);
/* authentication functions not ready for public api */
ykpiv_rc ykpiv_auth_getchallenge(ykpiv_state *state, uint8_t *challenge, const size_t challenge_len);
+45 -103
View File
@@ -208,8 +208,9 @@ Cleanup:
}
ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state) {
if (!state || state->context == SCARD_E_INVALID_HANDLE)
if (!state || !state->context || (state->context == (uintptr_t)-1)) {
return DEVTYPE_UNKNOWN;
}
return (state->isNEO ? DEVTYPE_NEOr3 : DEVTYPE_YK4);
}
@@ -343,7 +344,15 @@ ykpiv_rc ykpiv_util_read_cert(ykpiv_state *state, uint8_t slot, uint8_t **data,
*data_len = 0;
if (YKPIV_OK == (res = _read_certificate(state, slot, buf, &cbBuf))) {
if (NULL == (*data = _ykpiv_alloc(state, cbBuf))) {
/* handle those who write empty certificate blobs to PIV objects */
if (cbBuf == 0) {
*data = NULL;
*data_len = 0;
goto Cleanup;
}
if (!(*data = _ykpiv_alloc(state, cbBuf))) {
res = YKPIV_MEMORY_ERROR;
goto Cleanup;
}
@@ -415,7 +424,7 @@ ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state) {
memcpy(&flags, p_item, cb_item);
}
else {
if (state->verbose) { fprintf(stderr, "admin flags exist, but are incorrect size = %zu", cb_item); }
if (state->verbose) { fprintf(stderr, "admin flags exist, but are incorrect size = %lu", (unsigned long)cb_item); }
}
}
}
@@ -454,17 +463,17 @@ ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers
if (YKPIV_OK == (res = _ykpiv_fetch_object(state, YKPIV_OBJ_MSCMAP, buf, (unsigned long*)&cbBuf))) {
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 */
if (cbBuf < CB_OBJ_TAG_MIN) {
res = YKPIV_OK;
goto Cleanup;
}
if (*ptr++ == TAG_MSCMAP) {
ptr += _ykpiv_get_length(ptr, &len);
ptr += (unsigned long)_ykpiv_get_length(ptr, &len);
// check that decoded length represents object contents
if (len > (cbBuf - (ptr - buf))) {
/* check that decoded length represents object contents */
if (len > (cbBuf - (size_t)(ptr - buf))) {
res = YKPIV_OK;
goto Cleanup;
}
@@ -474,7 +483,7 @@ ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers
goto Cleanup;
}
// should check if container map isn't corrupt
/* should check if container map isn't corrupt */
memcpy(*containers, ptr, len);
*n_containers = len / sizeof(ykpiv_container);
@@ -516,7 +525,7 @@ ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers
// encode object data for storage
// calculate the required length of the encoded object
req_len = 1 /* data tag */ + _ykpiv_set_length(buf, data_len) + data_len;
req_len = 1 /* data tag */ + (unsigned long)_ykpiv_set_length(buf, data_len) + data_len;
if (req_len > _obj_size_max(state)) {
res = YKPIV_SIZE_ERROR;
@@ -588,7 +597,7 @@ ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *dat
ptr += _ykpiv_get_length(ptr, &len);
// check that decoded length represents object contents
if (len > (cbBuf - (ptr - buf))) {
if (len > (cbBuf - (size_t)(ptr - buf))) {
res = YKPIV_OK;
goto Cleanup;
}
@@ -671,14 +680,14 @@ ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data
offset = 0;
data_chunk = MIN(cb_obj_max - CB_OBJ_TAG_MAX, data_len - data_offset);
// encode object data for storage
/* encode object data for storage */
buf[offset++] = (i == (n_objs - 1)) ? TAG_MSROOTS_END : TAG_MSROOTS_MID;
offset += _ykpiv_set_length(buf + offset, data_chunk);
memcpy(buf + offset, data + data_offset, data_chunk);
offset += data_chunk;
// write onto device
res = _ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1 + i, buf, offset);
/* write onto device */
res = _ykpiv_save_object(state, (int)(YKPIV_OBJ_MSROOTS1 + i), buf, offset);
if (YKPIV_OK != res) {
goto Cleanup;
@@ -811,7 +820,7 @@ ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algor
*in_ptr++ = touch_policy;
}
if (YKPIV_OK != (res = ykpiv_transfer_data(state, templ, in_data, (long)(in_ptr - in_data), data, &recv_len, &sw))) {
if (YKPIV_OK != (res = _ykpiv_transfer_data(state, templ, in_data, (long)(in_ptr - in_data), data, &recv_len, &sw))) {
if (state->verbose) { fprintf(stderr, "Failed to communicate.\n"); }
goto Cleanup;
}
@@ -1084,7 +1093,7 @@ ykpiv_rc ykpiv_util_get_derived_mgm(ykpiv_state *state, const uint8_t *pin, cons
if (YKPIV_OK == (res = _read_metadata(state, TAG_ADMIN, data, &cb_data))) {
if (YKPIV_OK == (res = _get_metadata_item(data, cb_data, TAG_ADMIN_SALT, &p_item, &cb_item))) {
if (cb_item != CB_ADMIN_SALT) {
if (state->verbose) fprintf(stderr, "derived mgm salt exists, but is incorrect size = %zu\n", cb_item);
if (state->verbose) fprintf(stderr, "derived mgm salt exists, but is incorrect size = %lu\n", (unsigned long)cb_item);
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
@@ -1127,7 +1136,7 @@ ykpiv_rc ykpiv_util_get_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) {
}
if (cb_item != member_size(ykpiv_mgm, data)) {
if (state->verbose) fprintf(stderr, "protected data contains mgm, but is the wrong size = %zu\n", cb_item);
if (state->verbose) fprintf(stderr, "protected data contains mgm, but is the wrong size = %lu\n", (unsigned long)cb_item);
res = YKPIV_AUTHENTICATION_ERROR;
goto Cleanup;
}
@@ -1245,7 +1254,7 @@ ykpiv_rc ykpiv_util_set_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm) {
memcpy(&flags_1, p_item, cb_item);
}
else {
if (state->verbose) fprintf(stderr, "admin data flags are an incorrect size = %zu\n", cb_item);
if (state->verbose) fprintf(stderr, "admin data flags are an incorrect size = %lu\n", (unsigned long)cb_item);
}
/* remove any existing salt */
@@ -1322,88 +1331,13 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) {
break;
}
return object_id;
}
/* caller must make sure that this is wrapped in a transaction for synchronized operation */
ykpiv_rc _ykpiv_util_get_serial(ykpiv_state *state, uint32_t *p_serial, bool f_force) {
ykpiv_rc res = YKPIV_OK;
APDU apdu;
const uint8_t yk_applet[] = { 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x01 };
unsigned char data[0xff];
uint32_t recv_len = sizeof(data);
int sw;
uint8_t *p_temp = NULL;
if (!state) {
return YKPIV_ARGUMENT_ERROR;
}
if (!f_force && (state->serial != 0)) {
if (p_serial) *p_serial = state->serial;
return YKPIV_OK;
}
/* this function does not use ykpiv_transfer_data because it requires two apdus and selects a different app */
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
apdu.st.p1 = 0x04;
apdu.st.lc = sizeof(yk_applet);
memcpy(apdu.st.data, yk_applet, sizeof(yk_applet));
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));
}
goto Cleanup;
}
else if (sw != SW_SUCCESS) {
if (state->verbose) {
fprintf(stderr, "Failed selecting yk application: %04x\n", sw);
}
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
recv_len = sizeof(data);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = 0x01;
apdu.st.p1 = 0x10;
apdu.st.lc = 0x00;
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));
}
goto Cleanup;
}
else if (sw != SW_SUCCESS) {
if (state->verbose) {
fprintf(stderr, "Failed retrieving serial number: %04x\n", sw);
}
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
p_temp = (uint8_t*)(&state->serial);
*p_temp++ = data[3];
*p_temp++ = data[2];
*p_temp++ = data[1];
*p_temp++ = data[0];
if (p_serial) *p_serial = state->serial;
Cleanup:
return res;
return (uint32_t)object_id;
}
static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len) {
ykpiv_rc res = YKPIV_OK;
uint8_t *ptr = NULL;
int object_id = ykpiv_util_slot_object(slot);
int object_id = (int)ykpiv_util_slot_object(slot);
size_t len = 0;
if (-1 == object_id) return YKPIV_INVALID_OBJECT;
@@ -1423,7 +1357,7 @@ static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf
ptr += _ykpiv_get_length(ptr, &len);
// check that decoded length represents object contents
if (len > (*buf_len - (ptr - buf))) {
if (len > (*buf_len - (size_t)(ptr - buf))) {
*buf_len = 0;
return YKPIV_OK;
}
@@ -1441,7 +1375,7 @@ 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) {
uint8_t buf[CB_OBJ_MAX];
int object_id = ykpiv_util_slot_object(slot);
int object_id = (int)ykpiv_util_slot_object(slot);
size_t offset = 0;
size_t req_len = 0;
@@ -1579,16 +1513,24 @@ static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_da
/* length doesn't match, expand/shrink to fit */
p_next = p_temp + cb_temp;
cb_moved = (long)cb_item - (long)cb_temp + ((long)(cb_item != 0 ? _get_length_size(cb_item) : -1 /* for tag, if deleting */) - (long)cb_len); /* accounts for different length encoding */
cb_moved = (long)cb_item - (long)cb_temp +
((long)(cb_item != 0 ? _get_length_size(cb_item) : -1 /* for tag, if deleting */) -
(long)cb_len); /* accounts for different length encoding */
/* length would cause buffer overflow, return error */
if (*pcb_data + cb_moved > cb_data_max) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
if ((size_t)(*pcb_data + cb_moved) > cb_data_max) {
return YKPIV_GENERIC_ERROR;
}
#pragma GCC diagnostic pop
/* move remaining data */
memmove(p_next + cb_moved, p_next, *pcb_data - (p_next - data));
memmove(p_next + cb_moved, p_next, *pcb_data - (size_t)(p_next - data));
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
*pcb_data += cb_moved;
#pragma GCC diagnostic pop
/* re-encode item and insert */
if (cb_item != 0) {
@@ -1598,7 +1540,7 @@ static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_da
}
return YKPIV_OK;
} //if tag found
} /* if tag found */
p_temp += cb_temp;
}
@@ -1610,7 +1552,7 @@ static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_da
// we did not find an existing tag, append
p_temp = data + *pcb_data;
cb_len = _get_length_size(cb_item);
cb_len = (size_t)_get_length_size(cb_item);
// length would cause buffer overflow, return error
if (*pcb_data + cb_len + cb_item > cb_data_max) {
@@ -1666,7 +1608,7 @@ static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, s
p_temp += _ykpiv_get_length(p_temp, pcb_data);
if (*pcb_data > ((size_t)cb_temp - (p_temp - data))) {
if (*pcb_data > (cb_temp - (size_t)(p_temp - data))) {
*pcb_data = 0;
return YKPIV_GENERIC_ERROR;
}
@@ -1712,7 +1654,7 @@ static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data,
memcpy(pTemp, data, cb_data);
pTemp += cb_data;
res = _ykpiv_save_object(state, obj_id, buf, pTemp - buf);
res = _ykpiv_save_object(state, obj_id, buf, (size_t)(pTemp - buf));
}
return res;
+256 -28
View File
@@ -76,11 +76,36 @@
#define ENABLE_APPLICATION_RESELECTION 0
#endif
/**
* ENABLE_IMPLICIT_TRANSACTIONS - call SCardBeginTransaction for all public API calls
*
* If this is enabled, every public call (prefixed with \r ykpiv_) will call
* SCardBeginTransaction on entry and SCardEndTransaction on exit.
*
* For applications that do not do their own transaction management, like the piv tool
* itself, retaining the default setting of enabled can allow other applications and
* threads to make calls to CCID that can interfere with multi-block data sent to the
* card via SCardTransmitData.
*/
#ifndef ENABLE_IMPLICIT_TRANSACTIONS
#define ENABLE_IMPLICIT_TRANSACTIONS 1
#endif
/**
* Platform specific definitions
*/
#ifdef _MSC_VER
#define strncasecmp _strnicmp
#endif
#define YKPIV_MGM_DEFAULT "\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"
static ykpiv_rc _cache_pin(ykpiv_state *state, const char *pin, size_t len);
static ykpiv_rc _ykpiv_get_serial(ykpiv_state *state, uint32_t *p_serial, bool force);
static ykpiv_rc _ykpiv_get_version(ykpiv_state *state, ykpiv_version_t *p_version);
unsigned const char aid[] = {
static unsigned const char aid[] = {
0xa0, 0x00, 0x00, 0x03, 0x08
};
@@ -130,7 +155,7 @@ static void dump_hex(const unsigned char *buf, unsigned int len) {
}
}
int _ykpiv_set_length(unsigned char *buffer, size_t length) {
unsigned int _ykpiv_set_length(unsigned char *buffer, size_t length) {
if(length < 0x80) {
*buffer++ = (unsigned char)length;
return 1;
@@ -146,7 +171,7 @@ int _ykpiv_set_length(unsigned char *buffer, size_t length) {
}
}
int _ykpiv_get_length(const unsigned char *buffer, size_t *len) {
unsigned int _ykpiv_get_length(const unsigned char *buffer, size_t *len) {
if(buffer[0] < 0x81) {
*len = buffer[0];
return 1;
@@ -193,7 +218,7 @@ ykpiv_rc ykpiv_init_with_allocator(ykpiv_state **state, int verbose, const ykpiv
s->pin = NULL;
s->allocator = *allocator;
s->verbose = verbose;
s->context = SCARD_E_INVALID_HANDLE;
s->context = (SCARDCONTEXT)-1;
*state = s;
return YKPIV_OK;
}
@@ -226,7 +251,7 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
if(SCardIsValidContext(state->context) == SCARD_S_SUCCESS) {
SCardReleaseContext(state->context);
state->context = SCARD_E_INVALID_HANDLE;
state->context = (SCARDCONTEXT)-1;
}
return YKPIV_OK;
@@ -239,8 +264,6 @@ ykpiv_rc _ykpiv_select_application(ykpiv_state *state) {
int sw;
ykpiv_rc res = YKPIV_OK;
_ykpiv_util_get_serial(state, NULL, false);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
apdu.st.p1 = 0x04;
@@ -260,7 +283,16 @@ ykpiv_rc _ykpiv_select_application(ykpiv_state *state) {
return YKPIV_GENERIC_ERROR;
}
/* now that the PIV application is selected, retrieve the version
* and serial number. Previously the NEO/YK4 required switching
* to the yk applet to retrieve the serial, YK5 implements this
* as a PIV applet command. Unfortunately, this change requires
* that we retrieve the version number first, so that get_serial
* can determine how to get the serial number, which for the NEO/Yk4
* will result in another selection of the PIV applet. */
_ykpiv_get_version(state, NULL);
_ykpiv_get_serial(state, NULL, false);
return res;
}
@@ -284,6 +316,7 @@ ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) {
return res;
#else
(void)state;
return res;
#endif
}
@@ -456,7 +489,7 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
}
SCardReleaseContext(state->context);
state->context = SCARD_E_INVALID_HANDLE;
state->context = (SCARDCONTEXT)-1;
return YKPIV_PCSC_ERROR;
}
@@ -471,7 +504,7 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
}
SCardReleaseContext(state->context);
state->context = SCARD_E_INVALID_HANDLE;
state->context = (SCARDCONTEXT)-1;
return YKPIV_PCSC_ERROR;
}
@@ -481,11 +514,12 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
}
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) {
#if ENABLE_IMPLICIT_TRANSACTIONS
long rc;
ykpiv_rc res;
rc = SCardBeginTransaction(state->card);
if((rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) {
if((long)((unsigned long)rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) {
ykpiv_rc res = YKPIV_OK;
if((res = reconnect(state)) != YKPIV_OK) {
return res;
}
@@ -497,27 +531,33 @@ ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) {
}
return YKPIV_PCSC_ERROR;
}
#endif /* ENABLE_IMPLICIT_TRANSACTIONS */
return YKPIV_OK;
}
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state) {
#if ENABLE_IMPLICIT_TRANSACTIONS
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;
}
#endif /* ENABLE_IMPLICIT_TRANSACTIONS */
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) {
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;
*out_len = 0;
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
do {
size_t this_size = 0xff;
unsigned char data[261];
@@ -587,6 +627,19 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
}
}
Cleanup:
return res;
}
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) {
ykpiv_rc res;
if ((res = _ykpiv_begin_transaction(state)) != YKPIV_OK) {
*out_len = 0;
return YKPIV_PCSC_ERROR;
}
res = _ykpiv_transfer_data(state, templ, in_data, in_len, out_data, out_len, sw);
_ykpiv_end_transaction(state);
return res;
}
@@ -838,6 +891,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
switch(algorithm) {
case YKPIV_ALGO_RSA1024:
key_len = 128;
// fall through
case YKPIV_ALGO_RSA2048:
if(key_len == 0) {
key_len = 256;
@@ -848,6 +902,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
break;
case YKPIV_ALGO_ECCP256:
key_len = 32;
// fall through
case YKPIV_ALGO_ECCP384:
if(key_len == 0) {
key_len = 48;
@@ -932,11 +987,12 @@ ykpiv_rc ykpiv_sign_data(ykpiv_state *state,
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;
/* don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS */
/*if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;*/
res = _general_authenticate(state, raw_in, in_len, sign_out, out_len,
algorithm, key, false);
Cleanup:
/* Cleanup: */
_ykpiv_end_transaction(state);
return res;
}
@@ -949,19 +1005,19 @@ ykpiv_rc ykpiv_decipher_data(ykpiv_state *state, const unsigned char *in,
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;
/* don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS */
/*if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;*/
res = _general_authenticate(state, in, in_len, out, out_len,
algorithm, key, true);
Cleanup:
/* Cleanup: */
_ykpiv_end_transaction(state);
return res;
}
ykpiv_rc _ykpiv_get_version(ykpiv_state *state, ykpiv_version_t *p_version) {
static ykpiv_rc _ykpiv_get_version(ykpiv_state *state, ykpiv_version_t *p_version) {
APDU apdu;
unsigned char data[261];
uint32_t recv_len = sizeof(data);
@@ -1022,6 +1078,138 @@ Cleanup:
return res;
}
/* caller must make sure that this is wrapped in a transaction for synchronized operation */
static ykpiv_rc _ykpiv_get_serial(ykpiv_state *state, uint32_t *p_serial, bool f_force) {
ykpiv_rc res = YKPIV_OK;
APDU apdu;
const uint8_t yk_applet[] = { 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x01 };
unsigned char data[0xff];
uint32_t recv_len = sizeof(data);
int sw;
uint8_t *p_temp = NULL;
if (!state) {
return YKPIV_ARGUMENT_ERROR;
}
if (!f_force && (state->serial != 0)) {
if (p_serial) *p_serial = state->serial;
return YKPIV_OK;
}
if (state->ver.major < 5) {
/* get serial from neo/yk4 devices using the otp applet */
uint8_t temp[0xff];
recv_len = sizeof(temp);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
apdu.st.p1 = 0x04;
apdu.st.lc = sizeof(yk_applet);
memcpy(apdu.st.data, yk_applet, sizeof(yk_applet));
if ((res = _send_data(state, &apdu, temp, &recv_len, &sw)) < YKPIV_OK) {
if (state->verbose) {
fprintf(stderr, "Failed communicating with card: '%s'\n", ykpiv_strerror(res));
}
goto Cleanup;
}
else if (sw != SW_SUCCESS) {
if (state->verbose) {
fprintf(stderr, "Failed selecting yk application: %04x\n", sw);
}
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
recv_len = sizeof(data);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = 0x01;
apdu.st.p1 = 0x10;
apdu.st.lc = 0x00;
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));
}
goto Cleanup;
}
else if (sw != SW_SUCCESS) {
if (state->verbose) {
fprintf(stderr, "Failed retrieving serial number: %04x\n", sw);
}
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
recv_len = sizeof(temp);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
apdu.st.p1 = 0x04;
apdu.st.lc = (unsigned char)sizeof(aid);
memcpy(apdu.st.data, aid, sizeof(aid));
if((res = _send_data(state, &apdu, temp, &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) {
if(state->verbose) {
fprintf(stderr, "Failed selecting application: %04x\n", sw);
}
return YKPIV_GENERIC_ERROR;
}
}
else {
/* get serial from yk5 and later devices using the f8 command */
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_GET_SERIAL;
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) {
if(state->verbose) {
fprintf(stderr, "Failed retrieving serial number: %04x\n", sw);
}
return YKPIV_GENERIC_ERROR;
}
}
p_temp = (uint8_t*)(&state->serial);
*p_temp++ = data[3];
*p_temp++ = data[2];
*p_temp++ = data[1];
*p_temp++ = data[0];
if (p_serial) *p_serial = state->serial;
Cleanup:
return res;
}
ykpiv_rc ykpiv_get_serial(ykpiv_state *state, uint32_t *p_serial) {
ykpiv_rc res = YKPIV_OK;
if ((res = _ykpiv_begin_transaction(state)) != YKPIV_OK) return YKPIV_PCSC_ERROR;
if ((res = _ykpiv_ensure_application_selected(state)) != YKPIV_OK) goto Cleanup;
res = _ykpiv_get_serial(state, p_serial, false);
Cleanup:
_ykpiv_end_transaction(state);
return res;
}
static ykpiv_rc _cache_pin(ykpiv_state *state, const char *pin, size_t len) {
#if DISABLE_PIN_CACHE
// Some embedded applications of this library may not want to keep the PIN
@@ -1290,13 +1478,13 @@ ykpiv_rc _ykpiv_fetch_object(ykpiv_state *state, int object_id,
if(sw == SW_SUCCESS) {
size_t outlen;
int offs = _ykpiv_get_length(data + 1, &outlen);
unsigned int offs = _ykpiv_get_length(data + 1, &outlen);
if(offs == 0) {
return YKPIV_SIZE_ERROR;
}
if(outlen + offs + 1 != *len) {
if(state->verbose) {
fprintf(stderr, "Invalid length indicated in object, total objlen is %lu, indicated length is %lu.", *len, outlen);
fprintf(stderr, "Invalid length indicated in object, total objlen is %lu, indicated length is %lu.", *len, (unsigned long)outlen);
}
return YKPIV_SIZE_ERROR;
}
@@ -1322,8 +1510,11 @@ Cleanup:
return res;
}
ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id,
unsigned char *indata, size_t len) {
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 templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff};
@@ -1343,7 +1534,7 @@ ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id,
memcpy(dataptr, indata, len);
dataptr += len;
if((res = ykpiv_transfer_data(state, templ, data, (long)(dataptr - data), NULL, &outlen,
if((res = _ykpiv_transfer_data(state, templ, data, (long)(dataptr - data), NULL, &outlen,
&sw)) != YKPIV_OK) {
return res;
}
@@ -1436,10 +1627,13 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
}
else if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
if ((size_t)ec_data_len >= sizeof(key_data)) {
// This can never be true, but check to be explicit.
/* This can never be true, but check to be explicit. */
return YKPIV_SIZE_ERROR;
}
#pragma GCC diagnostic pop
if (algorithm == YKPIV_ALGO_ECCP256)
elem_len = 32;
@@ -1621,11 +1815,45 @@ Cleanup:
return res;
}
static const uint8_t MGMT_AID[] = { 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 };
/* deauthenticates the user pin and mgm key */
ykpiv_rc ykpiv_auth_deauthenticate(ykpiv_state *state) {
ykpiv_rc res = YKPIV_OK;
APDU apdu;
unsigned char data[0xff];
uint32_t recv_len = sizeof(data);
int sw;
if (!state) {
return YKPIV_ARGUMENT_ERROR;
}
/* this function does not use ykpiv_transfer_data because it selects a different app */
if ((res = _ykpiv_begin_transaction(state)) < YKPIV_OK) return res;
_ykpiv_util_get_serial(state, NULL, true);
memset(apdu.raw, 0, sizeof(apdu));
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
apdu.st.p1 = 0x04;
apdu.st.lc = sizeof(MGMT_AID);
memcpy(apdu.st.data, MGMT_AID, sizeof(MGMT_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));
}
goto Cleanup;
}
else if (sw != SW_SUCCESS) {
if (state->verbose) {
fprintf(stderr, "Failed selecting mgmt application: %04x\n", sw);
}
res = YKPIV_GENERIC_ERROR;
goto Cleanup;
}
Cleanup:
_ykpiv_end_transaction(state);
return res;
}
+18 -1
View File
@@ -194,6 +194,19 @@ extern "C"
*/
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select);
/**
* Get serial number
*
* The card must be connected to call this function.
*
* @param state [in] State handle
* @param p_serial [out] uint32 to store retrieved serial number
*
* @return ykpiv_rc error code
*
*/
ykpiv_rc ykpiv_get_serial(ykpiv_state *state, uint32_t* p_serial);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -492,7 +505,7 @@ extern "C"
* @param state state
* @param ccc Unique Card ID to set. If NULL, randomly generate.
*
* @return ypiv_rc error code
* @return ykpiv_rc error code
*
*/
ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc);
@@ -647,6 +660,7 @@ extern "C"
#define YKPIV_INS_RESET 0xfb
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
#define YKPIV_INS_ATTEST 0xf9
#define YKPIV_INS_GET_SERIAL 0xf8
#define YKPIV_PINPOLICY_TAG 0xaa
#define YKPIV_PINPOLICY_DEFAULT 0
@@ -671,12 +685,15 @@ extern "C"
#define YKPIV_ATR_NEO_R3 "\x3b\xfc\x13\x00\x00\x81\x31\xfe\x15\x59\x75\x62\x69\x6b\x65\x79\x4e\x45\x4f\x72\x33\xe1"
#define YKPIV_ATR_YK4 "\x3b\xf8\x13\x00\x00\x81\x31\xfe\x15\x59\x75\x62\x69\x6b\x65\x79\x34\xd4"
#define YKPIV_ATR_YK5_P1 "\x3b\xf8\x13\x00\x00\x81\x31\xfe\x15\x01\x59\x75\x62\x69\x4b\x65\x79\xc1"
#define YKPIV_ATR_YK5 "\x3b\xfd\x13\x00\x00\x81\x31\xfe\x15\x80\x73\xc0\x21\xc0\x57\x59\x75\x62\x69\x4b\x65\x79\x40"
#define DEVTYPE_UNKNOWN 0x00000000
#define DEVTYPE_NEO 0x4E450000 //"NE"
#define DEVTYPE_YK 0x594B0000 //"YK"
#define DEVTYPE_NEOr3 (DEVTYPE_NEO | 0x00007233) //"r3"
#define DEVTYPE_YK4 (DEVTYPE_YK | 0x00000034) // "4"
#define DEVYTPE_YK5 (DEVTYPE_YK | 0x00000035) // "5"
#ifdef __cplusplus
}
+6
View File
@@ -113,3 +113,9 @@ global:
ykpiv_util_write_msroots;
ykpiv_verify_select;
} YKPIV_1.3.0;
YKPIV_1.6.0
{
global:
ykpiv_get_serial;
} YKPIV_1.5.0;
+32 -11
View File
@@ -54,7 +54,6 @@
#include "util.h"
#define MAX(a,b) (a) > (b) ? (a) : (b)
#define MIN(a,b) (a) < (b) ? (a) : (b)
#define CHUID 0
#define CCC 1
@@ -450,11 +449,11 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
}
rc = ykpiv_import_private_key(state, key, algorithm,
p, element_len,
q, element_len,
dmp1, element_len,
dmq1, element_len,
iqmp, element_len,
p, (size_t)element_len,
q, (size_t)element_len,
dmp1, (size_t)element_len,
dmq1, (size_t)element_len,
iqmp, (size_t)element_len,
NULL, 0,
pp, tp);
}
@@ -586,7 +585,7 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format,
} else {
i2d_X509(cert, &certptr);
}
if ((res = ykpiv_util_write_cert(state, get_slot_hex(slot), certdata, cert_len, compress)) != YKPIV_OK) {
if ((res = ykpiv_util_write_cert(state, get_slot_hex(slot), certdata, (size_t)cert_len, compress)) != YKPIV_OK) {
fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res));
} else {
ret = true;
@@ -1067,6 +1066,9 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
op = ykpiv_change_puk;
}
res = op(state, pin, pin_len, new_pin, new_len, &tries);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (res) {
case YKPIV_OK:
return true;
@@ -1088,6 +1090,7 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
fprintf(stderr, "Failed changing/unblocking code, error: %s\n", ykpiv_strerror(res));
return false;
}
#pragma GCC diagnostic pop
}
static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
@@ -1258,7 +1261,7 @@ out:
static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_MD *md,
FILE *output) {
int object = ykpiv_util_slot_object(get_slot_hex(slot));
int object = (int)ykpiv_util_slot_object(get_slot_hex(slot));
int slot_name;
unsigned char data[3072];
const unsigned char *ptr = data;
@@ -1376,7 +1379,9 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
unsigned char buf[3072];
long unsigned len = sizeof(buf);
int i;
uint32_t serial = 0;
FILE *output_file = open_file(output_file_name, OUTPUT_TEXT);
if(!output_file) {
return false;
}
@@ -1386,6 +1391,20 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
return false;
}
fprintf(output_file, "Version:\t");
if (ykpiv_get_version(state, (char*)buf, (size_t)len) != YKPIV_OK) {
fprintf(output_file, "No data available\n");
} else {
fprintf(output_file, "%s\n", (char*)buf);
}
fprintf(output_file, "Serial Number:\t");
if (ykpiv_get_serial(state, &serial) != YKPIV_OK) {
fprintf(output_file, "No data available\n");
} else {
fprintf(output_file, "%d\n", serial);
}
fprintf(output_file, "CHUID:\t");
if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len) != YKPIV_OK) {
fprintf(output_file, "No data available\n");
@@ -1714,7 +1733,7 @@ static bool list_readers(ykpiv_state *state) {
static bool attest(ykpiv_state *state, enum enum_slot slot,
enum enum_key_format key_format, const char *output_file_name) {
unsigned char data[2048];
unsigned long len = sizeof(data);
size_t len = sizeof(data);
bool ret = false;
X509 *x509 = NULL;
int key;
@@ -1736,7 +1755,7 @@ static bool attest(ykpiv_state *state, enum enum_slot slot,
if(key_format == key_format_arg_PEM) {
const unsigned char *ptr = data;
int len2 = len;
int len2 = (int)len;
x509 = X509_new();
if(!x509) {
fprintf(stderr, "Failed allocating x509 structure.\n");
@@ -1787,7 +1806,7 @@ static bool write_object(ykpiv_state *state, int id,
}
if(verbosity) {
fprintf(stderr, "Writing %lu bytes of data to object %x.\n", len, id);
fprintf(stderr, "Writing %lu bytes of data to object %x.\n", (long unsigned int)len, id);
}
if((res = ykpiv_save_object(state, id, data, len)) != YKPIV_OK) {
@@ -1858,6 +1877,7 @@ int main(int argc, char *argv[]) {
cmdline_parser_action_values[action]);
return EXIT_FAILURE;
}
/* fall through */
case action_arg_generate:
case action_arg_importMINUS_key:
case action_arg_importMINUS_certificate:
@@ -1929,6 +1949,7 @@ int main(int argc, char *argv[]) {
}
password = pwbuf;
}
/* fall through */
case action_arg_generate:
case action_arg_setMINUS_mgmMINUS_key:
case action_arg_pinMINUS_retries: