From cbd5ba51229c599b95deb43bc99ffa2f4a1c06e5 Mon Sep 17 00:00:00 2001 From: Dave Pate Date: Fri, 14 Sep 2018 14:29:39 -0700 Subject: [PATCH] libykpiv/piv-tool 1.6.3 lib: promote get_serial to base API lib: add ykpiv_get_serial to external API tool: add serial number/version to status command build: fix msvc build of case insensitive-reader (missing strncasecmp and cast warnings) lib: consolidate neo/yk4 + yk5 serial number routines lib: fix GCC 8 compilier warnings lib: reimplement deauthenticate to select mgmt aid build: disable -Waggregate-return lib: fix warning differences between gcc and msvc lib: add option to disable implicit card transactions lib: remove application reselect prior to crypt operations build: fix msvc warnings wrt length checking logic fixes lib: fix error condition logic in untransacted internal functions lib: create internal transactionless ykpiv_transfer_data --- configure.ac | 7 +- lib/internal.c | 19 ++- lib/internal.h | 19 ++- lib/util.c | 150 +++++++-------------- lib/ykpiv.c | 296 ++++++++++++++++++++++++++++++++++++----- lib/ykpiv.h | 19 ++- lib/ykpiv.map | 6 + tool/yubico-piv-tool.c | 43 ++++-- 8 files changed, 396 insertions(+), 163 deletions(-) diff --git a/configure.ac b/configure.ac index c1679b1..908950f 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/lib/internal.c b/lib/internal.c index 99f9d5f..20b911a 100644 --- a/lib/internal.c +++ b/lib/internal.c @@ -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); diff --git a/lib/internal.h b/lib/internal.h index bdc1e68..498b912 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -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); diff --git a/lib/util.c b/lib/util.c index f801d11..626eab3 100644 --- a/lib/util.c +++ b/lib/util.c @@ -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 */ @@ -1303,7 +1312,7 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) { object_id = YKPIV_OBJ_SIGNATURE; break; - case YKPIV_KEY_KEYMGM: + case YKPIV_KEY_KEYMGM: object_id = YKPIV_OBJ_KEY_MANAGEMENT; break; @@ -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; diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 48b6d84..3466b12 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -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,12 +514,13 @@ 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((res = reconnect(state)) != YKPIV_OK) { + if((long)((unsigned long)rc & 0xFFFFFFFF) == SCARD_W_RESET_CARD) { + ykpiv_rc res = YKPIV_OK; + if((res = reconnect(state)) != YKPIV_OK) { return res; } rc = SCardBeginTransaction(state->card); @@ -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,24 +891,26 @@ 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; + key_len = 256; } if(in_len != key_len) { - return YKPIV_SIZE_ERROR; + return YKPIV_SIZE_ERROR; } break; case YKPIV_ALGO_ECCP256: key_len = 32; + // fall through case YKPIV_ALGO_ECCP384: if(key_len == 0) { - key_len = 48; + key_len = 48; } if(!decipher && in_len > key_len) { - return YKPIV_SIZE_ERROR; + return YKPIV_SIZE_ERROR; } else if(decipher && in_len != (key_len * 2) + 1) { - return YKPIV_SIZE_ERROR; + return YKPIV_SIZE_ERROR; } break; default: @@ -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; } diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 2d9b230..5b0694c 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -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 } diff --git a/lib/ykpiv.map b/lib/ykpiv.map index 5381cb7..2c11ce4 100644 --- a/lib/ykpiv.map +++ b/lib/ykpiv.map @@ -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; diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 4996e05..9088ea0 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -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: