1 /* -*- mode:C; c-file-style: "bsd" -*- */
3 * Copyright (c) 2011-2012 Yubico AB.
6 * Author : Fredrik Thulin <fredrik@yubico.com>
8 * Some basic code copied from ykpersonalize.c.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 "Usage: ykchalresp [options] challenge\n"
47 "\t-1 Send challenge to slot 1. This is the default.\n"
48 "\t-2 Send challenge to slot 2.\n"
49 "\t-H Send a 64 byte HMAC challenge. This is the default.\n"
50 "\t-Y Send a 6 byte Yubico challenge.\n"
51 "\t-N Abort if Yubikey requires button press.\n"
52 "\t-x Challenge is hex encoded.\n"
55 "\t-h help (this text)\n"
59 const char *optstring = "12xvhHYN";
61 static void report_yk_error()
64 fprintf(stderr, "Yubikey personalization error: %s\n",
65 ykp_strerror(ykp_errno));
67 if (yk_errno == YK_EUSBERR) {
68 fprintf(stderr, "USB error: %s\n",
71 fprintf(stderr, "Yubikey core error: %s\n",
72 yk_strerror(yk_errno));
77 int parse_args(int argc, char **argv,
78 int *slot, bool *verbose,
79 unsigned char **challenge, unsigned int *challenge_len,
80 bool *hmac, bool *may_block,
84 bool hex_encoded = false;
86 while((c = getopt(argc, argv, optstring)) != -1) {
111 fputs(usage, stderr);
117 if (optind >= argc) {
119 fputs(usage, stderr);
124 static unsigned char decoded[SHA1_MAX_BLOCK_SIZE];
127 int strl = strlen(argv[optind]);
129 if (strl > sizeof(decoded) * 2) {
130 fprintf(stderr, "Hex-encoded challenge too long (max %lu chars)\n",
131 sizeof(decoded) * 2);
136 fprintf(stderr, "Odd number of characters in hex-encoded challenge\n");
140 memset(decoded, 0, sizeof(decoded));
142 if (yubikey_hex_p(argv[optind])) {
143 yubikey_hex_decode((char *)decoded, argv[optind], sizeof(decoded));
145 fprintf(stderr, "Bad hex-encoded string '%s'\n", argv[optind]);
148 *challenge = (unsigned char *) &decoded;
149 *challenge_len = strl / 2;
151 *challenge = (unsigned char *) argv[optind];
152 *challenge_len = strlen(argv[optind]);
158 int check_firmware(YK_KEY *yk, bool verbose)
160 YK_STATUS *st = ykds_alloc();
162 if (!yk_get_status(yk, st)) {
168 printf("Firmware version %d.%d.%d\n",
169 ykds_version_major(st),
170 ykds_version_minor(st),
171 ykds_version_build(st));
175 if (ykds_version_major(st) < 2 ||
176 (ykds_version_major(st) == 2
177 && ykds_version_minor(st) < 2)) {
178 fprintf(stderr, "Challenge-response not supported before YubiKey 2.2.\n");
187 int challenge_response(YK_KEY *yk, int slot,
188 unsigned char *challenge, unsigned int len,
189 bool hmac, bool may_block, bool verbose)
191 unsigned char response[64];
192 unsigned char output_buf[(SHA1_MAX_BLOCK_SIZE * 2) + 1];
194 unsigned int flags = 0;
195 unsigned int response_len = 0;
196 unsigned int expect_bytes = 0;
198 memset(response, 0, sizeof(response));
201 flags |= YK_FLAG_MAYBLOCK;
204 fprintf(stderr, "Sending %i bytes %s challenge to slot %i\n", len, (hmac == true)?"HMAC":"Yubico", slot);
205 //_yk_hexdump(challenge, len);
210 yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC1 : SLOT_CHAL_OTP1;
213 yk_cmd = (hmac == true) ? SLOT_CHAL_HMAC2 : SLOT_CHAL_OTP2;
217 if (!yk_write_to_key(yk, yk_cmd, challenge, len))
221 fprintf(stderr, "Reading response...\n");
224 /* HMAC responses are 160 bits, Yubico 128 */
225 expect_bytes = (hmac == true) ? 20 : 16;
227 if (! yk_read_response_from_key(yk, slot, flags,
228 &response, sizeof(response),
233 if (hmac && response_len > 20)
235 if (! hmac && response_len > 16)
238 memset(output_buf, 0, sizeof(output_buf));
240 yubikey_hex_encode((char *)output_buf, (char *)response, response_len);
242 yubikey_modhex_encode((char *)output_buf, (char *)response, response_len);
244 printf("%s\n", output_buf);
249 int main(int argc, char **argv)
256 bool verbose = false;
257 bool hex_encoded = false;
259 bool may_block = true;
260 unsigned char *challenge;
261 unsigned int challenge_len;
267 if (! parse_args(argc, argv,
269 &challenge, &challenge_len,
279 if (!(yk = yk_open_first_key())) {
284 if (! check_firmware(yk, verbose)) {
289 if (! challenge_response(yk, slot,
290 challenge, challenge_len,
291 hmac, may_block, verbose)) {
300 if (error || exit_code != 0) {
304 if (yk && !yk_close_key(yk)) {