WIP port minidriver ykpiv_util_* functions

This commit is contained in:
Trevor Bentley
2017-07-04 16:43:55 +02:00
parent 86a0e72dbe
commit 6c5d5545bf
5 changed files with 1279 additions and 34 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ AM_CPPFLAGS = $(OPENSSL_CFLAGS) $(PCSC_CFLAGS)
lib_LTLIBRARIES = libykpiv.la
libykpiv_la_SOURCES = ykpiv.c version.c ykpiv.pc.in ykpiv.map internal.h
libykpiv_la_SOURCES = ykpiv.c util.c version.c ykpiv.pc.in ykpiv.map internal.h
libykpiv_la_SOURCES += error.c
libykpiv_la_includedir = $(includedir)/ykpiv
libykpiv_la_include_HEADERS = ykpiv.h ykpiv-version.h
+39 -3
View File
@@ -45,11 +45,32 @@
#define READER_LEN 32
#define MAX_READERS 16
#define DES_LEN_3DES 8*3
#define CB_MGM_KEY DES_LEN_3DES
typedef void* (*ykpiv_pfn_alloc)(void* alloc_data, size_t size);
typedef void* (*ykpiv_pfn_realloc)(void* alloc_data, void* address, size_t size);
typedef void (*ykpiv_pfn_free)(void* alloc_data, void* address);
typedef struct {
ykpiv_pfn_alloc pfn_alloc;
ykpiv_pfn_realloc pfn_realloc;
ykpiv_pfn_free pfn_free;
void * alloc_data;
} ykpiv_allocator;
extern ykpiv_allocator _mem_default_allocator;
struct ykpiv_state {
SCARDCONTEXT context;
SCARDHANDLE card;
int verbose;
char *pin;
ykpiv_allocator allocator;
bool isNEO;
uint8_t mgmKey[CB_MGM_KEY];
bool fMgmKeySet;
};
union u_APDU {
@@ -66,8 +87,23 @@ union u_APDU {
typedef union u_APDU APDU;
unsigned const char aid[] = {
0xa0, 0x00, 0x00, 0x03, 0x08
};
extern unsigned const char aid[];
// the object size is restricted to the firmware's message buffer size, which
// always contains 0x5C + 1 byte len + 3 byte id + 0x53 + 3 byte len = 9 bytes,
// so while the message buffer == CB_BUF_MAX, the maximum object we can store
// is CB_BUF_MAX - 9
#define CB_OBJ_MAX_NEO (CB_BUF_MAX_NEO - 9)
#define CB_OBJ_MAX_YK4 (CB_BUF_MAX_YK4 - 9)
#define CB_OBJ_MAX CB_OBJ_MAX_YK4
#define CB_BUF_MAX_NEO 2048
#define CB_BUF_MAX_YK4 3072
#define CB_BUF_MAX CB_BUF_MAX_YK4
#define CB_ATR_MAX 33
#define 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 ATR_YK4 "\x3b\xf8\x13\x00\x00\x81\x31\xfe\x15\x59\x75\x62\x69\x6b\x65\x79\x34\xd4"
#endif
+1003
View File
File diff suppressed because it is too large Load Diff
+115 -30
View File
@@ -44,6 +44,33 @@
static ykpiv_rc send_data(ykpiv_state *state, APDU *apdu,
unsigned char *data, unsigned long *recv_len, int *sw);
unsigned const char aid[] = {
0xa0, 0x00, 0x00, 0x03, 0x08
};
static void* _default_alloc(void *data, size_t cb) {
(void)data;
return calloc(cb, 1);
}
static void * _default_realloc(void *data, void *p, size_t cb) {
(void)data;
return realloc(p, cb);
}
static void _default_free(void *data, void *p) {
(void)data;
free(p);
}
ykpiv_allocator _default_allocator = {
.pfn_alloc = _default_alloc,
.pfn_realloc = _default_realloc,
.pfn_free = _default_free,
.alloc_data = 0
};
static void dump_hex(const unsigned char *buf, unsigned int len) {
unsigned int i;
for (i = 0; i < len; i++) {
@@ -51,7 +78,7 @@ static void dump_hex(const unsigned char *buf, unsigned int len) {
}
}
static int set_length(unsigned char *buffer, size_t length) {
int _ykpiv_set_length(unsigned char *buffer, size_t length) {
if(length < 0x80) {
*buffer++ = length;
return 1;
@@ -67,7 +94,7 @@ static int set_length(unsigned char *buffer, size_t length) {
}
}
static int get_length(const unsigned char *buffer, size_t *len) {
int _ykpiv_get_length(const unsigned char *buffer, size_t *len) {
if(buffer[0] < 0x81) {
*len = buffer[0];
return 1;
@@ -96,19 +123,33 @@ static unsigned char *set_object(int object_id, unsigned char *buffer) {
return buffer;
}
ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
ykpiv_state *s = malloc(sizeof(ykpiv_state));
if(s == NULL) {
ykpiv_rc ykpiv_init_with_allocator(ykpiv_state **state, int verbose, const ykpiv_allocator *allocator) {
ykpiv_state *s;
if (NULL == state) {
return YKPIV_GENERIC_ERROR;
}
if (NULL == allocator || !allocator->pfn_alloc || !allocator->pfn_realloc || !allocator->pfn_free) {
return YKPIV_MEMORY_ERROR;
}
s = allocator->pfn_alloc(allocator->alloc_data, sizeof(ykpiv_state));
if (NULL == s) {
return YKPIV_MEMORY_ERROR;
}
memset(s, 0, sizeof(ykpiv_state));
s->pin = NULL;
s->allocator = *allocator;
s->verbose = verbose;
s->context = SCARD_E_INVALID_HANDLE;
s->context = SCARD_E_INVALID_HANDLE; // TREV TODO -1 on Windows
*state = s;
return YKPIV_OK;
}
ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
return ykpiv_init_with_allocator(state, verbose, &_default_allocator);
}
ykpiv_rc ykpiv_done(ykpiv_state *state) {
ykpiv_disconnect(state);
free(state->pin);
@@ -130,7 +171,7 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
return YKPIV_OK;
}
static ykpiv_rc select_application(ykpiv_state *state) {
ykpiv_rc _ykpiv_select_application(ykpiv_state *state) {
APDU apdu;
unsigned char data[0xff];
unsigned long recv_len = sizeof(data);
@@ -158,12 +199,32 @@ static ykpiv_rc select_application(ykpiv_state *state) {
}
}
ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state) {
ykpiv_rc res = YKPIV_OK;
if (NULL == state) {
return YKPIV_GENERIC_ERROR;
}
res = ykpiv_verify(state, NULL, 0);
if ((YKPIV_OK != res) && (YKPIV_WRONG_PIN != res)) {
res = _ykpiv_select_application(state);
}
else {
res = YKPIV_OK;
}
return res;
}
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
unsigned long active_protocol;
char reader_buf[2048];
size_t num_readers = sizeof(reader_buf);
long rc;
char *reader_ptr;
SCARDHANDLE card = (SCARDHANDLE)-1;
ykpiv_rc ret = ykpiv_list_readers(state, reader_buf, &num_readers);
if(ret != YKPIV_OK) {
@@ -183,7 +244,7 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
fprintf(stderr, "trying to connect to reader '%s'.\n", reader_ptr);
}
rc = SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T1, &state->card, &active_protocol);
SCARD_PROTOCOL_T1, &card, &active_protocol);
if(rc != SCARD_S_SUCCESS)
{
if(state->verbose) {
@@ -191,7 +252,24 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
}
continue;
}
if (select_application(state) != YKPIV_OK) {
// if card handle has changed, determine if handle is valid (less efficient, but complete)
if ((card != state->card)) {
char reader[CB_BUF_MAX];
uint32_t reader_len = (uint32_t)sizeof(reader);
uint8_t atr[CB_ATR_MAX];
uint32_t atr_len = (uint32_t)sizeof(atr);
// Cannot set the reader len to NULL. Confirmed in OSX 10.10, so we have to retrieve it even though we don't need it.
if (SCARD_S_SUCCESS != SCardStatus(card, reader, &reader_len, NULL, NULL, atr, &atr_len)) {
return YKPIV_PCSC_ERROR;
}
state->isNEO = (((sizeof(ATR_NEO_R3) - 1) == atr_len) && (0 == memcmp(ATR_NEO_R3, atr, atr_len)));
}
state->card = card;
if (_ykpiv_select_application(state) != YKPIV_OK) {
continue;
}
return YKPIV_OK;
@@ -226,7 +304,7 @@ static ykpiv_rc reconnect(ykpiv_state *state) {
}
return YKPIV_PCSC_ERROR;
}
if ((res = select_application(state)) != YKPIV_OK) {
if ((res = _ykpiv_select_application(state)) != YKPIV_OK) {
return res;
}
if (state->pin) {
@@ -279,7 +357,7 @@ ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
return YKPIV_OK;
}
static ykpiv_rc begin_transaction(ykpiv_state *state) {
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state) {
long rc;
ykpiv_rc res;
@@ -299,7 +377,7 @@ static ykpiv_rc begin_transaction(ykpiv_state *state) {
return YKPIV_OK;
}
static ykpiv_rc end_transaction(ykpiv_state *state) {
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state) {
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);
@@ -316,7 +394,7 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
ykpiv_rc res;
*out_len = 0;
res = begin_transaction(state);
res = _ykpiv_begin_transaction(state);
if (res != YKPIV_OK) {
return res;
}
@@ -340,16 +418,16 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
memcpy(apdu.st.data, in_ptr, this_size);
res = send_data(state, &apdu, data, &recv_len, sw);
if(res != YKPIV_OK) {
end_transaction(state);
_ykpiv_end_transaction(state);
return res;
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
return end_transaction(state);
return _ykpiv_end_transaction(state);
}
if(*out_len + recv_len - 2 > max_out) {
if(state->verbose) {
fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.\n", *out_len + recv_len - 2, max_out);
}
end_transaction(state);
_ykpiv_end_transaction(state);
return YKPIV_SIZE_ERROR;
}
if(out_data) {
@@ -372,10 +450,10 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
apdu.st.ins = 0xc0;
res = send_data(state, &apdu, data, &recv_len, sw);
if(res != YKPIV_OK) {
end_transaction(state);
_ykpiv_end_transaction(state);
return res;
} else if(*sw != SW_SUCCESS && *sw >> 8 != 0x61) {
return end_transaction(state);
return _ykpiv_end_transaction(state);
}
if(*out_len + recv_len - 2 > max_out) {
fprintf(stderr, "Output buffer to small, wanted to write %lu, max was %lu.", *out_len + recv_len - 2, max_out);
@@ -386,7 +464,7 @@ ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
*out_len += recv_len - 2;
}
}
return end_transaction(state);
return _ykpiv_end_transaction(state);
}
static ykpiv_rc send_data(ykpiv_state *state, APDU *apdu,
@@ -430,6 +508,8 @@ ykpiv_rc ykpiv_authenticate(ykpiv_state *state, unsigned const char *key) {
DES_key_schedule ks1, ks2, ks3;
// TREV TODO: default/derived key
/* set up our key */
{
const_DES_cblock key_tmp;
@@ -639,11 +719,11 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
}
*dataptr++ = 0x7c;
dataptr += set_length(dataptr, in_len + bytes + 3);
dataptr += _ykpiv_set_length(dataptr, in_len + bytes + 3);
*dataptr++ = 0x82;
*dataptr++ = 0x00;
*dataptr++ = YKPIV_IS_EC(algorithm) && decipher ? 0x85 : 0x81;
dataptr += set_length(dataptr, in_len);
dataptr += _ykpiv_set_length(dataptr, in_len);
memcpy(dataptr, sign_in, (size_t)in_len);
dataptr += in_len;
@@ -670,7 +750,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
return YKPIV_PARSE_ERROR;
}
dataptr = data + 1;
dataptr += get_length(dataptr, &len);
dataptr += _ykpiv_get_length(dataptr, &len);
/* skip the 82 tag */
if(*dataptr != 0x82) {
if(state->verbose) {
@@ -679,7 +759,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
return YKPIV_PARSE_ERROR;
}
dataptr++;
dataptr += get_length(dataptr, &len);
dataptr += _ykpiv_get_length(dataptr, &len);
if(len > *out_len) {
if(state->verbose) {
fprintf(stderr, "Wrong size on output buffer.\n");
@@ -768,10 +848,10 @@ ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries) {
}
return YKPIV_OK;
} else if((sw >> 8) == 0x63) {
*tries = (sw & 0xf);
if (tries) *tries = (sw & 0xf);
return YKPIV_WRONG_PIN;
} else if(sw == SW_ERR_AUTH_BLOCKED) {
*tries = 0;
if (tries) *tries = 0;
return YKPIV_WRONG_PIN;
} else {
return YKPIV_GENERIC_ERROR;
@@ -869,7 +949,7 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
if(sw == SW_SUCCESS) {
size_t outlen;
int offs = get_length(data + 1, &outlen);
int offs = _ykpiv_get_length(data + 1, &outlen);
if(offs == 0) {
return YKPIV_SIZE_ERROR;
}
@@ -884,6 +964,7 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
unsigned char *indata, size_t len) {
// TREV TODO: buffer sizes different in minidriver
unsigned char data[3072];
unsigned char *dataptr = data;
unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff};
@@ -899,7 +980,7 @@ ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
return YKPIV_INVALID_OBJECT;
}
*dataptr++ = 0x53;
dataptr += set_length(dataptr, len);
dataptr += _ykpiv_set_length(dataptr, len);
memcpy(dataptr, indata, len);
dataptr += len;
@@ -908,9 +989,13 @@ ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
return res;
}
if(sw == SW_SUCCESS) {
if(SW_SUCCESS == sw) {
return YKPIV_OK;
} else {
}
else if (SW_ERR_SECURITY_STATUS == sw) {
return YKPIV_AUTHENTICATION_ERROR;
}
else {
return YKPIV_GENERIC_ERROR;
}
}
@@ -1008,7 +1093,7 @@ ykpiv_rc ykpiv_import_private_key(ykpiv_state *state, const unsigned char key, u
for (i = 0; i < n_params; i++) {
*in_ptr++ = param_tag + i;
in_ptr += set_length(in_ptr, elem_len);
in_ptr += _ykpiv_set_length(in_ptr, elem_len);
padding = elem_len - lens[i];
memset(in_ptr, 0, padding);
in_ptr += padding;
+121
View File
@@ -58,6 +58,9 @@ extern "C"
YKPIV_INVALID_OBJECT = -11,
YKPIV_ALGORITHM_ERROR = -12,
YKPIV_PIN_LOCKED = -13,
YKPIV_ARGUMENT_ERROR = -14, //i.e. invalid input argument
YKPIV_RANGE_ERROR = -15 //i.e. value range error
} ykpiv_rc;
const char *ykpiv_strerror(ykpiv_rc err);
@@ -220,6 +223,124 @@ extern "C"
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
//
// UTIL
//
#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"
typedef uint32_t ykpiv_devmodel;
#pragma pack(push, 1)
typedef struct _ykpiv_key {
uint8_t slot;
uint16_t cert_len;
uint8_t cert[1];
} ykpiv_key;
typedef struct _ykpiv_container {
wchar_t name[40];
uint8_t slot;
uint8_t key_spec;
uint16_t key_size_bits;
uint8_t flags;
uint8_t pin_id;
uint8_t associated_echd_container;
uint8_t cert_fingerprint[20];
} ykpiv_container;
#pragma pack(pop)
/* Util api always allocates data on your behalf, if data = 0, *data != 0, or data_len = 0 an invalid parameter will be returned; to free data, call ykpiv_util_free(). */
/**
* Free allocated data
*
* @param state state
* @param data pointer to buffer allocated by ykpiv
*
* @return ypiv_rc error code
*/
ykpiv_rc ykpiv_util_free(ykpiv_state *state, void *data);
ykpiv_rc ykpiv_util_list_keys(ykpiv_state *state, uint8_t *key_count, ykpiv_key **data, size_t *data_len);
ykpiv_rc ykpiv_util_read_cert(ykpiv_state *state, uint8_t slot, uint8_t **data, size_t *data_len);
ykpiv_rc ykpiv_util_write_cert(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len);
ykpiv_rc ykpiv_util_delete_cert(ykpiv_state *state, uint8_t slot);
/**
* Generate Key
*
* @param state state
* @param slot key slot
* @param algorithm algorithm
*
* @return ykpiv_rc error code
*
* If algorithm is RSA1024 or RSA2048, the modulus, modulus_len, exp, and exp_len output parameters must be supplied. They are filled with with public modulus (big-endian), its size, the public exponent (big-endian), and its size respectively.
* If algorithm is ECCP256 or ECCP384, the point and point_len output parameters must be supplied. They are filled with the public point (uncompressed octet-string encoded per SEC1 section 2.3.4)
* If algorithm is ECCP256, the curve is always ANSI X9.62 Prime 256v1
* If algorithm is ECCP384, the curve is always secp384r1
*/
ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algorithm, uint8_t pin_policy, uint8_t touch_policy, uint8_t **modulus, size_t *modulus_len, uint8_t **exp, size_t *exp_len, uint8_t **point, size_t *point_len);
ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers, size_t *n_containers);
ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers, size_t n_containers);
ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *data_len);
ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data_len);
ykpiv_rc ykpiv_util_reset(ykpiv_state *state);
/**
* Card identifier
*/
typedef struct {
uint8_t data[16];
} ykpiv_cardid;
/**
* Get card identifier
*
* @param state state
* @param cardid ykpiv_cardid return value
*
* @return ykpiv_rc error code
*/
ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid);
/**
* Set card identifier
*
* The card must be authenticated to call this function.
*
* @param state state
* @param cardid cardid to set, if NULL, randomly generate
*
* @return ypiv_rc error code
*
*/
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid);
/**
* Get device model
*
* The card must be connected to call this function.
*
* @param state state
*
* @return device model
*
*/
ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state);
#ifdef __cplusplus
}
#endif