1 /* -*- mode:C; c-file-style: "bsd" -*- */
3 * Copyright (c) 2008-2012 Yubico AB
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "ykcore_lcl.h"
46 unsigned int yk_major_version;
47 unsigned int yk_minor_version;
48 unsigned int configuration_number;
50 YK_CONFIG ykcore_config;
53 static const YK_CONFIG default_config1 = {
54 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* fixed */
55 { 0, 0, 0, 0, 0, 0 }, /* uid */
56 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* key */
57 { 0, 0, 0, 0, 0, 0 }, /* accCode */
60 TKTFLAG_APPEND_CR, /* tktFlags */
66 static const YK_CONFIG default_config2 = {
67 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* fixed */
68 { 0, 0, 0, 0, 0, 0 }, /* uid */
69 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* key */
70 { 0, 0, 0, 0, 0, 0 }, /* accCode */
73 TKTFLAG_APPEND_CR, /* tktFlags */
75 CFGFLAG_STATIC_TICKET | CFGFLAG_STRONG_PW1 | CFGFLAG_STRONG_PW2 | CFGFLAG_MAN_UPDATE,
80 YKP_CONFIG *ykp_create_config(void)
82 YKP_CONFIG *cfg = malloc(sizeof(YKP_CONFIG));
84 memcpy(&cfg->ykcore_config, &default_config1,
85 sizeof(default_config1));
86 cfg->yk_major_version = 1;
87 cfg->yk_minor_version = 3;
88 cfg->configuration_number = 1;
94 int ykp_free_config(YKP_CONFIG *cfg)
103 int ykp_configure_for(YKP_CONFIG *cfg, int confnum, YK_STATUS *st)
105 cfg->yk_major_version = st->versionMajor;
106 cfg->yk_minor_version = st->versionMinor;
110 memcpy(&cfg->ykcore_config, &default_config1,
111 sizeof(default_config1));
112 cfg->configuration_number = 1;
115 if (cfg->yk_major_version >= 2) {
116 memcpy(&cfg->ykcore_config, &default_config2,
117 sizeof(default_config2));
118 cfg->configuration_number = 2;
121 ykp_errno = YKP_EOLDYUBIKEY;
124 ykp_errno = YKP_EINVCONFNUM;
130 /* Return number of bytes of key data for this configuration.
131 * 20 bytes is 160 bits, 16 bytes is 128.
133 int _get_supported_key_length(const YKP_CONFIG *cfg)
135 bool key_bits_in_uid = false;
137 /* OATH-HOTP and HMAC-SHA1 challenge response support 20 byte (160 bits)
138 * keys, holding the last four bytes in the uid field.
140 if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
143 if ((cfg->ykcore_config.tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
144 (cfg->ykcore_config.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
151 /* Decode 128 bit AES key into cfg->ykcore_config.key */
152 int ykp_AES_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
155 /* Make sure that the hexkey is exactly 32 characters */
156 if (strlen(hexkey) != 32) {
157 return 1; /* Bad AES key */
160 /* Make sure that the hexkey is made up of only [0-9a-f] */
161 if (! yubikey_hex_p(hexkey))
164 yubikey_hex_decode(aesbin, hexkey, sizeof(aesbin));
165 memcpy(cfg->ykcore_config.key, aesbin, sizeof(cfg->ykcore_config.key));
170 /* Decode 160 bits HMAC key, used with OATH and HMAC challenge-response.
172 * The first 128 bits of the HMAC go key into cfg->ykcore_config.key,
173 * and 32 bits into the first four bytes of cfg->ykcore_config.uid.
175 int ykp_HMAC_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
179 /* Make sure that the hexkey is exactly 40 characters */
180 if (strlen(hexkey) != 40) {
181 return 1; /* Bad HMAC key */
184 /* Make sure that the hexkey is made up of only [0-9a-f] */
185 if (! yubikey_hex_p(hexkey))
188 yubikey_hex_decode(aesbin, hexkey, sizeof(aesbin));
189 i = sizeof(cfg->ykcore_config.key);
190 memcpy(cfg->ykcore_config.key, aesbin, i);
191 memcpy(cfg->ykcore_config.uid, aesbin + i, 20 - i);
196 /* Generate an AES (128 bits) or HMAC (despite the function name) (160 bits)
197 * key from user entered input.
199 * Use user provided salt, or use salt from an available random device.
200 * If no random device is available we fall back to using 2048 bits of
201 * system time data, together with the user input, as salt.
203 int ykp_AES_key_from_passphrase(YKP_CONFIG *cfg, const char *passphrase,
207 char *random_places[] = {
215 size_t _salt_len = 0;
216 unsigned char buf[sizeof(cfg->ykcore_config.key) + 4];
218 int key_bytes = _get_supported_key_length(cfg);
220 assert (key_bytes <= sizeof(buf));
223 _salt_len = strlen(salt);
226 memcpy(_salt, salt, _salt_len);
228 for (random_place = random_places;
231 FILE *random_file = fopen(*random_place, "r");
233 size_t read_bytes = 0;
235 while (read_bytes < sizeof(_salt)) {
236 size_t n = fread(&_salt[read_bytes],
237 1, sizeof (_salt) - read_bytes,
244 _salt_len = sizeof(_salt);
246 break; /* from for loop */
250 if (_salt_len == 0) {
251 /* There was no randomness files, so create a cheap
253 # include <ykpbkdf2.h>
255 time_t t = time(NULL);
256 uint8_t output[256]; /* 2048 bits is a lot! */
258 yk_hmac_sha1.prf_fn(passphrase, strlen(passphrase),
259 (char *)&t, sizeof(t),
260 output, sizeof(output));
261 memcpy(_salt, output, sizeof(_salt));
262 _salt_len = sizeof(_salt);
265 rc = yk_pbkdf2(passphrase,
272 memcpy(cfg->ykcore_config.key, buf, sizeof(cfg->ykcore_config.key));
274 if (key_bytes == 20) {
275 memcpy(cfg->ykcore_config.uid, buf + sizeof(cfg->ykcore_config.key), 4);
279 memset (buf, 0, sizeof(buf));
285 static bool vcheck_all(const YKP_CONFIG *cfg)
289 static bool vcheck_v1(const YKP_CONFIG *cfg)
291 return cfg->yk_major_version == 1;
293 static bool vcheck_no_v1(const YKP_CONFIG *cfg)
295 return cfg->yk_major_version > 1;
298 static bool vcheck_v21_or_greater(const YKP_CONFIG *cfg)
300 return (cfg->yk_major_version == 2 &&
301 cfg->yk_minor_version >= 1) ||
302 cfg->yk_major_version > 2;
305 static bool vcheck_v22_or_greater(const YKP_CONFIG *cfg)
307 return (cfg->yk_major_version == 2 &&
308 cfg->yk_minor_version >= 2) ||
309 cfg->yk_major_version > 2;
312 int ykp_set_oath_imf(YKP_CONFIG *cfg, unsigned long imf)
314 if (!vcheck_v22_or_greater(cfg)) {
315 ykp_errno = YKP_EYUBIKEYVER;
318 if (imf > 65535*16) {
319 ykp_errno = YKP_EINVAL;
323 ykp_errno = YKP_EINVAL;
326 /* IMF/16 is 16 bits stored big-endian in uid[4] */
328 cfg->ykcore_config.uid[4] = imf >> 8;
329 cfg->ykcore_config.uid[5] = imf;
333 unsigned long ykp_get_oath_imf(const YKP_CONFIG *cfg)
335 if (!vcheck_v22_or_greater(cfg)) {
339 /* we can't do a simple cast due to alignment issues */
340 return ((cfg->ykcore_config.uid[4] << 8)
341 | cfg->ykcore_config.uid[5]) << 4;
344 #define def_set_charfield(fnname,fieldname,size,extra,vcheck) \
345 int ykp_set_ ## fnname(YKP_CONFIG *cfg, unsigned char *input, size_t len) \
348 size_t max_chars = len; \
350 if (!vcheck(cfg)) { \
351 ykp_errno = YKP_EYUBIKEYVER; \
354 if (max_chars > (size)) \
355 max_chars = (size); \
357 memcpy(cfg->ykcore_config.fieldname, (input), max_chars); \
358 memset(cfg->ykcore_config.fieldname + max_chars, 0, \
359 (size) - max_chars); \
364 ykp_errno = YKP_ENOCFG; \
368 def_set_charfield(access_code,accCode,ACC_CODE_SIZE,,vcheck_all)
369 def_set_charfield(fixed,fixed,FIXED_SIZE,cfg->ykcore_config.fixedSize = max_chars,vcheck_all)
370 def_set_charfield(uid,uid,UID_SIZE,,vcheck_all)
372 #define def_set_tktflag(type,vcheck) \
373 int ykp_set_tktflag_ ## type(YKP_CONFIG *cfg, bool state) \
376 if (!vcheck(cfg)) { \
377 ykp_errno = YKP_EYUBIKEYVER; \
381 cfg->ykcore_config.tktFlags |= TKTFLAG_ ## type; \
383 cfg->ykcore_config.tktFlags &= ~TKTFLAG_ ## type; \
386 ykp_errno = YKP_ENOCFG; \
390 #define def_set_cfgflag(type,vcheck) \
391 int ykp_set_cfgflag_ ## type(YKP_CONFIG *cfg, bool state) \
394 if (!vcheck(cfg)) { \
395 ykp_errno = YKP_EYUBIKEYVER; \
399 cfg->ykcore_config.cfgFlags |= CFGFLAG_ ## type; \
401 cfg->ykcore_config.cfgFlags &= ~CFGFLAG_ ## type; \
404 ykp_errno = YKP_ENOCFG; \
408 #define def_set_extflag(type,vcheck) \
409 int ykp_set_extflag_ ## type(YKP_CONFIG *cfg, bool state) \
412 if (!vcheck(cfg)) { \
413 ykp_errno = YKP_EYUBIKEYVER; \
417 cfg->ykcore_config.extFlags |= EXTFLAG_ ## type; \
419 cfg->ykcore_config.extFlags &= ~EXTFLAG_ ## type; \
422 ykp_errno = YKP_ENOCFG; \
426 def_set_tktflag(TAB_FIRST,vcheck_all)
427 def_set_tktflag(APPEND_TAB1,vcheck_all)
428 def_set_tktflag(APPEND_TAB2,vcheck_all)
429 def_set_tktflag(APPEND_DELAY1,vcheck_all)
430 def_set_tktflag(APPEND_DELAY2,vcheck_all)
431 def_set_tktflag(APPEND_CR,vcheck_all)
432 def_set_tktflag(PROTECT_CFG2,vcheck_no_v1)
433 def_set_tktflag(OATH_HOTP,vcheck_v21_or_greater)
434 def_set_tktflag(CHAL_RESP,vcheck_v22_or_greater)
436 def_set_cfgflag(SEND_REF,vcheck_all)
437 def_set_cfgflag(TICKET_FIRST,vcheck_v1)
438 def_set_cfgflag(PACING_10MS,vcheck_all)
439 def_set_cfgflag(PACING_20MS,vcheck_all)
440 def_set_cfgflag(ALLOW_HIDTRIG,vcheck_v1)
441 def_set_cfgflag(STATIC_TICKET,vcheck_all)
442 def_set_cfgflag(SHORT_TICKET,vcheck_no_v1)
443 def_set_cfgflag(STRONG_PW1,vcheck_no_v1)
444 def_set_cfgflag(STRONG_PW2,vcheck_no_v1)
445 def_set_cfgflag(MAN_UPDATE,vcheck_no_v1)
446 def_set_cfgflag(OATH_HOTP8,vcheck_v21_or_greater)
447 def_set_cfgflag(OATH_FIXED_MODHEX1,vcheck_v21_or_greater)
448 def_set_cfgflag(OATH_FIXED_MODHEX2,vcheck_v21_or_greater)
449 def_set_cfgflag(OATH_FIXED_MODHEX,vcheck_v21_or_greater)
450 def_set_cfgflag(CHAL_YUBICO,vcheck_v22_or_greater)
451 def_set_cfgflag(CHAL_HMAC,vcheck_v22_or_greater)
452 def_set_cfgflag(HMAC_LT64,vcheck_v22_or_greater)
453 def_set_cfgflag(CHAL_BTN_TRIG,vcheck_v22_or_greater)
455 def_set_extflag(SERIAL_BTN_VISIBLE,vcheck_v22_or_greater)
456 def_set_extflag(SERIAL_USB_VISIBLE,vcheck_v22_or_greater)
457 def_set_extflag(SERIAL_API_VISIBLE,vcheck_v22_or_greater)
459 const char str_key_value_separator[] = ": ";
460 const char str_hex_prefix[] = "h:";
461 const char str_modhex_prefix[] = "m:";
462 const char str_fixed[] = "fixed";
463 const char str_oath_id[] = "OATH id";
464 const char str_uid[] = "uid";
465 const char str_key[] = "key";
466 const char str_acc_code[] = "acc_code";
467 const char str_oath_imf[] = "OATH IMF";
469 const char str_flags_separator[] = "|";
473 const char *flag_text;
474 bool (*vcheck)(const YKP_CONFIG *cfg);
475 unsigned char tkt_context;
478 const char str_ticket_flags[] = "ticket_flags";
479 struct map_st ticket_flags_map[] = {
480 { TKTFLAG_TAB_FIRST, "TAB_FIRST", vcheck_all, 0 },
481 { TKTFLAG_APPEND_TAB1, "APPEND_TAB1", vcheck_all, 0 },
482 { TKTFLAG_APPEND_TAB2, "APPEND_TAB2", vcheck_all, 0 },
483 { TKTFLAG_APPEND_DELAY1, "APPEND_DELAY1", vcheck_all, 0 },
484 { TKTFLAG_APPEND_DELAY2, "APPEND_DELAY2", vcheck_all, 0 },
485 { TKTFLAG_APPEND_CR, "APPEND_CR", vcheck_all, 0 },
486 { TKTFLAG_PROTECT_CFG2, "PROTECT_CFG2", vcheck_no_v1, 0 },
487 { TKTFLAG_OATH_HOTP, "OATH_HOTP", vcheck_v21_or_greater, 0 },
488 { TKTFLAG_CHAL_RESP, "CHAL_RESP", vcheck_v22_or_greater, 0 },
492 const char str_config_flags[] = "config_flags";
493 struct map_st config_flags_map[] = {
495 Values used to pretty-print a YKP_CONFIG in ykp_write_config().
497 The fourth field is a (tkt)context in which this (cfg)flag is valid.
498 Some cfgFlags share the same value (e.g. CFGFLAG_STRONG_PW2 and
499 CFGFLAG_OATH_FIXED_MODHEX2, both 0x40). Obvioulsy, STRONG_PW2 is not
500 in effect when we do OATH, so by setting tkt_context to TKTFLAG_OATH_HOTP
501 and having the OATH flags before STRONG_PW2 in this struct we will show
502 cfgFlag 0x40 as OATH_FIXED_MODHEX2 and not STRONG_PW2 if TKTFLAG_OATH_HOTP
505 { CFGFLAG_CHAL_YUBICO, "CHAL_YUBICO", vcheck_v22_or_greater, TKTFLAG_CHAL_RESP },
506 { CFGFLAG_CHAL_HMAC, "CHAL_HMAC", vcheck_v22_or_greater, TKTFLAG_CHAL_RESP },
507 { CFGFLAG_HMAC_LT64, "HMAC_LT64", vcheck_v22_or_greater, TKTFLAG_CHAL_RESP },
508 { CFGFLAG_CHAL_BTN_TRIG, "CHAL_BTN_TRIG", vcheck_v22_or_greater, TKTFLAG_CHAL_RESP },
509 { CFGFLAG_OATH_HOTP8, "OATH_HOTP8", vcheck_v21_or_greater, TKTFLAG_OATH_HOTP },
510 { CFGFLAG_OATH_FIXED_MODHEX1, "OATH_FIXED_MODHEX1", vcheck_v21_or_greater, TKTFLAG_OATH_HOTP },
511 { CFGFLAG_OATH_FIXED_MODHEX2, "OATH_FIXED_MODHEX2", vcheck_v21_or_greater, TKTFLAG_OATH_HOTP },
512 { CFGFLAG_OATH_FIXED_MODHEX, "OATH_FIXED_MODHEX", vcheck_v21_or_greater, TKTFLAG_OATH_HOTP },
513 { CFGFLAG_SEND_REF, "SEND_REF", vcheck_all, 0 },
514 { CFGFLAG_TICKET_FIRST, "TICKET_FIRST", vcheck_v1, 0 },
515 { CFGFLAG_PACING_10MS, "PACING_10MS", vcheck_all, 0 },
516 { CFGFLAG_PACING_20MS, "PACING_20MS", vcheck_all, 0 },
517 { CFGFLAG_ALLOW_HIDTRIG, "ALLOW_HIDTRIG", vcheck_v1, 0 },
518 { CFGFLAG_STATIC_TICKET, "STATIC_TICKET", vcheck_all, 0 },
519 { CFGFLAG_SHORT_TICKET, "SHORT_TICKET", vcheck_no_v1, 0 },
520 { CFGFLAG_STRONG_PW1, "STRONG_PW1", vcheck_no_v1, 0 },
521 { CFGFLAG_STRONG_PW2, "STRONG_PW2", vcheck_no_v1, 0 },
522 { CFGFLAG_MAN_UPDATE, "MAN_UPDATE", vcheck_no_v1, 0 },
526 const char str_extended_flags[] = "extended_flags";
527 struct map_st extended_flags_map[] = {
528 { EXTFLAG_SERIAL_BTN_VISIBLE, "SERIAL_BTN_VISIBLE", vcheck_v22_or_greater, 0 },
529 { EXTFLAG_SERIAL_USB_VISIBLE, "SERIAL_USB_VISIBLE", vcheck_v22_or_greater, 0 },
530 { EXTFLAG_SERIAL_API_VISIBLE, "SERIAL_API_VISIBLE", vcheck_v22_or_greater, 0 },
534 int ykp_write_config(const YKP_CONFIG *cfg,
535 int (*writer)(const char *buf, size_t count,
542 unsigned char t_flags;
543 bool key_bits_in_uid = false;
545 /* for OATH-HOTP and HMAC-SHA1 challenge response, there is four bytes
546 * additional key data in the uid field
548 key_bits_in_uid = (_get_supported_key_length(cfg) == 20);
550 /* fixed: or OATH id: */
551 if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP &&
552 cfg->ykcore_config.fixedSize) {
553 writer(str_oath_id, strlen(str_oath_id), userdata);
554 writer(str_key_value_separator,
555 strlen(str_key_value_separator),
557 /* First byte (vendor id) */
558 if ((cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX1) == CFGFLAG_OATH_FIXED_MODHEX1 ||
559 (cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX2) == CFGFLAG_OATH_FIXED_MODHEX2 ||
560 (cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) {
561 yubikey_modhex_encode(buffer, (char *)cfg->ykcore_config.fixed, 1);
563 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.fixed, 1);
565 /* Second byte (token type) */
566 if ((cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX2) == CFGFLAG_OATH_FIXED_MODHEX2 ||
567 (cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) {
568 yubikey_modhex_encode(buffer + 2, (char *)cfg->ykcore_config.fixed + 1, 1);
570 yubikey_hex_encode(buffer + 2, (char *)cfg->ykcore_config.fixed + 1, 1);
572 /* bytes 3-12 - MUI */
573 if ((cfg->ykcore_config.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX) == CFGFLAG_OATH_FIXED_MODHEX) {
574 yubikey_modhex_encode(buffer + 4, (char *)cfg->ykcore_config.fixed + 2, 8);
576 yubikey_hex_encode(buffer + 4, (char *)cfg->ykcore_config.fixed + 2, 8);
579 writer(buffer, strlen(buffer), userdata);
580 writer("\n", 1, userdata);
582 writer(str_fixed, strlen(str_fixed), userdata);
583 writer(str_key_value_separator,
584 strlen(str_key_value_separator),
586 writer(str_modhex_prefix,
587 strlen(str_modhex_prefix),
589 yubikey_modhex_encode(buffer, (char *)cfg->ykcore_config.fixed, cfg->ykcore_config.fixedSize);
590 writer(buffer, strlen(buffer), userdata);
591 writer("\n", 1, userdata);
595 writer(str_uid, strlen(str_uid), userdata);
596 writer(str_key_value_separator,
597 strlen(str_key_value_separator),
599 if (key_bits_in_uid) {
600 writer("n/a", 3, userdata);
602 writer(str_hex_prefix,
603 strlen(str_hex_prefix),
605 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.uid, UID_SIZE);
606 writer(buffer, strlen(buffer), userdata);
608 writer("\n", 1, userdata);
611 writer(str_key, strlen(str_key), userdata);
612 writer(str_key_value_separator,
613 strlen(str_key_value_separator),
615 writer(str_hex_prefix,
616 strlen(str_hex_prefix),
618 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.key, KEY_SIZE);
619 if (key_bits_in_uid) {
620 yubikey_hex_encode(buffer + KEY_SIZE * 2, (char *)cfg->ykcore_config.uid, 4);
622 writer(buffer, strlen(buffer), userdata);
623 writer("\n", 1, userdata);
626 writer(str_acc_code, strlen(str_acc_code), userdata);
627 writer(str_key_value_separator,
628 strlen(str_key_value_separator),
630 writer(str_hex_prefix,
631 strlen(str_hex_prefix),
633 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.accCode, ACC_CODE_SIZE);
634 writer(buffer, strlen(buffer), userdata);
635 writer("\n", 1, userdata);
638 if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP &&
639 vcheck_v22_or_greater(cfg)) {
640 writer(str_oath_imf, strlen(str_oath_imf), userdata);
641 writer(str_key_value_separator,
642 strlen(str_key_value_separator),
644 writer(str_hex_prefix,
645 strlen(str_hex_prefix),
647 sprintf(buffer, "%lx", ykp_get_oath_imf(cfg));
648 writer(buffer, strlen(buffer), userdata);
649 writer("\n", 1, userdata);
654 for (p = ticket_flags_map; p->flag; p++) {
655 if ((cfg->ykcore_config.tktFlags & p->flag) == p->flag
658 strcat(buffer, str_flags_separator);
659 strcat(buffer, p->flag_text);
661 strcpy(buffer, p->flag_text);
665 writer(str_ticket_flags, strlen(str_ticket_flags), userdata);
666 writer(str_key_value_separator,
667 strlen(str_key_value_separator),
669 writer(buffer, strlen(buffer), userdata);
670 writer("\n", 1, userdata);
674 t_flags = cfg->ykcore_config.cfgFlags;
675 for (p = config_flags_map; p->flag; p++) {
676 if ((t_flags & p->flag) == p->flag
678 && (cfg->ykcore_config.tktFlags & p->tkt_context) == p->tkt_context) {
680 strcat(buffer, str_flags_separator);
681 strcat(buffer, p->flag_text);
683 strcpy(buffer, p->flag_text);
685 /* make sure we don't show more than one cfgFlag per value -
686 some cfgflags share value in different contexts
691 writer(str_config_flags, strlen(str_config_flags), userdata);
692 writer(str_key_value_separator,
693 strlen(str_key_value_separator),
695 writer(buffer, strlen(buffer), userdata);
696 writer("\n", 1, userdata);
698 /* extended_flags: */
700 for (p = extended_flags_map; p->flag; p++) {
701 if ((cfg->ykcore_config.extFlags & p->flag) == p->flag
704 strcat(buffer, str_flags_separator);
705 strcat(buffer, p->flag_text);
707 strcpy(buffer, p->flag_text);
711 writer(str_extended_flags, strlen(str_extended_flags), userdata);
712 writer(str_key_value_separator,
713 strlen(str_key_value_separator),
715 writer(buffer, strlen(buffer), userdata);
716 writer("\n", 1, userdata);
723 int ykp_read_config(YKP_CONFIG *cfg,
724 int (*reader)(char *buf, size_t count,
728 ykp_errno = YKP_ENOTYETIMPL;
732 YK_CONFIG *ykp_core_config(YKP_CONFIG *cfg)
735 return &cfg->ykcore_config;
736 ykp_errno = YKP_ENOCFG;
740 int ykp_config_num(YKP_CONFIG *cfg)
743 return cfg->configuration_number;
744 ykp_errno = YKP_ENOCFG;
748 int * const _ykp_errno_location(void)
750 static int tsd_init = 0;
751 static int nothread_errno = 0;
752 YK_DEFINE_TSD_METADATA(errno_key);
756 if ((rc = YK_TSD_INIT(errno_key, free)) == 0) {
757 void *p = calloc(1, sizeof(int));
761 YK_TSD_SET(errno_key, p);
769 return YK_TSD_GET(int *, errno_key);
771 return ¬hread_errno;
774 static const char *errtext[] = {
776 "not yet implemented",
777 "no configuration structure given",
778 "option not available for this Yubikey version",
779 "too old yubikey for this operation",
780 "invalid configuration number (this is a programming error)",
781 "invalid option/argument value",
783 const char *ykp_strerror(int errnum)
785 if (errnum < sizeof(errtext)/sizeof(errtext[0]))
786 return errtext[errnum];