From 880c8a00614da391dbb82f1afa831eb8be427a2d Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Tue, 17 Jun 2014 15:11:02 +0200 Subject: [PATCH] move sign_data() function to library --- lib/Makefile.am | 1 + lib/error.c | 1 + lib/ykpiv.c | 107 +++++++++++++++++++++++++++++++++++++++++ lib/ykpiv.h | 26 +++++----- lib/ykpiv.map | 1 + tool/yubico-piv-tool.c | 76 ++++++----------------------- 6 files changed, 141 insertions(+), 71 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index ee448ab..729b57d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -33,6 +33,7 @@ libykpiv_la_SOURCES = ykpiv.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 +EXTRA_libykpiv_la_DEPENDENCIES = ykpiv.map libykpiv_la_LIBADD = $(OPENSSL_LIBS) $(PCSC_LIBS) libykpiv_la_LIBADD += $(LTLIBWINSCARD) $(PCSC_MACOSX_LIBS) diff --git a/lib/error.c b/lib/error.c index af3454f..4411665 100644 --- a/lib/error.c +++ b/lib/error.c @@ -50,6 +50,7 @@ static const err_t errors[] = { ERR (YKPIV_RANDOMNESS_ERROR, "Error getting randomness"), ERR (YKPIV_GENERIC_ERROR, "Something went wrong."), ERR (YKPIV_KEY_ERROR, "Error in key"), + ERR (YKPIV_PARSE_ERROR, "Parse error"), }; /** diff --git a/lib/ykpiv.c b/lib/ykpiv.c index 0e40c7d..6c76f62 100644 --- a/lib/ykpiv.c +++ b/lib/ykpiv.c @@ -45,6 +45,36 @@ static void dump_hex(const unsigned char *buf, unsigned int len) { } } +static int set_length(unsigned char *buffer, int length) { + if(length < 0x80) { + *buffer++ = length; + return 1; + } else if(length < 0xff) { + *buffer++ = 0x81; + *buffer++ = length; + return 2; + } else { + *buffer++ = 0x82; + *buffer++ = (length >> 8) & 0xff; + *buffer++ = length & 0xff; + return 3; + } +} + +static int get_length(unsigned char *buffer, int *len) { + if(buffer[0] < 0x81) { + *len = buffer[0]; + return 1; + } else if((*buffer & 0x7f) == 1) { + *len = buffer[1]; + return 2; + } else if((*buffer & 0x7f) == 2) { + *len = (buffer[1] << 8) + buffer[2]; + return 3; + } + return 0; +} + ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) { ykpiv_state *s = malloc(sizeof(ykpiv_state)); if(s == NULL) { @@ -428,3 +458,80 @@ ykpiv_rc ykpiv_parse_key(ykpiv_state *state, } return YKPIV_OK; } + +ykpiv_rc ykpiv_sign_data(ykpiv_state *state, + const unsigned char *sign_in, int in_len, + unsigned char *sign_out, int *out_len, + unsigned char algorithm, unsigned char key) { + + unsigned char indata[1024]; + unsigned char *dataptr = indata; + unsigned char data[1024]; + unsigned char templ[] = {0, YKPIV_INS_AUTHENTICATE, algorithm, key}; + unsigned long recv_len = sizeof(data); + int sw; + int bytes; + int len = 0; + ykpiv_rc res; + + if(in_len > 1000) { + return YKPIV_SIZE_ERROR; + } + + if(in_len < 0x80) { + bytes = 1; + } else if(in_len < 0xff) { + bytes = 2; + } else { + bytes = 3; + } + + *dataptr++ = 0x7c; + dataptr += set_length(dataptr, in_len + bytes + 3); + *dataptr++ = 0x82; + *dataptr++ = 0x00; + *dataptr++ = 0x81; + dataptr += set_length(dataptr, in_len); + memcpy(dataptr, sign_in, (size_t)in_len); + dataptr += in_len; + + if((res = ykpiv_transfer_data(state, templ, indata, dataptr - indata, data, + &recv_len, &sw)) != YKPIV_OK) { + if(state->verbose) { + fprintf(stderr, "Sign command failed to communicate.\n"); + } + return res; + } else if(sw != 0x9000) { + if(state->verbose) { + fprintf(stderr, "Failed sign command with code %x.\n", sw); + } + return YKPIV_GENERIC_ERROR; + } + /* skip the first 7c tag */ + if(data[0] != 0x7c) { + if(state->verbose) { + fprintf(stderr, "Failed parsing signature reply.\n"); + } + return YKPIV_PARSE_ERROR; + } + dataptr = data + 1; + dataptr += get_length(dataptr, &len); + /* skip the 82 tag */ + if(*dataptr != 0x82) { + if(state->verbose) { + fprintf(stderr, "Failed parsing signature reply.\n"); + } + return YKPIV_PARSE_ERROR; + } + dataptr++; + dataptr += get_length(dataptr, &len); + if(len > *out_len) { + if(state->verbose) { + fprintf(stderr, "Wrong size on output buffer.\n"); + } + return YKPIV_SIZE_ERROR; + } + *out_len = len; + memcpy(sign_out, dataptr, len); + return YKPIV_OK; +} diff --git a/lib/ykpiv.h b/lib/ykpiv.h index 054accf..e0b1067 100644 --- a/lib/ykpiv.h +++ b/lib/ykpiv.h @@ -50,6 +50,7 @@ extern "C" YKPIV_RANDOMNESS_ERROR = -6, YKPIV_GENERIC_ERROR = -7, YKPIV_KEY_ERROR = -8, + YKPIV_PARSE_ERROR = -9, } ykpiv_rc; const char *ykpiv_strerror(ykpiv_rc err); @@ -68,22 +69,25 @@ extern "C" ykpiv_rc ykpiv_set_mgmkey(ykpiv_state *state, const unsigned char *new_key); ykpiv_rc ykpiv_parse_key(ykpiv_state *state, const char *key_in, unsigned char *key_out); + ykpiv_rc ykpiv_sign_data(ykpiv_state *state, const unsigned char *sign_in, + int in_len,unsigned char *sign_out, int *out_len, + unsigned char algorithm, unsigned char key); -#define YKPIV_ALGO_3DES 0x03; -#define YKPIV_ALGO_RSA1024 0x06; -#define YKPIV_ALGO_RSA2048 0x07; -#define YKPIV_ALGO_ECCP256 0x11; +#define YKPIV_ALGO_3DES 0x03 +#define YKPIV_ALGO_RSA1024 0x06 +#define YKPIV_ALGO_RSA2048 0x07 +#define YKPIV_ALGO_ECCP256 0x11 -#define YKPIV_KEY_AUTHENTICATION 0x9a; -#define YKPIV_KEY_CARDMGM 0x9b; -#define YKPIV_KEY_SIGNATURE 0x9c; -#define YKPIV_KEY_KEYMGM 0x9d; -#define YKPIV_KEY_CARDAUTH 0x9e; +#define YKPIV_KEY_AUTHENTICATION 0x9a +#define YKPIV_KEY_CARDMGM 0x9b +#define YKPIV_KEY_SIGNATURE 0x9c +#define YKPIV_KEY_KEYMGM 0x9d +#define YKPIV_KEY_CARDAUTH 0x9e -#define YKPIV_INS_AUTHENTICATE 0x87; +#define YKPIV_INS_AUTHENTICATE 0x87 /* Yubico vendor specific instructions */ -#define YKPIV_INS_SET_MGMKEY 0xff; +#define YKPIV_INS_SET_MGMKEY 0xff #ifdef __cplusplus } diff --git a/lib/ykpiv.map b/lib/ykpiv.map index 1cbdfb9..eed8a19 100644 --- a/lib/ykpiv.map +++ b/lib/ykpiv.map @@ -39,6 +39,7 @@ global: ykpiv_authenticate; ykpiv_set_mgmkey; ykpiv_parse_key; + ykpiv_sign_data; local: *; diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 6b2b29f..6b73936 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -90,8 +90,6 @@ static int get_length(unsigned char*, int*); static X509_NAME *parse_name(char*); static unsigned char get_algorithm(EVP_PKEY*); static FILE *open_file(const char*, int); -static bool sign_data(ykpiv_state*, unsigned char*, int, unsigned char, unsigned char, - ASN1_BIT_STRING*); static int get_object_id(enum enum_slot slot); static void print_version(ykpiv_state *state) { @@ -634,8 +632,14 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for fprintf(stderr, "Unsupported algorithm %x.\n", algorithm); goto request_out; } - if(sign_data(state, signinput, len, algorithm, key, req->signature) == false) { - goto request_out; + { + unsigned char signature[1024]; + int sig_len = sizeof(signature); + if(ykpiv_sign_data(state, signinput, len, signature, &sig_len, algorithm, key) + != YKPIV_OK) { + goto request_out; + } + M_ASN1_BIT_STRING_set(req->signature, signature, sig_len); } if(key_format == key_format_arg_PEM) { @@ -764,8 +768,14 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo fprintf(stderr, "Unsupported algorithm %x.\n", algorithm); goto selfsign_out; } - if(sign_data(state, signinput, len, algorithm, key, x509->signature)) { - goto selfsign_out; + { + unsigned char signature[1024]; + int sig_len = sizeof(signature); + if(ykpiv_sign_data(state, signinput, len, signature, &sig_len, algorithm, key) + != YKPIV_OK) { + goto selfsign_out; + } + M_ASN1_BIT_STRING_set(x509->signature, signature, sig_len); } if(key_format == key_format_arg_PEM) { @@ -913,60 +923,6 @@ static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) { return ret; } -static bool sign_data(ykpiv_state *state, unsigned char *signinput, int in_len, - unsigned char algorithm, unsigned char key, ASN1_BIT_STRING *sig) { - unsigned char indata[1024]; - unsigned char *dataptr = indata; - unsigned char data[1024]; - unsigned char templ[] = {0, 0x87, algorithm, key}; - unsigned long recv_len = sizeof(data); - int sw; - int bytes; - int len; - - if(in_len < 0x80) { - bytes = 1; - } else if(in_len < 0xff) { - bytes = 2; - } else { - bytes = 3; - } - - *dataptr++ = 0x7c; - dataptr += set_length(dataptr, in_len + bytes + 3); - *dataptr++ = 0x82; - *dataptr++ = 0x00; - *dataptr++ = 0x81; - dataptr += set_length(dataptr, in_len); - memcpy(dataptr, signinput, (size_t)in_len); - dataptr += in_len; - - if(ykpiv_transfer_data(state, templ, indata, dataptr - indata, data, - &recv_len, &sw) != YKPIV_OK) { - fprintf(stderr, "Sign command failed to communicate.\n"); - return false; - } else if(sw != 0x9000) { - fprintf(stderr, "Failed sign command with code %x.\n", sw); - return false; - } - /* skip the first 7c tag */ - if(data[0] != 0x7c) { - fprintf(stderr, "Failed parsing signature reply.\n"); - return false; - } - dataptr = data + 1; - dataptr += get_length(dataptr, &len); - /* skip the 82 tag */ - if(*dataptr != 0x82) { - fprintf(stderr, "Failed parsing signature reply.\n"); - return false; - } - dataptr++; - dataptr += get_length(dataptr, &len); - M_ASN1_BIT_STRING_set(sig, dataptr, len); - return true; -} - static FILE *open_file(const char *file_name, int mode) { FILE *file; if(!strcmp(file_name, "-")) {