Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
ykyh.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2018 Yubico AB
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <stdio.h>
20#include <stdint.h>
21
22#include "internal.h"
23#include "ykyh.h"
24
25static ykyh_rc send_data(ykyh_state *state, APDU *apdu, unsigned char *data,
26 unsigned long *recv_len, int *sw);
27
28static void dump_hex(const unsigned char *buf, unsigned int len) {
29 unsigned int i;
30 for (i = 0; i < len; i++) {
31 fprintf(stderr, "%02x ", buf[i]);
32 }
33}
34
36 if (state == NULL) {
37 if (verbose) {
38 fprintf(stderr, "Unable to initialize: %s",
40 }
41
43 }
44
45 ykyh_state *s = malloc(sizeof(ykyh_state));
46
47 if (s == NULL) {
48 if (verbose) {
49 fprintf(stderr, "Unable to initialize: %s",
51 }
52
53 return YKYHR_MEMORY_ERROR;
54 }
55
56 memset(s, 0, sizeof(ykyh_state));
57 s->verbose = verbose;
58 s->context = SCARD_E_INVALID_HANDLE;
59 *state = s;
60
61 return YKYHR_SUCCESS;
62}
63
66
67 if (state != NULL) {
68 free(state);
69 }
70
71 return YKYHR_SUCCESS;
72}
73
75 if (state == NULL) {
77 }
78
79 if (state->card) {
80 SCardDisconnect(state->card, SCARD_RESET_CARD);
81 state->card = 0;
82 }
83
84 if (SCardIsValidContext(state->context) == SCARD_S_SUCCESS) {
85 SCardReleaseContext(state->context);
86 state->context = SCARD_E_INVALID_HANDLE;
87 }
88
89 return YKYHR_SUCCESS;
90}
91
92ykyh_rc ykyh_connect(ykyh_state *state, const char *wanted) {
93 unsigned long active_protocol;
94 char reader_buf[2048];
95 size_t num_readers = sizeof(reader_buf);
96 long rc;
97 char *reader_ptr;
98
99 if (state == NULL) {
101 }
102
103 ykyh_rc ret = ykyh_list_readers(state, reader_buf, &num_readers);
104 if (ret != YKYHR_SUCCESS) {
105 if (state->verbose) {
106 fprintf(stderr, "Unable to list_readers: %s", ykyh_strerror(ret));
107 }
108
109 return ret;
110 }
111
112 for (reader_ptr = reader_buf; *reader_ptr != '\0';
113 reader_ptr += strlen(reader_ptr) + 1) {
114 if (wanted) {
115 if (!strstr(reader_ptr, wanted)) {
116 if (state->verbose) {
117 fprintf(stderr, "skipping reader '%s' since it doesn't match '%s'\n",
118 reader_ptr, wanted);
119 }
120 continue;
121 }
122 }
123
124 if (state->verbose) {
125 fprintf(stderr, "trying to connect to reader '%s'\n", reader_ptr);
126 }
127
128 rc =
129 SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED,
130 SCARD_PROTOCOL_T1, &state->card, (LPDWORD) &active_protocol);
131
132 if (rc != SCARD_S_SUCCESS) {
133 if (state->verbose) {
134 fprintf(stderr, "SCardConnect failed, rc=%08lx\n", rc);
135 }
136 continue;
137 }
138
139 APDU apdu;
140 unsigned char data[0xff];
141 unsigned long recv_len = sizeof(data);
142 int sw;
143 ykyh_rc res;
144
145 memset(apdu.raw, 0, sizeof(apdu));
146 apdu.st.ins = 0xa4;
147 apdu.st.p1 = 0x04;
148 apdu.st.lc = sizeof(aid);
149 memcpy(apdu.st.data, aid, sizeof(aid));
150
151 if ((res = send_data(state, &apdu, data, &recv_len, &sw)) !=
153 if (state->verbose) {
154 fprintf(stderr, "Failed communicating with card: '%s'\n",
155 ykyh_strerror(res));
156 }
157
158 continue;
159 } else if (sw == SW_SUCCESS) {
160 return YKYHR_SUCCESS;
161 } else {
162 if (state->verbose) {
163 fprintf(stderr, "Failed selecting application: %04x\n", sw);
164 }
165 }
166 }
167
168 if (*reader_ptr == '\0') {
169 if (state->verbose) {
170 fprintf(stderr, "error: no usable reader found\n");
171 }
172 SCardReleaseContext(state->context);
173 state->context = SCARD_E_INVALID_HANDLE;
174 return YKYHR_PCSC_ERROR;
175 }
176
177 return YKYHR_GENERIC_ERROR;
178}
179
180ykyh_rc ykyh_list_readers(ykyh_state *state, char *readers, size_t *len) {
181 unsigned long num_readers = 0;
182 long rc;
183
184 if (state == NULL || readers == NULL) {
186 }
187
188 if (SCardIsValidContext(state->context) != SCARD_S_SUCCESS) {
189 rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &state->context);
190 if (rc != SCARD_S_SUCCESS) {
191 if (state->verbose) {
192 fprintf(stderr, "error: SCardEstablishContext failed, rc=%08lx\n", rc);
193 }
194 return YKYHR_PCSC_ERROR;
195 }
196 }
197
198 rc = SCardListReaders(state->context, NULL, NULL, (LPDWORD) &num_readers);
199 if (rc != SCARD_S_SUCCESS) {
200 if (state->verbose) {
201 fprintf(stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
202 }
203 SCardReleaseContext(state->context);
204 state->context = SCARD_E_INVALID_HANDLE;
205 return YKYHR_PCSC_ERROR;
206 }
207
208 if (num_readers > *len) {
209 num_readers = *len;
210 }
211
212 rc = SCardListReaders(state->context, NULL, readers, (LPDWORD) &num_readers);
213 if (rc != SCARD_S_SUCCESS) {
214 if (state->verbose) {
215 fprintf(stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
216 }
217 SCardReleaseContext(state->context);
218 state->context = SCARD_E_INVALID_HANDLE;
219 return YKYHR_PCSC_ERROR;
220 }
221
222 *len = num_readers;
223
224 return YKYHR_SUCCESS;
225}
226
227static ykyh_rc send_data(ykyh_state *state, APDU *apdu, unsigned char *data,
228 unsigned long *recv_len, int *sw) {
229 long rc;
230 unsigned int send_len = (unsigned int) apdu->st.lc + 5;
231
232 *sw = 0;
233
234 if (state->verbose > 1) {
235 fprintf(stderr, "> ");
236 dump_hex(apdu->raw, send_len);
237 fprintf(stderr, "\n");
238 }
239 rc = SCardTransmit(state->card, SCARD_PCI_T1, apdu->raw, send_len, NULL, data,
240 (LPDWORD) recv_len);
241 if (rc != SCARD_S_SUCCESS) {
242 if (state->verbose) {
243 fprintf(stderr, "error: SCardTransmit failed, rc=%08lx\n", rc);
244 }
245 return YKYHR_PCSC_ERROR;
246 }
247
248 if (state->verbose > 1) {
249 fprintf(stderr, "< ");
250 dump_hex(data, *recv_len);
251 fprintf(stderr, "\n");
252 }
253 if (*recv_len >= 2) {
254 *sw = (data[*recv_len - 2] << 8) | data[*recv_len - 1];
255 }
256
257 return YKYHR_SUCCESS;
258}
259
260ykyh_rc ykyh_get_version(ykyh_state *state, char *version, size_t len) {
261 APDU apdu;
262 unsigned char data[261];
263 unsigned long recv_len = sizeof(data);
264 int sw;
265 ykyh_rc res;
266
267 if (state == NULL || version == NULL) {
269 }
270
271 memset(apdu.raw, 0, sizeof(apdu));
272 apdu.st.ins = YKYH_INS_GET_VERSION;
273 if ((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKYHR_SUCCESS) {
274 return res;
275 } else if (sw == SW_SUCCESS) {
276 int result = snprintf(version, len, "%d.%d.%d", data[0], data[1], data[2]);
277 if (result < 0) {
278 if (state->verbose) {
279 fprintf(stderr, "Version buffer too small\n");
280 }
281 return YKYHR_GENERIC_ERROR;
282 }
283 return YKYHR_SUCCESS;
284 } else {
285 return YKYHR_GENERIC_ERROR;
286 }
287}
288
289ykyh_rc ykyh_put(ykyh_state *state, const char *name, const uint8_t *key_enc,
290 size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len,
291 const char *pw, const uint8_t touch_policy) {
292 APDU apdu;
293 uint8_t *ptr = apdu.st.data;
294 unsigned char data[261];
295 unsigned long recv_len = sizeof(data);
296 int sw;
297
298 if (state == NULL || name == NULL || strlen(name) < YKYH_MIN_NAME_LEN ||
299 strlen(name) > YKYH_MAX_NAME_LEN || key_enc == NULL ||
300 key_enc_len != YKYH_KEY_LEN || key_mac == NULL ||
301 key_mac_len != YKYH_KEY_LEN || pw == NULL || strlen(pw) != YKYH_KEY_LEN) {
303 }
304
305 memset(apdu.raw, 0, sizeof(apdu));
306 apdu.st.ins = YKYH_INS_PUT;
307
308 *(ptr++) = YKYH_TAG_NAME;
309 apdu.st.lc++;
310 *(ptr++) = strlen(name);
311 apdu.st.lc++;
312 memcpy(ptr, name, strlen(name));
313 ptr += strlen(name);
314 apdu.st.lc += strlen(name);
315
316 *(ptr++) = YKYH_TAG_ALGO;
317 apdu.st.lc++;
318 *(ptr++) = 1;
319 apdu.st.lc++;
320 *(ptr++) = YKYH_SCP03_ALGO;
321 apdu.st.lc++;
322
323 *(ptr++) = YKYH_TAG_KEY_ENC;
324 apdu.st.lc++;
325 *(ptr++) = 16;
326 apdu.st.lc++;
327 memcpy(ptr, key_enc, 16);
328 ptr += 16;
329 apdu.st.lc += 16;
330
331 *(ptr++) = YKYH_TAG_KEY_MAC;
332 apdu.st.lc++;
333 *(ptr++) = 16;
334 apdu.st.lc++;
335 memcpy(ptr, key_mac, 16);
336 ptr += 16;
337 apdu.st.lc += 16;
338
339 *(ptr++) = YKYH_TAG_PW;
340 apdu.st.lc++;
341 *(ptr++) = YKYH_PW_LEN;
342 apdu.st.lc++;
343 memcpy(ptr, pw, YKYH_PW_LEN);
344 ptr += YKYH_PW_LEN;
345 apdu.st.lc += YKYH_PW_LEN;
346
347 *(ptr++) = YKYH_TAG_TOUCH;
348 apdu.st.lc++;
349 *(ptr++) = 1;
350 apdu.st.lc++;
351 *(ptr++) = touch_policy ? 1 : 0;
352 apdu.st.lc++;
353
354 ykyh_rc rc = send_data(state, &apdu, data, &recv_len, &sw);
355 if (rc != YKYHR_SUCCESS) {
356 return rc;
357 } else if (sw != SW_SUCCESS) {
358 return YKYHR_GENERIC_ERROR; // TODO(adma): better error
359 }
360
361 return YKYHR_SUCCESS;
362}
363
365 APDU apdu;
366 uint8_t *ptr;
367 unsigned char data[64];
368 unsigned long recv_len = sizeof(data);
369 int sw;
370 ykyh_rc rc;
371
372 if (state == NULL || name == NULL || strlen(name) < YKYH_MIN_NAME_LEN ||
373 strlen(name) > YKYH_MAX_NAME_LEN) {
375 }
376
377 memset(apdu.raw, 0, sizeof(apdu));
378 apdu.st.ins = YKYH_INS_DELETE;
379
380 ptr = apdu.st.data;
381
382 *(ptr++) = YKYH_TAG_NAME;
383 apdu.st.lc++;
384 *(ptr++) = strlen(name);
385 apdu.st.lc++;
386 memcpy(ptr, name, strlen(name));
387 ptr += strlen(name);
388 apdu.st.lc += strlen(name);
389
390 rc = send_data(state, &apdu, data, &recv_len, &sw);
391 if (rc != YKYHR_SUCCESS) {
392 return rc;
393 } else if (sw != SW_SUCCESS) {
394 if (state->verbose) {
395 fprintf(stderr, "Unable to delete key: %04x\n", sw);
396 }
397 return YKYHR_GENERIC_ERROR;
398 }
399
400 return YKYHR_SUCCESS;
401}
402
404 size_t context_len, const char *pw, uint8_t *key_s_enc,
405 size_t key_s_enc_len, uint8_t *key_s_mac,
406 size_t key_s_mac_len, uint8_t *key_s_rmac,
407 size_t key_s_rmac_len, uint8_t *retries) {
408 APDU apdu;
409 uint8_t *ptr;
410 unsigned char data[64]; // NOTE(adma): must be >= (YKYH_KEY_LEN * 3) + 2 = 50
411 unsigned long recv_len = sizeof(data);
412 int sw;
413 ykyh_rc rc;
414
415 if (state == NULL || name == NULL || strlen(name) < YKYH_MIN_NAME_LEN ||
416 strlen(name) > YKYH_MAX_NAME_LEN || context == NULL ||
417 context_len != YKYH_CONTEXT_LEN || pw == NULL ||
418 strlen(pw) != YKYH_PW_LEN || key_s_enc == NULL ||
419 key_s_enc_len != YKYH_KEY_LEN || key_s_mac == NULL ||
420 key_s_mac_len != YKYH_KEY_LEN || key_s_rmac == NULL ||
421 key_s_rmac_len != YKYH_KEY_LEN) {
423 }
424
425 memset(apdu.raw, 0, sizeof(apdu));
426 apdu.st.ins = YKYH_INS_CALCULATE;
427
428 ptr = apdu.st.data;
429
430 *(ptr++) = YKYH_TAG_NAME;
431 apdu.st.lc++;
432 *(ptr++) = strlen(name);
433 apdu.st.lc++;
434 memcpy(ptr, name, strlen(name));
435 ptr += strlen(name);
436 apdu.st.lc += strlen(name);
437
438 *(ptr++) = YKYH_TAG_CONTEXT;
439 apdu.st.lc++;
440 *(ptr++) = context_len;
441 apdu.st.lc++;
442 memcpy(ptr, context, context_len);
443 ptr += context_len;
444 apdu.st.lc += context_len;
445
446 *(ptr++) = YKYH_TAG_PW;
447 apdu.st.lc++;
448 *(ptr++) = YKYH_PW_LEN;
449 apdu.st.lc++;
450 memcpy(ptr, pw, YKYH_PW_LEN);
451 ptr += YKYH_PW_LEN;
452 apdu.st.lc += YKYH_PW_LEN;
453
454 rc = send_data(state, &apdu, data, &recv_len, &sw);
455 if (rc != YKYHR_SUCCESS) {
456 return rc;
457 } else if (sw != SW_SUCCESS) {
458 if (state->verbose) {
459 fprintf(stderr, "Unable to derive keys: %04x\n", sw);
460 }
461 if ((sw & 0xfff0) == SW_ERR_AUTHENTICATION_FAILED) {
462 if (retries != NULL) {
463 *retries = sw & ~SW_ERR_AUTHENTICATION_FAILED;
464 }
465 return YKYHR_WRONG_PW;
466 } else {
468 }
469 }
470
471 ptr = data;
472
473 memcpy(key_s_enc, ptr, YKYH_KEY_LEN);
474 ptr += YKYH_KEY_LEN;
475 memcpy(key_s_mac, ptr, YKYH_KEY_LEN);
476 ptr += YKYH_KEY_LEN;
477 memcpy(key_s_rmac, ptr, YKYH_KEY_LEN);
478 ptr += YKYH_KEY_LEN;
479
480 return YKYHR_SUCCESS;
481}
482
484
485 APDU apdu;
486 unsigned char data[8];
487 unsigned long recv_len = sizeof(data);
488 int sw;
489 ykyh_rc res;
490
491 if (state == NULL) {
493 }
494
495 memset(apdu.raw, 0, sizeof(apdu));
496 apdu.st.ins = YKYH_INS_RESET;
497 apdu.st.p1 = YKYH_P1_RESET;
498 apdu.st.p2 = YKYH_P2_RESET;
499
500 res = send_data(state, &apdu, data, &recv_len, &sw);
501 if (sw != SW_SUCCESS) {
502 if (state->verbose) {
503 fprintf(stderr, "Unable to reset: %s\n", ykyh_strerror(res));
504 }
505 }
506
507 return res;
508}
509
511 size_t *list_items) {
512
513 APDU apdu;
514 unsigned char data[1024];
515 unsigned long recv_len = sizeof(data);
516 int sw;
517 ykyh_rc res;
518
519 if (state == NULL || list_items == NULL) {
521 }
522
523 memset(apdu.raw, 0, sizeof(apdu));
524 apdu.st.ins = YKYH_INS_LIST;
525
526 res = send_data(state, &apdu, data, &recv_len, &sw);
527 if (res != YKYHR_SUCCESS || sw != SW_SUCCESS) {
528 if (state->verbose) {
529 fprintf(stderr, "Unable to list keys: %s\n", ykyh_strerror(res));
530 }
531 return res;
532 }
533
534 if (list == NULL) {
535 *list_items = data[0];
536
537 return YKYHR_SUCCESS;
538 }
539
540 if (*list_items < data[0]) {
541 return YKYHR_GENERIC_ERROR; // TODO(adma): not enough space, better error?
542 }
543 *list_items = data[0];
544
545 size_t i = 1;
546 for (size_t j = 0; j < *list_items; j++) {
547 if (data[i++] == YKYH_TAG_NAME_LIST) {
548 size_t len = data[i++];
549 list[j].algo = data[i++];
550 memset(list[j].name, 0, sizeof(list[j].name));
551 memcpy(list[j].name, data + i, len - 2);
552 i += len - 2;
553 list[j].ctr = data[i++];
554 } else {
555 return YKYHR_GENERIC_ERROR;
556 }
557 }
558
559 if (i != recv_len - 2) {
560 return YKYHR_GENERIC_ERROR;
561 }
562
563 return YKYHR_SUCCESS;
564}
565
567
568 (void) state;
569 return YKYHR_SUCCESS;
570}
std::string name
void YH_INTERNAL dump_hex(FILE *file, const uint8_t *ptr, uint16_t len)
Definition lib_util.c:33
bool verbose
Definition main.cpp:190
unsigned char uint8_t
Definition stdint.h:124
struct context * context
Definition ykyh.h:86
unsigned char raw[0xff+5]
Definition internal.h:49
struct u_APDU::@119 st
const char * ykyh_strerror(ykyh_rc err)
Definition error.c:40
unsigned const char aid[]
Definition internal.h:54
ykyh_rc ykyh_put(ykyh_state *state, const char *name, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len, const char *pw, const uint8_t touch_policy)
Definition ykyh.c:289
ykyh_rc ykyh_get_version(ykyh_state *state, char *version, size_t len)
Definition ykyh.c:260
ykyh_rc ykyh_get_challenge(ykyh_state *state)
Definition ykyh.c:566
ykyh_rc ykyh_done(ykyh_state *state)
Definition ykyh.c:64
ykyh_rc ykyh_connect(ykyh_state *state, const char *wanted)
Definition ykyh.c:92
ykyh_rc ykyh_list_keys(ykyh_state *state, ykyh_list_entry *list, size_t *list_items)
Definition ykyh.c:510
ykyh_rc ykyh_reset(ykyh_state *state)
Definition ykyh.c:483
ykyh_rc ykyh_list_readers(ykyh_state *state, char *readers, size_t *len)
Definition ykyh.c:180
ykyh_rc ykyh_init(ykyh_state **state, int verbose)
Definition ykyh.c:35
ykyh_rc ykyh_delete(ykyh_state *state, char *name)
Definition ykyh.c:364
ykyh_rc ykyh_calculate(ykyh_state *state, const char *name, uint8_t *context, size_t context_len, const char *pw, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries)
Definition ykyh.c:403
ykyh_rc ykyh_disconnect(ykyh_state *state)
Definition ykyh.c:74
#define YKYH_PW_LEN
Definition ykyh.h:67
#define YKYH_TAG_TOUCH
Definition ykyh.h:54
#define SW_ERR_AUTHENTICATION_FAILED
Definition ykyh.h:61
#define YKYH_TAG_NAME
Definition ykyh.h:45
#define YKYH_SCP03_ALGO
Definition ykyh.h:57
#define YKYH_TAG_PW
Definition ykyh.h:47
#define SW_SUCCESS
Definition ykyh.h:60
#define YKYH_INS_RESET
Definition ykyh.h:35
#define YKYH_TAG_ALGO
Definition ykyh.h:48
#define YKYH_CONTEXT_LEN
Definition ykyh.h:68
#define YKYH_TAG_KEY_ENC
Definition ykyh.h:49
#define YKYH_INS_LIST
Definition ykyh.h:34
#define YKYH_INS_GET_VERSION
Definition ykyh.h:36
#define YKYH_TAG_KEY_MAC
Definition ykyh.h:50
ykyh_rc
Definition ykyh.h:76
@ YKYHR_INVALID_PARAMS
Definition ykyh.h:82
@ YKYHR_GENERIC_ERROR
Definition ykyh.h:80
@ YKYHR_SUCCESS
Definition ykyh.h:77
@ YKYHR_MEMORY_ERROR
Definition ykyh.h:78
@ YKYHR_PCSC_ERROR
Definition ykyh.h:79
@ YKYHR_ENTRY_NOT_FOUND
Definition ykyh.h:83
@ YKYHR_WRONG_PW
Definition ykyh.h:81
#define YKYH_INS_CALCULATE
Definition ykyh.h:32
#define YKYH_KEY_LEN
Definition ykyh.h:66
#define YKYH_INS_PUT
Definition ykyh.h:30
#define YKYH_P2_RESET
Definition ykyh.h:42
#define YKYH_P1_RESET
Definition ykyh.h:39
#define YKYH_MAX_NAME_LEN
Definition ykyh.h:65
#define YKYH_INS_DELETE
Definition ykyh.h:31
#define YKYH_MIN_NAME_LEN
Definition ykyh.h:64
#define YKYH_TAG_NAME_LIST
Definition ykyh.h:46
#define YKYH_TAG_CONTEXT
Definition ykyh.h:51
CK_RV ret
char * s
uint16_t j
size_t len
uint8_t buf[2048]
yh_rc rc
memset(pInfo->slotDescription, ' ', 64)
memcpy((char *) pInfo->slotDescription, s, l)