]> err.no Git - yubikey-personalization.old/commitdiff
Fixed a build error in self tests when '-z muldefs' is not supported.
authorSimon Josefsson <simon@josefsson.org>
Mon, 11 Apr 2011 12:46:29 +0000 (14:46 +0200)
committerSimon Josefsson <simon@josefsson.org>
Mon, 11 Apr 2011 12:46:29 +0000 (14:46 +0200)
Makefile.am
NEWS
tests/Makefile.am
ykpers-args.c [new file with mode: 0644]
ykpers-args.h [new file with mode: 0644]
ykpersonalize.c

index c796c859eb88bb8dfc9d4015d21dbe7b50d748af..e42bb5b29fe4182ea56cc05c3dd1fb315b93789d 100644 (file)
@@ -63,7 +63,7 @@ endif
 
 bin_PROGRAMS = ykpersonalize ykchalresp
 
-ykpersonalize_SOURCES = ykpersonalize.c
+ykpersonalize_SOURCES = ykpersonalize.c ykpers-args.h ykpers-args.c
 ykpersonalize_LDADD = ./libykpers-1.la ./ykcore/libykcore.la
 
 ykchalresp_SOURCES = ykchalresp.c
diff --git a/NEWS b/NEWS
index 5525bb986bf2a8c7d7808cd286c3c9d5d439b3ae..9e683a9b112c283688b2ecc7b9aa606c89f25b34 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ use --with-backend=windows to request it.
 
 *** Fixed a crash in the self test on 64-bit platforms.
 
+*** Fixed a build error in self tests when "-z muldefs" is not supported.
+
 *** -ofixed= was incorrectly excluded from pretty-printing of configuration
 for OATH-HOTP. 
 
