1 /* -*- mode:C; c-file-style: "bsd" -*- */
3 * Copyright (c) 2008-2014 Yubico AB
4 * Copyright (c) 2010 Tollef Fog Heen <tfheen@err.no>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include <yubikey.h> /* To get yubikey_modhex_encode and yubikey_hex_encode */
43 #include <ykpers-version.h>
44 #include "ykpers-args.h"
46 #define YUBICO_OATH_VENDOR_ID_HEX 0xe1 /* UB as hex */
47 #define YUBICO_HOTP_EVENT_TOKEN_TYPE 0x63 /* HE as hex */
50 "Usage: ykpersonalize [options]\n"
51 "-u update configuration without overwriting. This is only available\n"
52 " in YubiKey 2.3 and later. EXTFLAG_ALLOW_UPDATE will be set by\n"
54 "-1 change the first configuration. This is the default and\n"
55 " is normally used for true OTP generation.\n"
56 " In this configuration, TKTFLAG_APPEND_CR is set by default.\n"
57 "-2 change the second configuration. This is for Yubikey II only\n"
58 " and is then normally used for static key generation.\n"
59 " In this configuration, TKTFLAG_APPEND_CR, CFGFLAG_STATIC_TICKET,\n"
60 " CFGFLAG_STRONG_PW1, CFGFLAG_STRONG_PW2 and CFGFLAG_MAN_UPDATE\n"
61 " are set by default.\n"
62 "-x swap the configuration in slot 1 and 2. This is for YubiKey 2.3\n"
64 "-z delete the configuration in slot 1 or 2.\n"
65 "-sFILE save configuration to FILE instead of key.\n"
66 " (if FILE is -, send to stdout)\n"
67 "-iFILE read configuration from FILE.\n"
68 " (if FILE is -, read from stdin)\n"
69 "-fformat set the data format for -s and -i valid values are ycfg or legacy.\n"
70 "-a[XXX..] The AES secret key as a 32 (or 40 for OATH-HOTP/HMAC CHAL-RESP)\n"
71 " char hex value (not modhex) (none to prompt for key on stdin)\n"
72 " If -a is not used a random key will be generated.\n"
73 "-cXXX.. A 12 char hex value (not modhex) to use as access code for programming\n"
74 " (this does NOT SET the access code, that's done with -oaccess=)\n"
75 "-nXXX.. Write NDEF URI to YubiKey NEO, must be used with -1 or -2\n"
76 "-tXXX.. Write NDEF text to YubiKey NEO, must be used with -1 or -2\n"
77 "-mMODE Set the USB device configuration of the YubiKey NEO.\n"
78 " See the manpage for details\n"
79 "-S0605.. Set the scanmap to use with the YubiKey NEO. Must be 45 unique bytes,\n"
80 " in hex. Use with no argument to reset to the default.\n"
81 "-oOPTION change configuration option. Possible OPTION arguments are:\n"
82 " fixed=xxxxxxxxxxx The public identity of key, in MODHEX.\n"
83 " This is 0-16 characters long.\n"
84 " uid=xxxxxx The uid part of the generated ticket, in HEX.\n"
85 " MUST be 12 characters long.\n"
86 " access=xxxxxxxxxxx New access code to set, in HEX.\n"
87 " MUST be 12 characters long.\n"
88 " oath-imf=IMF OATH Initial Moving Factor to use.\n"
89 " oath-id[=h:OOTT...] OATH Token Identifier (none for serial-based)\n"
91 " Ticket flags for all firmware versions:\n"
92 " [-]tab-first set/clear TAB_FIRST\n"
93 " [-]append-tab1 set/clear APPEND_TAB1\n"
94 " [-]append-tab2 set/clear APPEND_TAB2\n"
95 " [-]append-delay1 set/clear APPEND_DELAY1\n"
96 " [-]append-delay2 set/clear APPEND_DELAY2\n"
97 " [-]append-cr set/clear APPEND_CR\n"
99 " Ticket flags for firmware version 2.0 and above:\n"
100 " [-]protect-cfg2 set/clear PROTECT_CFG2\n"
102 " Ticket flags for firmware version 2.1 and above:\n"
103 " [-]oath-hotp set/clear OATH_HOTP\n"
105 " Ticket flags for firmware version 2.2 and above:\n"
106 " [-]chal-resp set/clear CHAL_RESP\n"
108 " Configuration flags for all firmware versions:\n"
109 " [-]send-ref set/clear SEND_REF\n"
110 " [-]pacing-10ms set/clear PACING_10MS\n"
111 " [-]pacing-20ms set/clear PACING_20MS\n"
112 " [-]static-ticket set/clear STATIC_TICKET\n"
114 " Configuration flags for firmware version 1.x only:\n"
115 " [-]ticket-first set/clear TICKET_FIRST\n"
116 " [-]allow-hidtrig set/clear ALLOW_HIDTRIG\n"
118 " Configuration flags for firmware version 2.0 and above:\n"
119 " [-]short-ticket set/clear SHORT_TICKET\n"
120 " [-]strong-pw1 set/clear STRONG_PW1\n"
121 " [-]strong-pw2 set/clear STRONG_PW2\n"
122 " [-]man-update set/clear MAN_UPDATE\n"
124 " Configuration flags for firmware version 2.1 and above:\n"
125 " [-]oath-hotp8 set/clear OATH_HOTP8\n"
126 " [-]oath-fixed-modhex1 set/clear OATH_FIXED_MODHEX1\n"
127 " [-]oath-fixed-modhex2 set/clear OATH_FIXED_MODHEX2\n"
128 " [-]oath-fixed-modhex set/clear OATH_MODHEX\n"
130 " Configuration flags for firmware version 2.2 and above:\n"
131 " [-]chal-yubico set/clear CHAL_YUBICO\n"
132 " [-]chal-hmac set/clear CHAL_HMAC\n"
133 " [-]hmac-lt64 set/clear HMAC_LT64\n"
134 " [-]chal-btn-trig set/clear CHAL_BTN_TRIG\n"
136 " Extended flags for firmware version 2.2 and above:\n"
137 " [-]serial-btn-visible set/clear SERIAL_BTN_VISIBLE\n"
138 " [-]serial-usb-visible set/clear SERIAL_USB_VISIBLE\n"
139 " [-]serial-api-visible set/clear SERIAL_API_VISIBLE\n"
141 " Extended flags for firmware version 2.3 and above:\n"
142 " [-]use-numeric-keypad set/clear USE_NUMERIC_KEYPAD\n"
143 " [-]fast-trig set/clear FAST_TRIG\n"
144 " [-]allow-update set/clear ALLOW_UPDATE\n"
145 " [-]dormant set/clear DORMANT\n"
147 " Extended flags for firmware version 2.4/3.1 and above:\n"
148 " [-]led-inv set/clear LED_INV\n"
150 "-y always commit (do not prompt)\n"
152 "-d dry-run (don't write anything to key)\n"
156 "-h help (this text)\n"
158 const char *optstring = "u12xza::c:n:t:hi:o:s:f:dvym:S::V";
160 static int _set_fixed(char *opt, YKP_CONFIG *cfg);
161 static int _format_decimal_as_hex(uint8_t *dst, size_t dst_len, uint8_t *src);
162 static int _format_oath_id(uint8_t *dst, size_t dst_len, uint8_t vendor, uint8_t type, uint32_t mui);
163 static int _set_oath_id(char *opt, YKP_CONFIG *cfg, YK_KEY *yk, YK_STATUS *st);
165 static int hex_modhex_decode(unsigned char *result, size_t *resultlen,
166 const char *str, size_t strl,
167 size_t minsize, size_t maxsize,
168 bool primarily_modhex)
171 if (strncmp(str, "m:", 2) == 0
172 || strncmp(str, "M:", 2) == 0) {
175 primarily_modhex = true;
176 } else if (strncmp(str, "h:", 2) == 0
177 || strncmp(str, "H:", 2) == 0) {
180 primarily_modhex = false;
184 if ((strl % 2 != 0) || (strl < minsize) || (strl > maxsize)) {
188 *resultlen = strl / 2;
189 if (primarily_modhex) {
190 if (yubikey_modhex_p(str)) {
191 yubikey_modhex_decode((char *)result, str, strl);
195 if (yubikey_hex_p(str)) {
196 yubikey_hex_decode((char *)result, str, strl);
204 void report_yk_error(void)
207 fprintf(stderr, "Yubikey personalization error: %s\n",
208 ykp_strerror(ykp_errno));
210 if (yk_errno == YK_EUSBERR) {
211 fprintf(stderr, "USB error: %s\n",
214 fprintf(stderr, "Yubikey core error: %s\n",
215 yk_strerror(yk_errno));
221 * Parse all arguments supplied to this program and turn it into mainly
222 * a YKP_CONFIG (but return some other parameters as well, like
223 * access_code, verbose etc.).
225 * Done in this way to be testable (see tests/test_args_to_config.c).
227 int args_to_config(int argc, char **argv, YKP_CONFIG *cfg, YK_KEY *yk,
228 const char **infname, const char **outfname,
229 int *data_format, bool *autocommit,
230 YK_STATUS *st, bool *verbose, bool *dry_run,
231 unsigned char *access_code, bool *use_access_code,
232 char *keylocation, char *ndef_type, char *ndef,
233 unsigned char *usb_mode, bool *zap,
234 unsigned char *scan_bin, unsigned char *cr_timeout,
235 unsigned char *autoeject_timeout, int *num_modes_seen,
239 const char *aeshash = NULL;
240 bool new_access_code = false;
241 bool slot_chosen = false;
242 bool mode_chosen = false;
243 bool option_seen = false;
244 bool swap_seen = false;
245 bool update_seen = false;
246 bool ndef_seen = false;
247 bool usb_mode_seen = false;
248 bool scan_map_seen = false;
250 ykp_configure_version(cfg, st);
252 while((c = getopt(argc, argv, optstring)) != -1) {
254 if (strcmp(optarg, "oath-hotp") == 0 ||
255 strcmp(optarg, "chal-resp") == 0) {
257 fprintf(stderr, "You may only choose mode (-ooath-hotp / "
258 "-ochal-resp) once.\n");
264 fprintf(stderr, "Mode choosing flags (oath-hotp / chal-resp) "
265 "must be set prior to any other options (-o).\n");
270 /* The default flags (particularly for slot 2) does not apply to
271 * these new modes of operation found in Yubikey >= 2.1. Therefor,
272 * we reset them here and, as a consequence of that, require the
273 * mode choosing options to be specified before any other.
275 ykp_clear_config(cfg);
286 fprintf(stderr, "You must use update before slot (-1 / -2).\n");
291 fprintf(stderr, "Update (-u) and swap (-x) can't be combined.\n");
296 fprintf(stderr, "Update (-u) can not be combined with ndef (-n).\n");
306 fprintf(stderr, "You may only choose slot (-1 / -2) once.\n");
311 fprintf(stderr, "You must choose slot before any options (-o).\n");
316 fprintf(stderr, "You can not combine slot swap (-x) with configuring a slot.\n");
320 ykp_set_tktflag_APPEND_CR(cfg, true);
322 ykp_set_extflag_ALLOW_UPDATE(cfg, true);
324 command = SLOT_UPDATE1;
325 } else if(c == '2') {
326 command = SLOT_UPDATE2;
328 } else if (c == '1') {
329 command = SLOT_CONFIG;
330 } else if (c == '2') {
331 command = SLOT_CONFIG2;
332 ykp_set_cfgflag_STATIC_TICKET(cfg, true);
333 ykp_set_cfgflag_STRONG_PW1(cfg, true);
334 ykp_set_cfgflag_STRONG_PW2(cfg, true);
335 ykp_set_cfgflag_MAN_UPDATE(cfg, true);
338 if (!ykp_configure_command(cfg, command))
344 if (slot_chosen || option_seen || update_seen || ndef_seen || *zap || usb_mode_seen || scan_map_seen) {
345 fprintf(stderr, "Slot swap (-x) can not be used with other options.\n");
350 if (!ykp_configure_command(cfg, SLOT_SWAP)) {
356 if (swap_seen || update_seen || ndef_seen || usb_mode_seen || scan_map_seen) {
357 fprintf(stderr, "Zap (-z) can only be used with a slot (-1 / -2).\n");
370 if(strcmp(optarg, "ycfg") == 0) {
371 *data_format = YKP_FORMAT_YCFG;
372 } else if(strcmp(optarg, "legacy") == 0) {
373 *data_format = YKP_FORMAT_LEGACY;
375 fprintf(stderr, "The only valid formats to -f is ycfg and legacy.\n");
389 size_t access_code_len = 0;
390 int rc = hex_modhex_decode(access_code, &access_code_len,
391 optarg, strlen(optarg),
395 "Invalid access code string: %s\n",
400 if (!new_access_code)
401 ykp_set_access_code(cfg,
404 *use_access_code = true;
414 if (swap_seen || update_seen || option_seen || *zap || usb_mode_seen || scan_map_seen) {
415 fprintf(stderr, "Ndef (-n/-t) can only be used with a slot (-1/-2).\n");
419 if(ykp_command(cfg) == SLOT_CONFIG) {
421 } else if(ykp_command(cfg) == SLOT_CONFIG2) {
422 command = SLOT_NDEF2;
426 if (!ykp_configure_command(cfg, command)) {
429 memcpy(ndef, optarg, strlen(optarg));
434 if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || scan_map_seen) {
435 fprintf(stderr, "USB mode (-m) can not be combined with other options.\n");
439 unsigned char mode, crtime, autotime;
440 int matched = sscanf(optarg, "%hhx:%hhd:%hhd", &mode, &crtime, &autotime);
444 *cr_timeout = crtime;
446 *autoeject_timeout = autotime;
449 usb_mode_seen = true;
450 *num_modes_seen = matched;
452 fprintf(stderr, "Invalid USB operation mode.\n");
456 if (!ykp_configure_command(cfg, SLOT_DEVICE_CONFIG))
462 size_t scanlength = strlen(SCAN_MAP);
463 if(slot_chosen || swap_seen || update_seen || option_seen || ndef_seen || *zap || usb_mode_seen) {
464 fprintf(stderr, "Scanmap (-S) can not be combined with other options.\n");
470 size_t scanlen = strlen (optarg);
471 int rc = hex_modhex_decode(scan_bin, &scanbinlen,
473 scanlength * 2, scanlength * 2,
478 "Invalid scanmap string %s\n",
484 memset(scan_bin, 0, scanlength);
486 scan_map_seen = true;
488 if (!ykp_configure_command(cfg, SLOT_SCAN_MAP))
493 fprintf(stderr, "No options can be given with zap (-z).\n");
497 if (strncmp(optarg, "fixed=", 6) == 0) {
498 if (_set_fixed(optarg + 6, cfg) != 1) {
500 "Invalid fixed string: %s\n",
506 else if (strncmp(optarg, "uid=", 4) == 0) {
507 const char *uid = optarg+4;
508 size_t uidlen = strlen (uid);
509 unsigned char uidbin[256];
510 size_t uidbinlen = 0;
511 int rc = hex_modhex_decode(uidbin, &uidbinlen,
516 "Invalid uid string: %s\n",
521 /* for OATH-HOTP and CHAL-RESP, uid is not applicable */
522 if (ykp_get_tktflag_OATH_HOTP(cfg) || ykp_get_tktflag_CHAL_RESP(cfg)) {
524 "Option uid= not valid with -ooath-hotp or -ochal-resp.\n"
529 ykp_set_uid(cfg, uidbin, uidbinlen);
531 else if (strncmp(optarg, "access=", 7) == 0) {
532 const char *acc = optarg+7;
533 size_t acclen = strlen (acc);
534 unsigned char accbin[256];
535 size_t accbinlen = 0;
536 int rc = hex_modhex_decode (accbin, &accbinlen,
541 "Invalid access code string: %s\n",
546 ykp_set_access_code(cfg, accbin, accbinlen);
547 new_access_code = true;
549 #define TKTFLAG(o, f) \
550 else if (strcmp(optarg, o) == 0) { \
551 if (!ykp_set_tktflag_##f(cfg, true)) { \
555 } else if (strcmp(optarg, "-" o) == 0) { \
556 if (! ykp_set_tktflag_##f(cfg, false)) { \
561 TKTFLAG("tab-first", TAB_FIRST)
562 TKTFLAG("append-tab1", APPEND_TAB1)
563 TKTFLAG("append-tab2", APPEND_TAB2)
564 TKTFLAG("append-delay1", APPEND_DELAY1)
565 TKTFLAG("append-delay2", APPEND_DELAY2)
566 TKTFLAG("append-cr", APPEND_CR)
567 TKTFLAG("protect-cfg2", PROTECT_CFG2)
568 TKTFLAG("oath-hotp", OATH_HOTP)
569 TKTFLAG("chal-resp", CHAL_RESP)
572 #define CFGFLAG(o, f) \
573 else if (strcmp(optarg, o) == 0) { \
574 if (! ykp_set_cfgflag_##f(cfg, true)) { \
578 } else if (strcmp(optarg, "-" o) == 0) { \
579 if (! ykp_set_cfgflag_##f(cfg, false)) { \
584 CFGFLAG("send-ref", SEND_REF)
585 CFGFLAG("ticket-first", TICKET_FIRST)
586 CFGFLAG("pacing-10ms", PACING_10MS)
587 CFGFLAG("pacing-20ms", PACING_20MS)
588 CFGFLAG("allow-hidtrig", ALLOW_HIDTRIG)
589 CFGFLAG("static-ticket", STATIC_TICKET)
590 CFGFLAG("short-ticket", SHORT_TICKET)
591 CFGFLAG("strong-pw1", STRONG_PW1)
592 CFGFLAG("strong-pw2", STRONG_PW2)
593 CFGFLAG("man-update", MAN_UPDATE)
594 CFGFLAG("oath-hotp8", OATH_HOTP8)
595 CFGFLAG("oath-fixed-modhex1", OATH_FIXED_MODHEX1)
596 CFGFLAG("oath-fixed-modhex2", OATH_FIXED_MODHEX2)
597 CFGFLAG("oath-fixed-modhex", OATH_FIXED_MODHEX)
598 CFGFLAG("chal-yubico", CHAL_YUBICO)
599 CFGFLAG("chal-hmac", CHAL_HMAC)
600 CFGFLAG("hmac-lt64", HMAC_LT64)
601 CFGFLAG("chal-btn-trig", CHAL_BTN_TRIG)
603 else if (strncmp(optarg, "oath-imf=", 9) == 0) {
606 if (!ykp_get_tktflag_OATH_HOTP(cfg)) {
608 "Option oath-imf= only valid with -ooath-hotp or -ooath-hotp8.\n"
614 if (sscanf(optarg+9, "%lu", &imf) != 1 ||
615 /* yubikey limitations */
616 imf > 65535*16 || imf % 16 != 0) {
618 "Invalid value %s for oath-imf=.\n", optarg+9
623 if (! ykp_set_oath_imf(cfg, imf)) {
628 else if (strncmp(optarg, "oath-id=", 8) == 0 || strcmp(optarg, "oath-id") == 0) {
629 if (_set_oath_id(optarg, cfg, yk, st) != 1) {
635 #define EXTFLAG(o, f) \
636 else if (strcmp(optarg, o) == 0) { \
637 if (! ykp_set_extflag_##f(cfg, true)) { \
641 } else if (strcmp(optarg, "-" o) == 0) { \
642 if (! ykp_set_extflag_##f(cfg, false)) { \
647 EXTFLAG("serial-btn-visible", SERIAL_BTN_VISIBLE)
648 EXTFLAG("serial-usb-visible", SERIAL_USB_VISIBLE)
649 EXTFLAG("serial-api-visible", SERIAL_API_VISIBLE)
650 EXTFLAG("use-numeric-keypad", USE_NUMERIC_KEYPAD)
651 EXTFLAG("fast-trig", FAST_TRIG)
652 EXTFLAG("allow-update", ALLOW_UPDATE)
653 EXTFLAG("dormant", DORMANT)
654 EXTFLAG("led-inv", LED_INV)
657 fprintf(stderr, "Unknown option '%s'\n",
659 fputs(usage, stderr);
674 fputs(YKPERS_VERSION_STRING "\n", stderr);
679 fputs(usage, stderr);
685 if (!slot_chosen && !ndef_seen && !swap_seen && !usb_mode_seen && !scan_map_seen) {
686 fprintf(stderr, "A slot must be chosen with -1 or -2.\n");
692 struct config_st *core_config = (struct config_st *) ykp_core_config(cfg);
693 if ((core_config->tktFlags & TKTFLAG_UPDATE_MASK) != core_config->tktFlags) {
694 fprintf(stderr, "Unallowed ticket flags with update.\n");
698 if ((core_config->cfgFlags & CFGFLAG_UPDATE_MASK) != core_config->cfgFlags) {
699 fprintf(stderr, "Unallowed cfg flags with update.\n");
703 if ((core_config->extFlags & EXTFLAG_UPDATE_MASK) != core_config->extFlags) {
704 fprintf(stderr, "Unallowed ext flags with update.\n");
710 if (*keylocation == 1) {
711 bool long_key_valid = ykp_get_supported_key_length(cfg) == 20 ? true : false;
714 if (long_key_valid && strlen(aeshash) == 40) {
715 res = ykp_HMAC_key_from_hex(cfg, aeshash);
717 res = ykp_AES_key_from_hex(cfg, aeshash);
721 fprintf(stderr, "Bad %s key: %s\n", long_key_valid ? "HMAC":"AES", aeshash);
730 static int _set_fixed(char *opt, YKP_CONFIG *cfg) {
731 const char *fixed = opt;
732 size_t fixedlen = strlen (fixed);
733 unsigned char fixedbin[256];
734 size_t fixedbinlen = 0;
735 int rc = hex_modhex_decode(fixedbin, &fixedbinlen,
741 ykp_set_fixed(cfg, fixedbin, fixedbinlen);
746 /* re-format decimal 12345678 into 'hex' 0x12 0x34 0x56 0x78 */
747 static int _format_decimal_as_hex(uint8_t *dst, size_t dst_len, uint8_t *src)
752 while (src[0] && src[1]) {
755 *dst = ((src[0] - '0') * 0x10) + src[1] - '0';
763 /* For details, see YubiKey Manual 2010-09-16 section 5.3.4 - OATH-HOTP Token Identifier */
764 static int _format_oath_id(uint8_t *dst, size_t dst_len, uint8_t vendor, uint8_t type, uint32_t mui)
771 /* two bytes vendor and token type, and eight bytes MUI */
775 /* Make the YubiKey output the MUI number in decimal */
776 snprintf(buf, sizeof(buf), "%08i", mui);
781 if (_format_decimal_as_hex(dst + 2, dst_len - 2, buf) != 1)
787 static int _set_oath_id(char *opt, YKP_CONFIG *cfg, YK_KEY *yk, YK_STATUS *st) {
788 /* For details, see YubiKey Manual 2010-09-16 section 5.3.4 - OATH-HOTP Token Identifier */
789 if (!ykp_get_tktflag_OATH_HOTP(cfg)) {
791 "Option oath-id= only valid with -ooath-hotp or -ooath-hotp8.\n"
795 if (! ykp_set_cfgflag_OATH_FIXED_MODHEX2(cfg, true))
797 if (! ykp_set_extflag_SERIAL_API_VISIBLE(cfg, true))
800 if (strlen(opt) > 7) {
801 if (_set_fixed(opt + 8, cfg) != 1) {
803 "Invalid OATH token identifier %s supplied with oath-id=.\n", opt + 8
808 /* No Token Id supplied, try to create one automatically based on
809 * the serial number of the YubiKey.
812 uint8_t oath_id[12] = {0};
813 if (ykds_version_major(st) > 2 ||
814 (ykds_version_major(st) == 2 &&
815 ykds_version_minor(st) >= 2)) {
816 if (! yk_get_serial(yk, 0, 0, &serial)) {
818 "YubiKey refuses reading serial number. "
819 "Can't use -ooath-id.\n"
825 "YubiKey %d.%d.%d does not support reading serial number. "
826 "Can't use -ooath-id.\n",
827 ykds_version_major(st),
828 ykds_version_minor(st),
829 ykds_version_build(st)
834 if (_format_oath_id(oath_id, sizeof(oath_id), YUBICO_OATH_VENDOR_ID_HEX,
835 YUBICO_HOTP_EVENT_TOKEN_TYPE, serial) != 1) {
836 fprintf(stderr, "Failed formatting OATH token identifier.\n");
840 if (ykp_set_fixed(cfg, oath_id, 6) != 1) {
842 "Failed setting OATH token identifier.\n"