2 * Copyright (c) 2018 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
7 #include <openssl/sha.h>
14 typedef struct dev_manifest_func_node {
15 dev_manifest_func_t manifest_func;
16 struct dev_manifest_func_node *next;
17 } dev_manifest_func_node_t;
19 static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
20 static TLS bool disable_u2f_fallback;
23 find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
24 dev_manifest_func_node_t **prev)
27 *curr = manifest_funcs;
29 while (*curr != NULL && (*curr)->manifest_func != f) {
31 *curr = (*curr)->next;
37 set_random_report_len(fido_dev_t *dev)
39 dev->rx_len = CTAP_MIN_REPORT_LEN +
40 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
41 dev->tx_len = CTAP_MIN_REPORT_LEN +
42 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
47 fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
49 char * const *ptr = fido_cbor_info_extensions_ptr(info);
50 size_t len = fido_cbor_info_extensions_len(info);
52 for (size_t i = 0; i < len; i++)
53 if (strcmp(ptr[i], "credProtect") == 0)
54 dev->flags |= FIDO_DEV_CRED_PROT;
58 fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
60 char * const *ptr = fido_cbor_info_options_name_ptr(info);
61 const bool *val = fido_cbor_info_options_value_ptr(info);
62 size_t len = fido_cbor_info_options_len(info);
64 for (size_t i = 0; i < len; i++)
65 if (strcmp(ptr[i], "clientPin") == 0) {
66 dev->flags |= val[i] ? FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
67 } else if (strcmp(ptr[i], "credMgmt") == 0 ||
68 strcmp(ptr[i], "credentialMgmtPreview") == 0) {
70 dev->flags |= FIDO_DEV_CREDMAN;
71 } else if (strcmp(ptr[i], "uv") == 0) {
72 dev->flags |= val[i] ? FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
73 } else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
75 dev->flags |= FIDO_DEV_TOKEN_PERMS;
80 fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
82 const uint8_t *ptr = fido_cbor_info_protocols_ptr(info);
83 size_t len = fido_cbor_info_protocols_len(info);
85 for (size_t i = 0; i < len; i++)
87 case CTAP_PIN_PROTOCOL1:
88 dev->flags |= FIDO_DEV_PIN_PROTOCOL1;
90 case CTAP_PIN_PROTOCOL2:
91 dev->flags |= FIDO_DEV_PIN_PROTOCOL2;
94 fido_log_debug("%s: unknown protocol %u", __func__,
101 fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
103 fido_dev_set_extension_flags(dev, info);
104 fido_dev_set_option_flags(dev, info);
105 fido_dev_set_protocol_flags(dev, info);
109 fido_dev_open_tx(fido_dev_t *dev, const char *path)
113 if (dev->io_handle != NULL) {
114 fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
115 return (FIDO_ERR_INVALID_ARGUMENT);
118 if (dev->io.open == NULL || dev->io.close == NULL) {
119 fido_log_debug("%s: NULL open/close", __func__);
120 return (FIDO_ERR_INVALID_ARGUMENT);
123 if (dev->cid != CTAP_CID_BROADCAST) {
124 fido_log_debug("%s: cid=0x%x", __func__, dev->cid);
125 return (FIDO_ERR_INVALID_ARGUMENT);
128 if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) {
129 fido_log_debug("%s: fido_get_random", __func__);
130 return (FIDO_ERR_INTERNAL);
133 if ((dev->io_handle = dev->io.open(path)) == NULL) {
134 fido_log_debug("%s: dev->io.open", __func__);
135 return (FIDO_ERR_INTERNAL);
139 dev->rx_len = CTAP_MAX_REPORT_LEN;
140 dev->tx_len = CTAP_MAX_REPORT_LEN;
142 dev->rx_len = fido_hid_report_in_len(dev->io_handle);
143 dev->tx_len = fido_hid_report_out_len(dev->io_handle);
147 set_random_report_len(dev);
150 if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
151 dev->rx_len > CTAP_MAX_REPORT_LEN) {
152 fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
157 if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
158 dev->tx_len > CTAP_MAX_REPORT_LEN) {
159 fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
164 if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce)) < 0) {
165 fido_log_debug("%s: fido_tx", __func__);
172 dev->io.close(dev->io_handle);
173 dev->io_handle = NULL;
179 fido_dev_open_rx(fido_dev_t *dev, int ms)
181 fido_cbor_info_t *info = NULL;
185 if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
186 sizeof(dev->attr), ms)) < 0) {
187 fido_log_debug("%s: fido_rx", __func__);
193 dev->attr.nonce = dev->nonce;
196 if ((size_t)reply_len != sizeof(dev->attr) ||
197 dev->attr.nonce != dev->nonce) {
198 fido_log_debug("%s: invalid nonce", __func__);
204 dev->cid = dev->attr.cid;
206 if (fido_dev_is_fido2(dev)) {
207 if ((info = fido_cbor_info_new()) == NULL) {
208 fido_log_debug("%s: fido_cbor_info_new", __func__);
209 r = FIDO_ERR_INTERNAL;
212 if ((r = fido_dev_get_cbor_info_wait(dev, info,
214 fido_log_debug("%s: fido_dev_cbor_info_wait: %d",
216 if (disable_u2f_fallback)
218 fido_log_debug("%s: falling back to u2f", __func__);
219 fido_dev_force_u2f(dev);
221 fido_dev_set_flags(dev, info);
225 if (fido_dev_is_fido2(dev) && info != NULL) {
226 dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info);
227 fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
228 FIDO_MAXMSG, (unsigned long)dev->maxmsgsize);
233 fido_cbor_info_free(&info);
236 dev->io.close(dev->io_handle);
237 dev->io_handle = NULL;
244 fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
249 if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
250 return (fido_winhello_open(dev));
252 if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
253 (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
260 fido_dev_register_manifest_func(const dev_manifest_func_t f)
262 dev_manifest_func_node_t *prev, *curr, *n;
264 find_manifest_func_node(f, &curr, &prev);
268 if ((n = calloc(1, sizeof(*n))) == NULL) {
269 fido_log_debug("%s: calloc", __func__);
270 return (FIDO_ERR_INTERNAL);
273 n->manifest_func = f;
274 n->next = manifest_funcs;
281 fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
283 dev_manifest_func_node_t *prev, *curr;
285 find_manifest_func_node(f, &curr, &prev);
289 prev->next = curr->next;
291 manifest_funcs = curr->next;
297 fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
299 dev_manifest_func_node_t *curr = NULL;
300 dev_manifest_func_t m_func;
306 if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
307 return (FIDO_ERR_INTERNAL);
309 if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK)
310 return (FIDO_ERR_INTERNAL);
313 if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK)
314 return (FIDO_ERR_INTERNAL);
317 for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
319 m_func = curr->manifest_func;
320 r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
332 fido_dev_open_with_info(fido_dev_t *dev)
334 if (dev->path == NULL)
335 return (FIDO_ERR_INVALID_ARGUMENT);
337 return (fido_dev_open_wait(dev, dev->path, -1));
341 fido_dev_open(fido_dev_t *dev, const char *path)
345 * this is a hack to get existing applications up and running with nfc;
346 * it will *NOT* be part of a libfido2 release. to support nfc in your
347 * application, please change it to use fido_dev_open_with_info().
349 if (strncmp(path, "/sys", strlen("/sys")) == 0 && strlen(path) > 4 &&
350 path[strlen(path) - 4] == 'n' && path[strlen(path) - 3] == 'f' &&
351 path[strlen(path) - 2] == 'c') {
353 dev->io = (fido_dev_io_t) {
359 dev->transport = (fido_dev_transport_t) {
366 return (fido_dev_open_wait(dev, path, -1));
370 fido_dev_close(fido_dev_t *dev)
373 if (dev->flags & FIDO_DEV_WINHELLO)
374 return (fido_winhello_close(dev));
376 if (dev->io_handle == NULL || dev->io.close == NULL)
377 return (FIDO_ERR_INVALID_ARGUMENT);
379 dev->io.close(dev->io_handle);
380 dev->io_handle = NULL;
381 dev->cid = CTAP_CID_BROADCAST;
387 fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
389 if (dev->io_own || dev->io_handle == NULL || sigmask == NULL)
390 return (FIDO_ERR_INVALID_ARGUMENT);
393 if (dev->transport.rx == fido_nfc_rx)
394 return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
396 return (fido_hid_set_sigmask(dev->io_handle, sigmask));
400 fido_dev_cancel(fido_dev_t *dev)
403 if (dev->flags & FIDO_DEV_WINHELLO)
404 return (fido_winhello_cancel(dev));
406 if (fido_dev_is_fido2(dev) == false)
407 return (FIDO_ERR_INVALID_ARGUMENT);
408 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
409 return (FIDO_ERR_TX);
415 fido_dev_get_touch_begin(fido_dev_t *dev)
418 cbor_item_t *argv[9];
419 const char *clientdata = FIDO_DUMMY_CLIENTDATA;
420 const uint8_t user_id = FIDO_DUMMY_USER_ID;
421 unsigned char cdh[SHA256_DIGEST_LENGTH];
424 int r = FIDO_ERR_INTERNAL;
426 memset(&f, 0, sizeof(f));
427 memset(argv, 0, sizeof(argv));
428 memset(cdh, 0, sizeof(cdh));
429 memset(&rp, 0, sizeof(rp));
430 memset(&user, 0, sizeof(user));
432 if (fido_dev_is_fido2(dev) == false)
433 return (u2f_get_touch_begin(dev));
435 if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
436 fido_log_debug("%s: sha256", __func__);
437 return (FIDO_ERR_INTERNAL);
440 if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
441 (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
442 fido_log_debug("%s: strdup", __func__);
446 if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
447 fido_log_debug("%s: fido_blob_set", __func__);
451 if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
452 (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
453 (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
454 (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
455 fido_log_debug("%s: cbor encode", __func__);
459 if (fido_dev_supports_pin(dev)) {
460 if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
461 (argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
462 fido_log_debug("%s: cbor encode", __func__);
467 if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
468 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
469 fido_log_debug("%s: fido_tx", __func__);
476 cbor_vector_free(argv, nitems(argv));
486 fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
492 if (fido_dev_is_fido2(dev) == false)
493 return (u2f_get_touch_status(dev, touched, ms));
495 switch ((r = fido_rx_cbor_status(dev, ms))) {
496 case FIDO_ERR_PIN_AUTH_INVALID:
497 case FIDO_ERR_PIN_INVALID:
498 case FIDO_ERR_PIN_NOT_SET:
499 case FIDO_ERR_SUCCESS:
506 fido_log_debug("%s: fido_rx_cbor_status", __func__);
514 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
516 if (dev->io_handle != NULL) {
517 fido_log_debug("%s: non-NULL handle", __func__);
518 return (FIDO_ERR_INVALID_ARGUMENT);
521 if (io == NULL || io->open == NULL || io->close == NULL ||
522 io->read == NULL || io->write == NULL) {
523 fido_log_debug("%s: NULL function", __func__);
524 return (FIDO_ERR_INVALID_ARGUMENT);
534 fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
536 if (dev->io_handle != NULL) {
537 fido_log_debug("%s: non-NULL handle", __func__);
538 return (FIDO_ERR_INVALID_ARGUMENT);
550 if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
553 disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK);
561 if ((dev = calloc(1, sizeof(*dev))) == NULL)
564 dev->cid = CTAP_CID_BROADCAST;
565 dev->io = (fido_dev_io_t) {
576 fido_dev_new_with_info(const fido_dev_info_t *di)
580 if ((dev = calloc(1, sizeof(*dev))) == NULL)
584 if (di->io.open == NULL || di->io.close == NULL ||
585 di->io.read == NULL || di->io.write == NULL) {
586 fido_log_debug("%s: NULL function", __func__);
593 dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
594 dev->transport = di->transport;
595 dev->cid = CTAP_CID_BROADCAST;
597 if ((dev->path = strdup(di->path)) == NULL) {
598 fido_log_debug("%s: strdup", __func__);
607 fido_dev_free(fido_dev_t **dev_p)
611 if (dev_p == NULL || (dev = *dev_p) == NULL)
621 fido_dev_protocol(const fido_dev_t *dev)
623 return (dev->attr.protocol);
627 fido_dev_major(const fido_dev_t *dev)
629 return (dev->attr.major);
633 fido_dev_minor(const fido_dev_t *dev)
635 return (dev->attr.minor);
639 fido_dev_build(const fido_dev_t *dev)
641 return (dev->attr.build);
645 fido_dev_flags(const fido_dev_t *dev)
647 return (dev->attr.flags);
651 fido_dev_is_fido2(const fido_dev_t *dev)
653 return (dev->attr.flags & FIDO_CAP_CBOR);
657 fido_dev_is_winhello(const fido_dev_t *dev)
659 return (dev->flags & FIDO_DEV_WINHELLO);
663 fido_dev_supports_pin(const fido_dev_t *dev)
665 return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
669 fido_dev_has_pin(const fido_dev_t *dev)
671 return (dev->flags & FIDO_DEV_PIN_SET);
675 fido_dev_supports_cred_prot(const fido_dev_t *dev)
677 return (dev->flags & FIDO_DEV_CRED_PROT);
681 fido_dev_supports_credman(const fido_dev_t *dev)
683 return (dev->flags & FIDO_DEV_CREDMAN);
687 fido_dev_supports_uv(const fido_dev_t *dev)
689 return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET));
693 fido_dev_has_uv(const fido_dev_t *dev)
695 return (dev->flags & FIDO_DEV_UV_SET);
699 fido_dev_supports_permissions(const fido_dev_t *dev)
701 return (dev->flags & FIDO_DEV_TOKEN_PERMS);
705 fido_dev_force_u2f(fido_dev_t *dev)
707 dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
712 fido_dev_force_fido2(fido_dev_t *dev)
714 dev->attr.flags |= FIDO_CAP_CBOR;
718 fido_dev_get_pin_protocol(const fido_dev_t *dev)
720 if (dev->flags & FIDO_DEV_PIN_PROTOCOL2)
721 return (CTAP_PIN_PROTOCOL2);
722 else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1)
723 return (CTAP_PIN_PROTOCOL1);
729 fido_dev_maxmsgsize(const fido_dev_t *dev)
731 return (dev->maxmsgsize);