diff --git a/.gitignore b/.gitignore
index 4c1cce0..9363123 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,4 +65,7 @@ tool/.libs/
tool/libpiv_cmd.la
tool/libpiv_cmd_la-cmdline.lo
tool/libpiv_cmd_la-cmdline.o
+tool/libpiv_util.la
+tool/util.lo
+tool/util.o
diff --git a/tool/Makefile.am b/tool/Makefile.am
index 60f13f4..657f09e 100644
--- a/tool/Makefile.am
+++ b/tool/Makefile.am
@@ -30,12 +30,15 @@ AM_CPPFLAGS += -I$(top_srcdir)/lib -I$(top_builddir)/lib
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 libpiv_cmd.la
+yubico_piv_tool_LDADD = $(OPENSSL_LIBS) ../lib/libykpiv.la
+yubico_piv_tool_LDADD += libpiv_cmd.la libpiv_util.la
-noinst_LTLIBRARIES = libpiv_cmd.la
+noinst_LTLIBRARIES = libpiv_cmd.la libpiv_util.la
libpiv_cmd_la_SOURCES = cmdline.ggo cmdline.c cmdline.h
libpiv_cmd_la_CFLAGS =
+libpiv_util_la_SOURCES = util.c internal.h
+
cmdline.c cmdline.h: cmdline.ggo Makefile.am
$(GENGETOPT) --input $^
diff --git a/tool/internal.h b/tool/internal.h
new file mode 100644
index 0000000..03e2ca2
--- /dev/null
+++ b/tool/internal.h
@@ -0,0 +1,58 @@
+ /*
+ * 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.
+ *
+ */
+
+#ifndef YUBICO_PIV_TOOL_INTERNAL_H
+#define YUBICO_PIV_TOOL_INTERNAL_H
+
+#define INPUT 1
+#define OUTPUT 2
+
+union u_APDU {
+ struct {
+ unsigned char cla;
+ unsigned char ins;
+ unsigned char p1;
+ unsigned char p2;
+ unsigned char lc;
+ unsigned char data[0xff];
+ } st;
+ unsigned char raw[0xff + 5];
+};
+
+typedef union u_APDU APDU;
+
+void dump_hex(unsigned const char*, unsigned int);
+int set_length(unsigned char*, int);
+int get_length(unsigned char*, int*);
+X509_NAME *parse_name(char*);
+unsigned char get_algorithm(EVP_PKEY*);
+FILE *open_file(const char*, int);
+int get_object_id(enum enum_slot slot);
+
+#endif
diff --git a/tool/util.c b/tool/util.c
new file mode 100644
index 0000000..6c99119
--- /dev/null
+++ b/tool/util.c
@@ -0,0 +1,197 @@
+ /*
+ * 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
+
+#ifdef _WIN32
+#include
+#endif
+
+#include
+
+#include
+
+#include "cmdline.h"
+#include "internal.h"
+
+FILE *open_file(const char *file_name, int mode) {
+ FILE *file;
+ if(!strcmp(file_name, "-")) {
+ file = mode == INPUT ? stdin : stdout;
+ } else {
+ file = fopen(file_name, mode == INPUT ? "r" : "w");
+ if(!file) {
+ fprintf(stderr, "Failed opening '%s'!\n", file_name);
+ return NULL;
+ }
+ }
+ return file;
+}
+
+unsigned char get_algorithm(EVP_PKEY *key) {
+ int type = EVP_PKEY_type(key->type);
+ switch(type) {
+ case EVP_PKEY_RSA:
+ {
+ RSA *rsa = EVP_PKEY_get1_RSA(key);
+ int size = RSA_size(rsa);
+ if(size == 256) {
+ return YKPIV_ALGO_RSA2048;
+ } else if(size == 128) {
+ return YKPIV_ALGO_RSA1024;
+ } else {
+ fprintf(stderr, "Unuseable key of %d bits, only 1024 and 2048 is supported.\n", size * 8);
+ return 0;
+ }
+ }
+ case EVP_PKEY_EC:
+ {
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ int curve = EC_GROUP_get_curve_name(group);
+ if(curve == NID_X9_62_prime256v1) {
+ return YKPIV_ALGO_ECCP256;
+ } else {
+ fprintf(stderr, "Unknown EC curve %d\n", curve);
+ return 0;
+ }
+ }
+ default:
+ fprintf(stderr, "Unknown algorithm %d.\n", type);
+ return 0;
+ }
+}
+
+X509_NAME *parse_name(char *name) {
+ X509_NAME *parsed = NULL;
+ char *ptr = name;
+ char *part;
+ if(*name != '/') {
+ fprintf(stderr, "Name does not start with '/'!\n");
+ return NULL;
+ }
+ parsed = X509_NAME_new();
+ if(!parsed) {
+ fprintf(stderr, "Failed to allocate memory\n");
+ return NULL;
+ }
+ while((part = strtok(ptr, "/"))) {
+ char *key;
+ char *value;
+ char *equals = strchr(part, '=');
+ if(!equals) {
+ fprintf(stderr, "The part '%s' doesn't seem to contain a =.\n", part);
+ goto parse_err;
+ }
+ *equals++ = '\0';
+ value = equals;
+ key = part;
+
+ ptr = NULL;
+ if(!key) {
+ fprintf(stderr, "Malformed name (%s)\n", part);
+ goto parse_err;
+ }
+ if(!value) {
+ fprintf(stderr, "Malformed name (%s)\n", part);
+ goto parse_err;
+ }
+ if(!X509_NAME_add_entry_by_txt(parsed, key, MBSTRING_UTF8, (unsigned char*)value, -1, -1, 0)) {
+ fprintf(stderr, "Failed adding %s=%s to name.\n", key, value);
+ goto parse_err;
+ }
+ }
+ return parsed;
+parse_err:
+ X509_NAME_free(parsed);
+ return NULL;
+}
+
+void dump_hex(const unsigned char *buf, unsigned int len) {
+ unsigned int i;
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%02x ", buf[i]);
+ }
+}
+
+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;
+}
+
+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;
+ }
+}
+
+int get_object_id(enum enum_slot slot) {
+ int object;
+
+ switch(slot) {
+ case slot_arg_9a:
+ object = 0x5fc105;
+ break;
+ case slot_arg_9c:
+ object = 0x5fc10a;
+ break;
+ case slot_arg_9d:
+ object = 0x5fc10b;
+ break;
+ case slot_arg_9e:
+ object = 0x5fc101;
+ break;
+ case slot__NULL:
+ default:
+ object = 0;
+ }
+ return object;
+}
diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c
index d15c672..15e04e5 100644
--- a/tool/yubico-piv-tool.c
+++ b/tool/yubico-piv-tool.c
@@ -44,6 +44,7 @@
#include
#include "cmdline.h"
+#include "internal.h"
/* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
@@ -67,31 +68,6 @@ unsigned const char sha256oid[] = {
#define KEY_LEN 24
-#define INPUT 1
-#define OUTPUT 2
-
-union u_APDU {
- struct {
- unsigned char cla;
- unsigned char ins;
- unsigned char p1;
- unsigned char p2;
- unsigned char lc;
- unsigned char data[0xff];
- } st;
- unsigned char raw[0xff + 5];
-};
-
-typedef union u_APDU APDU;
-
-static void dump_hex(unsigned const char*, unsigned int);
-static int set_length(unsigned char*, int);
-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 int get_object_id(enum enum_slot slot);
-
static void print_version(ykpiv_state *state) {
char version[7];
if(ykpiv_get_version(state, version, sizeof(version)) == YKPIV_OK) {
@@ -905,159 +881,6 @@ static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
return ret;
}
-static FILE *open_file(const char *file_name, int mode) {
- FILE *file;
- if(!strcmp(file_name, "-")) {
- file = mode == INPUT ? stdin : stdout;
- } else {
- file = fopen(file_name, mode == INPUT ? "r" : "w");
- if(!file) {
- fprintf(stderr, "Failed opening '%s'!\n", file_name);
- return NULL;
- }
- }
- return file;
-}
-
-static unsigned char get_algorithm(EVP_PKEY *key) {
- int type = EVP_PKEY_type(key->type);
- switch(type) {
- case EVP_PKEY_RSA:
- {
- RSA *rsa = EVP_PKEY_get1_RSA(key);
- int size = RSA_size(rsa);
- if(size == 256) {
- return YKPIV_ALGO_RSA2048;
- } else if(size == 128) {
- return YKPIV_ALGO_RSA1024;
- } else {
- fprintf(stderr, "Unuseable key of %d bits, only 1024 and 2048 is supported.\n", size * 8);
- return 0;
- }
- }
- case EVP_PKEY_EC:
- {
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
- const EC_GROUP *group = EC_KEY_get0_group(ec);
- int curve = EC_GROUP_get_curve_name(group);
- if(curve == NID_X9_62_prime256v1) {
- return YKPIV_ALGO_ECCP256;
- } else {
- fprintf(stderr, "Unknown EC curve %d\n", curve);
- return 0;
- }
- }
- default:
- fprintf(stderr, "Unknown algorithm %d.\n", type);
- return 0;
- }
-}
-
-static X509_NAME *parse_name(char *name) {
- X509_NAME *parsed = NULL;
- char *ptr = name;
- char *part;
- if(*name != '/') {
- fprintf(stderr, "Name does not start with '/'!\n");
- return NULL;
- }
- parsed = X509_NAME_new();
- if(!parsed) {
- fprintf(stderr, "Failed to allocate memory\n");
- return NULL;
- }
- while((part = strtok(ptr, "/"))) {
- char *key;
- char *value;
- char *equals = strchr(part, '=');
- if(!equals) {
- fprintf(stderr, "The part '%s' doesn't seem to contain a =.\n", part);
- goto parse_err;
- }
- *equals++ = '\0';
- value = equals;
- key = part;
-
- ptr = NULL;
- if(!key) {
- fprintf(stderr, "Malformed name (%s)\n", part);
- goto parse_err;
- }
- if(!value) {
- fprintf(stderr, "Malformed name (%s)\n", part);
- goto parse_err;
- }
- if(!X509_NAME_add_entry_by_txt(parsed, key, MBSTRING_UTF8, (unsigned char*)value, -1, -1, 0)) {
- fprintf(stderr, "Failed adding %s=%s to name.\n", key, value);
- goto parse_err;
- }
- }
- return parsed;
-parse_err:
- X509_NAME_free(parsed);
- return NULL;
-}
-
-static void dump_hex(const unsigned char *buf, unsigned int len) {
- unsigned int i;
- for (i = 0; i < len; i++) {
- fprintf(stderr, "%02x ", buf[i]);
- }
-}
-
-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;
-}
-
-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_object_id(enum enum_slot slot) {
- int object;
-
- switch(slot) {
- case slot_arg_9a:
- object = 0x5fc105;
- break;
- case slot_arg_9c:
- object = 0x5fc10a;
- break;
- case slot_arg_9d:
- object = 0x5fc10b;
- break;
- case slot_arg_9e:
- object = 0x5fc101;
- break;
- case slot__NULL:
- default:
- object = 0;
- }
- return object;
-}
-
int main(int argc, char *argv[]) {
struct gengetopt_args_info args_info;
ykpiv_state *state;