diff --git a/.gitignore b/.gitignore
index 9d0e0fe..baea115 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,10 +73,3 @@ tool/tests/parse_name
tool/tests/parse_name.log
tool/tests/parse_name.o
tool/tests/parse_name.trs
-tool/cmdline-signer.c
-tool/cmdline-signer.h
-tool/libpivsigner_cmd.la
-tool/libpivsigner_cmd_la-cmdline-signer.lo
-tool/libpivsigner_cmd_la-cmdline-signer.o
-tool/yubico-piv-signer
-tool/yubico-piv-signer.o
diff --git a/tool/Makefile.am b/tool/Makefile.am
index 6567ed8..0e5af5e 100644
--- a/tool/Makefile.am
+++ b/tool/Makefile.am
@@ -30,16 +30,12 @@ AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
AM_CPPFLAGS = $(OPENSSL_CFLAGS)
AM_CPPFLAGS += -I$(top_srcdir)/lib -I$(top_builddir)/lib
-bin_PROGRAMS = yubico-piv-tool yubico-piv-signer
+bin_PROGRAMS = yubico-piv-tool
yubico_piv_tool_SOURCES = yubico-piv-tool.c yubico-piv-tool.h2m
yubico_piv_tool_LDADD = $(OPENSSL_LIBS) ../lib/libykpiv.la
yubico_piv_tool_LDADD += libpiv_cmd.la libpiv_util.la
-yubico_piv_signer_SOURCES = yubico-piv-signer.c
-yubico_piv_signer_LDADD = $(OPENSSL_LIBS) ../lib/libykpiv.la
-yubico_piv_signer_LDADD += libpivsigner_cmd.la libpiv_util.la
-
-noinst_LTLIBRARIES = libpiv_cmd.la libpiv_util.la libpivsigner_cmd.la
+noinst_LTLIBRARIES = libpiv_cmd.la libpiv_util.la
libpiv_cmd_la_SOURCES = cmdline.ggo cmdline.c cmdline.h
libpiv_cmd_la_CFLAGS =
@@ -49,12 +45,6 @@ libpiv_util_la_LIBADD = $(OPENSSL_LIBS)
cmdline.c cmdline.h: cmdline.ggo Makefile.am
$(GENGETOPT) --input $^
-libpivsigner_cmd_la_SOURCES = cmdline-signer.ggo cmdline-signer.c cmdline-signer.h
-libpivsigner_cmd_la_CFLAGS =
-
-cmdline-signer.c cmdline-signer.h: cmdline-signer.ggo Makefile.am
- $(GENGETOPT) --input $^ -F cmdline-signer
-
BUILT_SOURCES = cmdline.c cmdline.h
MAINTAINERCLEANFILES = $(BUILT_SOURCES)
diff --git a/tool/cmdline-signer.ggo b/tool/cmdline-signer.ggo
deleted file mode 100644
index d758eb5..0000000
--- a/tool/cmdline-signer.ggo
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2014 Yubico AB
-# All rights reserved.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-# Additional permission under GNU GPL version 3 section 7
-#
-# If you modify this program, or any covered work, by linking or
-# combining it with the OpenSSL project's OpenSSL library (or a
-# modified version of that library), containing parts covered by the
-# terms of the OpenSSL or SSLeay licenses, We grant you additional
-# permission to convey the resulting work. Corresponding Source for a
-# non-source form of such a combination shall include the source code
-# for the parts of OpenSSL used as well as that of the covered work.
-
-option "verbose" v "Print more information" int optional default="0" argoptional
-option "reader" r "Only use a matching reader" string optional default="Yubikey"
-option "slot" s "What key slot to operate on" values="9a","9c","9d","9e" enum
-text "
- 9a is for PIV Authentication
- 9c is for Digital Signature (PIN always checked)
- 9d is for Key Management
- 9e is for Card Authentication (PIN never checked)\n"
-option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256" enum optional default="RSA2048"
-option "hash" H "Hash to use for the signature" values="SHA1","SHA256","SHA512" enum optional default="SHA1"
-option "input" i "Filename to use as input, - for stdin" string optional default="-"
-option "output" o "Filename to use as output, - for stdout" string optional default="-"
-option "pin" P "Pin code for verification" string
diff --git a/tool/cmdline.ggo b/tool/cmdline.ggo
index de79960..d1734db 100644
--- a/tool/cmdline.ggo
+++ b/tool/cmdline.ggo
@@ -41,6 +41,7 @@ text "
9d is for Key Management
9e is for Card Authentication (PIN never checked)\n"
option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256" enum optional default="RSA2048"
+option "hash" H "Hash to use for signatures" values="SHA1","SHA256","SHA512" enum optional default="SHA256"
option "new-key" n "New authentication key to use" string optional
option "pin-retries" - "Number of retries before the pin code is blocked" int optional dependon="puk-retries"
option "puk-retries" - "Number of retries before the puk code is blocked" int optional dependon="pin-retries"
@@ -54,3 +55,4 @@ text "
/CN=host.example.com/OU=test/O=example.com/\n"
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 "sign" - "Sign data" flag off hidden
diff --git a/tool/yubico-piv-signer.c b/tool/yubico-piv-signer.c
deleted file mode 100644
index 3aca575..0000000
--- a/tool/yubico-piv-signer.c
+++ /dev/null
@@ -1,245 +0,0 @@
- /*
- * Copyright (c) 2014 Yubico AB
- * All rights reserved.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * Additional permission under GNU GPL version 3 section 7
- *
- * If you modify this program, or any covered work, by linking or
- * combining it with the OpenSSL project's OpenSSL library (or a
- * modified version of that library), containing parts covered by the
- * terms of the OpenSSL or SSLeay licenses, We grant you additional
- * permission to convey the resulting work. Corresponding Source for a
- * non-source form of such a combination shall include the source code
- * for the parts of OpenSSL used as well as that of the covered work.
- *
- */
-
-#include
-#include
-#include
-#include
-
-#include "ykpiv.h"
-
-#ifdef _WIN32
-#include
-#endif
-
-#include "cmdline-signer.h"
-#include "util.h"
-
-static bool verify_pin(ykpiv_state *state, const char *pin) {
- int tries = -1;
- ykpiv_rc res;
- int len = strlen(pin);
-
- if(len > 8) {
- fprintf(stderr, "Maximum 8 digits of PIN supported.\n");
- }
-
- res = ykpiv_verify(state, pin, &tries);
- if(res == YKPIV_OK) {
- return true;
- } else if(res == YKPIV_WRONG_PIN) {
- if(tries > 0) {
- fprintf(stderr, "Pin verification failed, %d tries left before pin is blocked.\n", tries);
- } else {
- fprintf(stderr, "Pin code blocked.\n");
- }
- } else {
- fprintf(stderr, "Pin code verification failed: '%s'\n", ykpiv_strerror(res));
- }
- return false;
-}
-
-static bool sign_file(ykpiv_state *state, const char *input, const char *output,
- const char *slot, enum enum_algorithm algorithm, enum enum_hash hash,
- int verbosity) {
- FILE *input_file = NULL;
- FILE *output_file = NULL;
- int key;
- unsigned int hash_len;
- unsigned char hashed[EVP_MAX_MD_SIZE];
- bool ret = false;
- int algo;
- int nid;
-
- sscanf(slot, "%x", &key);
-
- input_file = open_file(input, INPUT);
- if(!input_file) {
- return false;
- }
-
- output_file = open_file(output, OUTPUT);
- if(!output_file) {
- return false;
- }
-
- switch(algorithm) {
- case algorithm_arg_RSA2048:
- algo = YKPIV_ALGO_RSA2048;
- break;
- case algorithm_arg_RSA1024:
- algo = YKPIV_ALGO_RSA1024;
- break;
- case algorithm_arg_ECCP256:
- algo = YKPIV_ALGO_ECCP256;
- break;
- case algorithm__NULL:
- default:
- goto out;
- }
-
- {
- const EVP_MD *md;
- EVP_MD_CTX *mdctx;
-
- switch(hash) {
- case hash_arg_SHA1:
- md = EVP_sha1();
- nid = NID_sha1;
- break;
- case hash_arg_SHA256:
- md = EVP_sha256();
- nid = NID_sha256;
- break;
- case hash_arg_SHA512:
- md = EVP_sha512();
- nid = NID_sha512;
- break;
- case hash__NULL:
- default:
- goto out;
- }
-
- mdctx = EVP_MD_CTX_create();
- EVP_DigestInit_ex(mdctx, md, NULL);
- while(!feof(input_file)) {
- char buf[1024];
- size_t len = fread(buf, 1, 1024, input_file);
- EVP_DigestUpdate(mdctx, buf, len);
- }
- EVP_DigestFinal_ex(mdctx, hashed, &hash_len);
-
- if(verbosity) {
- fprintf(stderr, "file hashed as: ");
- dump_hex(hashed, hash_len);
- fprintf(stderr, "\n");
- }
- EVP_MD_CTX_destroy(mdctx);
- }
-
- if(algo == YKPIV_ALGO_RSA1024 || algo == YKPIV_ALGO_RSA2048) {
- X509_SIG digestInfo;
- X509_ALGOR algor;
- ASN1_TYPE parameter;
- ASN1_OCTET_STRING digest;
- unsigned char buf[1024];
- unsigned char *ptr = hashed;
-
- memcpy(buf, hashed, hash_len);
-
- digestInfo.algor = &algor;
- digestInfo.algor->algorithm = OBJ_nid2obj(nid);
- digestInfo.algor->parameter = ¶meter;
- digestInfo.algor->parameter->type = V_ASN1_NULL;
- digestInfo.algor->parameter->value.ptr = NULL;
- digestInfo.digest = &digest;
- digestInfo.digest->data = buf;
- digestInfo.digest->length = (int)hash_len;
- hash_len = (unsigned int)i2d_X509_SIG(&digestInfo, &ptr);
- }
-
- {
- unsigned char buf[1024];
- size_t len = sizeof(buf);
- ykpiv_rc rc = ykpiv_sign_data(state, hashed, hash_len, buf, &len, algo, key);
- if(rc != YKPIV_OK) {
- fprintf(stderr, "failed signing file: %s\n", ykpiv_strerror(rc));
- goto out;
- }
-
- if(verbosity) {
- fprintf(stderr, "file signed as: ");
- dump_hex(buf, len);
- fprintf(stderr, "\n");
- }
- fwrite(buf, 1, len, output_file);
- ret = true;
- }
-
-out:
- if(input_file && input_file != stdin) {
- fclose(input_file);
- }
-
- if(output_file && output_file != stdout) {
- fclose(output_file);
- }
-
- return ret;
-}
-
-int main(int argc, char *argv[]) {
- struct gengetopt_args_info args_info;
- ykpiv_state *state;
- int verbosity;
- int ret = EXIT_SUCCESS;
- bool rc;
-
- if(cmdline_parser(argc, argv, &args_info) != 0) {
- return EXIT_FAILURE;
- }
-
- verbosity = args_info.verbose_arg + (int)args_info.verbose_given;
-
- if(ykpiv_init(&state, verbosity) != YKPIV_OK) {
- fprintf(stderr, "Failed initializing library.\n");
- return EXIT_FAILURE;
- }
-
- if(ykpiv_connect(state, args_info.reader_arg) != YKPIV_OK) {
- fprintf(stderr, "Failed to connect to reader.\n");
- return EXIT_FAILURE;
- }
-
- if(verify_pin(state, args_info.pin_arg)) {
- if(verbosity) {
- fprintf(stderr, "Successfully verified PIN.\n");
- }
- } else {
- return EXIT_FAILURE;
- }
-
- /* openssl setup.. */
- OpenSSL_add_all_algorithms();
-
- rc = sign_file(state, args_info.input_arg, args_info.output_arg,
- args_info.slot_orig, args_info.algorithm_arg, args_info.hash_arg,
- verbosity);
-
- if(rc == false) {
- fprintf(stderr, "Failed signing!\n");
- ret = EXIT_FAILURE;
- } else {
- fprintf(stderr, "Signature successful!\n");
- }
-
- ykpiv_done(state);
- EVP_cleanup();
- return ret;
-}
diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c
index af24e6c..cd86a92 100644
--- a/tool/yubico-piv-tool.c
+++ b/tool/yubico-piv-tool.c
@@ -820,6 +820,135 @@ static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
}
}
+static bool sign_file(ykpiv_state *state, const char *input, const char *output,
+ const char *slot, enum enum_algorithm algorithm, enum enum_hash hash,
+ int verbosity) {
+ FILE *input_file = NULL;
+ FILE *output_file = NULL;
+ int key;
+ unsigned int hash_len;
+ unsigned char hashed[EVP_MAX_MD_SIZE];
+ bool ret = false;
+ int algo;
+ int nid;
+
+ sscanf(slot, "%x", &key);
+
+ input_file = open_file(input, INPUT);
+ if(!input_file) {
+ return false;
+ }
+
+ output_file = open_file(output, OUTPUT);
+ if(!output_file) {
+ return false;
+ }
+
+ switch(algorithm) {
+ case algorithm_arg_RSA2048:
+ algo = YKPIV_ALGO_RSA2048;
+ break;
+ case algorithm_arg_RSA1024:
+ algo = YKPIV_ALGO_RSA1024;
+ break;
+ case algorithm_arg_ECCP256:
+ algo = YKPIV_ALGO_ECCP256;
+ break;
+ case algorithm__NULL:
+ default:
+ goto out;
+ }
+
+ {
+ const EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+
+ switch(hash) {
+ case hash_arg_SHA1:
+ md = EVP_sha1();
+ nid = NID_sha1;
+ break;
+ case hash_arg_SHA256:
+ md = EVP_sha256();
+ nid = NID_sha256;
+ break;
+ case hash_arg_SHA512:
+ md = EVP_sha512();
+ nid = NID_sha512;
+ break;
+ case hash__NULL:
+ default:
+ goto out;
+ }
+
+ mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, md, NULL);
+ while(!feof(input_file)) {
+ char buf[1024];
+ size_t len = fread(buf, 1, 1024, input_file);
+ EVP_DigestUpdate(mdctx, buf, len);
+ }
+ EVP_DigestFinal_ex(mdctx, hashed, &hash_len);
+
+ if(verbosity) {
+ fprintf(stderr, "file hashed as: ");
+ dump_hex(hashed, hash_len);
+ fprintf(stderr, "\n");
+ }
+ EVP_MD_CTX_destroy(mdctx);
+ }
+
+ if(algo == YKPIV_ALGO_RSA1024 || algo == YKPIV_ALGO_RSA2048) {
+ X509_SIG digestInfo;
+ X509_ALGOR algor;
+ ASN1_TYPE parameter;
+ ASN1_OCTET_STRING digest;
+ unsigned char buf[1024];
+ unsigned char *ptr = hashed;
+
+ memcpy(buf, hashed, hash_len);
+
+ digestInfo.algor = &algor;
+ digestInfo.algor->algorithm = OBJ_nid2obj(nid);
+ digestInfo.algor->parameter = ¶meter;
+ digestInfo.algor->parameter->type = V_ASN1_NULL;
+ digestInfo.algor->parameter->value.ptr = NULL;
+ digestInfo.digest = &digest;
+ digestInfo.digest->data = buf;
+ digestInfo.digest->length = (int)hash_len;
+ hash_len = (unsigned int)i2d_X509_SIG(&digestInfo, &ptr);
+ }
+
+ {
+ unsigned char buf[1024];
+ size_t len = sizeof(buf);
+ ykpiv_rc rc = ykpiv_sign_data(state, hashed, hash_len, buf, &len, algo, key);
+ if(rc != YKPIV_OK) {
+ fprintf(stderr, "failed signing file: %s\n", ykpiv_strerror(rc));
+ goto out;
+ }
+
+ if(verbosity) {
+ fprintf(stderr, "file signed as: ");
+ dump_hex(buf, len);
+ fprintf(stderr, "\n");
+ }
+ fwrite(buf, 1, len, output_file);
+ ret = true;
+ }
+
+out:
+ if(input_file && input_file != stdin) {
+ fclose(input_file);
+ }
+
+ if(output_file && output_file != stdout) {
+ fclose(output_file);
+ }
+
+ return ret;
+}
+
int main(int argc, char *argv[]) {
struct gengetopt_args_info args_info;
ykpiv_state *state;
@@ -1058,6 +1187,21 @@ int main(int argc, char *argv[]) {
}
}
+ if(ret == EXIT_SUCCESS && args_info.sign_flag) {
+ if(args_info.slot_arg == slot__NULL) {
+ fprintf(stderr, "The sign action needs a slot (-s) to operate on.\n");
+ ret = EXIT_FAILURE;
+ }
+ else if(sign_file(state, args_info.input_arg, args_info.output_arg,
+ args_info.slot_orig, args_info.algorithm_arg, args_info.hash_arg,
+ verbosity)) {
+ fprintf(stderr, "Signature successful!\n");
+ } else {
+ fprintf(stderr, "Failed signing!\n");
+ ret = EXIT_FAILURE;
+ }
+ }
+
ykpiv_done(state);
EVP_cleanup();
return ret;