]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libfido2/src/dev.c
Merge bearssl-20220418
[FreeBSD/FreeBSD.git] / contrib / libfido2 / src / dev.c
1 /*
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.
5  */
6
7 #include <openssl/sha.h>
8 #include "fido.h"
9
10 #ifndef TLS
11 #define TLS
12 #endif
13
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;
18
19 static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
20 static TLS bool disable_u2f_fallback;
21
22 static void
23 find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
24     dev_manifest_func_node_t **prev)
25 {
26         *prev = NULL;
27         *curr = manifest_funcs;
28
29         while (*curr != NULL && (*curr)->manifest_func != f) {
30                 *prev = *curr;
31                 *curr = (*curr)->next;
32         }
33 }
34
35 #ifdef FIDO_FUZZ
36 static void
37 set_random_report_len(fido_dev_t *dev)
38 {
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);
43 }
44 #endif
45
46 static void
47 fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
48 {
49         char * const    *ptr = fido_cbor_info_extensions_ptr(info);
50         size_t           len = fido_cbor_info_extensions_len(info);
51
52         for (size_t i = 0; i < len; i++)
53                 if (strcmp(ptr[i], "credProtect") == 0)
54                         dev->flags |= FIDO_DEV_CRED_PROT;
55 }
56
57 static void
58 fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
59 {
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);
63
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) {
69                         if (val[i])
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) {
74                         if (val[i])
75                                 dev->flags |= FIDO_DEV_TOKEN_PERMS;
76                 }
77 }
78
79 static void
80 fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
81 {
82         const uint8_t   *ptr = fido_cbor_info_protocols_ptr(info);
83         size_t           len = fido_cbor_info_protocols_len(info);
84
85         for (size_t i = 0; i < len; i++)
86                 switch (ptr[i]) {
87                 case CTAP_PIN_PROTOCOL1:
88                         dev->flags |= FIDO_DEV_PIN_PROTOCOL1;
89                         break;
90                 case CTAP_PIN_PROTOCOL2:
91                         dev->flags |= FIDO_DEV_PIN_PROTOCOL2;
92                         break;
93                 default:
94                         fido_log_debug("%s: unknown protocol %u", __func__,
95                             ptr[i]);
96                         break;
97                 }
98 }
99
100 static void
101 fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
102 {
103         fido_dev_set_extension_flags(dev, info);
104         fido_dev_set_option_flags(dev, info);
105         fido_dev_set_protocol_flags(dev, info);
106 }
107
108 static int
109 fido_dev_open_tx(fido_dev_t *dev, const char *path)
110 {
111         int r;
112
113         if (dev->io_handle != NULL) {
114                 fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
115                 return (FIDO_ERR_INVALID_ARGUMENT);
116         }
117
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);
121         }
122
123         if (dev->cid != CTAP_CID_BROADCAST) {
124                 fido_log_debug("%s: cid=0x%x", __func__, dev->cid);
125                 return (FIDO_ERR_INVALID_ARGUMENT);
126         }
127
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);
131         }
132
133         if ((dev->io_handle = dev->io.open(path)) == NULL) {
134                 fido_log_debug("%s: dev->io.open", __func__);
135                 return (FIDO_ERR_INTERNAL);
136         }
137
138         if (dev->io_own) {
139                 dev->rx_len = CTAP_MAX_REPORT_LEN;
140                 dev->tx_len = CTAP_MAX_REPORT_LEN;
141         } else {
142                 dev->rx_len = fido_hid_report_in_len(dev->io_handle);
143                 dev->tx_len = fido_hid_report_out_len(dev->io_handle);
144         }
145
146 #ifdef FIDO_FUZZ
147         set_random_report_len(dev);
148 #endif
149
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);
153                 r = FIDO_ERR_RX;
154                 goto fail;
155         }
156
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);
160                 r = FIDO_ERR_TX;
161                 goto fail;
162         }
163
164         if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce)) < 0) {
165                 fido_log_debug("%s: fido_tx", __func__);
166                 r = FIDO_ERR_TX;
167                 goto fail;
168         }
169
170         return (FIDO_OK);
171 fail:
172         dev->io.close(dev->io_handle);
173         dev->io_handle = NULL;
174
175         return (r);
176 }
177
178 static int
179 fido_dev_open_rx(fido_dev_t *dev, int ms)
180 {
181         fido_cbor_info_t        *info = NULL;
182         int                      reply_len;
183         int                      r;
184
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__);
188                 r = FIDO_ERR_RX;
189                 goto fail;
190         }
191
192 #ifdef FIDO_FUZZ
193         dev->attr.nonce = dev->nonce;
194 #endif
195
196         if ((size_t)reply_len != sizeof(dev->attr) ||
197             dev->attr.nonce != dev->nonce) {
198                 fido_log_debug("%s: invalid nonce", __func__);
199                 r = FIDO_ERR_RX;
200                 goto fail;
201         }
202
203         dev->flags = 0;
204         dev->cid = dev->attr.cid;
205
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;
210                         goto fail;
211                 }
212                 if ((r = fido_dev_get_cbor_info_wait(dev, info,
213                     ms)) != FIDO_OK) {
214                         fido_log_debug("%s: fido_dev_cbor_info_wait: %d",
215                             __func__, r);
216                         if (disable_u2f_fallback)
217                                 goto fail;
218                         fido_log_debug("%s: falling back to u2f", __func__);
219                         fido_dev_force_u2f(dev);
220                 } else {
221                         fido_dev_set_flags(dev, info);
222                 }
223         }
224
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);
229         }
230
231         r = FIDO_OK;
232 fail:
233         fido_cbor_info_free(&info);
234
235         if (r != FIDO_OK) {
236                 dev->io.close(dev->io_handle);
237                 dev->io_handle = NULL;
238         }
239
240         return (r);
241 }
242
243 static int
244 fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
245 {
246         int r;
247
248 #ifdef USE_WINHELLO
249         if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
250                 return (fido_winhello_open(dev));
251 #endif
252         if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
253             (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
254                 return (r);
255
256         return (FIDO_OK);
257 }
258
259 int
260 fido_dev_register_manifest_func(const dev_manifest_func_t f)
261 {
262         dev_manifest_func_node_t *prev, *curr, *n;
263
264         find_manifest_func_node(f, &curr, &prev);
265         if (curr != NULL)
266                 return (FIDO_OK);
267
268         if ((n = calloc(1, sizeof(*n))) == NULL) {
269                 fido_log_debug("%s: calloc", __func__);
270                 return (FIDO_ERR_INTERNAL);
271         }
272
273         n->manifest_func = f;
274         n->next = manifest_funcs;
275         manifest_funcs = n;
276
277         return (FIDO_OK);
278 }
279
280 void
281 fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
282 {
283         dev_manifest_func_node_t *prev, *curr;
284
285         find_manifest_func_node(f, &curr, &prev);
286         if (curr == NULL)
287                 return;
288         if (prev != NULL)
289                 prev->next = curr->next;
290         else
291                 manifest_funcs = curr->next;
292
293         free(curr);
294 }
295
296 int
297 fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
298 {
299         dev_manifest_func_node_t        *curr = NULL;
300         dev_manifest_func_t              m_func;
301         size_t                           curr_olen;
302         int                              r;
303
304         *olen = 0;
305
306         if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
307                 return (FIDO_ERR_INTERNAL);
308 #ifdef NFC_LINUX
309         if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK)
310                 return (FIDO_ERR_INTERNAL);
311 #endif
312 #ifdef USE_WINHELLO
313         if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK)
314                 return (FIDO_ERR_INTERNAL);
315 #endif
316
317         for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
318                 curr_olen = 0;
319                 m_func = curr->manifest_func;
320                 r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
321                 if (r != FIDO_OK)
322                         return (r);
323                 *olen += curr_olen;
324                 if (*olen == ilen)
325                         break;
326         }
327
328         return (FIDO_OK);
329 }
330
331 int
332 fido_dev_open_with_info(fido_dev_t *dev)
333 {
334         if (dev->path == NULL)
335                 return (FIDO_ERR_INVALID_ARGUMENT);
336
337         return (fido_dev_open_wait(dev, dev->path, -1));
338 }
339
340 int
341 fido_dev_open(fido_dev_t *dev, const char *path)
342 {
343 #ifdef NFC_LINUX
344         /*
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().
348          */
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') {
352                 dev->io_own = true;
353                 dev->io = (fido_dev_io_t) {
354                         fido_nfc_open,
355                         fido_nfc_close,
356                         fido_nfc_read,
357                         fido_nfc_write,
358                 };
359                 dev->transport = (fido_dev_transport_t) {
360                         fido_nfc_rx,
361                         fido_nfc_tx,
362                 };
363         }
364 #endif
365
366         return (fido_dev_open_wait(dev, path, -1));
367 }
368
369 int
370 fido_dev_close(fido_dev_t *dev)
371 {
372 #ifdef USE_WINHELLO
373         if (dev->flags & FIDO_DEV_WINHELLO)
374                 return (fido_winhello_close(dev));
375 #endif
376         if (dev->io_handle == NULL || dev->io.close == NULL)
377                 return (FIDO_ERR_INVALID_ARGUMENT);
378
379         dev->io.close(dev->io_handle);
380         dev->io_handle = NULL;
381         dev->cid = CTAP_CID_BROADCAST;
382
383         return (FIDO_OK);
384 }
385
386 int
387 fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
388 {
389         if (dev->io_own || dev->io_handle == NULL || sigmask == NULL)
390                 return (FIDO_ERR_INVALID_ARGUMENT);
391
392 #ifdef NFC_LINUX
393         if (dev->transport.rx == fido_nfc_rx)
394                 return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
395 #endif
396         return (fido_hid_set_sigmask(dev->io_handle, sigmask));
397 }
398
399 int
400 fido_dev_cancel(fido_dev_t *dev)
401 {
402 #ifdef USE_WINHELLO
403         if (dev->flags & FIDO_DEV_WINHELLO)
404                 return (fido_winhello_cancel(dev));
405 #endif
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);
410
411         return (FIDO_OK);
412 }
413
414 int
415 fido_dev_get_touch_begin(fido_dev_t *dev)
416 {
417         fido_blob_t      f;
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];
422         fido_rp_t        rp;
423         fido_user_t      user;
424         int              r = FIDO_ERR_INTERNAL;
425
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));
431
432         if (fido_dev_is_fido2(dev) == false)
433                 return (u2f_get_touch_begin(dev));
434
435         if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
436                 fido_log_debug("%s: sha256", __func__);
437                 return (FIDO_ERR_INTERNAL);
438         }
439
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__);
443                 goto fail;
444         }
445
446         if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
447                 fido_log_debug("%s: fido_blob_set", __func__);
448                 goto fail;
449         }
450
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__);
456                 goto fail;
457         }
458
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__);
463                         goto fail;
464                 }
465         }
466
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__);
470                 r = FIDO_ERR_TX;
471                 goto fail;
472         }
473
474         r = FIDO_OK;
475 fail:
476         cbor_vector_free(argv, nitems(argv));
477         free(f.ptr);
478         free(rp.id);
479         free(user.name);
480         free(user.id.ptr);
481
482         return (r);
483 }
484
485 int
486 fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
487 {
488         int r;
489
490         *touched = 0;
491
492         if (fido_dev_is_fido2(dev) == false)
493                 return (u2f_get_touch_status(dev, touched, ms));
494
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:
500                 *touched = 1;
501                 break;
502         case FIDO_ERR_RX:
503                 /* ignore */
504                 break;
505         default:
506                 fido_log_debug("%s: fido_rx_cbor_status", __func__);
507                 return (r);
508         }
509
510         return (FIDO_OK);
511 }
512
513 int
514 fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
515 {
516         if (dev->io_handle != NULL) {
517                 fido_log_debug("%s: non-NULL handle", __func__);
518                 return (FIDO_ERR_INVALID_ARGUMENT);
519         }
520
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);
525         }
526
527         dev->io = *io;
528         dev->io_own = true;
529
530         return (FIDO_OK);
531 }
532
533 int
534 fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
535 {
536         if (dev->io_handle != NULL) {
537                 fido_log_debug("%s: non-NULL handle", __func__);
538                 return (FIDO_ERR_INVALID_ARGUMENT);
539         }
540
541         dev->transport = *t;
542         dev->io_own = true;
543
544         return (FIDO_OK);
545 }
546
547 void
548 fido_init(int flags)
549 {
550         if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
551                 fido_log_init();
552
553         disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK);
554 }
555
556 fido_dev_t *
557 fido_dev_new(void)
558 {
559         fido_dev_t *dev;
560
561         if ((dev = calloc(1, sizeof(*dev))) == NULL)
562                 return (NULL);
563
564         dev->cid = CTAP_CID_BROADCAST;
565         dev->io = (fido_dev_io_t) {
566                 &fido_hid_open,
567                 &fido_hid_close,
568                 &fido_hid_read,
569                 &fido_hid_write,
570         };
571
572         return (dev);
573 }
574
575 fido_dev_t *
576 fido_dev_new_with_info(const fido_dev_info_t *di)
577 {
578         fido_dev_t *dev;
579
580         if ((dev = calloc(1, sizeof(*dev))) == NULL)
581                 return (NULL);
582
583 #if 0
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__);
587                 fido_dev_free(&dev);
588                 return (NULL);
589         }
590 #endif
591
592         dev->io = di->io;
593         dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
594         dev->transport = di->transport;
595         dev->cid = CTAP_CID_BROADCAST;
596
597         if ((dev->path = strdup(di->path)) == NULL) {
598                 fido_log_debug("%s: strdup", __func__);
599                 fido_dev_free(&dev);
600                 return (NULL);
601         }
602
603         return (dev);
604 }
605
606 void
607 fido_dev_free(fido_dev_t **dev_p)
608 {
609         fido_dev_t *dev;
610
611         if (dev_p == NULL || (dev = *dev_p) == NULL)
612                 return;
613
614         free(dev->path);
615         free(dev);
616
617         *dev_p = NULL;
618 }
619
620 uint8_t
621 fido_dev_protocol(const fido_dev_t *dev)
622 {
623         return (dev->attr.protocol);
624 }
625
626 uint8_t
627 fido_dev_major(const fido_dev_t *dev)
628 {
629         return (dev->attr.major);
630 }
631
632 uint8_t
633 fido_dev_minor(const fido_dev_t *dev)
634 {
635         return (dev->attr.minor);
636 }
637
638 uint8_t
639 fido_dev_build(const fido_dev_t *dev)
640 {
641         return (dev->attr.build);
642 }
643
644 uint8_t
645 fido_dev_flags(const fido_dev_t *dev)
646 {
647         return (dev->attr.flags);
648 }
649
650 bool
651 fido_dev_is_fido2(const fido_dev_t *dev)
652 {
653         return (dev->attr.flags & FIDO_CAP_CBOR);
654 }
655
656 bool
657 fido_dev_is_winhello(const fido_dev_t *dev)
658 {
659         return (dev->flags & FIDO_DEV_WINHELLO);
660 }
661
662 bool
663 fido_dev_supports_pin(const fido_dev_t *dev)
664 {
665         return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
666 }
667
668 bool
669 fido_dev_has_pin(const fido_dev_t *dev)
670 {
671         return (dev->flags & FIDO_DEV_PIN_SET);
672 }
673
674 bool
675 fido_dev_supports_cred_prot(const fido_dev_t *dev)
676 {
677         return (dev->flags & FIDO_DEV_CRED_PROT);
678 }
679
680 bool
681 fido_dev_supports_credman(const fido_dev_t *dev)
682 {
683         return (dev->flags & FIDO_DEV_CREDMAN);
684 }
685
686 bool
687 fido_dev_supports_uv(const fido_dev_t *dev)
688 {
689         return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET));
690 }
691
692 bool
693 fido_dev_has_uv(const fido_dev_t *dev)
694 {
695         return (dev->flags & FIDO_DEV_UV_SET);
696 }
697
698 bool
699 fido_dev_supports_permissions(const fido_dev_t *dev)
700 {
701         return (dev->flags & FIDO_DEV_TOKEN_PERMS);
702 }
703
704 void
705 fido_dev_force_u2f(fido_dev_t *dev)
706 {
707         dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
708         dev->flags = 0;
709 }
710
711 void
712 fido_dev_force_fido2(fido_dev_t *dev)
713 {
714         dev->attr.flags |= FIDO_CAP_CBOR;
715 }
716
717 uint8_t
718 fido_dev_get_pin_protocol(const fido_dev_t *dev)
719 {
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);
724
725         return (0);
726 }
727
728 uint64_t
729 fido_dev_maxmsgsize(const fido_dev_t *dev)
730 {
731         return (dev->maxmsgsize);
732 }