Add ykpiv_util_(get/set)_cccid(), and use in yubico-piv-tool
This commit is contained in:
@@ -73,8 +73,6 @@ extern "C"
|
|||||||
|
|
||||||
#define CB_ATR_MAX 33
|
#define CB_ATR_MAX 33
|
||||||
|
|
||||||
#define CB_CARDID 16
|
|
||||||
|
|
||||||
#define CHREF_ACT_CHANGE_PIN 0
|
#define CHREF_ACT_CHANGE_PIN 0
|
||||||
#define CHREF_ACT_UNBLOCK_PIN 1
|
#define CHREF_ACT_UNBLOCK_PIN 1
|
||||||
#define CHREF_ACT_CHANGE_PUK 2
|
#define CHREF_ACT_CHANGE_PUK 2
|
||||||
@@ -97,10 +95,6 @@ extern "C"
|
|||||||
#define TAG_RSA_EXP 0x82
|
#define TAG_RSA_EXP 0x82
|
||||||
#define TAG_ECC_POINT 0x86
|
#define TAG_ECC_POINT 0x86
|
||||||
|
|
||||||
|
|
||||||
#define CCC_ID_OFFS 9
|
|
||||||
#define CB_CCC_ID 14
|
|
||||||
|
|
||||||
#define CB_ECC_POINTP256 65
|
#define CB_ECC_POINTP256 65
|
||||||
#define CB_ECC_POINTP384 97
|
#define CB_ECC_POINTP384 97
|
||||||
|
|
||||||
|
|||||||
+75
-8
@@ -41,6 +41,20 @@
|
|||||||
#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 MIN(a,b) (a) < (b) ? (a) : (b)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format defined in SP-800-73-4, Appendix A, Table 9
|
||||||
|
*
|
||||||
|
* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
|
||||||
|
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
|
||||||
|
* bytes. This CHUID has an expiry of 2030-01-01.
|
||||||
|
*
|
||||||
|
* Defined fields:
|
||||||
|
* - 0x30: FASC-N (hard-coded)
|
||||||
|
* - 0x34: Card UUID / GUID (settable)
|
||||||
|
* - 0x35: Exp. Date (hard-coded)
|
||||||
|
* - 0x3e: Signature (hard-coded, empty)
|
||||||
|
* - 0xfe: Error Detection Code (hard-coded)
|
||||||
|
*/
|
||||||
const uint8_t CHUID_TMPL[] = {
|
const uint8_t CHUID_TMPL[] = {
|
||||||
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
|
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
|
||||||
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x38, 0x42, 0x10, 0xc3,
|
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x38, 0x42, 0x10, 0xc3,
|
||||||
@@ -50,12 +64,18 @@ const uint8_t CHUID_TMPL[] = {
|
|||||||
};
|
};
|
||||||
#define CHUID_GUID_OFFS 29
|
#define CHUID_GUID_OFFS 29
|
||||||
|
|
||||||
|
// f0: Card Identifier
|
||||||
|
// - 0xa000000116 == GSC-IS RID
|
||||||
|
// - 0xff == Manufacturer ID (dummy)
|
||||||
|
// - 0x02 == Card type (javaCard)
|
||||||
|
// - next 14 bytes: card ID
|
||||||
const uint8_t CCC_TMPL[] = {
|
const uint8_t CCC_TMPL[] = {
|
||||||
0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
|
0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21,
|
||||||
0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00,
|
0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00,
|
||||||
0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00
|
0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00
|
||||||
};
|
};
|
||||||
|
#define CCC_ID_OFFS 9
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
@@ -89,7 +109,7 @@ ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid) {
|
|||||||
res = YKPIV_GENERIC_ERROR;
|
res = YKPIV_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memcpy(cardid->data, buf + CHUID_GUID_OFFS, CB_CARDID);
|
memcpy(cardid->data, buf + CHUID_GUID_OFFS, YKPIV_CARDID_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +121,7 @@ Cleanup:
|
|||||||
|
|
||||||
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) {
|
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) {
|
||||||
ykpiv_rc res = YKPIV_OK;
|
ykpiv_rc res = YKPIV_OK;
|
||||||
uint8_t id[CB_CARDID];
|
uint8_t id[YKPIV_CARDID_SIZE];
|
||||||
uint8_t buf[sizeof(CHUID_TMPL)];
|
uint8_t buf[sizeof(CHUID_TMPL)];
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
@@ -125,13 +145,30 @@ ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid) {
|
|||||||
|
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_CHUID, buf, len);
|
res = ykpiv_save_object(state, YKPIV_OBJ_CHUID, buf, len);
|
||||||
|
|
||||||
if (YKPIV_OK == res) {
|
Cleanup:
|
||||||
// also set the CCC for use with systems that require it
|
|
||||||
len = sizeof(CCC_TMPL);
|
|
||||||
memcpy(buf, CCC_TMPL, len);
|
|
||||||
memcpy(buf + CCC_ID_OFFS, id, CB_CCC_ID);
|
|
||||||
|
|
||||||
res = ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY, buf, len);
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc) {
|
||||||
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
uint8_t buf[CB_OBJ_MAX];
|
||||||
|
size_t len = sizeof(buf);
|
||||||
|
|
||||||
|
if (!ccc) 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;
|
||||||
|
|
||||||
|
res = ykpiv_fetch_object(state, YKPIV_OBJ_CAPABILITY, buf, (unsigned long *)&len);
|
||||||
|
if (YKPIV_OK == res) {
|
||||||
|
if (len != sizeof(CCC_TMPL)) {
|
||||||
|
res = YKPIV_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(ccc->data, buf + CCC_ID_OFFS, YKPIV_CCCID_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
@@ -140,6 +177,36 @@ Cleanup:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc) {
|
||||||
|
ykpiv_rc res = YKPIV_OK;
|
||||||
|
uint8_t id[YKPIV_CCCID_SIZE];
|
||||||
|
uint8_t buf[sizeof(CCC_TMPL)];
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (!state) return YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
|
if (!ccc) {
|
||||||
|
if (PRNG_OK != _ykpiv_prng_generate(id, sizeof(id))) {
|
||||||
|
return YKPIV_RANDOMNESS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(id, ccc->data, sizeof(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR;
|
||||||
|
if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup;
|
||||||
|
|
||||||
|
len = sizeof(CCC_TMPL);
|
||||||
|
memcpy(buf, CCC_TMPL, len);
|
||||||
|
memcpy(buf + CCC_ID_OFFS, id, YKPIV_CCCID_SIZE);
|
||||||
|
res = ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY, buf, len);
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
_ykpiv_end_transaction(state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
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 == SCARD_E_INVALID_HANDLE)
|
||||||
return DEVTYPE_UNKNOWN;
|
return DEVTYPE_UNKNOWN;
|
||||||
|
|||||||
+40
-7
@@ -259,8 +259,25 @@ extern "C"
|
|||||||
#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"
|
||||||
|
|
||||||
typedef uint32_t ykpiv_devmodel;
|
typedef uint32_t ykpiv_devmodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card identifier
|
||||||
|
*/
|
||||||
|
#define YKPIV_CARDID_SIZE 16
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[YKPIV_CARDID_SIZE];
|
||||||
|
} ykpiv_cardid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card Capability
|
||||||
|
*/
|
||||||
|
#define YKPIV_CCCID_SIZE 14
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[YKPIV_CCCID_SIZE];
|
||||||
|
} ykpiv_cccid;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
typedef struct _ykpiv_key {
|
typedef struct _ykpiv_key {
|
||||||
@@ -408,13 +425,6 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
ykpiv_rc ykpiv_util_reset(ykpiv_state *state);
|
ykpiv_rc ykpiv_util_reset(ykpiv_state *state);
|
||||||
|
|
||||||
/**
|
|
||||||
* Card identifier
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uint8_t data[16];
|
|
||||||
} ykpiv_cardid;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get card identifier
|
* Get card identifier
|
||||||
*
|
*
|
||||||
@@ -438,6 +448,29 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid);
|
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get card capabilities identifier
|
||||||
|
*
|
||||||
|
* @param state state
|
||||||
|
* @param cardid ykpiv_cardid return value
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set card capabilities identifier
|
||||||
|
*
|
||||||
|
* The card must be authenticated to call this function.
|
||||||
|
*
|
||||||
|
* @param state state
|
||||||
|
* @param ccc card ID to set. if NULL, randomly generate
|
||||||
|
*
|
||||||
|
* @return ypiv_rc error code
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get device model
|
* Get device model
|
||||||
*
|
*
|
||||||
|
|||||||
+20
-56
@@ -50,26 +50,8 @@
|
|||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
|
#define MAX(a,b) (a) > (b) ? (a) : (b)
|
||||||
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
|
#define MIN(a,b) (a) < (b) ? (a) : (b)
|
||||||
* bytes. */
|
|
||||||
/* this CHUID has an expiry of 2030-01-01, maybe that should be variable.. */
|
|
||||||
unsigned const char chuid_tmpl[] = {
|
|
||||||
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
|
|
||||||
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x38, 0x42, 0x10, 0xc3,
|
|
||||||
0xf5, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30,
|
|
||||||
0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
|
|
||||||
};
|
|
||||||
#define CHUID_GUID_OFFS 29
|
|
||||||
|
|
||||||
unsigned const char ccc_tmpl[] = {
|
|
||||||
0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21,
|
|
||||||
0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00,
|
|
||||||
0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00
|
|
||||||
};
|
|
||||||
#define CCC_ID_OFFS 9
|
|
||||||
|
|
||||||
#define CHUID 0
|
#define CHUID 0
|
||||||
#define CCC 1
|
#define CCC 1
|
||||||
@@ -530,41 +512,28 @@ import_cert_out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_dataobject(ykpiv_state *state, int verbose, int type) {
|
static bool set_cardid(ykpiv_state *state, int verbose, int type) {
|
||||||
unsigned char obj[1024];
|
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
size_t offs, rand_len, len;
|
unsigned char id[MAX(sizeof(ykpiv_cardid), sizeof(ykpiv_cccid))];
|
||||||
const unsigned char *tmpl;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
if(type == CHUID) {
|
if(type == CHUID) {
|
||||||
offs = CHUID_GUID_OFFS;
|
res = ykpiv_util_set_cardid(state, NULL);
|
||||||
len = sizeof(chuid_tmpl);
|
|
||||||
rand_len = 0x10;
|
|
||||||
tmpl = chuid_tmpl;
|
|
||||||
id = YKPIV_OBJ_CHUID;
|
|
||||||
} else {
|
} else {
|
||||||
offs = CCC_ID_OFFS;
|
res = ykpiv_util_set_cccid(state, NULL);
|
||||||
rand_len = 0xe;
|
|
||||||
len = sizeof(ccc_tmpl);
|
|
||||||
tmpl = ccc_tmpl;
|
|
||||||
id = YKPIV_OBJ_CAPABILITY;
|
|
||||||
}
|
|
||||||
memcpy(obj, tmpl, len);
|
|
||||||
if(RAND_pseudo_bytes(obj + offs, rand_len) == -1) {
|
|
||||||
fprintf(stderr, "error: no randomness.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(verbose) {
|
|
||||||
fprintf(stderr, "Setting the %s to: ", type == CHUID ? "CHUID" : "CCC");
|
|
||||||
dump_data(obj, len, stderr, true, format_arg_hex);
|
|
||||||
}
|
|
||||||
if((res = ykpiv_save_object(state, id, obj, len)) != YKPIV_OK) {
|
|
||||||
fprintf(stderr, "Failed communicating with device: %s\n", ykpiv_strerror(res));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if(res == YKPIV_OK && verbose) {
|
||||||
|
if (type == CHUID) {
|
||||||
|
res = ykpiv_util_get_cardid(state, (ykpiv_cardid*)id);
|
||||||
|
} else {
|
||||||
|
res = ykpiv_util_get_cccid(state, (ykpiv_cccid*)id);
|
||||||
|
}
|
||||||
|
if (res == YKPIV_OK) {
|
||||||
|
fprintf(stderr, "Set the %s ID to: ", type == CHUID ? "CHUID" : "CCC");
|
||||||
|
dump_data(id, type == CHUID ? YKPIV_CARDID_SIZE : YKPIV_CCCID_SIZE, stderr, true, format_arg_hex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res == YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool request_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
static bool request_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
||||||
@@ -1166,12 +1135,7 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot == slot_arg_9a)
|
slot_name = get_slot_hex(slot);
|
||||||
slot_name = 0x9a;
|
|
||||||
else if (slot >= slot_arg_9c && slot <= slot_arg_9e)
|
|
||||||
slot_name = 0x9b + slot;
|
|
||||||
else
|
|
||||||
slot_name = 0x82 + (slot - slot_arg_82);
|
|
||||||
|
|
||||||
fprintf(output, "Slot %x:\t", slot_name);
|
fprintf(output, "Slot %x:\t", slot_name);
|
||||||
|
|
||||||
@@ -1974,7 +1938,7 @@ int main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case action_arg_setMINUS_ccc:
|
case action_arg_setMINUS_ccc:
|
||||||
case action_arg_setMINUS_chuid:
|
case action_arg_setMINUS_chuid:
|
||||||
if(set_dataobject(state, verbosity, action == action_arg_setMINUS_chuid ? CHUID : CCC) == false) {
|
if(set_cardid(state, verbosity, action == action_arg_setMINUS_chuid ? CHUID : CCC) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC");
|
fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC");
|
||||||
|
|||||||
Reference in New Issue
Block a user