From 2e818dd9147d73afc93b573ff03bd5a5265b86d5 Mon Sep 17 00:00:00 2001 From: Trevor Bentley Date: Mon, 25 Sep 2017 16:03:48 +0200 Subject: [PATCH] Add ykpiv_util_(get/set)_cccid(), and use in yubico-piv-tool --- lib/internal.h | 6 --- lib/util.c | 83 ++++++++++++++++++++++++++++++++++++++---- lib/ykpiv.h | 47 ++++++++++++++++++++---- tool/yubico-piv-tool.c | 76 ++++++++++---------------------------- 4 files changed, 135 insertions(+), 77 deletions(-) diff --git a/lib/internal.h b/lib/internal.h index 1efb014..8c3f925 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -73,8 +73,6 @@ extern "C" #define CB_ATR_MAX 33 -#define CB_CARDID 16 - #define CHREF_ACT_CHANGE_PIN 0 #define CHREF_ACT_UNBLOCK_PIN 1 #define CHREF_ACT_CHANGE_PUK 2 @@ -97,10 +95,6 @@ extern "C" #define TAG_RSA_EXP 0x82 #define TAG_ECC_POINT 0x86 - -#define CCC_ID_OFFS 9 -#define CB_CCC_ID 14 - #define CB_ECC_POINTP256 65 #define CB_ECC_POINTP384 97 diff --git a/lib/util.c b/lib/util.c index aa2b1f3..d0712e3 100644 --- a/lib/util.c +++ b/lib/util.c @@ -41,6 +41,20 @@ #define MAX(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[] = { 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, @@ -50,12 +64,18 @@ const uint8_t CHUID_TMPL[] = { }; #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[] = { 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 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); @@ -89,7 +109,7 @@ ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid) { res = YKPIV_GENERIC_ERROR; } 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 res = YKPIV_OK; - uint8_t id[CB_CARDID]; + uint8_t id[YKPIV_CARDID_SIZE]; uint8_t buf[sizeof(CHUID_TMPL)]; 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); - if (YKPIV_OK == res) { - // 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); +Cleanup: - 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: @@ -140,6 +177,36 @@ Cleanup: 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) { if (!state || state->context == SCARD_E_INVALID_HANDLE) return DEVTYPE_UNKNOWN; diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 3455f43..c6d8c7f 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -259,8 +259,25 @@ extern "C" #define DEVTYPE_YK 0x594B0000 //"YK" #define DEVTYPE_NEOr3 (DEVTYPE_NEO | 0x00007233) //"r3" #define DEVTYPE_YK4 (DEVTYPE_YK | 0x00000034) // "4" + 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) typedef struct _ykpiv_key { @@ -408,13 +425,6 @@ extern "C" */ ykpiv_rc ykpiv_util_reset(ykpiv_state *state); - /** - * Card identifier - */ - typedef struct { - uint8_t data[16]; - } ykpiv_cardid; - /** * Get card identifier * @@ -438,6 +448,29 @@ extern "C" */ 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 * diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index af32edf..b1bfd09 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -50,26 +50,8 @@ #include "cmdline.h" #include "util.h" -/* 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, 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 MAX(a,b) (a) > (b) ? (a) : (b) +#define MIN(a,b) (a) < (b) ? (a) : (b) #define CHUID 0 #define CCC 1 @@ -530,41 +512,28 @@ import_cert_out: return ret; } -static bool set_dataobject(ykpiv_state *state, int verbose, int type) { - unsigned char obj[1024]; +static bool set_cardid(ykpiv_state *state, int verbose, int type) { ykpiv_rc res; - size_t offs, rand_len, len; - const unsigned char *tmpl; - int id; + unsigned char id[MAX(sizeof(ykpiv_cardid), sizeof(ykpiv_cccid))]; if(type == CHUID) { - offs = CHUID_GUID_OFFS; - len = sizeof(chuid_tmpl); - rand_len = 0x10; - tmpl = chuid_tmpl; - id = YKPIV_OBJ_CHUID; + res = ykpiv_util_set_cardid(state, NULL); } else { - offs = CCC_ID_OFFS; - 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; + res = ykpiv_util_set_cccid(state, NULL); } - 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, @@ -1166,12 +1135,7 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M return; } - if (slot == slot_arg_9a) - 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); + slot_name = get_slot_hex(slot); fprintf(output, "Slot %x:\t", slot_name); @@ -1974,7 +1938,7 @@ int main(int argc, char *argv[]) { break; case action_arg_setMINUS_ccc: 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; } else { fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC");