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.
42 #include "ykpers-args.h"
44 int main(int argc, char **argv)
46 FILE *inf = NULL; const char *infname = NULL;
47 FILE *outf = NULL; const char *outfname = NULL;
48 int data_format = YKP_FORMAT_LEGACY;
51 bool use_access_code = false;
52 unsigned char access_code[256];
53 unsigned char scan_codes[sizeof(SCAN_MAP)];
55 YKP_CONFIG *cfg = ykp_alloc();
56 YK_STATUS *st = ykds_alloc();
57 bool autocommit = false;
62 char ndef_string[128] = {0};
64 unsigned char usb_mode = 0;
65 unsigned char cr_timeout = 0;
66 unsigned char autoeject_timeout = 0;
67 int num_modes_seen = 0;
76 /* Assume the worst */
84 if (argc == 2 && strcmp (argv[1], "-h") == 0) {
89 if (!(yk = yk_open_first_key())) {
94 if (!yk_get_status(yk, st)) {
99 printf("Firmware version %d.%d.%d Touch level %d ",
100 ykds_version_major(st),
101 ykds_version_minor(st),
102 ykds_version_build(st),
103 ykds_touch_level(st));
104 if (ykds_pgm_seq(st))
105 printf("Program sequence %d\n",
108 printf("Unconfigured\n");
110 if (!(yk_check_firmware_version2(st))) {
111 if (yk_errno == YK_EFIRMWARE) {
112 printf("Unsupported firmware revision - some "
113 "features may not be available\n"
115 "http://opensource.yubico.com/yubikey-personalization/doc/Compatibility.html\n"
116 "for more information.\n");
122 /* Parse all arguments in a testable way */
123 if (! args_to_config(argc, argv, cfg, yk,
125 &data_format, &autocommit,
126 st, &verbose, &dry_run,
127 access_code, &use_access_code,
128 &keylocation, &ndef_type, ndef_string,
129 &usb_mode, &zap, scan_codes, &cr_timeout,
130 &autoeject_timeout, &num_modes_seen, &exit_code)) {
134 if (verbose && (ykds_version_major(st) > 2 ||
135 (ykds_version_major(st) == 2 &&
136 ykds_version_minor(st) >= 2) ||
137 (ykds_version_major(st) == 2 && // neo has serial functions
138 ykds_version_minor(st) == 1 &&
139 ykds_version_build(st) >= 4))) {
141 if (! yk_get_serial(yk, 0, 0, &serial)) {
142 printf ("Failed to read serial number (serial-api-visible disabled?).\n");
145 printf ("Serial number : %i\n", serial);
152 if (strcmp(infname, "-") == 0)
155 inf = fopen(infname, "r");
158 "Couldn't open %s for reading: %s\n",
167 if (strcmp(outfname, "-") == 0)
170 outf = fopen(outfname, "w");
173 "Couldn't open %s for writing: %s\n",
181 if(!ykp_clear_config(cfg))
183 if(!fread(data, 1, 1024, inf))
185 if (!ykp_import_config(cfg, data, strlen(data), data_format))
187 } else if (! zap && (ykp_command(cfg) == SLOT_CONFIG || ykp_command(cfg) == SLOT_CONFIG2)) {
188 int key_bytes = ykp_get_supported_key_length(cfg);
191 if(keylocation == 2) {
192 if(key_bytes == 20) {
193 fprintf(stderr, " HMAC key, 20 bytes (40 characters hex) : ");
195 fprintf(stderr, " AES key, 16 bytes (32 characters hex) : ");
198 if(!fgets(keybuf, sizeof(keybuf), stdin)) {
204 keylen = strnlen(keybuf, sizeof(keybuf));
205 if(keybuf[keylen - 1] == '\n') {
206 keybuf[keylen - 1] = '\0';
208 if(key_bytes == 20) {
209 if(ykp_HMAC_key_from_hex(cfg, keybuf)) {
213 if(ykp_AES_key_from_hex(cfg, keybuf)) {
217 } else if(keylocation == 0) {
218 const char *random_places[] = {
224 const char **random_place;
225 size_t read_bytes = 0;
227 for (random_place = random_places; *random_place; random_place++) {
228 FILE *random_file = fopen(*random_place, "r");
232 while (read_bytes < key_bytes) {
233 size_t n = fread(&keybuf[read_bytes], 1,
234 key_bytes - read_bytes, random_file);
242 if(read_bytes < key_bytes) {
243 ykp_errno = YKP_ENORANDOM;
246 if(key_bytes == 20) {
247 if(ykp_HMAC_key_from_raw(cfg, keybuf)) {
251 if(ykp_AES_key_from_raw(cfg, keybuf)) {
259 if(!(ykp_export_config(cfg, data, 1024, data_format))) {
262 if(!(fwrite(data, 1, strlen(data), outf))) {
266 char commitbuf[256]; size_t commitlen;
268 if (ykp_command(cfg) == SLOT_SWAP) {
269 fprintf(stderr, "Configuration in slot 1 and 2 will be swapped\n");
270 } else if(ykp_command(cfg) == SLOT_NDEF || ykp_command(cfg) == SLOT_NDEF2) {
271 fprintf(stderr, "New NDEF will be written as:\n%s\n", ndef_string);
272 } else if(ykp_command(cfg) == SLOT_DEVICE_CONFIG) {
273 fprintf(stderr, "The USB mode will be set to: 0x%x\n", usb_mode);
274 if(num_modes_seen > 1) {
275 fprintf(stderr, "The challenge response timeout will be set to: %d\n", cr_timeout);
276 if(num_modes_seen > 2) {
277 fprintf(stderr, "The smartcard autoeject timeout will be set to: %d\n", autoeject_timeout);
280 } else if(ykp_command(cfg) == SLOT_SCAN_MAP) {
281 fprintf(stderr, "A new scanmap will be written.\n");
283 fprintf(stderr, "Configuration in slot %d will be deleted\n", ykp_config_num(cfg));
285 if (ykp_command(cfg) == SLOT_CONFIG || ykp_command(cfg) == SLOT_CONFIG2) {
286 fprintf(stderr, "Configuration data to be written to key configuration %d:\n\n", ykp_config_num(cfg));
288 fprintf(stderr, "Configuration data to be updated in key configuration %d:\n\n", ykp_command(cfg) == SLOT_UPDATE1 ? 1 : 2);
290 ykp_export_config(cfg, data, 1024, YKP_FORMAT_LEGACY);
291 fwrite(data, 1, strlen(data), stderr);
293 fprintf(stderr, "\nCommit? (y/n) [n]: ");
295 strcpy(commitbuf, "yes");
298 if (!fgets(commitbuf, sizeof(commitbuf), stdin))
304 commitlen = strlen(commitbuf);
305 if (commitbuf[commitlen - 1] == '\n')
306 commitbuf[commitlen - 1] = '\0';
307 if (strcmp(commitbuf, "y") == 0
308 || strcmp(commitbuf, "yes") == 0) {
312 printf("Attempting to write configuration to the yubikey...");
314 printf("Not writing anything to key due to dry_run requested.\n");
316 else if(ykp_command(cfg) == SLOT_NDEF || ykp_command(cfg) == SLOT_NDEF2) {
317 YK_NDEF *ndef = ykp_alloc_ndef();
319 if(ndef_type == 'U') {
320 ykp_construct_ndef_uri(ndef, ndef_string);
321 } else if(ndef_type == 'T') {
322 ykp_construct_ndef_text(ndef, ndef_string, "en", false);
324 if(use_access_code) {
325 ykp_set_ndef_access_code(ndef, access_code);
327 if(ykp_command(cfg) == SLOT_NDEF2) {
330 if (!yk_write_ndef2(yk, ndef, confnum)) {
332 printf(" failure\n");
336 } else if(ykp_command(cfg) == SLOT_DEVICE_CONFIG) {
337 YK_DEVICE_CONFIG *device_config = ykp_alloc_device_config();
338 ykp_set_device_mode(device_config, usb_mode);
339 if(num_modes_seen > 1) {
340 ykp_set_device_chalresp_timeout(device_config, cr_timeout);
341 if(num_modes_seen > 2) {
342 ykp_set_device_autoeject_time(device_config, autoeject_timeout);
346 if(!yk_write_device_config(yk, device_config)) {
348 printf(" failure\n");
351 ykp_free_device_config(device_config);
354 } else if(ykp_command(cfg) == SLOT_SCAN_MAP) {
355 if(!yk_write_scan_map(yk, scan_codes)) {
357 printf(" failure\n");
361 YK_CONFIG *ycfg = NULL;
362 /* if we're deleting a slot we send the configuration as NULL */
364 ycfg = ykp_core_config(cfg);
366 if (!yk_write_command(yk,
367 ycfg, ykp_command(cfg),
368 use_access_code ? access_code : NULL)) {
370 printf(" failure\n");
375 if (verbose && !dry_run)
376 printf(" success\n");
395 if (yk && !yk_close_key(yk)) {
406 ykp_free_config(cfg);