Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/tools/token.c
39534 views
1
/*
2
* Copyright (c) 2018-2022 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
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#include <fido.h>
9
#include <stdbool.h>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#ifdef HAVE_UNISTD_H
14
#include <unistd.h>
15
#endif
16
17
#include "../openbsd-compat/openbsd-compat.h"
18
#include "extern.h"
19
20
static void
21
format_flags(char *ret, size_t retlen, uint8_t flags)
22
{
23
memset(ret, 0, retlen);
24
25
if (flags & FIDO_CAP_WINK) {
26
if (strlcat(ret, "wink,", retlen) >= retlen)
27
goto toolong;
28
} else {
29
if (strlcat(ret, "nowink,", retlen) >= retlen)
30
goto toolong;
31
}
32
33
if (flags & FIDO_CAP_CBOR) {
34
if (strlcat(ret, " cbor,", retlen) >= retlen)
35
goto toolong;
36
} else {
37
if (strlcat(ret, " nocbor,", retlen) >= retlen)
38
goto toolong;
39
}
40
41
if (flags & FIDO_CAP_NMSG) {
42
if (strlcat(ret, " nomsg", retlen) >= retlen)
43
goto toolong;
44
} else {
45
if (strlcat(ret, " msg", retlen) >= retlen)
46
goto toolong;
47
}
48
49
return;
50
toolong:
51
strlcpy(ret, "toolong", retlen);
52
}
53
54
static void
55
print_attr(const fido_dev_t *dev)
56
{
57
char flags_txt[128];
58
59
printf("proto: 0x%02x\n", fido_dev_protocol(dev));
60
printf("major: 0x%02x\n", fido_dev_major(dev));
61
printf("minor: 0x%02x\n", fido_dev_minor(dev));
62
printf("build: 0x%02x\n", fido_dev_build(dev));
63
64
format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
65
printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
66
}
67
68
static void
69
print_str_array(const char *label, char * const *sa, size_t len)
70
{
71
if (len == 0)
72
return;
73
74
printf("%s strings: ", label);
75
76
for (size_t i = 0; i < len; i++)
77
printf("%s%s", i > 0 ? ", " : "", sa[i]);
78
79
printf("\n");
80
}
81
82
static void
83
print_opt_array(const char *label, char * const *name, const bool *value,
84
size_t len)
85
{
86
if (len == 0)
87
return;
88
89
printf("%s: ", label);
90
91
for (size_t i = 0; i < len; i++)
92
printf("%s%s%s", i > 0 ? ", " : "",
93
value[i] ? "" : "no", name[i]);
94
95
printf("\n");
96
}
97
98
static void
99
print_cert_array(const char *label, char * const *name, const uint64_t *value,
100
size_t len)
101
{
102
if (len == 0)
103
return;
104
105
printf("%s: ", label);
106
107
for (size_t i = 0; i < len; i++)
108
printf("%s%s %llu", i > 0 ? ", " : "", name[i],
109
(unsigned long long)value[i]);
110
111
printf("\n");
112
}
113
114
static void
115
print_algorithms(const fido_cbor_info_t *ci)
116
{
117
const char *cose, *type;
118
size_t len;
119
120
if ((len = fido_cbor_info_algorithm_count(ci)) == 0)
121
return;
122
123
printf("algorithms: ");
124
125
for (size_t i = 0; i < len; i++) {
126
cose = type = "unknown";
127
switch (fido_cbor_info_algorithm_cose(ci, i)) {
128
case COSE_ES256:
129
cose = "es256";
130
break;
131
case COSE_ES384:
132
cose = "es384";
133
break;
134
case COSE_RS256:
135
cose = "rs256";
136
break;
137
case COSE_EDDSA:
138
cose = "eddsa";
139
break;
140
}
141
if (fido_cbor_info_algorithm_type(ci, i) != NULL)
142
type = fido_cbor_info_algorithm_type(ci, i);
143
printf("%s%s (%s)", i > 0 ? ", " : "", cose, type);
144
}
145
146
printf("\n");
147
}
148
149
static void
150
print_aaguid(const unsigned char *buf, size_t buflen)
151
{
152
printf("aaguid: ");
153
154
while (buflen--)
155
printf("%02x", *buf++);
156
157
printf("\n");
158
}
159
160
static void
161
print_maxmsgsiz(uint64_t maxmsgsiz)
162
{
163
printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
164
}
165
166
static void
167
print_maxcredcntlst(uint64_t maxcredcntlst)
168
{
169
printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
170
}
171
172
static void
173
print_maxcredidlen(uint64_t maxcredidlen)
174
{
175
printf("maxcredlen: %d\n", (int)maxcredidlen);
176
}
177
178
static void
179
print_maxlargeblob(uint64_t maxlargeblob)
180
{
181
printf("maxlargeblob: %d\n", (int)maxlargeblob);
182
}
183
184
static void
185
print_maxrpid_minpinlen(uint64_t maxrpid)
186
{
187
if (maxrpid > 0)
188
printf("maxrpids in minpinlen: %d\n", (int)maxrpid);
189
}
190
191
static void
192
print_minpinlen(uint64_t minpinlen)
193
{
194
if (minpinlen > 0)
195
printf("minpinlen: %d\n", (int)minpinlen);
196
}
197
198
static void
199
print_uv_attempts(uint64_t uv_attempts)
200
{
201
if (uv_attempts > 0)
202
printf("platform uv attempt(s): %d\n", (int)uv_attempts);
203
}
204
205
static void
206
print_uv_modality(uint64_t uv_modality)
207
{
208
uint64_t mode;
209
bool printed = false;
210
211
if (uv_modality == 0)
212
return;
213
214
printf("uv modality: 0x%x (", (int)uv_modality);
215
216
for (size_t i = 0; i < 64; i++) {
217
mode = 1ULL << i;
218
if ((uv_modality & mode) == 0)
219
continue;
220
if (printed)
221
printf(", ");
222
switch (mode) {
223
case FIDO_UV_MODE_TUP:
224
printf("test of user presence");
225
break;
226
case FIDO_UV_MODE_FP:
227
printf("fingerprint check");
228
break;
229
case FIDO_UV_MODE_PIN:
230
printf("pin check");
231
break;
232
case FIDO_UV_MODE_VOICE:
233
printf("voice recognition");
234
break;
235
case FIDO_UV_MODE_FACE:
236
printf("face recognition");
237
break;
238
case FIDO_UV_MODE_LOCATION:
239
printf("location check");
240
break;
241
case FIDO_UV_MODE_EYE:
242
printf("eyeprint check");
243
break;
244
case FIDO_UV_MODE_DRAWN:
245
printf("drawn pattern check");
246
break;
247
case FIDO_UV_MODE_HAND:
248
printf("handprint verification");
249
break;
250
case FIDO_UV_MODE_NONE:
251
printf("none");
252
break;
253
case FIDO_UV_MODE_ALL:
254
printf("all required");
255
break;
256
case FIDO_UV_MODE_EXT_PIN:
257
printf("external pin");
258
break;
259
case FIDO_UV_MODE_EXT_DRAWN:
260
printf("external drawn pattern check");
261
break;
262
default:
263
printf("unknown 0x%llx", (unsigned long long)mode);
264
break;
265
}
266
printed = true;
267
}
268
269
printf(")\n");
270
}
271
272
static void
273
print_rk_remaining(int64_t rk_remaining)
274
{
275
if (rk_remaining != -1)
276
printf("remaining rk(s): %d\n", (int)rk_remaining);
277
}
278
279
static void
280
print_fwversion(uint64_t fwversion)
281
{
282
printf("fwversion: 0x%x\n", (int)fwversion);
283
}
284
285
static void
286
print_byte_array(const char *label, const uint8_t *ba, size_t len)
287
{
288
if (len == 0)
289
return;
290
291
printf("%s: ", label);
292
293
for (size_t i = 0; i < len; i++)
294
printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
295
296
printf("\n");
297
}
298
299
int
300
token_info(int argc, char **argv, char *path)
301
{
302
char *cred_id = NULL;
303
char *rp_id = NULL;
304
fido_cbor_info_t *ci = NULL;
305
fido_dev_t *dev = NULL;
306
int ch;
307
int credman = 0;
308
int r;
309
int retrycnt;
310
311
optind = 1;
312
313
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
314
switch (ch) {
315
case 'c':
316
credman = 1;
317
break;
318
case 'i':
319
cred_id = optarg;
320
break;
321
case 'k':
322
rp_id = optarg;
323
break;
324
default:
325
break; /* ignore */
326
}
327
}
328
329
if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL)))
330
usage();
331
332
dev = open_dev(path);
333
334
if (credman)
335
return (credman_get_metadata(dev, path));
336
if (cred_id && rp_id)
337
return (credman_print_rk(dev, path, rp_id, cred_id));
338
if (cred_id || rp_id)
339
usage();
340
341
print_attr(dev);
342
343
if (fido_dev_is_fido2(dev) == false)
344
goto end;
345
if ((ci = fido_cbor_info_new()) == NULL)
346
errx(1, "fido_cbor_info_new");
347
if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
348
errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
349
350
/* print supported protocol versions */
351
print_str_array("version", fido_cbor_info_versions_ptr(ci),
352
fido_cbor_info_versions_len(ci));
353
354
/* print supported extensions */
355
print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
356
fido_cbor_info_extensions_len(ci));
357
358
/* print supported transports */
359
print_str_array("transport", fido_cbor_info_transports_ptr(ci),
360
fido_cbor_info_transports_len(ci));
361
362
/* print supported algorithms */
363
print_algorithms(ci);
364
365
/* print aaguid */
366
print_aaguid(fido_cbor_info_aaguid_ptr(ci),
367
fido_cbor_info_aaguid_len(ci));
368
369
/* print supported options */
370
print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
371
fido_cbor_info_options_value_ptr(ci),
372
fido_cbor_info_options_len(ci));
373
374
/* print certifications */
375
print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci),
376
fido_cbor_info_certs_value_ptr(ci),
377
fido_cbor_info_certs_len(ci));
378
379
/* print firmware version */
380
print_fwversion(fido_cbor_info_fwversion(ci));
381
382
/* print maximum message size */
383
print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
384
385
/* print maximum number of credentials allowed in credential lists */
386
print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
387
388
/* print maximum length of a credential ID */
389
print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
390
391
/* print maximum length of serialized largeBlob array */
392
print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
393
394
/* print maximum number of RP IDs in fido_dev_set_pin_minlen_rpid() */
395
print_maxrpid_minpinlen(fido_cbor_info_maxrpid_minpinlen(ci));
396
397
/* print estimated number of resident credentials */
398
print_rk_remaining(fido_cbor_info_rk_remaining(ci));
399
400
/* print minimum pin length */
401
print_minpinlen(fido_cbor_info_minpinlen(ci));
402
403
/* print supported pin protocols */
404
print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
405
fido_cbor_info_protocols_len(ci));
406
407
if (fido_dev_get_retry_count(dev, &retrycnt) != FIDO_OK)
408
printf("pin retries: undefined\n");
409
else
410
printf("pin retries: %d\n", retrycnt);
411
412
printf("pin change required: %s\n",
413
fido_cbor_info_new_pin_required(ci) ? "true" : "false");
414
415
if (fido_dev_get_uv_retry_count(dev, &retrycnt) != FIDO_OK)
416
printf("uv retries: undefined\n");
417
else
418
printf("uv retries: %d\n", retrycnt);
419
420
/* print platform uv attempts */
421
print_uv_attempts(fido_cbor_info_uv_attempts(ci));
422
423
/* print supported uv mechanisms */
424
print_uv_modality(fido_cbor_info_uv_modality(ci));
425
426
bio_info(dev);
427
428
fido_cbor_info_free(&ci);
429
end:
430
fido_dev_close(dev);
431
fido_dev_free(&dev);
432
433
exit(0);
434
}
435
436
int
437
token_reset(char *path)
438
{
439
fido_dev_t *dev = NULL;
440
int r;
441
442
if (path == NULL)
443
usage();
444
445
dev = open_dev(path);
446
if ((r = fido_dev_reset(dev)) != FIDO_OK)
447
errx(1, "fido_dev_reset: %s", fido_strerr(r));
448
449
fido_dev_close(dev);
450
fido_dev_free(&dev);
451
452
exit(0);
453
}
454
455
int
456
token_get(int argc, char **argv, char *path)
457
{
458
char *id = NULL;
459
char *key = NULL;
460
char *name = NULL;
461
int blob = 0;
462
int ch;
463
464
optind = 1;
465
466
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
467
switch (ch) {
468
case 'b':
469
blob = 1;
470
break;
471
case 'i':
472
id = optarg;
473
break;
474
case 'k':
475
key = optarg;
476
break;
477
case 'n':
478
name = optarg;
479
break;
480
default:
481
break; /* ignore */
482
}
483
}
484
485
argc -= optind;
486
argv += optind;
487
488
if (blob == 0 || argc != 2)
489
usage();
490
491
return blob_get(path, key, name, id, argv[0]);
492
}
493
494
int
495
token_set(int argc, char **argv, char *path)
496
{
497
char *id = NULL;
498
char *key = NULL;
499
char *len = NULL;
500
char *display_name = NULL;
501
char *name = NULL;
502
char *rpid = NULL;
503
int blob = 0;
504
int cred = 0;
505
int ch;
506
int enroll = 0;
507
int ea = 0;
508
int uv = 0;
509
bool force = false;
510
511
optind = 1;
512
513
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
514
switch (ch) {
515
case 'a':
516
ea = 1;
517
break;
518
case 'b':
519
blob = 1;
520
break;
521
case 'c':
522
cred = 1;
523
break;
524
case 'e':
525
enroll = 1;
526
break;
527
case 'f':
528
force = true;
529
break;
530
case 'i':
531
id = optarg;
532
break;
533
case 'k':
534
key = optarg;
535
break;
536
case 'l':
537
len = optarg;
538
break;
539
case 'p':
540
display_name = optarg;
541
break;
542
case 'm':
543
rpid = optarg;
544
break;
545
case 'n':
546
name = optarg;
547
break;
548
case 'u':
549
uv = 1;
550
break;
551
default:
552
break; /* ignore */
553
}
554
}
555
556
argc -= optind;
557
argv += optind;
558
559
if (path == NULL)
560
usage();
561
562
if (blob) {
563
if (argc != 2)
564
usage();
565
return (blob_set(path, key, name, id, argv[0]));
566
}
567
568
if (cred) {
569
if (!id || !key)
570
usage();
571
if (!name && !display_name)
572
usage();
573
return (credman_update_rk(path, key, id, name, display_name));
574
}
575
576
if (enroll) {
577
if (ea || uv)
578
usage();
579
if (id && name)
580
return (bio_set_name(path, id, name));
581
if (!id && !name)
582
return (bio_enroll(path));
583
usage();
584
}
585
586
if (ea) {
587
if (uv)
588
usage();
589
return (config_entattest(path));
590
}
591
592
if (len)
593
return (config_pin_minlen(path, len));
594
if (rpid)
595
return (config_pin_minlen_rpid(path, rpid));
596
if (force)
597
return (config_force_pin_change(path));
598
if (uv)
599
return (config_always_uv(path, 1));
600
601
return (pin_set(path));
602
}
603
604
int
605
token_list(int argc, char **argv, char *path)
606
{
607
fido_dev_info_t *devlist;
608
size_t ndevs;
609
const char *rp_id = NULL;
610
int blobs = 0;
611
int enrolls = 0;
612
int keys = 0;
613
int rplist = 0;
614
int ch;
615
int r;
616
617
optind = 1;
618
619
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
620
switch (ch) {
621
case 'b':
622
blobs = 1;
623
break;
624
case 'e':
625
enrolls = 1;
626
break;
627
case 'k':
628
keys = 1;
629
rp_id = optarg;
630
break;
631
case 'r':
632
rplist = 1;
633
break;
634
default:
635
break; /* ignore */
636
}
637
}
638
639
if (blobs || enrolls || keys || rplist) {
640
if (path == NULL)
641
usage();
642
if (blobs)
643
return (blob_list(path));
644
if (enrolls)
645
return (bio_list(path));
646
if (keys)
647
return (credman_list_rk(path, rp_id));
648
if (rplist)
649
return (credman_list_rp(path));
650
/* NOTREACHED */
651
}
652
653
if ((devlist = fido_dev_info_new(64)) == NULL)
654
errx(1, "fido_dev_info_new");
655
if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
656
errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
657
658
for (size_t i = 0; i < ndevs; i++) {
659
const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
660
printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n",
661
fido_dev_info_path(di),
662
(uint16_t)fido_dev_info_vendor(di),
663
(uint16_t)fido_dev_info_product(di),
664
fido_dev_info_manufacturer_string(di),
665
fido_dev_info_product_string(di));
666
}
667
668
fido_dev_info_free(&devlist, ndevs);
669
670
exit(0);
671
}
672
673
int
674
token_delete(int argc, char **argv, char *path)
675
{
676
char *id = NULL;
677
char *key = NULL;
678
char *name = NULL;
679
int blob = 0;
680
int ch;
681
int enroll = 0;
682
int uv = 0;
683
684
optind = 1;
685
686
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
687
switch (ch) {
688
case 'b':
689
blob = 1;
690
break;
691
case 'e':
692
enroll = 1;
693
break;
694
case 'i':
695
id = optarg;
696
break;
697
case 'k':
698
key = optarg;
699
break;
700
case 'n':
701
name = optarg;
702
break;
703
case 'u':
704
uv = 1;
705
break;
706
default:
707
break; /* ignore */
708
}
709
}
710
711
if (path == NULL)
712
usage();
713
714
if (blob)
715
return (blob_delete(path, key, name, id));
716
717
if (id) {
718
if (uv)
719
usage();
720
if (enroll == 0)
721
return (credman_delete_rk(path, id));
722
return (bio_delete(path, id));
723
}
724
725
if (uv == 0)
726
usage();
727
728
return (config_always_uv(path, 0));
729
}
730
731