index 29dd782707f5284edbd34ffd68683aaa3a815432..7070d1f930d321be0c861e014bc15e76f8f45894 100644 (file)
@@ -37,7 +37,6 @@ ctests = selftest$(EXEEXT) test_args_to_config$(EXEEXT) test_key_generation$(EXE
 check_PROGRAMS = $(ctests)
 TESTS = $(ctests)
 
-test_args_to_config_LDADD = ../ykpersonalize.o $(LDADD) $(ykpersonalize_LDADD)
-test_args_to_config_LDFLAGS = -z muldefs
+test_args_to_config_LDADD = ../ykpers-args.o $(LDADD) $(ykpersonalize_LDADD)
 
 TESTS_ENVIRONMENT = $(VALGRIND)
diff --git a/ykpers-args.c b/ykpers-args.c
new file mode 100644 (file)
index 0000000..49c2baf
--- /dev/null
@@ -0,0 +1,476 @@
+/* -*- mode:C; c-file-style: "bsd" -*- */
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, Yubico AB
+ * Copyright (c) 2010  Tollef Fog Heen <tfheen@err.no>
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <ykpers.h>
+#include <yubikey.h> /* To get yubikey_modhex_encode and yubikey_hex_encode */
+#include <ykdef.h>
+
+const char *usage =
+"Usage: ykpersonalize [options]\n"
+"-1        change the first configuration.  This is the default and\n"
+"          is normally used for true OTP generation.\n"
+"          In this configuration, TKTFLAG_APPEND_CR is set by default.\n"
+"-2        change the second configuration.  This is for Yubikey II only\n"
+"          and is then normally used for static key generation.\n"
+"          In this configuration, TKTFLAG_APPEND_CR, CFGFLAG_STATIC_TICKET,\n"
+"          CFGFLAG_STRONG_PW1, CFGFLAG_STRONG_PW2 and CFGFLAG_MAN_UPDATE\n"
+"          are set by default.\n"
+"-sFILE    save configuration to FILE instead of key.\n"
+"          (if FILE is -, send to stdout)\n"
+"-iFILE    read configuration from FILE.\n"
+"          (if FILE is -, read from stdin)\n"
+"-aXXX..   The AES secret key as a 32 (or 40 for OATH-HOTP/HMAC CHAL-RESP)\n"
+"          char hex value (not modhex)\n"
+"-cXXX..   A 12 char hex value (not modhex) to use as access code for programming\n"
+"          (this does NOT SET the access code, that's done with -oaccess=)\n"
+"-oOPTION  change configuration option.  Possible OPTION arguments are:\n"
+"          salt=ssssssss       Salt to be used when deriving key from a\n"
+"                              password.  If none is given, a unique random\n"
+"                              one will be generated.\n"
+"          fixed=xxxxxxxxxxx   The public identity of key, in MODHEX.\n"
+"                              This is 0-16 characters long.\n"
+"          uid=xxxxxx          The uid part of the generated ticket, in HEX.\n"
+"                              MUST be 12 characters long.\n"
+"          access=xxxxxxxxxxx  New access code to set, in HEX.\n"
+"                              MUST be 12 characters long.\n"
+"\n"
+"          Ticket flags for all firmware versions:\n"
+"          [-]tab-first           set/clear TAB_FIRST\n"
+"          [-]append-tab1         set/clear APPEND_TAB1\n"
+"          [-]append-tab2         set/clear APPEND_TAB2\n"
+"          [-]append-delay1       set/clear APPEND_DELAY1\n"
+"          [-]append-delay2       set/clear APPEND_DELAY2\n"
+"          [-]append-cr           set/clear APPEND_CR\n"
+"\n"
+"          Ticket flags for firmware version 2.0 and above:\n"
+"          [-]protect-cfg2        set/clear PROTECT_CFG2\n"
+"\n"
+"          Ticket flags for firmware version 2.1 and above:\n"
+"          [-]oath-hotp           set/clear OATH_HOTP\n"
+"\n"
+"          Ticket flags for firmware version 2.2 and above:\n"
+"          [-]chal-resp           set/clear CHAL_RESP\n"
+"\n"
+"          Configuration flags for all firmware versions:\n"
+"          [-]send-ref            set/clear SEND_REF\n"
+"          [-]pacing-10ms         set/clear PACING_10MS\n"
+"          [-]pacing-20ms         set/clear PACING_20MS\n"
+"          [-]static-ticket       set/clear STATIC_TICKET\n"
+"\n"
+"          Configuration flags for firmware version 1.x only:\n"
+"          [-]ticket-first        set/clear TICKET_FIRST\n"
+"          [-]allow-hidtrig       set/clear ALLOW_HIDTRIG\n"
+"\n"
+"          Configuration flags for firmware version 2.0 and above:\n"
+"          [-]short-ticket        set/clear SHORT_TICKET\n"
+"          [-]strong-pw1          set/clear STRONG_PW1\n"
+"          [-]strong-pw2          set/clear STRONG_PW2\n"
+"          [-]man-update          set/clear MAN_UPDATE\n"
+"\n"
+"          Configuration flags for firmware version 2.1 and above:\n"
+"          [-]oath-hotp8          set/clear OATH_HOTP8\n"
+"          [-]oath-fixed-modhex1  set/clear OATH_FIXED_MODHEX1\n"
+"          [-]oath-fixed-modhex2  set/clear OATH_FIXED_MODHEX2\n"
+"          [-]oath-fixed-modhex   set/clear OATH_MODHEX\n"
+"\n"
+"          Configuration flags for firmware version 2.2 and above:\n"
+"          [-]chal-yubico         set/clear CHAL_YUBICO\n"
+"          [-]chal-hmac           set/clear CHAL_HMAC\n"
+"          [-]hmac-lt64           set/clear HMAC_LT64\n"
+"          [-]chal-btn-trig       set/clear CHAL_BTN_TRIG\n"
+"\n"
+"          Extended flags for firmware version 2.2 and above:\n"
+"          [-]serial-btn-visible  set/clear SERIAL_BTN_VISIBLE\n"
+"          [-]serial-usb-visible  set/clear SERIAL_USB_VISIBLE\n"
+"          [-]serial-api-visible  set/clear SERIAL_API_VISIBLE\n"
+"\n"
+"-y        always commit (do not prompt)\n"
+"\n"
+"-v        verbose\n"
+"-h        help (this text)\n"
+;
+const char *optstring = "12a:c:hi:o:s:vy";
+
+static int hex_modhex_decode(unsigned char *result, size_t *resultlen,
+                            const char *str, size_t strl,
+                            size_t minsize, size_t maxsize,
+                            bool primarily_modhex)
+{
+       if (strl >= 2) {
+               if (strncmp(str, "m:", 2) == 0
+                   || strncmp(str, "M:", 2) == 0) {
+                       str += 2;
+                       strl -= 2;
+                       primarily_modhex = true;
+               } else if (strncmp(str, "h:", 2) == 0
+                          || strncmp(str, "H:", 2) == 0) {
+                       str += 2;
+                       strl -= 2;
+                       primarily_modhex = false;
+               }
+       }
+
+       if ((strl % 2 != 0) || (strl < minsize) || (strl > maxsize)) {
+               return -1;
+       }
+
+       *resultlen = strl / 2;
+       if (primarily_modhex) {
+               if (yubikey_modhex_p(str)) {
+                       yubikey_modhex_decode((char *)result, str, strl);
+                       return 1;
+               }
+       } else {
+               if (yubikey_hex_p(str)) {
+                       yubikey_hex_decode((char *)result, str, strl);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+void report_yk_error()
+{
+       if (ykp_errno)
+               fprintf(stderr, "Yubikey personalization error: %s\n",
+                       ykp_strerror(ykp_errno));
+       if (yk_errno) {
+               if (yk_errno == YK_EUSBERR) {
+                       fprintf(stderr, "USB error: %s\n",
+                               yk_usb_strerror());
+               } else {
+                       fprintf(stderr, "Yubikey core error: %s\n",
+                               yk_strerror(yk_errno));
+               }
+       }
+}
+
+/*
+ * Parse all arguments supplied to this program and turn it into mainly
+ * a YKP_CONFIG (but return some other parameters as well, like
+ * access_code, verbose etc.).
+ *
+ * Done in this way to be testable (see tests/test_args_to_config.c).
+ */
+int args_to_config(int argc, char **argv, YKP_CONFIG *cfg,
+                  const char **infname, const char **outfname,
+                  bool *autocommit, char *salt,
+                  YK_STATUS *st, bool *verbose,
+                  unsigned char *access_code, bool *use_access_code,
+                  bool *aesviahash,
+                  int *exit_code)
+{
+       char c;
+       const char *aeshash = NULL;
+       bool new_access_code = false;
+       bool slot_chosen = false;
+       bool mode_chosen = false;
+       bool option_seen = false;
+
+       struct config_st *ycfg = (struct config_st *) ykp_core_config(cfg);
+
+       while((c = getopt(argc, argv, optstring)) != -1) {
+               if (c == 'o') {
+                       if (strcmp(optarg, "oath-hotp") == 0 ||
+                           strcmp(optarg, "chal-resp") == 0) {
+                               if (mode_chosen) {
+                                       fprintf(stderr, "You may only choose mode (-ooath-hotp / "
+                                               "-ochal-resp) once.\n");
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+
+                               if (option_seen) {
+                                       fprintf(stderr, "Mode choosing flags (oath-hotp / chal-resp) "
+                                               "must be set prior to any other options (-o).\n");
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+
+                               /* The default flags (particularly for slot 2) does not apply to
+                                * these new modes of operation found in Yubikey >= 2.1. Therefor,
+                                * we reset them here and, as a consequence of that, require the
+                                * mode choosing options to be specified before any other.
+                                */
+                               ycfg->tktFlags = 0;
+                               ycfg->cfgFlags = 0;
+                               ycfg->extFlags = 0;
+
+                               mode_chosen = 1;
+                       }
+
+                       option_seen = true;
+               }
+
+               switch (c) {
+               case '1':
+                       if (slot_chosen) {
+                               fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
+                               *exit_code = 1;
+                               return 0;
+                       }
+                       if (!ykp_configure_for(cfg, 1, st))
+                               return 0;
+                       slot_chosen = true;
+                       break;
+               case '2':
+                       if (slot_chosen) {
+                               fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
+                               *exit_code = 1;
+                               return 0;
+                       }
+                       if (!ykp_configure_for(cfg, 2, st))
+                               return 0;
+                       slot_chosen = true;
+                       break;
+               case 'i':
+                       *infname = optarg;
+                       break;
+               case 's':
+                       *outfname = optarg;
+                       break;
+               case 'a':
+                       *aesviahash = true;
+                       aeshash = optarg;
+                       break;
+               case 'c': {
+                       size_t access_code_len = 0;
+                       int rc = hex_modhex_decode(access_code, &access_code_len,
+                                                  optarg, strlen(optarg),
+                                                  12, 12, false);
+                       if (rc <= 0) {
+                               fprintf(stderr,
+                                       "Invalid access code string: %s\n",
+                                       optarg);
+                               *exit_code = 1;
+                               return 0;
+                       }
+                       if (!new_access_code)
+                               ykp_set_access_code(cfg,
+                                                   access_code,
+                                                   access_code_len);
+                       *use_access_code = true;
+                       break;
+               }
+               case 'o':
+                       if (strncmp(optarg, "salt=", 5) == 0)
+                               salt = strdup(optarg+5);
+                       else if (strncmp(optarg, "fixed=", 6) == 0) {
+                               const char *fixed = optarg+6;
+                               size_t fixedlen = strlen (fixed);
+                               unsigned char fixedbin[256];
+                               size_t fixedbinlen = 0;
+                               int rc = hex_modhex_decode(fixedbin, &fixedbinlen,
+                                                          fixed, fixedlen,
+                                                          0, 16, true);
+                               if (rc <= 0) {
+                                       fprintf(stderr,
+                                               "Invalid fixed string: %s\n",
+                                               fixed);
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+                               ykp_set_fixed(cfg, fixedbin, fixedbinlen);
+                       }
+                       else if (strncmp(optarg, "uid=", 4) == 0) {
+                               const char *uid = optarg+4;
+                               size_t uidlen = strlen (uid);
+                               unsigned char uidbin[256];
+                               size_t uidbinlen = 0;
+                               int rc = hex_modhex_decode(uidbin, &uidbinlen,
+                                                          uid, uidlen,
+                                                          12, 12, false);
+                               if (rc <= 0) {
+                                       fprintf(stderr,
+                                               "Invalid uid string: %s\n",
+                                               uid);
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+                               /* for OATH-HOTP and CHAL-RESP, uid is not applicable */
+                               if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP ||
+                                   (ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP) {
+                                       fprintf(stderr,
+                                               "Option uid= not valid with -ooath-hotp or -ochal-resp.\n"
+                                               );
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+                               ykp_set_uid(cfg, uidbin, uidbinlen);
+                       }
+                       else if (strncmp(optarg, "access=", 7) == 0) {
+                               const char *acc = optarg+7;
+                               size_t acclen = strlen (acc);
+                               unsigned char accbin[256];
+                               size_t accbinlen = 0;
+                               int rc = hex_modhex_decode (accbin, &accbinlen,
+                                                           acc, acclen,
+                                                           12, 12, false);
+                               if (rc <= 0) {
+                                       fprintf(stderr,
+                                               "Invalid access code string: %s\n",
+                                               acc);
+                                       *exit_code = 1;
+                                       return 0;
+                               }
+                               ykp_set_access_code(cfg, accbin, accbinlen);
+                               new_access_code = true;
+                       }
+#define TKTFLAG(o, f)                                                  \
+                       else if (strcmp(optarg, o) == 0) {              \
+                               if (!ykp_set_tktflag_##f(cfg, true)) {  \
+                                       *exit_code = 1;                 \
+                                       return 0;               \
+                               }                                       \
+                       } else if (strcmp(optarg, "-" o) == 0) {        \
+                               if (! ykp_set_tktflag_##f(cfg, false)) { \
+                                       *exit_code = 1;                 \
+                                       return 0;               \
+                               }                                       \
+                       }
+                       TKTFLAG("tab-first", TAB_FIRST)
+                       TKTFLAG("append-tab1", APPEND_TAB1)
+                       TKTFLAG("append-tab2", APPEND_TAB2)
+                       TKTFLAG("append-delay1", APPEND_DELAY1)
+                       TKTFLAG("append-delay2", APPEND_DELAY2)
+                       TKTFLAG("append-cr", APPEND_CR)
+                       TKTFLAG("protect-cfg2", PROTECT_CFG2)
+                       TKTFLAG("oath-hotp", OATH_HOTP)
+                       TKTFLAG("chal-resp", CHAL_RESP)
+#undef TKTFLAG
+
+#define CFGFLAG(o, f)                                                  \
+                       else if (strcmp(optarg, o) == 0) {              \
+                               if (! ykp_set_cfgflag_##f(cfg, true)) { \
+                                       *exit_code = 1;                 \
+                                       return 0;                       \
+                               }                                       \
+                       } else if (strcmp(optarg, "-" o) == 0) {        \
+                               if (! ykp_set_cfgflag_##f(cfg, false)) { \
+                                       *exit_code = 1;                 \
+                                       return 0;                       \
+                               }                                       \
+                       }
+                       CFGFLAG("send-ref", SEND_REF)
+                       CFGFLAG("ticket-first", TICKET_FIRST)
+                       CFGFLAG("pacing-10ms", PACING_10MS)
+                       CFGFLAG("pacing-20ms", PACING_20MS)
+                       CFGFLAG("allow-hidtrig", ALLOW_HIDTRIG)
+                       CFGFLAG("static-ticket", STATIC_TICKET)
+                       CFGFLAG("short-ticket", SHORT_TICKET)
+                       CFGFLAG("strong-pw1", STRONG_PW1)
+                       CFGFLAG("strong-pw2", STRONG_PW2)
+                       CFGFLAG("man-update", MAN_UPDATE)
+                       CFGFLAG("oath-hotp8", OATH_HOTP8)
+                       CFGFLAG("oath-fixed-modhex1", OATH_FIXED_MODHEX1)
+                       CFGFLAG("oath-fixed-modhex2", OATH_FIXED_MODHEX2)
+                       CFGFLAG("oath-fixed-modhex", OATH_FIXED_MODHEX)
+                       CFGFLAG("chal-yubico", CHAL_YUBICO)
+                       CFGFLAG("chal-hmac", CHAL_HMAC)
+                       CFGFLAG("hmac-lt64", HMAC_LT64)
+                       CFGFLAG("chal-btn-trig", CHAL_BTN_TRIG)
+#undef CFGFLAG
+
+#define EXTFLAG(o, f)                                                  \
+                       else if (strcmp(optarg, o) == 0) {              \
+                               if (! ykp_set_extflag_##f(cfg, true)) { \
+                                       *exit_code = 1;                 \
+                                       return 0;                       \
+                               }                                       \
+                       } else if (strcmp(optarg, "-" o) == 0) {        \
+                               if (! ykp_set_extflag_##f(cfg, false)) { \
+                                       *exit_code = 1;                 \
+                                       return 0;                       \
+                               }                                       \
+                       }
+                       EXTFLAG("serial-btn-visible", SERIAL_BTN_VISIBLE)
+                       EXTFLAG("serial-usb-visible", SERIAL_USB_VISIBLE)
+                       EXTFLAG("serial-api-visible", SERIAL_API_VISIBLE)
+#undef EXTFLAG
+                       else {
+                               fprintf(stderr, "Unknown option '%s'\n",
+                                       optarg);
+                               fputs(usage, stderr);
+                               *exit_code = 1;
+                               return 0;
+                       }
+                       break;
+               case 'v':
+                       *verbose = true;
+                       break;
+               case 'y':
+                       *autocommit = true;
+                       break;
+               case 'h':
+               default:
+                       fputs(usage, stderr);
+                       *exit_code = 0;
+                       return 0;
+               }
+       }
+
+       if (*aesviahash) {
+               bool long_key_valid = false;
+               int res = 0;
+
+               /* for OATH-HOTP, 160 bits key is also valid */
+               if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
+                       long_key_valid = true;
+
+               /* for HMAC (not Yubico) challenge-response, 160 bits key is also valid */
+               if ((ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
+                   (ycfg->cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
+                       long_key_valid = true;
+               }
+
+               if (long_key_valid && strlen(aeshash) == 40) {
+                       res = ykp_HMAC_key_from_hex(cfg, aeshash);
+               } else {
+                       res = ykp_AES_key_from_hex(cfg, aeshash);
+               }
+
+               if (res) {
+                       fprintf(stderr, "Bad %s key: %s\n", long_key_valid ? "HMAC":"AES", aeshash);
+                       fflush(stderr);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
diff --git a/ykpers-args.h b/ykpers-args.h
new file mode 100644 (file)
index 0000000..873b2ef
--- /dev/null
@@ -0,0 +1,46 @@
+/* -*- mode:C; c-file-style: "bsd" -*- */
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 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.
+ */
+
+#ifndef YKPERS_ARGS_H
+#define YKPERS_ARGS_H
+
+const char *usage;
+
+int args_to_config(int argc, char **argv, YKP_CONFIG *cfg,
+                  const char **infname, const char **outfname,
+                  bool *autocommit, char *salt,
+                  YK_STATUS *st, bool *verbose,
+                  unsigned char *access_code, bool *use_access_code,
+                  bool *aesviahash,
+                  int *exit_code);
+
+void report_yk_error();
+
+#endif
index 44f470f1227cf1b60c6d320988cf4bf1f1d31bd2..581c829801c1b3ca1ca632d6cd902760df469126 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode:C; c-file-style: "bsd" -*- */
 /*
- * Copyright (c) 2008, 2009, 2010, Yubico AB
+ * Copyright (c) 2008, 2009, 2010, 2011, Yubico AB
  * Copyright (c) 2010  Tollef Fog Heen <tfheen@err.no>
  * All rights reserved.
  *
 #include <errno.h>
 
 #include <ykpers.h>
-#include <yubikey.h> /* To get yubikey_modhex_encode and yubikey_hex_encode */
 #include <ykdef.h>
 
-const char *usage =
-"Usage: ykpersonalize [options]\n"
-"-1        change the first configuration.  This is the default and\n"
-"          is normally used for true OTP generation.\n"
-"          In this configuration, TKTFLAG_APPEND_CR is set by default.\n"
-"-2        change the second configuration.  This is for Yubikey II only\n"
-"          and is then normally used for static key generation.\n"
-"          In this configuration, TKTFLAG_APPEND_CR, CFGFLAG_STATIC_TICKET,\n"
-"          CFGFLAG_STRONG_PW1, CFGFLAG_STRONG_PW2 and CFGFLAG_MAN_UPDATE\n"
-"          are set by default.\n"
-"-sFILE    save configuration to FILE instead of key.\n"
-"          (if FILE is -, send to stdout)\n"
-"-iFILE    read configuration from FILE.\n"
-"          (if FILE is -, read from stdin)\n"
-"-aXXX..   The AES secret key as a 32 (or 40 for OATH-HOTP/HMAC CHAL-RESP)\n"
-"          char hex value (not modhex)\n"
-"-cXXX..   A 12 char hex value (not modhex) to use as access code for programming\n"
-"          (this does NOT SET the access code, that's done with -oaccess=)\n"
-"-oOPTION  change configuration option.  Possible OPTION arguments are:\n"
-"          salt=ssssssss       Salt to be used when deriving key from a\n"
-"                              password.  If none is given, a unique random\n"
-"                              one will be generated.\n"
-"          fixed=xxxxxxxxxxx   The public identity of key, in MODHEX.\n"
-"                              This is 0-16 characters long.\n"
-"          uid=xxxxxx          The uid part of the generated ticket, in HEX.\n"
-"                              MUST be 12 characters long.\n"
-"          access=xxxxxxxxxxx  New access code to set, in HEX.\n"
-"                              MUST be 12 characters long.\n"
-"\n"
-"          Ticket flags for all firmware versions:\n"
-"          [-]tab-first           set/clear TAB_FIRST\n"
-"          [-]append-tab1         set/clear APPEND_TAB1\n"
-"          [-]append-tab2         set/clear APPEND_TAB2\n"
-"          [-]append-delay1       set/clear APPEND_DELAY1\n"
-"          [-]append-delay2       set/clear APPEND_DELAY2\n"
-"          [-]append-cr           set/clear APPEND_CR\n"
-"\n"
-"          Ticket flags for firmware version 2.0 and above:\n"
-"          [-]protect-cfg2        set/clear PROTECT_CFG2\n"
-"\n"
-"          Ticket flags for firmware version 2.1 and above:\n"
-"          [-]oath-hotp           set/clear OATH_HOTP\n"
-"\n"
-"          Ticket flags for firmware version 2.2 and above:\n"
-"          [-]chal-resp           set/clear CHAL_RESP\n"
-"\n"
-"          Configuration flags for all firmware versions:\n"
-"          [-]send-ref            set/clear SEND_REF\n"
-"          [-]pacing-10ms         set/clear PACING_10MS\n"
-"          [-]pacing-20ms         set/clear PACING_20MS\n"
-"          [-]static-ticket       set/clear STATIC_TICKET\n"
-"\n"
-"          Configuration flags for firmware version 1.x only:\n"
-"          [-]ticket-first        set/clear TICKET_FIRST\n"
-"          [-]allow-hidtrig       set/clear ALLOW_HIDTRIG\n"
-"\n"
-"          Configuration flags for firmware version 2.0 and above:\n"
-"          [-]short-ticket        set/clear SHORT_TICKET\n"
-"          [-]strong-pw1          set/clear STRONG_PW1\n"
-"          [-]strong-pw2          set/clear STRONG_PW2\n"
-"          [-]man-update          set/clear MAN_UPDATE\n"
-"\n"
-"          Configuration flags for firmware version 2.1 and above:\n"
-"          [-]oath-hotp8          set/clear OATH_HOTP8\n"
-"          [-]oath-fixed-modhex1  set/clear OATH_FIXED_MODHEX1\n"
-"          [-]oath-fixed-modhex2  set/clear OATH_FIXED_MODHEX2\n"
-"          [-]oath-fixed-modhex   set/clear OATH_MODHEX\n"
-"\n"
-"          Configuration flags for firmware version 2.2 and above:\n"
-"          [-]chal-yubico         set/clear CHAL_YUBICO\n"
-"          [-]chal-hmac           set/clear CHAL_HMAC\n"
-"          [-]hmac-lt64           set/clear HMAC_LT64\n"
-"          [-]chal-btn-trig       set/clear CHAL_BTN_TRIG\n"
-"\n"
-"          Extended flags for firmware version 2.2 and above:\n"
-"          [-]serial-btn-visible  set/clear SERIAL_BTN_VISIBLE\n"
-"          [-]serial-usb-visible  set/clear SERIAL_USB_VISIBLE\n"
-"          [-]serial-api-visible  set/clear SERIAL_API_VISIBLE\n"
-"\n"
-"-y        always commit (do not prompt)\n"
-"\n"
-"-v        verbose\n"
-"-h        help (this text)\n"
-;
-const char *optstring = "12a:c:hi:o:s:vy";
+#include "ykpers-args.h"
 
 static int reader(char *buf, size_t count, void *stream)
 {
@@ -135,355 +50,6 @@ static int writer(const char *buf, size_t count, void *stream)
        return (int)fwrite(buf, 1, count, (FILE *)stream);
 }
 
-static int hex_modhex_decode(unsigned char *result, size_t *resultlen,
-                            const char *str, size_t strl,
-                            size_t minsize, size_t maxsize,
-                            bool primarily_modhex)
-{
-       if (strl >= 2) {
-               if (strncmp(str, "m:", 2) == 0
-                   || strncmp(str, "M:", 2) == 0) {
-                       str += 2;
-                       strl -= 2;
-                       primarily_modhex = true;
-               } else if (strncmp(str, "h:", 2) == 0
-                          || strncmp(str, "H:", 2) == 0) {
-                       str += 2;
-                       strl -= 2;
-                       primarily_modhex = false;
-               }
-       }
-
-       if ((strl % 2 != 0) || (strl < minsize) || (strl > maxsize)) {
-               return -1;
-       }
-
-       *resultlen = strl / 2;
-       if (primarily_modhex) {
-               if (yubikey_modhex_p(str)) {
-                       yubikey_modhex_decode((char *)result, str, strl);
-                       return 1;
-               }
-       } else {
-               if (yubikey_hex_p(str)) {
-                       yubikey_hex_decode((char *)result, str, strl);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static void report_yk_error()
-{
-       if (ykp_errno)
-               fprintf(stderr, "Yubikey personalization error: %s\n",
-                       ykp_strerror(ykp_errno));
-       if (yk_errno) {
-               if (yk_errno == YK_EUSBERR) {
-                       fprintf(stderr, "USB error: %s\n",
-                               yk_usb_strerror());
-               } else {
-                       fprintf(stderr, "Yubikey core error: %s\n",
-                               yk_strerror(yk_errno));
-               }
-       }
-}
-
-/*
- * Parse all arguments supplied to this program and turn it into mainly
- * a YKP_CONFIG (but return some other parameters as well, like
- * access_code, verbose etc.).
- *
- * Done in this way to be testable (see tests/test_args_to_config.c).
- */
-int args_to_config(int argc, char **argv, YKP_CONFIG *cfg,
-                  const char **infname, const char **outfname,
-                  bool *autocommit, char *salt,
-                  YK_STATUS *st, bool *verbose,
-                  unsigned char *access_code, bool *use_access_code,
-                  bool *aesviahash,
-                  int *exit_code)
-{
-       char c;
-       const char *aeshash = NULL;
-       bool new_access_code = false;
-       bool slot_chosen = false;
-       bool mode_chosen = false;
-       bool option_seen = false;
-
-       struct config_st *ycfg = (struct config_st *) ykp_core_config(cfg);
-
-       while((c = getopt(argc, argv, optstring)) != -1) {
-               if (c == 'o') {
-                       if (strcmp(optarg, "oath-hotp") == 0 ||
-                           strcmp(optarg, "chal-resp") == 0) {
-                               if (mode_chosen) {
-                                       fprintf(stderr, "You may only choose mode (-ooath-hotp / "
-                                               "-ochal-resp) once.\n");
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-
-                               if (option_seen) {
-                                       fprintf(stderr, "Mode choosing flags (oath-hotp / chal-resp) "
-                                               "must be set prior to any other options (-o).\n");
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-
-                               /* The default flags (particularly for slot 2) does not apply to
-                                * these new modes of operation found in Yubikey >= 2.1. Therefor,
-                                * we reset them here and, as a consequence of that, require the
-                                * mode choosing options to be specified before any other.
-                                */
-                               ycfg->tktFlags = 0;
-                               ycfg->cfgFlags = 0;
-                               ycfg->extFlags = 0;
-
-                               mode_chosen = 1;
-                       }
-
-                       option_seen = true;
-               }
-
-               switch (c) {
-               case '1':
-                       if (slot_chosen) {
-                               fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
-                               *exit_code = 1;
-                               return 0;
-                       }
-                       if (!ykp_configure_for(cfg, 1, st))
-                               return 0;
-                       slot_chosen = true;
-                       break;
-               case '2':
-                       if (slot_chosen) {
-                               fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
-                               *exit_code = 1;
-                               return 0;
-                       }
-                       if (!ykp_configure_for(cfg, 2, st))
-                               return 0;
-                       slot_chosen = true;
-                       break;
-               case 'i':
-                       *infname = optarg;
-                       break;
-               case 's':
-                       *outfname = optarg;
-                       break;
-               case 'a':
-                       *aesviahash = true;
-                       aeshash = optarg;
-                       break;
-               case 'c': {
-                       size_t access_code_len = 0;
-                       int rc = hex_modhex_decode(access_code, &access_code_len,
-                                                  optarg, strlen(optarg),
-                                                  12, 12, false);
-                       if (rc <= 0) {
-                               fprintf(stderr,
-                                       "Invalid access code string: %s\n",
-                                       optarg);
-                               *exit_code = 1;
-                               return 0;
-                       }
-                       if (!new_access_code)
-                               ykp_set_access_code(cfg,
-                                                   access_code,
-                                                   access_code_len);
-                       *use_access_code = true;
-                       break;
-               }
-               case 'o':
-                       if (strncmp(optarg, "salt=", 5) == 0)
-                               salt = strdup(optarg+5);
-                       else if (strncmp(optarg, "fixed=", 6) == 0) {
-                               const char *fixed = optarg+6;
-                               size_t fixedlen = strlen (fixed);
-                               unsigned char fixedbin[256];
-                               size_t fixedbinlen = 0;
-                               int rc = hex_modhex_decode(fixedbin, &fixedbinlen,
-                                                          fixed, fixedlen,
-                                                          0, 16, true);
-                               if (rc <= 0) {
-                                       fprintf(stderr,
-                                               "Invalid fixed string: %s\n",
-                                               fixed);
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-                               ykp_set_fixed(cfg, fixedbin, fixedbinlen);
-                       }
-                       else if (strncmp(optarg, "uid=", 4) == 0) {
-                               const char *uid = optarg+4;
-                               size_t uidlen = strlen (uid);
-                               unsigned char uidbin[256];
-                               size_t uidbinlen = 0;
-                               int rc = hex_modhex_decode(uidbin, &uidbinlen,
-                                                          uid, uidlen,
-                                                          12, 12, false);
-                               if (rc <= 0) {
-                                       fprintf(stderr,
-                                               "Invalid uid string: %s\n",
-                                               uid);
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-                               /* for OATH-HOTP and CHAL-RESP, uid is not applicable */
-                               if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP ||
-                                   (ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP) {
-                                       fprintf(stderr,
-                                               "Option uid= not valid with -ooath-hotp or -ochal-resp.\n"
-                                               );
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-                               ykp_set_uid(cfg, uidbin, uidbinlen);
-                       }
-                       else if (strncmp(optarg, "access=", 7) == 0) {
-                               const char *acc = optarg+7;
-                               size_t acclen = strlen (acc);
-                               unsigned char accbin[256];
-                               size_t accbinlen = 0;
-                               int rc = hex_modhex_decode (accbin, &accbinlen,
-                                                           acc, acclen,
-                                                           12, 12, false);
-                               if (rc <= 0) {
-                                       fprintf(stderr,
-                                               "Invalid access code string: %s\n",
-                                               acc);
-                                       *exit_code = 1;
-                                       return 0;
-                               }
-                               ykp_set_access_code(cfg, accbin, accbinlen);
-                               new_access_code = true;
-                       }
-#define TKTFLAG(o, f)                                                  \
-                       else if (strcmp(optarg, o) == 0) {              \
-                               if (!ykp_set_tktflag_##f(cfg, true)) {  \
-                                       *exit_code = 1;                 \
-                                       return 0;               \
-                               }                                       \
-                       } else if (strcmp(optarg, "-" o) == 0) {        \
-                               if (! ykp_set_tktflag_##f(cfg, false)) { \
-                                       *exit_code = 1;                 \
-                                       return 0;               \
-                               }                                       \
-                       }
-                       TKTFLAG("tab-first", TAB_FIRST)
-                       TKTFLAG("append-tab1", APPEND_TAB1)
-                       TKTFLAG("append-tab2", APPEND_TAB2)
-                       TKTFLAG("append-delay1", APPEND_DELAY1)
-                       TKTFLAG("append-delay2", APPEND_DELAY2)
-                       TKTFLAG("append-cr", APPEND_CR)
-                       TKTFLAG("protect-cfg2", PROTECT_CFG2)
-                       TKTFLAG("oath-hotp", OATH_HOTP)
-                       TKTFLAG("chal-resp", CHAL_RESP)
-#undef TKTFLAG
-
-#define CFGFLAG(o, f)                                                  \
-                       else if (strcmp(optarg, o) == 0) {              \
-                               if (! ykp_set_cfgflag_##f(cfg, true)) { \
-                                       *exit_code = 1;                 \
-                                       return 0;                       \
-                               }                                       \
-                       } else if (strcmp(optarg, "-" o) == 0) {        \
-                               if (! ykp_set_cfgflag_##f(cfg, false)) { \
-                                       *exit_code = 1;                 \
-                                       return 0;                       \
-                               }                                       \
-                       }
-                       CFGFLAG("send-ref", SEND_REF)
-                       CFGFLAG("ticket-first", TICKET_FIRST)
-                       CFGFLAG("pacing-10ms", PACING_10MS)
-                       CFGFLAG("pacing-20ms", PACING_20MS)
-                       CFGFLAG("allow-hidtrig", ALLOW_HIDTRIG)
-                       CFGFLAG("static-ticket", STATIC_TICKET)
-                       CFGFLAG("short-ticket", SHORT_TICKET)
-                       CFGFLAG("strong-pw1", STRONG_PW1)
-                       CFGFLAG("strong-pw2", STRONG_PW2)
-                       CFGFLAG("man-update", MAN_UPDATE)
-                       CFGFLAG("oath-hotp8", OATH_HOTP8)
-                       CFGFLAG("oath-fixed-modhex1", OATH_FIXED_MODHEX1)
-                       CFGFLAG("oath-fixed-modhex2", OATH_FIXED_MODHEX2)
-                       CFGFLAG("oath-fixed-modhex", OATH_FIXED_MODHEX)
-                       CFGFLAG("chal-yubico", CHAL_YUBICO)
-                       CFGFLAG("chal-hmac", CHAL_HMAC)
-                       CFGFLAG("hmac-lt64", HMAC_LT64)
-                       CFGFLAG("chal-btn-trig", CHAL_BTN_TRIG)
-#undef CFGFLAG
-
-#define EXTFLAG(o, f)                                                  \
-                       else if (strcmp(optarg, o) == 0) {              \
-                               if (! ykp_set_extflag_##f(cfg, true)) { \
-                                       *exit_code = 1;                 \
-                                       return 0;                       \
-                               }                                       \
-                       } else if (strcmp(optarg, "-" o) == 0) {        \
-                               if (! ykp_set_extflag_##f(cfg, false)) { \
-                                       *exit_code = 1;                 \
-                                       return 0;                       \
-                               }                                       \
-                       }
-                       EXTFLAG("serial-btn-visible", SERIAL_BTN_VISIBLE)
-                       EXTFLAG("serial-usb-visible", SERIAL_USB_VISIBLE)
-                       EXTFLAG("serial-api-visible", SERIAL_API_VISIBLE)
-#undef EXTFLAG
-                       else {
-                               fprintf(stderr, "Unknown option '%s'\n",
-                                       optarg);
-                               fputs(usage, stderr);
-                               *exit_code = 1;
-                               return 0;
-                       }
-                       break;
-               case 'v':
-                       *verbose = true;
-                       break;
-               case 'y':
-                       *autocommit = true;
-                       break;
-               case 'h':
-               default:
-                       fputs(usage, stderr);
-                       *exit_code = 0;
-                       return 0;
-               }
-       }
-
-       if (*aesviahash) {
-               bool long_key_valid = false;
-               int res = 0;
-
-               /* for OATH-HOTP, 160 bits key is also valid */
-               if ((ycfg->tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
-                       long_key_valid = true;
-
-               /* for HMAC (not Yubico) challenge-response, 160 bits key is also valid */
-               if ((ycfg->tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
-                   (ycfg->cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
-                       long_key_valid = true;
-               }
-
-               if (long_key_valid && strlen(aeshash) == 40) {
-                       res = ykp_HMAC_key_from_hex(cfg, aeshash);
-               } else {
-                       res = ykp_AES_key_from_hex(cfg, aeshash);
-               }
-
-               if (res) {
-                       fprintf(stderr, "Bad %s key: %s\n", long_key_valid ? "HMAC":"AES", aeshash);
-                       fflush(stderr);
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
 int main(int argc, char **argv)
 {
        FILE *inf = NULL; const char *infname = NULL;