Merge branch 'pr-165'
This commit is contained in:
+4
-3
@@ -33,9 +33,9 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||||||
# Interfaces changed/added/removed: CURRENT++ REVISION=0
|
# Interfaces changed/added/removed: CURRENT++ REVISION=0
|
||||||
# Interfaces added: AGE++
|
# Interfaces added: AGE++
|
||||||
# Interfaces removed: AGE=0
|
# Interfaces removed: AGE=0
|
||||||
AC_SUBST([LT_CURRENT], 5)
|
AC_SUBST([LT_CURRENT], 6)
|
||||||
AC_SUBST([LT_REVISION], 5)
|
AC_SUBST([LT_REVISION], 0)
|
||||||
AC_SUBST([LT_AGE], 4)
|
AC_SUBST([LT_AGE], 5)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||||
AM_SILENT_RULES([yes])
|
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 -Wconversion" # Too many warnings for now
|
||||||
nw="$nw -Wsuggest-attribute=pure" # Is it worth using attributes?
|
nw="$nw -Wsuggest-attribute=pure" # Is it worth using attributes?
|
||||||
nw="$nw -Wsuggest-attribute=const" # 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_ALL_GCC([ws])
|
||||||
gl_MANYWARN_COMPLEMENT(ws, [$ws], [$nw])
|
gl_MANYWARN_COMPLEMENT(ws, [$ws], [$nw])
|
||||||
|
|||||||
+16
-3
@@ -304,8 +304,11 @@ des_rc des_encrypt(des_key* key, const unsigned char* in, const size_t inlen, un
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
/* openssl returns void */
|
/* openssl returns void */
|
||||||
DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 1);
|
DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 1);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -336,8 +339,11 @@ des_rc des_decrypt(des_key* key, const unsigned char* in, const size_t inlen, un
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
/* openssl returns void */
|
/* openssl returns void */
|
||||||
DES_ecb3_encrypt((const_DES_cblock*)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 0);
|
DES_ecb3_encrypt((const_DES_cblock*)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 0);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -400,7 +406,12 @@ bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
(void)cb_key; /* unused */
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
return DES_is_weak_key((const_DES_cblock *)key);
|
return DES_is_weak_key((const_DES_cblock *)key);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +442,7 @@ prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req) {
|
|||||||
return rc;
|
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;
|
pkcs5_rc rc = PKCS5_OK;
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
@@ -459,8 +470,11 @@ pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_passwo
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
/* for some reason openssl always returns 1 for PBKDF2 */
|
/* 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
|
#endif
|
||||||
|
|
||||||
@@ -491,7 +505,6 @@ setting_bool_t _get_bool_config(const char *sz_setting) {
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HKEY hKey = 0;
|
HKEY hKey = 0;
|
||||||
DWORD dwErr = 0;
|
|
||||||
DWORD dwValue = 0;
|
DWORD dwValue = 0;
|
||||||
DWORD dwType = 0;
|
DWORD dwType = 0;
|
||||||
DWORD cbValue = sizeof(dwValue);
|
DWORD cbValue = sizeof(dwValue);
|
||||||
|
|||||||
+12
-7
@@ -178,21 +178,20 @@ union u_APDU {
|
|||||||
typedef union u_APDU APDU;
|
typedef union u_APDU APDU;
|
||||||
typedef struct des_key des_key;
|
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_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_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_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);
|
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);
|
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);
|
prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req);
|
||||||
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state);
|
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state);
|
||||||
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state);
|
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state);
|
||||||
ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state);
|
ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state);
|
||||||
int _ykpiv_set_length(unsigned char *buffer, size_t length);
|
ykpiv_rc _ykpiv_select_application(ykpiv_state *state);
|
||||||
int _ykpiv_get_length(const unsigned char *buffer, size_t *len);
|
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_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);
|
||||||
@@ -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_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 _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 _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_transfer_data(
|
||||||
ykpiv_rc _ykpiv_util_get_serial(ykpiv_state *state, uint32_t *p_serial, bool f_force);
|
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 */
|
/* authentication functions not ready for public api */
|
||||||
ykpiv_rc ykpiv_auth_getchallenge(ykpiv_state *state, uint8_t *challenge, const size_t challenge_len);
|
ykpiv_rc ykpiv_auth_getchallenge(ykpiv_state *state, uint8_t *challenge, const size_t challenge_len);
|
||||||
|
|||||||
+45
-103
@@ -208,8 +208,9 @@ Cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state) {
|
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 DEVTYPE_UNKNOWN;
|
||||||
|
}
|
||||||
return (state->isNEO ? DEVTYPE_NEOr3 : DEVTYPE_YK4);
|
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;
|
*data_len = 0;
|
||||||
|
|
||||||
if (YKPIV_OK == (res = _read_certificate(state, slot, buf, &cbBuf))) {
|
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;
|
res = YKPIV_MEMORY_ERROR;
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
@@ -415,7 +424,7 @@ ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state) {
|
|||||||
memcpy(&flags, p_item, cb_item);
|
memcpy(&flags, p_item, cb_item);
|
||||||
}
|
}
|
||||||
else {
|
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))) {
|
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 */
|
||||||
if (cbBuf < CB_OBJ_TAG_MIN) {
|
if (cbBuf < CB_OBJ_TAG_MIN) {
|
||||||
res = YKPIV_OK;
|
res = YKPIV_OK;
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr++ == TAG_MSCMAP) {
|
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
|
/* check that decoded length represents object contents */
|
||||||
if (len > (cbBuf - (ptr - buf))) {
|
if (len > (cbBuf - (size_t)(ptr - buf))) {
|
||||||
res = YKPIV_OK;
|
res = YKPIV_OK;
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
@@ -474,7 +483,7 @@ ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers
|
|||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// should check if container map isn't corrupt
|
/* should check if container map isn't corrupt */
|
||||||
|
|
||||||
memcpy(*containers, ptr, len);
|
memcpy(*containers, ptr, len);
|
||||||
*n_containers = len / sizeof(ykpiv_container);
|
*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
|
// encode object data for storage
|
||||||
|
|
||||||
// calculate the required length of the encoded object
|
// 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)) {
|
if (req_len > _obj_size_max(state)) {
|
||||||
res = YKPIV_SIZE_ERROR;
|
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);
|
ptr += _ykpiv_get_length(ptr, &len);
|
||||||
|
|
||||||
// check that decoded length represents object contents
|
// check that decoded length represents object contents
|
||||||
if (len > (cbBuf - (ptr - buf))) {
|
if (len > (cbBuf - (size_t)(ptr - buf))) {
|
||||||
res = YKPIV_OK;
|
res = YKPIV_OK;
|
||||||
goto Cleanup;
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
@@ -671,14 +680,14 @@ ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data
|
|||||||
offset = 0;
|
offset = 0;
|
||||||
data_chunk = MIN(cb_obj_max - CB_OBJ_TAG_MAX, data_len - data_offset);
|
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;
|
buf[offset++] = (i == (n_objs - 1)) ? TAG_MSROOTS_END : TAG_MSROOTS_MID;
|
||||||
offset += _ykpiv_set_length(buf + offset, data_chunk);
|
offset += _ykpiv_set_length(buf + offset, data_chunk);
|
||||||
memcpy(buf + offset, data + data_offset, data_chunk);
|
memcpy(buf + offset, data + data_offset, data_chunk);
|
||||||
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, (int)(YKPIV_OBJ_MSROOTS1 + i), buf, offset);
|
||||||
|
|
||||||
if (YKPIV_OK != res) {
|
if (YKPIV_OK != res) {
|
||||||
goto Cleanup;
|
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;
|
*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"); }
|
if (state->verbose) { fprintf(stderr, "Failed to communicate.\n"); }
|
||||||
goto Cleanup;
|
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 = _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 (YKPIV_OK == (res = _get_metadata_item(data, cb_data, TAG_ADMIN_SALT, &p_item, &cb_item))) {
|
||||||
if (cb_item != CB_ADMIN_SALT) {
|
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;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
goto Cleanup;
|
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 (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;
|
res = YKPIV_AUTHENTICATION_ERROR;
|
||||||
goto Cleanup;
|
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);
|
memcpy(&flags_1, p_item, cb_item);
|
||||||
}
|
}
|
||||||
else {
|
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 */
|
/* remove any existing salt */
|
||||||
@@ -1322,88 +1331,13 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return object_id;
|
return (uint32_t)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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
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 = (int)ykpiv_util_slot_object(slot);
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (-1 == object_id) return YKPIV_INVALID_OBJECT;
|
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);
|
ptr += _ykpiv_get_length(ptr, &len);
|
||||||
|
|
||||||
// check that decoded length represents object contents
|
// check that decoded length represents object contents
|
||||||
if (len > (*buf_len - (ptr - buf))) {
|
if (len > (*buf_len - (size_t)(ptr - buf))) {
|
||||||
*buf_len = 0;
|
*buf_len = 0;
|
||||||
return YKPIV_OK;
|
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) {
|
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];
|
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 offset = 0;
|
||||||
size_t req_len = 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 */
|
/* length doesn't match, expand/shrink to fit */
|
||||||
p_next = p_temp + cb_temp;
|
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 */
|
/* 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;
|
return YKPIV_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
/* move remaining data */
|
/* 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;
|
*pcb_data += cb_moved;
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
/* re-encode item and insert */
|
/* re-encode item and insert */
|
||||||
if (cb_item != 0) {
|
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;
|
return YKPIV_OK;
|
||||||
} //if tag found
|
} /* if tag found */
|
||||||
|
|
||||||
p_temp += cb_temp;
|
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
|
// we did not find an existing tag, append
|
||||||
p_temp = data + *pcb_data;
|
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
|
// length would cause buffer overflow, return error
|
||||||
if (*pcb_data + cb_len + cb_item > cb_data_max) {
|
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);
|
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;
|
*pcb_data = 0;
|
||||||
return YKPIV_GENERIC_ERROR;
|
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);
|
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, (size_t)(pTemp - buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
+256
-28
@@ -76,11 +76,36 @@
|
|||||||
#define ENABLE_APPLICATION_RESELECTION 0
|
#define ENABLE_APPLICATION_RESELECTION 0
|
||||||
#endif
|
#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"
|
#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 _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
|
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) {
|
if(length < 0x80) {
|
||||||
*buffer++ = (unsigned char)length;
|
*buffer++ = (unsigned char)length;
|
||||||
return 1;
|
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) {
|
if(buffer[0] < 0x81) {
|
||||||
*len = buffer[0];
|
*len = buffer[0];
|
||||||
return 1;
|
return 1;
|
||||||
@@ -193,7 +218,7 @@ ykpiv_rc ykpiv_init_with_allocator(ykpiv_state **state, int verbose, const ykpiv
|
|||||||
s->pin = NULL;
|
s->pin = NULL;
|
||||||
s->allocator = *allocator;
|
s->allocator = *allocator;
|
||||||
s->verbose = verbose;
|
s->verbose = verbose;
|
||||||
s->context = SCARD_E_INVALID_HANDLE;
|
s->context = (SCARDCONTEXT)-1;
|
||||||
*state = s;
|
*state = s;
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
@@ -226,7 +251,7 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
|||||||
|
|
||||||
if(SCardIsValidContext(state->context) == SCARD_S_SUCCESS) {
|
if(SCardIsValidContext(state->context) == SCARD_S_SUCCESS) {
|
||||||
SCardReleaseContext(state->context);
|
SCardReleaseContext(state->context);
|
||||||
state->context = SCARD_E_INVALID_HANDLE;
|
state->context = (SCARDCONTEXT)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
@@ -239,8 +264,6 @@ ykpiv_rc _ykpiv_select_application(ykpiv_state *state) {
|
|||||||
int sw;
|
int sw;
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
|
||||||
_ykpiv_util_get_serial(state, NULL, false);
|
|
||||||
|
|
||||||
memset(apdu.raw, 0, sizeof(apdu));
|
memset(apdu.raw, 0, sizeof(apdu));
|
||||||
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
|
apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
|
||||||
apdu.st.p1 = 0x04;
|
apdu.st.p1 = 0x04;
|
||||||
@@ -260,7 +283,16 @@ ykpiv_rc _ykpiv_select_application(ykpiv_state *state) {
|
|||||||
return YKPIV_GENERIC_ERROR;
|
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_version(state, NULL);
|
||||||
|
_ykpiv_get_serial(state, NULL, false);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -284,6 +316,7 @@ ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
#else
|
#else
|
||||||
|
(void)state;
|
||||||
return res;
|
return res;
|
||||||
#endif
|
#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);
|
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||||
}
|
}
|
||||||
SCardReleaseContext(state->context);
|
SCardReleaseContext(state->context);
|
||||||
state->context = SCARD_E_INVALID_HANDLE;
|
state->context = (SCARDCONTEXT)-1;
|
||||||
return YKPIV_PCSC_ERROR;
|
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);
|
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||||
}
|
}
|
||||||
SCardReleaseContext(state->context);
|
SCardReleaseContext(state->context);
|
||||||
state->context = SCARD_E_INVALID_HANDLE;
|
state->context = (SCARDCONTEXT)-1;
|
||||||
return YKPIV_PCSC_ERROR;
|
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) {
|
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) {
|
||||||
|
#if ENABLE_IMPLICIT_TRANSACTIONS
|
||||||
long rc;
|
long rc;
|
||||||
ykpiv_rc res;
|
|
||||||
|
|
||||||
rc = SCardBeginTransaction(state->card);
|
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) {
|
if((res = reconnect(state)) != YKPIV_OK) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -497,27 +531,33 @@ ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) {
|
|||||||
}
|
}
|
||||||
return YKPIV_PCSC_ERROR;
|
return YKPIV_PCSC_ERROR;
|
||||||
}
|
}
|
||||||
|
#endif /* ENABLE_IMPLICIT_TRANSACTIONS */
|
||||||
|
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state) {
|
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state) {
|
||||||
|
#if ENABLE_IMPLICIT_TRANSACTIONS
|
||||||
long rc = SCardEndTransaction(state->card, SCARD_LEAVE_CARD);
|
long rc = SCardEndTransaction(state->card, SCARD_LEAVE_CARD);
|
||||||
if(rc != SCARD_S_SUCCESS && state->verbose) {
|
if(rc != SCARD_S_SUCCESS && state->verbose) {
|
||||||
fprintf(stderr, "error: Failed to end pcsc transaction, rc=%08lx\n", rc);
|
fprintf(stderr, "error: Failed to end pcsc transaction, rc=%08lx\n", rc);
|
||||||
return YKPIV_PCSC_ERROR;
|
return YKPIV_PCSC_ERROR;
|
||||||
}
|
}
|
||||||
|
#endif /* ENABLE_IMPLICIT_TRANSACTIONS */
|
||||||
return YKPIV_OK;
|
return YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
ykpiv_rc _ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
||||||
const unsigned char *in_data, long in_len,
|
const unsigned char *in_data,
|
||||||
unsigned char *out_data, unsigned long *out_len, int *sw) {
|
long in_len,
|
||||||
|
unsigned char *out_data,
|
||||||
|
unsigned long *out_len,
|
||||||
|
int *sw) {
|
||||||
const unsigned char *in_ptr = in_data;
|
const unsigned char *in_ptr = in_data;
|
||||||
unsigned long max_out = *out_len;
|
unsigned long max_out = *out_len;
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
*out_len = 0;
|
*out_len = 0;
|
||||||
|
|
||||||
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
|
||||||
do {
|
do {
|
||||||
size_t this_size = 0xff;
|
size_t this_size = 0xff;
|
||||||
unsigned char data[261];
|
unsigned char data[261];
|
||||||
@@ -587,6 +627,19 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cleanup:
|
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);
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -838,6 +891,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
|||||||
switch(algorithm) {
|
switch(algorithm) {
|
||||||
case YKPIV_ALGO_RSA1024:
|
case YKPIV_ALGO_RSA1024:
|
||||||
key_len = 128;
|
key_len = 128;
|
||||||
|
// fall through
|
||||||
case YKPIV_ALGO_RSA2048:
|
case YKPIV_ALGO_RSA2048:
|
||||||
if(key_len == 0) {
|
if(key_len == 0) {
|
||||||
key_len = 256;
|
key_len = 256;
|
||||||
@@ -848,6 +902,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
|||||||
break;
|
break;
|
||||||
case YKPIV_ALGO_ECCP256:
|
case YKPIV_ALGO_ECCP256:
|
||||||
key_len = 32;
|
key_len = 32;
|
||||||
|
// fall through
|
||||||
case YKPIV_ALGO_ECCP384:
|
case YKPIV_ALGO_ECCP384:
|
||||||
if(key_len == 0) {
|
if(key_len == 0) {
|
||||||
key_len = 48;
|
key_len = 48;
|
||||||
@@ -932,11 +987,12 @@ 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;
|
||||||
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,
|
res = _general_authenticate(state, raw_in, in_len, sign_out, out_len,
|
||||||
algorithm, key, false);
|
algorithm, key, false);
|
||||||
Cleanup:
|
/* Cleanup: */
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
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 (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;
|
||||||
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,
|
res = _general_authenticate(state, in, in_len, out, out_len,
|
||||||
algorithm, key, true);
|
algorithm, key, true);
|
||||||
|
|
||||||
Cleanup:
|
/* Cleanup: */
|
||||||
|
|
||||||
_ykpiv_end_transaction(state);
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
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;
|
APDU apdu;
|
||||||
unsigned char data[261];
|
unsigned char data[261];
|
||||||
uint32_t recv_len = sizeof(data);
|
uint32_t recv_len = sizeof(data);
|
||||||
@@ -1022,6 +1078,138 @@ Cleanup:
|
|||||||
return res;
|
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) {
|
static ykpiv_rc _cache_pin(ykpiv_state *state, const char *pin, size_t len) {
|
||||||
#if DISABLE_PIN_CACHE
|
#if DISABLE_PIN_CACHE
|
||||||
// Some embedded applications of this library may not want to keep the PIN
|
// 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) {
|
if(sw == SW_SUCCESS) {
|
||||||
size_t outlen;
|
size_t outlen;
|
||||||
int offs = _ykpiv_get_length(data + 1, &outlen);
|
unsigned int offs = _ykpiv_get_length(data + 1, &outlen);
|
||||||
if(offs == 0) {
|
if(offs == 0) {
|
||||||
return YKPIV_SIZE_ERROR;
|
return YKPIV_SIZE_ERROR;
|
||||||
}
|
}
|
||||||
if(outlen + offs + 1 != *len) {
|
if(outlen + offs + 1 != *len) {
|
||||||
if(state->verbose) {
|
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;
|
return YKPIV_SIZE_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1322,8 +1510,11 @@ Cleanup:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id,
|
ykpiv_rc _ykpiv_save_object(
|
||||||
unsigned char *indata, size_t len) {
|
ykpiv_state *state,
|
||||||
|
int object_id,
|
||||||
|
unsigned char *indata,
|
||||||
|
size_t len) {
|
||||||
unsigned char data[CB_BUF_MAX];
|
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};
|
||||||
@@ -1343,7 +1534,7 @@ ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id,
|
|||||||
memcpy(dataptr, indata, len);
|
memcpy(dataptr, indata, len);
|
||||||
dataptr += 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) {
|
&sw)) != YKPIV_OK) {
|
||||||
return res;
|
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) {
|
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)) {
|
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;
|
return YKPIV_SIZE_ERROR;
|
||||||
}
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
if (algorithm == YKPIV_ALGO_ECCP256)
|
if (algorithm == YKPIV_ALGO_ECCP256)
|
||||||
elem_len = 32;
|
elem_len = 32;
|
||||||
@@ -1621,11 +1815,45 @@ Cleanup:
|
|||||||
return res;
|
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 ykpiv_auth_deauthenticate(ykpiv_state *state) {
|
||||||
ykpiv_rc res = YKPIV_OK;
|
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;
|
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);
|
_ykpiv_end_transaction(state);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-1
@@ -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);
|
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 state state
|
||||||
* @param ccc Unique Card ID to set. If NULL, randomly generate.
|
* @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);
|
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_RESET 0xfb
|
||||||
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
|
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
|
||||||
#define YKPIV_INS_ATTEST 0xf9
|
#define YKPIV_INS_ATTEST 0xf9
|
||||||
|
#define YKPIV_INS_GET_SERIAL 0xf8
|
||||||
|
|
||||||
#define YKPIV_PINPOLICY_TAG 0xaa
|
#define YKPIV_PINPOLICY_TAG 0xaa
|
||||||
#define YKPIV_PINPOLICY_DEFAULT 0
|
#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_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_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_UNKNOWN 0x00000000
|
||||||
#define DEVTYPE_NEO 0x4E450000 //"NE"
|
#define DEVTYPE_NEO 0x4E450000 //"NE"
|
||||||
#define DEVTYPE_YK 0x594B0000 //"YK"
|
#define DEVTYPE_YK 0x594B0000 //"YK"
|
||||||
#define DEVTYPE_NEOr3 (DEVTYPE_NEO | 0x00007233) //"r3"
|
#define DEVTYPE_NEOr3 (DEVTYPE_NEO | 0x00007233) //"r3"
|
||||||
#define DEVTYPE_YK4 (DEVTYPE_YK | 0x00000034) // "4"
|
#define DEVTYPE_YK4 (DEVTYPE_YK | 0x00000034) // "4"
|
||||||
|
#define DEVYTPE_YK5 (DEVTYPE_YK | 0x00000035) // "5"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,3 +113,9 @@ global:
|
|||||||
ykpiv_util_write_msroots;
|
ykpiv_util_write_msroots;
|
||||||
ykpiv_verify_select;
|
ykpiv_verify_select;
|
||||||
} YKPIV_1.3.0;
|
} YKPIV_1.3.0;
|
||||||
|
|
||||||
|
YKPIV_1.6.0
|
||||||
|
{
|
||||||
|
global:
|
||||||
|
ykpiv_get_serial;
|
||||||
|
} YKPIV_1.5.0;
|
||||||
|
|||||||
+32
-11
@@ -54,7 +54,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define MAX(a,b) (a) > (b) ? (a) : (b)
|
#define MAX(a,b) (a) > (b) ? (a) : (b)
|
||||||
#define MIN(a,b) (a) < (b) ? (a) : (b)
|
|
||||||
|
|
||||||
#define CHUID 0
|
#define CHUID 0
|
||||||
#define CCC 1
|
#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,
|
rc = ykpiv_import_private_key(state, key, algorithm,
|
||||||
p, element_len,
|
p, (size_t)element_len,
|
||||||
q, element_len,
|
q, (size_t)element_len,
|
||||||
dmp1, element_len,
|
dmp1, (size_t)element_len,
|
||||||
dmq1, element_len,
|
dmq1, (size_t)element_len,
|
||||||
iqmp, element_len,
|
iqmp, (size_t)element_len,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
pp, tp);
|
pp, tp);
|
||||||
}
|
}
|
||||||
@@ -586,7 +585,7 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format,
|
|||||||
} else {
|
} else {
|
||||||
i2d_X509(cert, &certptr);
|
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));
|
fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res));
|
||||||
} else {
|
} else {
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -1067,6 +1066,9 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
|
|||||||
op = ykpiv_change_puk;
|
op = ykpiv_change_puk;
|
||||||
}
|
}
|
||||||
res = op(state, pin, pin_len, new_pin, new_len, &tries);
|
res = op(state, pin, pin_len, new_pin, new_len, &tries);
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case YKPIV_OK:
|
case YKPIV_OK:
|
||||||
return true;
|
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));
|
fprintf(stderr, "Failed changing/unblocking code, error: %s\n", ykpiv_strerror(res));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
|
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,
|
static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_MD *md,
|
||||||
FILE *output) {
|
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;
|
int slot_name;
|
||||||
unsigned char data[3072];
|
unsigned char data[3072];
|
||||||
const unsigned char *ptr = data;
|
const unsigned char *ptr = data;
|
||||||
@@ -1376,7 +1379,9 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
|
|||||||
unsigned char buf[3072];
|
unsigned char buf[3072];
|
||||||
long unsigned len = sizeof(buf);
|
long unsigned len = sizeof(buf);
|
||||||
int i;
|
int i;
|
||||||
|
uint32_t serial = 0;
|
||||||
FILE *output_file = open_file(output_file_name, OUTPUT_TEXT);
|
FILE *output_file = open_file(output_file_name, OUTPUT_TEXT);
|
||||||
|
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1386,6 +1391,20 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
|
|||||||
return false;
|
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");
|
fprintf(output_file, "CHUID:\t");
|
||||||
if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len) != YKPIV_OK) {
|
if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, buf, &len) != YKPIV_OK) {
|
||||||
fprintf(output_file, "No data available\n");
|
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,
|
static bool attest(ykpiv_state *state, enum enum_slot slot,
|
||||||
enum enum_key_format key_format, const char *output_file_name) {
|
enum enum_key_format key_format, const char *output_file_name) {
|
||||||
unsigned char data[2048];
|
unsigned char data[2048];
|
||||||
unsigned long len = sizeof(data);
|
size_t len = sizeof(data);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
int key;
|
int key;
|
||||||
@@ -1736,7 +1755,7 @@ static bool attest(ykpiv_state *state, enum enum_slot slot,
|
|||||||
|
|
||||||
if(key_format == key_format_arg_PEM) {
|
if(key_format == key_format_arg_PEM) {
|
||||||
const unsigned char *ptr = data;
|
const unsigned char *ptr = data;
|
||||||
int len2 = len;
|
int len2 = (int)len;
|
||||||
x509 = X509_new();
|
x509 = X509_new();
|
||||||
if(!x509) {
|
if(!x509) {
|
||||||
fprintf(stderr, "Failed allocating x509 structure.\n");
|
fprintf(stderr, "Failed allocating x509 structure.\n");
|
||||||
@@ -1787,7 +1806,7 @@ static bool write_object(ykpiv_state *state, int id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(verbosity) {
|
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) {
|
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]);
|
cmdline_parser_action_values[action]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
case action_arg_generate:
|
case action_arg_generate:
|
||||||
case action_arg_importMINUS_key:
|
case action_arg_importMINUS_key:
|
||||||
case action_arg_importMINUS_certificate:
|
case action_arg_importMINUS_certificate:
|
||||||
@@ -1929,6 +1949,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
password = pwbuf;
|
password = pwbuf;
|
||||||
}
|
}
|
||||||
|
/* fall through */
|
||||||
case action_arg_generate:
|
case action_arg_generate:
|
||||||
case action_arg_setMINUS_mgmMINUS_key:
|
case action_arg_setMINUS_mgmMINUS_key:
|
||||||
case action_arg_pinMINUS_retries:
|
case action_arg_pinMINUS_retries:
|
||||||
|
|||||||
Reference in New Issue
Block a user