From a1c2e4e8d158555867d9ad130639ed002699ef95 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 26 Jun 2014 08:02:44 +0200 Subject: [PATCH] refactor writing object to it's own library function ykpiv_save_object(), use that for writing certs --- lib/ykpiv.c | 71 +++++++++++++++++++++++++++++++++--------- lib/ykpiv.h | 2 ++ lib/ykpiv.map | 1 + tool/yubico-piv-tool.c | 29 +++-------------- 4 files changed, 64 insertions(+), 39 deletions(-) diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 0102298..568f447 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -80,6 +80,19 @@ static int get_length(const unsigned char *buffer, size_t *len) { return 0; } +static unsigned char *set_object(int object_id, unsigned char *buffer) { + if(object_id == YKPIV_OBJ_DISCOVERY) { + *buffer++ = 1; + *buffer++ = YKPIV_OBJ_DISCOVERY; + } else if(object_id > 0xffff && object_id <= 0xffffff) { + *buffer++ = 3; + *buffer++ = (object_id >> 16) & 0xff; + *buffer++ = (object_id >> 8) & 0xff; + *buffer++ = object_id & 0xff; + } + return buffer; +} + ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) { ykpiv_state *s = malloc(sizeof(ykpiv_state)); if(s == NULL) { @@ -633,25 +646,17 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len) { int sw; unsigned char indata[5]; + unsigned char *inptr = indata; unsigned char templ[] = {0, YKPIV_INS_GET_DATA, 0x3f, 0xff}; - long inlen = 5; ykpiv_rc res; - indata[0] = 0x5c; - if(object_id == YKPIV_OBJ_DISCOVERY) { - indata[1] = 1; - indata[2] = YKPIV_OBJ_DISCOVERY; - inlen = 3; - } else if(object_id > 0xffff && object_id <= 0xffffff) { - indata[1] = 3; - indata[2] = (object_id >> 16) & 0xff; - indata[3] = (object_id >> 8) & 0xff; - indata[4] = object_id & 0xff; - } else { + *inptr++ = 0x5c; + inptr = set_object(object_id, inptr); + if(inptr == NULL) { return YKPIV_INVALID_OBJECT; } - if((res = ykpiv_transfer_data(state, templ, indata, inlen, data, len, &sw)) + if((res = ykpiv_transfer_data(state, templ, indata, inptr - indata, data, len, &sw)) != YKPIV_OK) { return res; } @@ -662,5 +667,43 @@ ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, memmove(data, data + 1 + offs, outlen); *len = outlen; } - return YKPIV_OK; + if(sw == 0x9000) { + return YKPIV_OK; + } else { + return YKPIV_GENERIC_ERROR; + } +} + +ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, + unsigned char *indata, size_t len) { + + unsigned char data[2048]; + unsigned char *dataptr = data; + unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff}; + int sw; + ykpiv_rc res; + + if(len > sizeof(data) - 9) { + return YKPIV_SIZE_ERROR; + } + *dataptr++ = 0x5c; + dataptr = set_object(object_id, dataptr); + if(dataptr == NULL) { + return YKPIV_INVALID_OBJECT; + } + *dataptr++ = 0x53; + dataptr += set_length(dataptr, len); + memcpy(dataptr, indata, len); + dataptr += len; + + if((res = ykpiv_transfer_data(state, templ, data, dataptr - data, NULL, 0, + &sw)) != YKPIV_OK) { + return res; + } + + if(sw == 0x9000) { + return YKPIV_OK; + } else { + return YKPIV_GENERIC_ERROR; + } } diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 03715c0..afb64a2 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -79,6 +79,8 @@ extern "C" ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries); ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len); + ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id, + unsigned char *indata, size_t len); #define YKPIV_ALGO_3DES 0x03 #define YKPIV_ALGO_RSA1024 0x06 diff --git a/lib/ykpiv.map b/lib/ykpiv.map index 619ea09..fc97ac0 100644 --- a/lib/ykpiv.map +++ b/lib/ykpiv.map @@ -42,6 +42,7 @@ global: ykpiv_get_version; ykpiv_verify; ykpiv_fetch_object; + ykpiv_save_object; local: *; diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index c13d4b6..000c717 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -377,7 +377,6 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, X509 *cert = NULL; PKCS12 *p12 = NULL; EVP_PKEY *private_key = NULL; - int object = get_object_id(slot); input_file = open_file(input_file_name, INPUT); if(!input_file) { @@ -409,31 +408,14 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, { unsigned char certdata[2100]; unsigned char *certptr = certdata; - unsigned char data[0xff]; - unsigned char templ[] = {0, YKPIV_INS_PUT_DATA, 0x3f, 0xff}; - unsigned long recv_len = sizeof(data); + int object = get_object_id(slot); int cert_len = i2d_X509(cert, NULL); - int bytes; - int sw; + ykpiv_rc res; if(cert_len > 2048) { fprintf(stderr, "Certificate to large, maximum 2048 bytes (was %d bytes).\n", cert_len); goto import_cert_out; } - *certptr++ = 0x5c; - *certptr++ = 0x03; - *certptr++ = (object >> 16) & 0xff; - *certptr++ = (object >> 8) & 0xff; - *certptr++ = object & 0xff; - *certptr++ = 0x53; - if(cert_len < 0x80) { - bytes = 1; - } else if(cert_len < 0xff) { - bytes = 2; - } else { - bytes = 3; - } - certptr += set_length(certptr, cert_len + bytes + 6); *certptr++ = 0x70; certptr += set_length(certptr, cert_len); /* i2d_X509 increments certptr here.. */ @@ -444,11 +426,8 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format, *certptr++ = 0xfe; /* LRC */ *certptr++ = 0; - if(ykpiv_transfer_data(state, templ, certdata, certptr - certdata, data, - &recv_len, &sw) != YKPIV_OK) { - fprintf(stderr, "Failed commands with device.\n"); - } else if(sw != 0x9000) { - fprintf(stderr, "Failed loading certificate to device with code %x.\n", sw); + if((res = ykpiv_save_object(state, object, certdata, (size_t)(certptr - certdata))) != YKPIV_OK) { + fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res)); } else { ret = true; }