]> err.no Git - yubikey-personalization.old/blob - ykpers.c
Merge tag 'v1.6.4'
[yubikey-personalization.old] / ykpers.c
1 /* -*- mode:C; c-file-style: "bsd" -*- */
2 /*
3  * Copyright (c) 2008-2012 Yubico AB
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *
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.
17  *
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.
29  */
30
31 #include "ykcore_lcl.h"
32 #include "ykpbkdf2.h"
33 #include "yktsd.h"
34
35 #include <ykpers.h>
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <time.h>
40 #include <ctype.h>
41 #include <assert.h>
42
43 #include <yubikey.h>
44
45 struct ykp_config_t {
46         unsigned int yk_major_version;
47         unsigned int yk_minor_version;
48         unsigned int configuration_number;
49
50         YK_CONFIG ykcore_config;
51 };
52
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 */
58         0,                      /* fixedSize */
59         0,                      /* extFlags */
60         TKTFLAG_APPEND_CR,      /* tktFlags */
61         0,                      /* cfgFlags */
62         0,                      /* ctrOffs */
63         0                       /* crc */
64 };
65
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 */
71         0,                      /* fixedSize */
72         0,                      /* extFlags */
73         TKTFLAG_APPEND_CR,      /* tktFlags */
74         /* cfgFlags */
75         CFGFLAG_STATIC_TICKET | CFGFLAG_STRONG_PW1 | CFGFLAG_STRONG_PW2 | CFGFLAG_MAN_UPDATE,
76         0,                      /* ctrOffs */
77         0                       /* crc */
78 };
79
80 YKP_CONFIG *ykp_create_config(void)
81 {
82         YKP_CONFIG *cfg = malloc(sizeof(YKP_CONFIG));
83         if (cfg) {
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;
89                 return cfg;
90         }
91         return 0;
92 }
93
94 int ykp_free_config(YKP_CONFIG *cfg)
95 {
96         if (cfg) {
97                 free(cfg);
98                 return 1;
99         }
100         return 0;
101 }
102
103 int ykp_configure_for(YKP_CONFIG *cfg, int confnum, YK_STATUS *st)
104 {
105         cfg->yk_major_version = st->versionMajor;
106         cfg->yk_minor_version = st->versionMinor;
107
108         switch(confnum) {
109         case 1:
110                 memcpy(&cfg->ykcore_config, &default_config1,
111                        sizeof(default_config1));
112                 cfg->configuration_number = 1;
113                 return 1;
114         case 2:
115                 if (cfg->yk_major_version >= 2) {
116                         memcpy(&cfg->ykcore_config, &default_config2,
117                                sizeof(default_config2));
118                         cfg->configuration_number = 2;
119                         return 1;
120                 }
121                 ykp_errno = YKP_EOLDYUBIKEY;
122                 break;
123         default:
124                 ykp_errno = YKP_EINVCONFNUM;
125                 break;
126         }
127         return 0;
128 }
129
130 /* Return number of bytes of key data for this configuration.
131  * 20 bytes is 160 bits, 16 bytes is 128.
132  */
133 int _get_supported_key_length(const YKP_CONFIG *cfg)
134 {
135         bool key_bits_in_uid = false;
136
137         /* OATH-HOTP and HMAC-SHA1 challenge response support 20 byte (160 bits)
138          * keys, holding the last four bytes in the uid field.
139          */
140         if ((cfg->ykcore_config.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP)
141                 return 20;
142
143         if ((cfg->ykcore_config.tktFlags & TKTFLAG_CHAL_RESP) == TKTFLAG_CHAL_RESP &&
144             (cfg->ykcore_config.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
145                 return 20;
146         }
147
148         return 16;
149 }
150
151 /* Decode 128 bit AES key into cfg->ykcore_config.key */
152 int ykp_AES_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
153         char aesbin[256];
154
155         /* Make sure that the hexkey is exactly 32 characters */
156         if (strlen(hexkey) != 32) {
157                 return 1;  /* Bad AES key */
158         }
159
160         /* Make sure that the hexkey is made up of only [0-9a-f] */
161         if (! yubikey_hex_p(hexkey))
162                 return 1;
163
164         yubikey_hex_decode(aesbin, hexkey, sizeof(aesbin));
165         memcpy(cfg->ykcore_config.key, aesbin, sizeof(cfg->ykcore_config.key));
166
167         return 0;
168 }
169
170 /* Decode 160 bits HMAC key, used with OATH and HMAC challenge-response.
171  *
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.
174 */
175 int ykp_HMAC_key_from_hex(YKP_CONFIG *cfg, const char *hexkey) {
176         char aesbin[256];
177         int i;
178
179         /* Make sure that the hexkey is exactly 40 characters */
180         if (strlen(hexkey) != 40) {
181                 return 1;  /* Bad HMAC key */
182         }
183
184         /* Make sure that the hexkey is made up of only [0-9a-f] */
185         if (! yubikey_hex_p(hexkey))
186                 return 1;
187
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);
192
193         return 0;
194 }
195
196 /* Generate an AES (128 bits) or HMAC (despite the function name) (160 bits)
197  * key from user entered input.
198  *
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.
202  */
203 int ykp_AES_key_from_passphrase(YKP_CONFIG *cfg, const char *passphrase,
204                                 const char *salt)
205 {
206         if (cfg) {
207                 char *random_places[] = {
208                         "/dev/srandom",
209                         "/dev/urandom",
210                         "/dev/random",
211                         0
212                 };
213                 char **random_place;
214                 uint8_t _salt[8];
215                 size_t _salt_len = 0;
216                 unsigned char buf[sizeof(cfg->ykcore_config.key) + 4];
217                 int rc;
218                 int key_bytes = _get_supported_key_length(cfg);
219
220                 assert (key_bytes <= sizeof(buf));
221
222                 if (salt) {
223                         _salt_len = strlen(salt);
224                         if (_salt_len > 8)
225                                 _salt_len = 8;
226                         memcpy(_salt, salt, _salt_len);
227                 } else {
228                         for (random_place = random_places;
229                              *random_place;
230                              random_place++) {
231                                 FILE *random_file = fopen(*random_place, "r");
232                                 if (random_file) {
233                                         size_t read_bytes = 0;
234
235                                         while (read_bytes < sizeof(_salt)) {
236                                                 size_t n = fread(&_salt[read_bytes],
237                                                                  1, sizeof (_salt) - read_bytes,
238                                                                  random_file);
239                                                 read_bytes += n;
240                                         }
241
242                                         fclose(random_file);
243
244                                         _salt_len = sizeof(_salt);
245
246                                         break; /* from for loop */
247                                 }
248                         }
249                 }
250                 if (_salt_len == 0) {
251                         /* There was no randomness files, so create a cheap
252                            salt from time */
253 #                       include <ykpbkdf2.h>
254
255                         time_t t = time(NULL);
256                         uint8_t output[256]; /* 2048 bits is a lot! */
257
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);
263                 }
264
265                 rc = yk_pbkdf2(passphrase,
266                                _salt, _salt_len,
267                                1024,
268                                buf, key_bytes,
269                                &yk_hmac_sha1);
270
271                 if (rc) {
272                         memcpy(cfg->ykcore_config.key, buf, sizeof(cfg->ykcore_config.key));
273
274                         if (key_bytes == 20) {
275                                 memcpy(cfg->ykcore_config.uid, buf + sizeof(cfg->ykcore_config.key), 4);
276                         }
277                 }
278
279                 memset (buf, 0, sizeof(buf));
280                 return rc;
281         }
282         return 0;
283 }
284
285 static bool vcheck_all(const YKP_CONFIG *cfg)
286 {
287         return true;
288 }
289 static bool vcheck_v1(const YKP_CONFIG *cfg)
290 {
291         return cfg->yk_major_version == 1;
292 }
293 static bool vcheck_no_v1(const YKP_CONFIG *cfg)
294 {
295         return cfg->yk_major_version > 1;
296 }
297
298 static bool vcheck_v21_or_greater(const YKP_CONFIG *cfg)
299 {
300         return (cfg->yk_major_version == 2 &&
301                 cfg->yk_minor_version >= 1) ||
302                 cfg->yk_major_version > 2;
303 }
304
305 static bool vcheck_v22_or_greater(const YKP_CONFIG *cfg)
306 {
307         return (cfg->yk_major_version == 2 &&
308                 cfg->yk_minor_version >= 2) ||
309                 cfg->yk_major_version > 2;
310 }
311
312 int ykp_set_oath_imf(YKP_CONFIG *cfg, unsigned long imf)
313 {
314         if (!vcheck_v22_or_greater(cfg)) {
315                 ykp_errno = YKP_EYUBIKEYVER;
316                 return 0;
317         }
318         if (imf > 65535*16) {
319                 ykp_errno = YKP_EINVAL;
320                 return 0;
321         }
322         if (imf % 16 != 0) {
323                 ykp_errno = YKP_EINVAL;
324                 return 0;
325         }
326         /* IMF/16 is 16 bits stored big-endian in uid[4] */
327         imf /= 16;
328         cfg->ykcore_config.uid[4] = imf >> 8;
329         cfg->ykcore_config.uid[5] = imf;
330         return 1;
331 }
332
333 unsigned long ykp_get_oath_imf(const YKP_CONFIG *cfg)
334 {
335         if (!vcheck_v22_or_greater(cfg)) {
336                 return 0;
337         }
338
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;
342 }
343
344 #define def_set_charfield(fnname,fieldname,size,extra,vcheck)   \
345 int ykp_set_ ## fnname(YKP_CONFIG *cfg, unsigned char *input, size_t len)       \
346 {                                                               \
347         if (cfg) {                                              \
348                 size_t max_chars = len;                         \
349                                                                 \
350                 if (!vcheck(cfg)) {                             \
351                         ykp_errno = YKP_EYUBIKEYVER;            \
352                         return 0;                               \
353                 }                                               \
354                 if (max_chars > (size))                         \
355                         max_chars = (size);                     \
356                                                                 \
357                 memcpy(cfg->ykcore_config.fieldname, (input), max_chars);       \
358                 memset(cfg->ykcore_config.fieldname + max_chars, 0,             \
359                        (size) - max_chars);                     \
360                 extra;                                          \
361                                                                 \
362                 return 1;                                       \
363         }                                                       \
364         ykp_errno = YKP_ENOCFG;                                 \
365         return 0;                                               \
366 }
367
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)
371
372 #define def_set_tktflag(type,vcheck)                            \
373 int ykp_set_tktflag_ ## type(YKP_CONFIG *cfg, bool state)       \
374 {                                                               \
375         if (cfg) {                                              \
376                 if (!vcheck(cfg)) {                             \
377                         ykp_errno = YKP_EYUBIKEYVER;            \
378                         return 0;                               \
379                 }                                               \
380                 if (state)                                      \
381                         cfg->ykcore_config.tktFlags |= TKTFLAG_ ## type;        \
382                 else                                            \
383                         cfg->ykcore_config.tktFlags &= ~TKTFLAG_ ## type;       \
384                 return 1;                                       \
385         }                                                       \
386         ykp_errno = YKP_ENOCFG;                                 \
387         return 0;                                               \
388 }
389
390 #define def_set_cfgflag(type,vcheck)                            \
391 int ykp_set_cfgflag_ ## type(YKP_CONFIG *cfg, bool state)               \
392 {                                                               \
393         if (cfg) {                                              \
394                 if (!vcheck(cfg)) {                             \
395                         ykp_errno = YKP_EYUBIKEYVER;            \
396                         return 0;                               \
397                 }                                               \
398                 if (state)                                      \
399                         cfg->ykcore_config.cfgFlags |= CFGFLAG_ ## type;        \
400                 else                                            \
401                         cfg->ykcore_config.cfgFlags &= ~CFGFLAG_ ## type;       \
402                 return 1;                                       \
403         }                                                       \
404         ykp_errno = YKP_ENOCFG;                                 \
405         return 0;                                               \
406 }
407
408 #define def_set_extflag(type,vcheck)                            \
409 int ykp_set_extflag_ ## type(YKP_CONFIG *cfg, bool state)               \
410 {                                                               \
411         if (cfg) {                                              \
412                 if (!vcheck(cfg)) {                             \
413                         ykp_errno = YKP_EYUBIKEYVER;            \
414                         return 0;                               \
415                 }                                               \
416                 if (state)                                      \
417                         cfg->ykcore_config.extFlags |= EXTFLAG_ ## type;        \
418                 else                                            \
419                         cfg->ykcore_config.extFlags &= ~EXTFLAG_ ## type;       \
420                 return 1;                                       \
421         }                                                       \
422         ykp_errno = YKP_ENOCFG;                                 \
423         return 0;                                               \
424 }
425
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)
435
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)
454
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)
458
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";
468
469 const char str_flags_separator[] = "|";
470
471 struct map_st {
472         uint8_t flag;
473         const char *flag_text;
474         bool (*vcheck)(const YKP_CONFIG *cfg);
475         unsigned char tkt_context;
476 };
477
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 },
489         { 0, "", 0 }
490 };
491
492 const char str_config_flags[] = "config_flags";
493 struct map_st config_flags_map[] = {
494         /*
495           Values used to pretty-print a YKP_CONFIG in ykp_write_config().
496
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
503           is set.
504         */
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 },
523         { 0, "" }
524 };
525
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 },
531         { 0, "", 0 }
532 };
533
534 int ykp_write_config(const YKP_CONFIG *cfg,
535                      int (*writer)(const char *buf, size_t count,
536                                    void *userdata),
537                      void *userdata)
538 {
539         if (cfg) {
540                 char buffer[256];
541                 struct map_st *p;
542                 unsigned char t_flags;
543                 bool key_bits_in_uid = false;
544
545                 /* for OATH-HOTP and HMAC-SHA1 challenge response, there is four bytes
546                  *  additional key data in the uid field
547                  */
548                 key_bits_in_uid = (_get_supported_key_length(cfg) == 20);
549
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),
556                                userdata);
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);
562                         } else {
563                                 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.fixed, 1);
564                         }
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);
569                         } else {
570                                 yubikey_hex_encode(buffer + 2, (char *)cfg->ykcore_config.fixed + 1, 1);
571                         }
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);
575                         } else {
576                                 yubikey_hex_encode(buffer + 4, (char *)cfg->ykcore_config.fixed + 2, 8);
577                         }
578                         buffer[12] = 0;
579                         writer(buffer, strlen(buffer), userdata);
580                         writer("\n", 1, userdata);
581                 } else {
582                         writer(str_fixed, strlen(str_fixed), userdata);
583                         writer(str_key_value_separator,
584                                strlen(str_key_value_separator),
585                                userdata);
586                         writer(str_modhex_prefix,
587                                strlen(str_modhex_prefix),
588                                userdata);
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);
592                 }
593
594                 /* uid: */
595                 writer(str_uid, strlen(str_uid), userdata);
596                 writer(str_key_value_separator,
597                        strlen(str_key_value_separator),
598                        userdata);
599                 if (key_bits_in_uid) {
600                         writer("n/a", 3, userdata);
601                 } else {
602                         writer(str_hex_prefix,
603                                strlen(str_hex_prefix),
604                                userdata);
605                         yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.uid, UID_SIZE);
606                         writer(buffer, strlen(buffer), userdata);
607                 }
608                 writer("\n", 1, userdata);
609
610                 /* key: */
611                 writer(str_key, strlen(str_key), userdata);
612                 writer(str_key_value_separator,
613                        strlen(str_key_value_separator),
614                        userdata);
615                 writer(str_hex_prefix,
616                        strlen(str_hex_prefix),
617                        userdata);
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);
621                 }
622                 writer(buffer, strlen(buffer), userdata);
623                 writer("\n", 1, userdata);
624
625                 /* acc_code: */
626                 writer(str_acc_code, strlen(str_acc_code), userdata);
627                 writer(str_key_value_separator,
628                        strlen(str_key_value_separator),
629                        userdata);
630                 writer(str_hex_prefix,
631                        strlen(str_hex_prefix),
632                        userdata);
633                 yubikey_hex_encode(buffer, (char *)cfg->ykcore_config.accCode, ACC_CODE_SIZE);
634                 writer(buffer, strlen(buffer), userdata);
635                 writer("\n", 1, userdata);
636
637                 /* OATH IMF: */
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),
643                                 userdata);
644                         writer(str_hex_prefix,
645                                 strlen(str_hex_prefix),
646                                 userdata);
647                         sprintf(buffer, "%lx", ykp_get_oath_imf(cfg));
648                         writer(buffer, strlen(buffer), userdata);
649                         writer("\n", 1, userdata);
650                 }
651
652                 /* ticket_flags: */
653                 buffer[0] = '\0';
654                 for (p = ticket_flags_map; p->flag; p++) {
655                         if ((cfg->ykcore_config.tktFlags & p->flag) == p->flag
656                             && p->vcheck(cfg)) {
657                                 if (*buffer) {
658                                         strcat(buffer, str_flags_separator);
659                                         strcat(buffer, p->flag_text);
660                                 } else {
661                                         strcpy(buffer, p->flag_text);
662                                 }
663                         }
664                 }
665                 writer(str_ticket_flags, strlen(str_ticket_flags), userdata);
666                 writer(str_key_value_separator,
667                        strlen(str_key_value_separator),
668                        userdata);
669                 writer(buffer, strlen(buffer), userdata);
670                 writer("\n", 1, userdata);
671
672                 /* config_flags: */
673                 buffer[0] = '\0';
674                 t_flags = cfg->ykcore_config.cfgFlags;
675                 for (p = config_flags_map; p->flag; p++) {
676                         if ((t_flags & p->flag) == p->flag
677                             && p->vcheck(cfg)
678                             && (cfg->ykcore_config.tktFlags & p->tkt_context) == p->tkt_context) {
679                                 if (*buffer) {
680                                         strcat(buffer, str_flags_separator);
681                                         strcat(buffer, p->flag_text);
682                                 } else {
683                                         strcpy(buffer, p->flag_text);
684                                 }
685                                 /* make sure we don't show more than one cfgFlag per value -
686                                    some cfgflags share value in different contexts
687                                 */
688                                 t_flags -= p->flag;
689                         }
690                 }
691                 writer(str_config_flags, strlen(str_config_flags), userdata);
692                 writer(str_key_value_separator,
693                        strlen(str_key_value_separator),
694                        userdata);
695                 writer(buffer, strlen(buffer), userdata);
696                 writer("\n", 1, userdata);
697
698                 /* extended_flags: */
699                 buffer[0] = '\0';
700                 for (p = extended_flags_map; p->flag; p++) {
701                         if ((cfg->ykcore_config.extFlags & p->flag) == p->flag
702                             && p->vcheck(cfg)) {
703                                 if (*buffer) {
704                                         strcat(buffer, str_flags_separator);
705                                         strcat(buffer, p->flag_text);
706                                 } else {
707                                         strcpy(buffer, p->flag_text);
708                                 }
709                         }
710                 }
711                 writer(str_extended_flags, strlen(str_extended_flags), userdata);
712                 writer(str_key_value_separator,
713                        strlen(str_key_value_separator),
714                        userdata);
715                 writer(buffer, strlen(buffer), userdata);
716                 writer("\n", 1, userdata);
717
718                 return 1;
719         }
720         return 0;
721 }
722
723 int ykp_read_config(YKP_CONFIG *cfg,
724                     int (*reader)(char *buf, size_t count,
725                                   void *userdata),
726                     void *userdata)
727 {
728         ykp_errno = YKP_ENOTYETIMPL;
729         return 0;
730 }
731
732 YK_CONFIG *ykp_core_config(YKP_CONFIG *cfg)
733 {
734         if (cfg)
735                 return &cfg->ykcore_config;
736         ykp_errno = YKP_ENOCFG;
737         return 0;
738 }
739
740 int ykp_config_num(YKP_CONFIG *cfg)
741 {
742         if (cfg)
743                 return cfg->configuration_number;
744         ykp_errno = YKP_ENOCFG;
745         return 0;
746 }
747
748 int * const _ykp_errno_location(void)
749 {
750         static int tsd_init = 0;
751         static int nothread_errno = 0;
752         YK_DEFINE_TSD_METADATA(errno_key);
753         int rc = 0;
754
755         if (tsd_init == 0) {
756                 if ((rc = YK_TSD_INIT(errno_key, free)) == 0) {
757                         void *p = calloc(1, sizeof(int));
758                         if (!p) {
759                                 tsd_init = -1;
760                         } else {
761                                 YK_TSD_SET(errno_key, p);
762                                 tsd_init = 1;
763                         }
764                 } else {
765                         tsd_init = -1;
766                 }
767         }
768         if (tsd_init == 1) {
769                 return YK_TSD_GET(int *, errno_key);
770         }
771         return &nothread_errno;
772 }
773
774 static const char *errtext[] = {
775         "",
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",
782 };
783 const char *ykp_strerror(int errnum)
784 {
785         if (errnum < sizeof(errtext)/sizeof(errtext[0]))
786                 return errtext[errnum];
787         return NULL;
788 }