Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/src/info.c
39478 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
10
static int
11
decode_string(const cbor_item_t *item, void *arg)
12
{
13
fido_str_array_t *a = arg;
14
const size_t i = a->len;
15
16
/* keep ptr[x] and len consistent */
17
if (cbor_string_copy(item, &a->ptr[i]) < 0) {
18
fido_log_debug("%s: cbor_string_copy", __func__);
19
return (-1);
20
}
21
22
a->len++;
23
24
return (0);
25
}
26
27
static int
28
decode_string_array(const cbor_item_t *item, fido_str_array_t *v)
29
{
30
v->ptr = NULL;
31
v->len = 0;
32
33
if (cbor_isa_array(item) == false ||
34
cbor_array_is_definite(item) == false) {
35
fido_log_debug("%s: cbor type", __func__);
36
return (-1);
37
}
38
39
v->ptr = calloc(cbor_array_size(item), sizeof(char *));
40
if (v->ptr == NULL)
41
return (-1);
42
43
if (cbor_array_iter(item, v, decode_string) < 0) {
44
fido_log_debug("%s: decode_string", __func__);
45
return (-1);
46
}
47
48
return (0);
49
}
50
51
static int
52
decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
53
{
54
if (cbor_isa_bytestring(item) == false ||
55
cbor_bytestring_is_definite(item) == false ||
56
cbor_bytestring_length(item) != aaguid_len) {
57
fido_log_debug("%s: cbor type", __func__);
58
return (-1);
59
}
60
61
memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
62
63
return (0);
64
}
65
66
static int
67
decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
68
{
69
fido_opt_array_t *o = arg;
70
const size_t i = o->len;
71
72
if (cbor_decode_bool(val, NULL) < 0) {
73
fido_log_debug("%s: cbor_decode_bool", __func__);
74
return (0); /* ignore */
75
}
76
77
if (cbor_string_copy(key, &o->name[i]) < 0) {
78
fido_log_debug("%s: cbor_string_copy", __func__);
79
return (0); /* ignore */
80
}
81
82
/* keep name/value and len consistent */
83
o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
84
o->len++;
85
86
return (0);
87
}
88
89
static int
90
decode_options(const cbor_item_t *item, fido_opt_array_t *o)
91
{
92
o->name = NULL;
93
o->value = NULL;
94
o->len = 0;
95
96
if (cbor_isa_map(item) == false ||
97
cbor_map_is_definite(item) == false) {
98
fido_log_debug("%s: cbor type", __func__);
99
return (-1);
100
}
101
102
o->name = calloc(cbor_map_size(item), sizeof(char *));
103
o->value = calloc(cbor_map_size(item), sizeof(bool));
104
if (o->name == NULL || o->value == NULL)
105
return (-1);
106
107
return (cbor_map_iter(item, o, decode_option));
108
}
109
110
static int
111
decode_protocol(const cbor_item_t *item, void *arg)
112
{
113
fido_byte_array_t *p = arg;
114
const size_t i = p->len;
115
116
if (cbor_isa_uint(item) == false ||
117
cbor_int_get_width(item) != CBOR_INT_8) {
118
fido_log_debug("%s: cbor type", __func__);
119
return (-1);
120
}
121
122
/* keep ptr[x] and len consistent */
123
p->ptr[i] = cbor_get_uint8(item);
124
p->len++;
125
126
return (0);
127
}
128
129
static int
130
decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
131
{
132
p->ptr = NULL;
133
p->len = 0;
134
135
if (cbor_isa_array(item) == false ||
136
cbor_array_is_definite(item) == false) {
137
fido_log_debug("%s: cbor type", __func__);
138
return (-1);
139
}
140
141
p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
142
if (p->ptr == NULL)
143
return (-1);
144
145
if (cbor_array_iter(item, p, decode_protocol) < 0) {
146
fido_log_debug("%s: decode_protocol", __func__);
147
return (-1);
148
}
149
150
return (0);
151
}
152
153
static int
154
decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
155
void *arg)
156
{
157
fido_algo_t *alg = arg;
158
char *name = NULL;
159
int ok = -1;
160
161
if (cbor_string_copy(key, &name) < 0) {
162
fido_log_debug("%s: cbor type", __func__);
163
ok = 0; /* ignore */
164
goto out;
165
}
166
167
if (!strcmp(name, "alg")) {
168
if (cbor_isa_negint(val) == false ||
169
cbor_get_int(val) > INT_MAX || alg->cose != 0) {
170
fido_log_debug("%s: alg", __func__);
171
goto out;
172
}
173
alg->cose = -(int)cbor_get_int(val) - 1;
174
} else if (!strcmp(name, "type")) {
175
if (cbor_string_copy(val, &alg->type) < 0) {
176
fido_log_debug("%s: type", __func__);
177
goto out;
178
}
179
}
180
181
ok = 0;
182
out:
183
free(name);
184
185
return (ok);
186
}
187
188
static int
189
decode_algorithm(const cbor_item_t *item, void *arg)
190
{
191
fido_algo_array_t *aa = arg;
192
const size_t i = aa->len;
193
194
if (cbor_isa_map(item) == false ||
195
cbor_map_is_definite(item) == false) {
196
fido_log_debug("%s: cbor type", __func__);
197
return (-1);
198
}
199
200
memset(&aa->ptr[i], 0, sizeof(aa->ptr[i]));
201
202
if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
203
fido_log_debug("%s: decode_algorithm_entry", __func__);
204
fido_algo_free(&aa->ptr[i]);
205
return (-1);
206
}
207
208
/* keep ptr[x] and len consistent */
209
aa->len++;
210
211
return (0);
212
}
213
214
static int
215
decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa)
216
{
217
aa->ptr = NULL;
218
aa->len = 0;
219
220
if (cbor_isa_array(item) == false ||
221
cbor_array_is_definite(item) == false) {
222
fido_log_debug("%s: cbor type", __func__);
223
return (-1);
224
}
225
226
aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t));
227
if (aa->ptr == NULL)
228
return (-1);
229
230
if (cbor_array_iter(item, aa, decode_algorithm) < 0) {
231
fido_log_debug("%s: decode_algorithm", __func__);
232
return (-1);
233
}
234
235
return (0);
236
}
237
238
static int
239
decode_cert(const cbor_item_t *key, const cbor_item_t *val, void *arg)
240
{
241
fido_cert_array_t *c = arg;
242
const size_t i = c->len;
243
244
if (cbor_is_int(val) == false) {
245
fido_log_debug("%s: cbor_is_int", __func__);
246
return (0); /* ignore */
247
}
248
249
if (cbor_string_copy(key, &c->name[i]) < 0) {
250
fido_log_debug("%s: cbor_string_copy", __func__);
251
return (0); /* ignore */
252
}
253
254
/* keep name/value and len consistent */
255
c->value[i] = cbor_get_int(val);
256
c->len++;
257
258
return (0);
259
}
260
261
static int
262
decode_certs(const cbor_item_t *item, fido_cert_array_t *c)
263
{
264
c->name = NULL;
265
c->value = NULL;
266
c->len = 0;
267
268
if (cbor_isa_map(item) == false ||
269
cbor_map_is_definite(item) == false) {
270
fido_log_debug("%s: cbor type", __func__);
271
return (-1);
272
}
273
274
c->name = calloc(cbor_map_size(item), sizeof(char *));
275
c->value = calloc(cbor_map_size(item), sizeof(uint64_t));
276
if (c->name == NULL || c->value == NULL)
277
return (-1);
278
279
return (cbor_map_iter(item, c, decode_cert));
280
}
281
282
static int
283
parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
284
{
285
fido_cbor_info_t *ci = arg;
286
uint64_t x;
287
288
if (cbor_isa_uint(key) == false ||
289
cbor_int_get_width(key) != CBOR_INT_8) {
290
fido_log_debug("%s: cbor type", __func__);
291
return (0); /* ignore */
292
}
293
294
switch (cbor_get_uint8(key)) {
295
case 1: /* versions */
296
return (decode_string_array(val, &ci->versions));
297
case 2: /* extensions */
298
return (decode_string_array(val, &ci->extensions));
299
case 3: /* aaguid */
300
return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
301
case 4: /* options */
302
return (decode_options(val, &ci->options));
303
case 5: /* maxMsgSize */
304
return (cbor_decode_uint64(val, &ci->maxmsgsiz));
305
case 6: /* pinProtocols */
306
return (decode_protocols(val, &ci->protocols));
307
case 7: /* maxCredentialCountInList */
308
return (cbor_decode_uint64(val, &ci->maxcredcntlst));
309
case 8: /* maxCredentialIdLength */
310
return (cbor_decode_uint64(val, &ci->maxcredidlen));
311
case 9: /* transports */
312
return (decode_string_array(val, &ci->transports));
313
case 10: /* algorithms */
314
return (decode_algorithms(val, &ci->algorithms));
315
case 11: /* maxSerializedLargeBlobArray */
316
return (cbor_decode_uint64(val, &ci->maxlargeblob));
317
case 12: /* forcePINChange */
318
return (cbor_decode_bool(val, &ci->new_pin_reqd));
319
case 13: /* minPINLength */
320
return (cbor_decode_uint64(val, &ci->minpinlen));
321
case 14: /* fwVersion */
322
return (cbor_decode_uint64(val, &ci->fwversion));
323
case 15: /* maxCredBlobLen */
324
return (cbor_decode_uint64(val, &ci->maxcredbloblen));
325
case 16: /* maxRPIDsForSetMinPINLength */
326
return (cbor_decode_uint64(val, &ci->maxrpid_minlen));
327
case 17: /* preferredPlatformUvAttempts */
328
return (cbor_decode_uint64(val, &ci->uv_attempts));
329
case 18: /* uvModality */
330
return (cbor_decode_uint64(val, &ci->uv_modality));
331
case 19: /* certifications */
332
return (decode_certs(val, &ci->certs));
333
case 20: /* remainingDiscoverableCredentials */
334
if (cbor_decode_uint64(val, &x) < 0 || x > INT64_MAX) {
335
fido_log_debug("%s: cbor_decode_uint64", __func__);
336
return (-1);
337
}
338
ci->rk_remaining = (int64_t)x;
339
return (0);
340
default: /* ignore */
341
fido_log_debug("%s: cbor type: 0x%02x", __func__, cbor_get_uint8(key));
342
return (0);
343
}
344
}
345
346
static int
347
fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms)
348
{
349
const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
350
351
fido_log_debug("%s: dev=%p", __func__, (void *)dev);
352
353
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
354
fido_log_debug("%s: fido_tx", __func__);
355
return (FIDO_ERR_TX);
356
}
357
358
return (FIDO_OK);
359
}
360
361
static int
362
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
363
{
364
unsigned char *msg;
365
int msglen;
366
int r;
367
368
fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
369
(void *)ci, *ms);
370
371
fido_cbor_info_reset(ci);
372
373
if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
374
r = FIDO_ERR_INTERNAL;
375
goto out;
376
}
377
378
if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
379
fido_log_debug("%s: fido_rx", __func__);
380
r = FIDO_ERR_RX;
381
goto out;
382
}
383
384
r = cbor_parse_reply(msg, (size_t)msglen, ci, parse_reply_element);
385
out:
386
freezero(msg, FIDO_MAXMSG);
387
388
return (r);
389
}
390
391
int
392
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
393
{
394
int r;
395
396
#ifdef USE_WINHELLO
397
if (dev->flags & FIDO_DEV_WINHELLO)
398
return (fido_winhello_get_cbor_info(dev, ci));
399
#endif
400
if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK ||
401
(r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
402
return (r);
403
404
return (FIDO_OK);
405
}
406
407
int
408
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
409
{
410
int ms = dev->timeout_ms;
411
412
return (fido_dev_get_cbor_info_wait(dev, ci, &ms));
413
}
414
415
/*
416
* get/set functions for fido_cbor_info_t; always at the end of the file
417
*/
418
419
fido_cbor_info_t *
420
fido_cbor_info_new(void)
421
{
422
fido_cbor_info_t *ci;
423
424
if ((ci = calloc(1, sizeof(fido_cbor_info_t))) == NULL)
425
return (NULL);
426
427
fido_cbor_info_reset(ci);
428
429
return (ci);
430
}
431
432
void
433
fido_cbor_info_reset(fido_cbor_info_t *ci)
434
{
435
fido_str_array_free(&ci->versions);
436
fido_str_array_free(&ci->extensions);
437
fido_str_array_free(&ci->transports);
438
fido_opt_array_free(&ci->options);
439
fido_byte_array_free(&ci->protocols);
440
fido_algo_array_free(&ci->algorithms);
441
fido_cert_array_free(&ci->certs);
442
ci->rk_remaining = -1;
443
}
444
445
void
446
fido_cbor_info_free(fido_cbor_info_t **ci_p)
447
{
448
fido_cbor_info_t *ci;
449
450
if (ci_p == NULL || (ci = *ci_p) == NULL)
451
return;
452
fido_cbor_info_reset(ci);
453
free(ci);
454
*ci_p = NULL;
455
}
456
457
char **
458
fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
459
{
460
return (ci->versions.ptr);
461
}
462
463
size_t
464
fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
465
{
466
return (ci->versions.len);
467
}
468
469
char **
470
fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
471
{
472
return (ci->extensions.ptr);
473
}
474
475
size_t
476
fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
477
{
478
return (ci->extensions.len);
479
}
480
481
char **
482
fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci)
483
{
484
return (ci->transports.ptr);
485
}
486
487
size_t
488
fido_cbor_info_transports_len(const fido_cbor_info_t *ci)
489
{
490
return (ci->transports.len);
491
}
492
493
const unsigned char *
494
fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
495
{
496
return (ci->aaguid);
497
}
498
499
size_t
500
fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
501
{
502
return (sizeof(ci->aaguid));
503
}
504
505
char **
506
fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
507
{
508
return (ci->options.name);
509
}
510
511
const bool *
512
fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
513
{
514
return (ci->options.value);
515
}
516
517
size_t
518
fido_cbor_info_options_len(const fido_cbor_info_t *ci)
519
{
520
return (ci->options.len);
521
}
522
523
uint64_t
524
fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci)
525
{
526
return (ci->maxcredbloblen);
527
}
528
529
uint64_t
530
fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
531
{
532
return (ci->maxmsgsiz);
533
}
534
535
uint64_t
536
fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
537
{
538
return (ci->maxcredcntlst);
539
}
540
541
uint64_t
542
fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
543
{
544
return (ci->maxcredidlen);
545
}
546
547
uint64_t
548
fido_cbor_info_maxlargeblob(const fido_cbor_info_t *ci)
549
{
550
return (ci->maxlargeblob);
551
}
552
553
uint64_t
554
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
555
{
556
return (ci->fwversion);
557
}
558
559
uint64_t
560
fido_cbor_info_minpinlen(const fido_cbor_info_t *ci)
561
{
562
return (ci->minpinlen);
563
}
564
565
uint64_t
566
fido_cbor_info_maxrpid_minpinlen(const fido_cbor_info_t *ci)
567
{
568
return (ci->maxrpid_minlen);
569
}
570
571
uint64_t
572
fido_cbor_info_uv_attempts(const fido_cbor_info_t *ci)
573
{
574
return (ci->uv_attempts);
575
}
576
577
uint64_t
578
fido_cbor_info_uv_modality(const fido_cbor_info_t *ci)
579
{
580
return (ci->uv_modality);
581
}
582
583
int64_t
584
fido_cbor_info_rk_remaining(const fido_cbor_info_t *ci)
585
{
586
return (ci->rk_remaining);
587
}
588
589
const uint8_t *
590
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
591
{
592
return (ci->protocols.ptr);
593
}
594
595
size_t
596
fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
597
{
598
return (ci->protocols.len);
599
}
600
601
size_t
602
fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci)
603
{
604
return (ci->algorithms.len);
605
}
606
607
const char *
608
fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx)
609
{
610
if (idx >= ci->algorithms.len)
611
return (NULL);
612
613
return (ci->algorithms.ptr[idx].type);
614
}
615
616
int
617
fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx)
618
{
619
if (idx >= ci->algorithms.len)
620
return (0);
621
622
return (ci->algorithms.ptr[idx].cose);
623
}
624
625
bool
626
fido_cbor_info_new_pin_required(const fido_cbor_info_t *ci)
627
{
628
return (ci->new_pin_reqd);
629
}
630
631
char **
632
fido_cbor_info_certs_name_ptr(const fido_cbor_info_t *ci)
633
{
634
return (ci->certs.name);
635
}
636
637
const uint64_t *
638
fido_cbor_info_certs_value_ptr(const fido_cbor_info_t *ci)
639
{
640
return (ci->certs.value);
641
}
642
643
size_t
644
fido_cbor_info_certs_len(const fido_cbor_info_t *ci)
645
{
646
return (ci->certs.len);
647
}
648
649