From a4ee5725b862544f9469119067a42bdcc667010c Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Mon, 14 Dec 2015 10:55:32 +0100 Subject: [PATCH 1/9] add generic write and read object actions for the tool this take in/out hex dump of the data --- tool/cmdline.ggo | 4 +- tool/yubico-piv-tool.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 5252868..33b968b 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -32,7 +32,8 @@ option "action" a "Action to take" values="version","generate","set-mgm-key", "reset","pin-retries","import-key","import-certificate","set-chuid", "request-certificate","verify-pin","change-pin","change-puk","unblock-pin", "selfsign-certificate","delete-certificate","read-certificate","status", - "test-signature","test-decipher","list-readers","set-ccc" enum multiple + "test-signature","test-decipher","list-readers","set-ccc","write-object", + "read-object" enum multiple text " Multiple actions may be given at once and will be executed in order for example --action=verify-pin --action=request-certificate\n" @@ -60,4 +61,5 @@ option "pin" P "Pin/puk code for verification" string optional option "new-pin" N "New pin/puk code for changing" string optional dependon="pin" option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always" enum optional +option "id" - "Id of object for write/get" int optional option "sign" - "Sign data" flag off hidden diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 0c00a59..ab3caef 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -1644,6 +1644,82 @@ static bool list_readers(ykpiv_state *state) { return true; } +static bool write_object(ykpiv_state *state, int id, + const char *input_file_name, int verbosity) { + bool ret = false; + FILE *input_file = NULL; + unsigned char data[3072]; + char raw_data[3072 * 2]; + size_t len = sizeof(data); + size_t raw_len = sizeof(raw_data); + ykpiv_rc res; + + input_file = open_file(input_file_name, INPUT); + if(!input_file) { + return false; + } + + if(isatty(fileno(input_file))) { + fprintf(stderr, "Please paste the data...\n"); + } + + raw_len = fread(raw_data, 1, raw_len, input_file); + if(raw_len == 0) { + fprintf(stderr, "Failed reading data\n"); + goto write_out; + } + if(raw_data[raw_len - 1] == '\n') { + raw_len -= 1; + } + + if(ykpiv_hex_decode(raw_data, raw_len, data, &len) != YKPIV_OK) { + fprintf(stderr, "Failed decoding data\n"); + goto write_out; + } + + if(verbosity) { + fprintf(stderr, "Writing %lu bytes of data to object %x.\n", len, id); + } + + if((res = ykpiv_save_object(state, id, data, len)) != YKPIV_OK) { + fprintf(stderr, "Failed writing data to device: %s\n", ykpiv_strerror(res)); + } else { + ret = true; + } + +write_out: + if(input_file != stdin) { + fclose(input_file); + } + return ret; +} + +static bool read_object(ykpiv_state *state, int id, const char *output_file_name) { + FILE *output_file = NULL; + unsigned char data[3072]; + size_t len = sizeof(data); + bool ret = false; + + output_file = open_file(output_file_name, OUTPUT); + if(!output_file) { + return false; + } + + if(ykpiv_fetch_object(state, id, data, &len) != YKPIV_OK) { + fprintf(stderr, "Failed fetching object.\n"); + goto read_out; + } + + dump_hex(data, len, output_file, false); + ret = true; + +read_out: + if(output_file != stdout) { + fclose(output_file); + } + return ret; +} + int main(int argc, char *argv[]) { struct gengetopt_args_info args_info; ykpiv_state *state; @@ -1688,6 +1764,14 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } break; + case action_arg_writeMINUS_object: + case action_arg_readMINUS_object: + if(!args_info.id_given) { + fprintf(stderr, "The '%s' action needs the --id argument.\n", + cmdline_parser_action_values[action]); + return EXIT_FAILURE; + } + break; case action_arg_changeMINUS_pin: case action_arg_changeMINUS_puk: case action_arg_unblockMINUS_pin: @@ -1727,6 +1811,7 @@ int main(int argc, char *argv[]) { case action_arg_setMINUS_chuid: case action_arg_setMINUS_ccc: case action_arg_deleteMINUS_certificate: + case action_arg_writeMINUS_object: if(verbosity) { fprintf(stderr, "Authenticating since action '%s' needs that.\n", cmdline_parser_action_values[action]); } @@ -1745,6 +1830,7 @@ int main(int argc, char *argv[]) { case action_arg_testMINUS_signature: case action_arg_testMINUS_decipher: case action_arg_listMINUS_readers: + case action_arg_readMINUS_object: case action__NULL: default: if(verbosity) { @@ -1945,6 +2031,15 @@ int main(int argc, char *argv[]) { if(list_readers(state) == false) { ret = EXIT_FAILURE; } + case action_arg_writeMINUS_object: + if(write_object(state, args_info.id_arg, args_info.input_arg, verbosity) == false) { + ret = EXIT_FAILURE; + } + break; + case action_arg_readMINUS_object: + if(read_object(state, args_info.id_arg, args_info.output_arg) == false) { + ret = EXIT_FAILURE; + } break; case action__NULL: default: From 30cc13aaff789b11c7d166d061276d35877a9944 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Tue, 15 Dec 2015 10:22:11 +0100 Subject: [PATCH 2/9] add format for read/write object as hex/base64/binary relates #31 --- tool/cmdline.ggo | 3 +- tool/util.c | 76 +++++++++++++++++++++++++++++++++++++++--- tool/util.h | 2 ++ tool/yubico-piv-tool.c | 27 ++++++--------- 4 files changed, 85 insertions(+), 23 deletions(-) diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo index 33b968b..03e61c9 100644 --- a/tool/cmdline.ggo +++ b/tool/cmdline.ggo @@ -61,5 +61,6 @@ option "pin" P "Pin/puk code for verification" string optional option "new-pin" N "New pin/puk code for changing" string optional dependon="pin" option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always" enum optional -option "id" - "Id of object for write/get" int optional +option "id" - "Id of object for write/read object" int optional +option "format" f "Format of data for write/read object" values="hex","base64","binary" enum optional default="hex" option "sign" - "Sign data" flag off hidden diff --git a/tool/util.c b/tool/util.c index d330daa..56a9588 100644 --- a/tool/util.c +++ b/tool/util.c @@ -148,12 +148,78 @@ parse_err: return NULL; } -void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, bool space) { - unsigned int i; - for (i = 0; i < len; i++) { - fprintf(output, "%02x%s", buf[i], space == true ? " " : ""); +size_t read_data(unsigned char *buf, size_t len, FILE* input, enum enum_format format) { + char raw_buf[3072 * 2]; + size_t raw_len = sizeof(raw_buf); + raw_len = fread(raw_buf, 1, raw_len, input); + switch(format) { + case format_arg_hex: + if(raw_buf[raw_len - 1] == '\n') { + raw_len -= 1; + } + if(ykpiv_hex_decode(raw_buf, raw_len, buf, &len) != YKPIV_OK) { + return 0; + } + return len; + case format_arg_base64: + { + int read; + BIO *b64 = BIO_new(BIO_f_base64()); + BIO *bio = BIO_new_mem_buf(raw_buf, raw_len); + BIO_push(b64, bio); + read = BIO_read(b64, buf, len); + BIO_free_all(b64); + if(read <= 0) { + return 0; + } else { + return (size_t)read; + } + } + break; + case format_arg_binary: + if(raw_len > len) { + return 0; + } + memcpy(buf, raw_buf, raw_len); + return raw_len; + case format__NULL: + default: + return 0; } - fprintf(output, "\n"); +} + +void dump_data(const unsigned char *buf, unsigned int len, FILE *output, bool space, enum enum_format format) { + switch(format) { + case format_arg_hex: + { + unsigned int i; + for (i = 0; i < len; i++) { + fprintf(output, "%02x%s", buf[i], space == true ? " " : ""); + } + fprintf(output, "\n"); + } + return; + case format_arg_base64: + { + BIO *b64 = BIO_new(BIO_f_base64()); + BIO *bio = BIO_new_fp(output, BIO_NOCLOSE); + BIO_push(b64, bio); + BIO_write(b64, buf, (int)len); + BIO_flush(b64); + BIO_free_all(b64); + } + return; + case format_arg_binary: + fwrite(buf, 1, len, output); + return; + case format__NULL: + default: + return; + } +} + +void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, bool space) { + dump_data(buf, len, output, space, format_arg_hex); } int get_length(const unsigned char *buffer, int *len) { diff --git a/tool/util.h b/tool/util.h index 21bb843..8b2b728 100644 --- a/tool/util.h +++ b/tool/util.h @@ -38,6 +38,8 @@ #define INPUT 1 #define OUTPUT 2 +size_t read_data(unsigned char*, size_t, FILE*, enum enum_format); +void dump_data(unsigned const char*, unsigned int, FILE*, bool, enum enum_format); void dump_hex(unsigned const char*, unsigned int, FILE*, bool); int set_length(unsigned char*, int); int get_length(const unsigned char*, int*); diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index ab3caef..40b71c3 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -1645,13 +1645,11 @@ static bool list_readers(ykpiv_state *state) { } static bool write_object(ykpiv_state *state, int id, - const char *input_file_name, int verbosity) { + const char *input_file_name, int verbosity, enum enum_format format) { bool ret = false; FILE *input_file = NULL; unsigned char data[3072]; - char raw_data[3072 * 2]; size_t len = sizeof(data); - size_t raw_len = sizeof(raw_data); ykpiv_rc res; input_file = open_file(input_file_name, INPUT); @@ -1663,19 +1661,11 @@ static bool write_object(ykpiv_state *state, int id, fprintf(stderr, "Please paste the data...\n"); } - raw_len = fread(raw_data, 1, raw_len, input_file); - if(raw_len == 0) { + len = read_data(data, len, input_file, format); + if(len == 0) { fprintf(stderr, "Failed reading data\n"); goto write_out; } - if(raw_data[raw_len - 1] == '\n') { - raw_len -= 1; - } - - if(ykpiv_hex_decode(raw_data, raw_len, data, &len) != YKPIV_OK) { - fprintf(stderr, "Failed decoding data\n"); - goto write_out; - } if(verbosity) { fprintf(stderr, "Writing %lu bytes of data to object %x.\n", len, id); @@ -1694,7 +1684,8 @@ write_out: return ret; } -static bool read_object(ykpiv_state *state, int id, const char *output_file_name) { +static bool read_object(ykpiv_state *state, int id, const char *output_file_name, + enum enum_format format) { FILE *output_file = NULL; unsigned char data[3072]; size_t len = sizeof(data); @@ -1710,7 +1701,7 @@ static bool read_object(ykpiv_state *state, int id, const char *output_file_name goto read_out; } - dump_hex(data, len, output_file, false); + dump_data(data, len, output_file, false, format); ret = true; read_out: @@ -2032,12 +2023,14 @@ int main(int argc, char *argv[]) { ret = EXIT_FAILURE; } case action_arg_writeMINUS_object: - if(write_object(state, args_info.id_arg, args_info.input_arg, verbosity) == false) { + if(write_object(state, args_info.id_arg, args_info.input_arg, verbosity, + args_info.format_arg) == false) { ret = EXIT_FAILURE; } break; case action_arg_readMINUS_object: - if(read_object(state, args_info.id_arg, args_info.output_arg) == false) { + if(read_object(state, args_info.id_arg, args_info.output_arg, + args_info.format_arg) == false) { ret = EXIT_FAILURE; } break; From a143c6d67dd9c864c245c149045845f4a3494d09 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Tue, 15 Dec 2015 10:27:54 +0100 Subject: [PATCH 3/9] remove the util function dump_hex() in favor of dump_data() --- tool/util.c | 4 ---- tool/util.h | 1 - tool/yubico-piv-tool.c | 20 ++++++++++---------- ykcs11/ykcs11.c | 8 ++++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/tool/util.c b/tool/util.c index 56a9588..aeb40c2 100644 --- a/tool/util.c +++ b/tool/util.c @@ -218,10 +218,6 @@ void dump_data(const unsigned char *buf, unsigned int len, FILE *output, bool sp } } -void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, bool space) { - dump_data(buf, len, output, space, format_arg_hex); -} - int get_length(const unsigned char *buffer, int *len) { if(buffer[0] < 0x81) { *len = buffer[0]; diff --git a/tool/util.h b/tool/util.h index 8b2b728..e045b07 100644 --- a/tool/util.h +++ b/tool/util.h @@ -40,7 +40,6 @@ size_t read_data(unsigned char*, size_t, FILE*, enum enum_format); void dump_data(unsigned const char*, unsigned int, FILE*, bool, enum enum_format); -void dump_hex(unsigned const char*, unsigned int, FILE*, bool); int set_length(unsigned char*, int); int get_length(const unsigned char*, int*); X509_NAME *parse_name(const char*); diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 40b71c3..9ee73ee 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -631,7 +631,7 @@ static bool set_dataobject(ykpiv_state *state, int verbose, int type) { } if(verbose) { fprintf(stderr, "Setting the %s to: ", type == CHUID ? "CHUID" : "CCC"); - dump_hex(obj, len, stderr, true); + 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)); @@ -1157,7 +1157,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output, if(verbosity) { fprintf(stderr, "file hashed as: "); - dump_hex(hashed, hash_len, stderr, true); + dump_data(hashed, hash_len, stderr, true, format_arg_hex); } EVP_MD_CTX_destroy(mdctx); } @@ -1176,7 +1176,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output, if(verbosity) { fprintf(stderr, "file signed as: "); - dump_hex(buf, len, stderr, true); + dump_data(buf, len, stderr, true, format_arg_hex); } fwrite(buf, 1, len, output_file); ret = true; @@ -1276,7 +1276,7 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M fprintf(output, "\n"); X509_digest(x509, md, data, &md_len); fprintf(output, "\tFingerprint:\t"); - dump_hex(data, md_len, output, false); + dump_data(data, md_len, output, false, format_arg_hex); bio = BIO_new_fp(output, BIO_NOCLOSE | BIO_FP_TEXT); not_before = X509_get_notBefore(x509); @@ -1325,7 +1325,7 @@ static bool status(ykpiv_state *state, enum enum_hash hash, if(ykpiv_fetch_object(state, YKPIV_OBJ_CHUID, chuid, &len) != YKPIV_OK) { fprintf(output_file, "No data available\n"); } else { - dump_hex(chuid, len, output_file, false); + dump_data(chuid, len, output_file, false, format_arg_hex); } if (slot == slot__NULL) @@ -1405,7 +1405,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot, EVP_DigestFinal_ex(mdctx, data, &data_len); if(verbose) { fprintf(stderr, "Test data hashes as: "); - dump_hex(data, data_len, stderr, true); + dump_data(data, data_len, stderr, true, format_arg_hex); } } @@ -1561,9 +1561,9 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, if(len == sizeof(secret)) { if(verbose) { fprintf(stderr, "Generated nonce: "); - dump_hex(secret, sizeof(secret), stderr, true); + dump_data(secret, sizeof(secret), stderr, true, format_arg_hex); fprintf(stderr, "Decrypted nonce: "); - dump_hex(secret2, sizeof(secret2), stderr, true); + dump_data(secret2, sizeof(secret2), stderr, true, format_arg_hex); } if(memcmp(secret, secret2, sizeof(secret)) == 0) { fprintf(stderr, "Successfully performed RSA decryption!\n"); @@ -1603,9 +1603,9 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot, } if(verbose) { fprintf(stderr, "ECDH host generated: "); - dump_hex(secret, len, stderr, true); + dump_data(secret, len, stderr, true, format_arg_hex); fprintf(stderr, "ECDH card generated: "); - dump_hex(secret2, len, stderr, true); + dump_data(secret2, len, stderr, true, format_arg_hex); } if(memcmp(secret, secret2, key_len) == 0) { fprintf(stderr, "Successfully performed ECDH exchange with card.\n"); diff --git a/ykcs11/ykcs11.c b/ykcs11/ykcs11.c index 23e290d..fa4458e 100644 --- a/ykcs11/ykcs11.c +++ b/ykcs11/ykcs11.c @@ -1840,7 +1840,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Sending %lu bytes to sign", ulDataLen); #if YKCS11_DBG == 1 - dump_hex(pData, ulDataLen, stderr, CK_TRUE); + dump_data(pData, ulDataLen, stderr, CK_TRUE, format_arg_hex); #endif if (is_hashed_mechanism(op_info.mechanism.mechanism) == CK_TRUE) { @@ -1882,7 +1882,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Using key %lx", op_info.op.sign.key_id); DBG("After padding and transformation there are %lu bytes", op_info.buf_len); #if YKCS11_DBG == 1 - dump_hex(op_info.buf, op_info.buf_len, stderr, CK_TRUE); + dump_data(op_info.buf, op_info.buf_len, stderr, CK_TRUE, format_arg_hex); #endif *pulSignatureLen = sizeof(op_info.buf); @@ -1903,7 +1903,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("Got %lu bytes back", *pulSignatureLen); #if YKCS11_DBG == 1 - dump_hex(pSignature, *pulSignatureLen, stderr, CK_TRUE); + dump_data(pSignature, *pulSignatureLen, stderr, CK_TRUE, format_arg_hex); #endif if (!is_RSA_mechanism(op_info.mechanism.mechanism)) { @@ -1913,7 +1913,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_Sign)( DBG("After removing DER encoding %lu", *pulSignatureLen); #if YKCS11_DBG == 1 - dump_hex(pSignature, *pulSignatureLen, stderr, CK_TRUE); + dump_data(pSignature, *pulSignatureLen, stderr, CK_TRUE, format_arg_hex); #endif } From c89387e8fccbee73c8f76e56a836663cdcb3c369 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Tue, 15 Dec 2015 10:43:29 +0100 Subject: [PATCH 4/9] add libykpiv as a dependency for libpiv_util --- tool/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/Makefile.am b/tool/Makefile.am index 3a9c760..0aebf99 100644 --- a/tool/Makefile.am +++ b/tool/Makefile.am @@ -41,7 +41,7 @@ libpiv_cmd_la_SOURCES = cmdline.ggo cmdline.c cmdline.h libpiv_cmd_la_CFLAGS = libpiv_util_la_SOURCES = util.c util.h -libpiv_util_la_LIBADD = $(OPENSSL_LIBS) +libpiv_util_la_LIBADD = $(top_builddir)/lib/libykpiv.la $(OPENSSL_LIBS) cmdline.c cmdline.h: cmdline.ggo Makefile.am $(GENGETOPT) --input $^ From e2f8ad21aa13d1860e4e3bfc35284f95a42f0979 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 17 Dec 2015 09:27:20 +0100 Subject: [PATCH 5/9] add a simple test case for the dump/read data functions --- .gitignore | 4 ++++ tool/tests/Makefile.am | 3 ++- tool/tests/test_inout.c | 53 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tool/tests/test_inout.c diff --git a/.gitignore b/.gitignore index 8ca8bbd..f9e3e3d 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,10 @@ tool/tests/parse_name tool/tests/parse_name.log tool/tests/parse_name.o tool/tests/parse_name.trs +tool/tests/test_inout +tool/tests/test_inout.log +tool/tests/test_inout.o +tool/tests/test_inout.trs coverage/ lib/error.gcno lib/version.gcno diff --git a/tool/tests/Makefile.am b/tool/tests/Makefile.am index 7148d1d..7c1ac31 100644 --- a/tool/tests/Makefile.am +++ b/tool/tests/Makefile.am @@ -37,8 +37,9 @@ AM_CPPFLAGS += $(OPENSSL_CFLAGS) AM_LDFLAGS = -no-install parse_name_LDADD = ../libpiv_util.la $(OPENSSL_LIBS) +test_inout_LDADD = ../libpiv_util.la -check_PROGRAMS = parse_name +check_PROGRAMS = parse_name test_inout TESTS = basic.sh $(check_PROGRAMS) if ENABLE_COV diff --git a/tool/tests/test_inout.c b/tool/tests/test_inout.c new file mode 100644 index 0000000..6a62906 --- /dev/null +++ b/tool/tests/test_inout.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "util.h" + +static void test_inout(enum enum_format format) { + unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + unsigned char buf2[sizeof(buf)]; + FILE *tmp = tmpfile(); + + dump_data(buf, sizeof(buf), tmp, false, format); + rewind(tmp); + read_data(buf2, sizeof(buf2), tmp, format); + assert(memcmp(buf, buf2, sizeof(buf)) == 0); +} + +int main(void) { + test_inout(format_arg_base64); + test_inout(format_arg_hex); + test_inout(format_arg_binary); + exit(0); +} From 3f874dd147e1a4d638a53b6d0d38019115eaca52 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 17 Dec 2015 09:54:52 +0100 Subject: [PATCH 6/9] don't use tmpfile(), it's broken on windows --- tool/tests/test_inout.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tool/tests/test_inout.c b/tool/tests/test_inout.c index 6a62906..4e05679 100644 --- a/tool/tests/test_inout.c +++ b/tool/tests/test_inout.c @@ -35,14 +35,18 @@ #include "util.h" static void test_inout(enum enum_format format) { - unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + const unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; unsigned char buf2[sizeof(buf)]; - FILE *tmp = tmpfile(); + char filename[] = "/tmp/pivtool_test_XXXXXX"; + int fd = mkstemp(filename); + FILE *tmp = fdopen(fd, "r+"); dump_data(buf, sizeof(buf), tmp, false, format); rewind(tmp); read_data(buf2, sizeof(buf2), tmp, format); assert(memcmp(buf, buf2, sizeof(buf)) == 0); + fclose(tmp); + remove(filename); } int main(void) { From 73585f241643ebb4ddfe1fd79386563d030a34db Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 17 Dec 2015 09:55:20 +0100 Subject: [PATCH 7/9] use unsigned long for len --- tool/yubico-piv-tool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index 9ee73ee..3410134 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -1688,7 +1688,7 @@ static bool read_object(ykpiv_state *state, int id, const char *output_file_name enum enum_format format) { FILE *output_file = NULL; unsigned char data[3072]; - size_t len = sizeof(data); + unsigned long len = sizeof(data); bool ret = false; output_file = open_file(output_file_name, OUTPUT); From d8bda22cdd9659d583269432df61c9788326d698 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 17 Dec 2015 10:18:01 +0100 Subject: [PATCH 8/9] rework inout test to use pipes for emulating files --- tool/tests/test_inout.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tool/tests/test_inout.c b/tool/tests/test_inout.c index 4e05679..50a5ed2 100644 --- a/tool/tests/test_inout.c +++ b/tool/tests/test_inout.c @@ -31,22 +31,28 @@ #include #include #include +#include #include "util.h" +#ifdef _WIN32 +#define pipe(fds) _pipe(fds,4096, 0) +#endif + static void test_inout(enum enum_format format) { const unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; unsigned char buf2[sizeof(buf)]; - char filename[] = "/tmp/pivtool_test_XXXXXX"; - int fd = mkstemp(filename); - FILE *tmp = fdopen(fd, "r+"); + int pipefd[2]; + FILE *tmp1, *tmp2; - dump_data(buf, sizeof(buf), tmp, false, format); - rewind(tmp); - read_data(buf2, sizeof(buf2), tmp, format); + assert(pipe(pipefd) == 0); + tmp1 = fdopen(pipefd[1], "w"); + dump_data(buf, sizeof(buf), tmp1, false, format); + fclose(tmp1); + tmp2 = fdopen(pipefd[0], "r"); + read_data(buf2, sizeof(buf2), tmp2, format); assert(memcmp(buf, buf2, sizeof(buf)) == 0); - fclose(tmp); - remove(filename); + fclose(tmp2); } int main(void) { From ab68b53b5c525a11e57f278661edff1976c70108 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 17 Dec 2015 13:26:53 +0100 Subject: [PATCH 9/9] rework dump_data() to keep an internal buffer and only fprintf() once --- tool/util.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tool/util.c b/tool/util.c index aeb40c2..9e3b675 100644 --- a/tool/util.c +++ b/tool/util.c @@ -192,11 +192,17 @@ void dump_data(const unsigned char *buf, unsigned int len, FILE *output, bool sp switch(format) { case format_arg_hex: { + char tmp[3072 * 3 + 1]; unsigned int i; - for (i = 0; i < len; i++) { - fprintf(output, "%02x%s", buf[i], space == true ? " " : ""); + int step = 2; + if(space) step += 1; + if(len > 3072) { + return; } - fprintf(output, "\n"); + for (i = 0; i < len; i++) { + sprintf(tmp + i * step, "%02x%s", buf[i], space == true ? " " : ""); + } + fprintf(output, "%s\n", tmp); } return; case format_arg_base64: