diff --git a/lib/tests/util.c b/lib/tests/util.c index efbce40..8b103c9 100644 --- a/lib/tests/util.c +++ b/lib/tests/util.c @@ -145,7 +145,7 @@ START_TEST(test_read_write_list_delete_cert) { size_t read_cert_len = 0; { - res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert)); + res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED); ck_assert_int_eq(res, YKPIV_OK); res = ykpiv_util_read_cert(g_state, YKPIV_KEY_AUTHENTICATION, &read_cert, &read_cert_len); @@ -411,7 +411,7 @@ START_TEST(test_generate_key) { ykpiv_rc res; uint8_t *mod, *exp; size_t mod_len, exp_len; - res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert)); + res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED); ck_assert_int_eq(res, YKPIV_OK); res = ykpiv_util_generate_key(g_state, YKPIV_KEY_AUTHENTICATION, @@ -666,7 +666,7 @@ uint8_t *alloc_auth_cert() { uint8_t *read_cert = NULL; size_t read_cert_len = 0; - res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert)); + res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED); ck_assert_int_eq(res, YKPIV_OK); res = ykpiv_util_read_cert(g_state, YKPIV_KEY_AUTHENTICATION, &read_cert, &read_cert_len); diff --git a/lib/util.c b/lib/util.c index f69e146..aa2b1f3 100644 --- a/lib/util.c +++ b/lib/util.c @@ -58,7 +58,7 @@ const uint8_t CCC_TMPL[] = { }; 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); +static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo); static ykpiv_rc _read_metadata(ykpiv_state *state, uint8_t tag, uint8_t* data, size_t* pcb_data); static ykpiv_rc _write_metadata(ykpiv_state *state, uint8_t tag, uint8_t *data, size_t cb_data); @@ -293,13 +293,13 @@ Cleanup: return res; } -ykpiv_rc ykpiv_util_write_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, uint8_t certinfo) { ykpiv_rc res = YKPIV_OK; if (YKPIV_OK != (res = _ykpiv_begin_transaction(state))) return YKPIV_PCSC_ERROR; if (YKPIV_OK != (res = _ykpiv_ensure_application_selected(state))) goto Cleanup; - res = _write_certificate(state, slot, data, data_len); + res = _write_certificate(state, slot, data, data_len, certinfo); Cleanup: @@ -308,7 +308,7 @@ Cleanup: } ykpiv_rc ykpiv_util_delete_cert(ykpiv_state *state, uint8_t slot) { - return ykpiv_util_write_cert(state, slot, NULL, 0); + return ykpiv_util_write_cert(state, slot, NULL, 0, 0); } ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state) { @@ -1252,7 +1252,7 @@ static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf return res; } -static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len) { +static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo) { // TREV TODO: should this select application? uint8_t buf[CB_OBJ_MAX]; size_t cbBuf = sizeof(buf); @@ -1290,8 +1290,8 @@ static ykpiv_rc _write_certificate(ykpiv_state *state, uint8_t slot, uint8_t *da // write compression info and LRC trailer buf[offset++] = TAG_CERT_COMPRESS; buf[offset++] = 0x01; - buf[offset++] = 0x00; // TODO: Handle compression when certificate exceeds buffer size - buf[offset++] = TAG_CERT_LRC; // LRC + buf[offset++] = certinfo == YKPIV_CERTINFO_GZIP ? 0x01 : 0x00; + buf[offset++] = TAG_CERT_LRC; buf[offset++] = 00; // write onto device diff --git a/lib/ykpiv.h b/lib/ykpiv.h index e39d9a8..28d2a73 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -198,6 +198,8 @@ extern "C" #define YKPIV_OBJ_ATTESTATION 0x5fff01 +#define YKPIV_OBJ_MAX_SIZE 3072 + #define YKPIV_INS_VERIFY 0x20 #define YKPIV_INS_CHANGE_REFERENCE 0x24 #define YKPIV_INS_RESET_RETRY 0x2c @@ -241,6 +243,8 @@ extern "C" #define YKPIV_RETRIES_DEFAULT 3 #define YKPIV_RETRIES_MAX 0xff +#define YKPIV_CERTINFO_UNCOMPRESSED 0 +#define YKPIV_CERTINFO_GZIP 1 // // UTIL @@ -291,7 +295,7 @@ extern "C" 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_write_cert(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo); ykpiv_rc ykpiv_util_delete_cert(ykpiv_state *state, uint8_t slot); /** diff --git a/tool/util.c b/tool/util.c index baea3f1..3ae4119 100644 --- a/tool/util.c +++ b/tool/util.c @@ -255,6 +255,51 @@ int set_length(unsigned char *buffer, int length) { } } +int get_slot_hex(enum enum_slot slot_enum) { + int slot = -1; + + switch (slot_enum) { + case slot_arg_9a: + slot = 0x9a; + break; + case slot_arg_9c: + case slot_arg_9d: + case slot_arg_9e: + slot = 0x9c + ((int)slot_enum - (int)slot_arg_9c); + break; + case slot_arg_82: + case slot_arg_83: + case slot_arg_84: + case slot_arg_85: + case slot_arg_86: + case slot_arg_87: + case slot_arg_88: + case slot_arg_89: + case slot_arg_8a: + case slot_arg_8b: + case slot_arg_8c: + case slot_arg_8d: + case slot_arg_8e: + case slot_arg_8f: + case slot_arg_90: + case slot_arg_91: + case slot_arg_92: + case slot_arg_93: + case slot_arg_94: + case slot_arg_95: + slot = 0x82 + ((int)slot_enum - (int)slot_arg_82); + break; + case slot_arg_f9: + slot = 0xf9; + break; + case slot__NULL: + default: + slot = -1; + } + + return slot; +} + int get_object_id(enum enum_slot slot) { int object; diff --git a/tool/util.h b/tool/util.h index 4f61713..a1f15b5 100644 --- a/tool/util.h +++ b/tool/util.h @@ -47,6 +47,7 @@ int get_length(const unsigned char*, int*); X509_NAME *parse_name(const char*); unsigned char get_algorithm(EVP_PKEY*); FILE *open_file(const char*, int); +int get_slot_hex(enum enum_slot slot_enum); int get_object_id(enum enum_slot slot); int key_to_object_id(int key); bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len); diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 58ed1bd..adde591 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -495,35 +495,18 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, } { - unsigned char certdata[3072]; + unsigned char certdata[YKPIV_OBJ_MAX_SIZE]; unsigned char *certptr = certdata; - int object = get_object_id(slot); ykpiv_rc res; - - if(4 + cert_len + 5 > sizeof(certdata)) { /* 4 is prefix size, 5 is postfix size */ - fprintf(stderr, "Certificate is too large to fit in buffer.\n"); - goto import_cert_out; - } - - *certptr++ = 0x70; - certptr += set_length(certptr, cert_len); if (compress) { - if (fread(certptr, 1, (size_t)cert_len, input_file) != (size_t)cert_len) { + if (fread(certdata, 1, (size_t)cert_len, input_file) != (size_t)cert_len) { fprintf(stderr, "Failed to read compressed certificate\n"); goto import_cert_out; } - certptr += cert_len; } else { - /* i2d_X509 increments certptr here.. */ i2d_X509(cert, &certptr); } - *certptr++ = 0x71; - *certptr++ = 1; - *certptr++ = compress; /* certinfo (gzip etc) */ - *certptr++ = 0xfe; /* LRC */ - *certptr++ = 0; - - if((res = ykpiv_save_object(state, object, certdata, (size_t)(certptr - certdata))) != YKPIV_OK) { + if ((res = ykpiv_util_write_cert(state, get_slot_hex(slot), certdata, cert_len, compress)) != YKPIV_OK) { fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res)); } else { ret = true;