Coverage Report

Created: 2022-01-17 10:46

/libfido2/src/bio.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019 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 "fido.h"
8
#include "fido/bio.h"
9
#include "fido/es256.h"
10
11
315
#define CMD_ENROLL_BEGIN        0x01
12
222
#define CMD_ENROLL_NEXT         0x02
13
0
#define CMD_ENROLL_CANCEL       0x03
14
457
#define CMD_ENUM                0x04
15
438
#define CMD_SET_NAME            0x05
16
322
#define CMD_ENROLL_REMOVE       0x06
17
1.00k
#define CMD_GET_INFO            0x07
18
19
static int
20
bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc,
21
    cbor_item_t **param, fido_blob_t *hmac_data)
22
1.71k
{
23
1.71k
        const uint8_t    prefix[2] = { 0x01 /* modality */, cmd };
24
1.71k
        int              ok = -1;
25
1.71k
        size_t           cbor_alloc_len;
26
1.71k
        size_t           cbor_len;
27
1.71k
        unsigned char   *cbor = NULL;
28
29
1.71k
        if (argv == NULL || param == NULL)
30
1.71k
                return (fido_blob_set(hmac_data, prefix, sizeof(prefix)));
31
32
1.26k
        if ((*param = cbor_flatten_vector(argv, argc)) == NULL) {
33
39
                fido_log_debug("%s: cbor_flatten_vector", __func__);
34
39
                goto fail;
35
39
        }
36
37
1.22k
        if ((cbor_len = cbor_serialize_alloc(*param, &cbor,
38
1.22k
            &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) {
39
12
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
40
12
                goto fail;
41
12
        }
42
43
1.21k
        if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) {
44
5
                fido_log_debug("%s: malloc", __func__);
45
5
                goto fail;
46
5
        }
47
48
1.20k
        memcpy(hmac_data->ptr, prefix, sizeof(prefix));
49
1.20k
        memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len);
50
1.20k
        hmac_data->len = cbor_len + sizeof(prefix);
51
52
1.20k
        ok = 0;
53
1.26k
fail:
54
1.26k
        free(cbor);
55
56
1.26k
        return (ok);
57
1.20k
}
58
59
static int
60
bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
61
    const char *pin, const fido_blob_t *token, int *ms)
62
2.73k
{
63
2.73k
        cbor_item_t     *argv[5];
64
2.73k
        es256_pk_t      *pk = NULL;
65
2.73k
        fido_blob_t     *ecdh = NULL;
66
2.73k
        fido_blob_t      f;
67
2.73k
        fido_blob_t      hmac;
68
2.73k
        const uint8_t    cmd = CTAP_CBOR_BIO_ENROLL_PRE;
69
2.73k
        int              r = FIDO_ERR_INTERNAL;
70
71
2.73k
        memset(&f, 0, sizeof(f));
72
2.73k
        memset(&hmac, 0, sizeof(hmac));
73
2.73k
        memset(&argv, 0, sizeof(argv));
74
75
        /* modality, subCommand */
76
2.73k
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
77
2.73k
            (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
78
23
                fido_log_debug("%s: cbor encode", __func__);
79
23
                goto fail;
80
23
        }
81
82
        /* subParams */
83
2.71k
        if (pin || token) {
84
1.71k
                if (bio_prepare_hmac(subcmd, sub_argv, sub_argc, &argv[2],
85
1.71k
                    &hmac) < 0) {
86
58
                        fido_log_debug("%s: bio_prepare_hmac", __func__);
87
58
                        goto fail;
88
58
                }
89
2.65k
        }
90
91
        /* pinProtocol, pinAuth */
92
2.65k
        if (pin) {
93
1.15k
                if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
94
875
                        fido_log_debug("%s: fido_do_ecdh", __func__);
95
875
                        goto fail;
96
875
                }
97
282
                if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
98
282
                    NULL, &argv[4], &argv[3], ms)) != FIDO_OK) {
99
144
                        fido_log_debug("%s: cbor_add_uv_params", __func__);
100
144
                        goto fail;
101
144
                }
102
1.49k
        } else if (token) {
103
495
                if ((argv[3] = cbor_encode_pin_opt(dev)) == NULL ||
104
495
                    (argv[4] = cbor_encode_pin_auth(dev, token, &hmac)) == NULL) {
105
13
                        fido_log_debug("%s: encode pin", __func__);
106
13
                        goto fail;
107
13
                }
108
1.62k
        }
109
110
        /* framing and transmission */
111
1.62k
        if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
112
1.62k
            fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
113
95
                fido_log_debug("%s: fido_tx", __func__);
114
95
                r = FIDO_ERR_TX;
115
95
                goto fail;
116
95
        }
117
118
1.52k
        r = FIDO_OK;
119
2.73k
fail:
120
2.73k
        cbor_vector_free(argv, nitems(argv));
121
2.73k
        es256_pk_free(&pk);
122
2.73k
        fido_blob_free(&ecdh);
123
2.73k
        free(f.ptr);
124
2.73k
        free(hmac.ptr);
125
126
2.73k
        return (r);
127
1.52k
}
128
129
static void
130
bio_reset_template(fido_bio_template_t *t)
131
2.19k
{
132
2.19k
        free(t->name);
133
2.19k
        t->name = NULL;
134
2.19k
        fido_blob_reset(&t->id);
135
2.19k
}
136
137
static void
138
bio_reset_template_array(fido_bio_template_array_t *ta)
139
523
{
140
694
        for (size_t i = 0; i < ta->n_alloc; i++)
141
171
                bio_reset_template(&ta->ptr[i]);
142
143
523
        free(ta->ptr);
144
523
        ta->ptr = NULL;
145
523
        memset(ta, 0, sizeof(*ta));
146
523
}
147
148
static int
149
decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg)
150
93
{
151
93
        fido_bio_template_t *t = arg;
152
153
93
        if (cbor_isa_uint(key) == false ||
154
93
            cbor_int_get_width(key) != CBOR_INT_8) {
155
16
                fido_log_debug("%s: cbor type", __func__);
156
16
                return (0); /* ignore */
157
16
        }
158
159
77
        switch (cbor_get_uint8(key)) {
160
36
        case 1: /* id */
161
36
                return (fido_blob_decode(val, &t->id));
162
29
        case 2: /* name */
163
29
                return (cbor_string_copy(val, &t->name));
164
12
        }
165
166
12
        return (0); /* ignore */
167
12
}
168
169
static int
170
decode_template_array(const cbor_item_t *item, void *arg)
171
129
{
172
129
        fido_bio_template_array_t *ta = arg;
173
174
129
        if (cbor_isa_map(item) == false ||
175
129
            cbor_map_is_definite(item) == false) {
176
11
                fido_log_debug("%s: cbor type", __func__);
177
11
                return (-1);
178
11
        }
179
180
118
        if (ta->n_rx >= ta->n_alloc) {
181
0
                fido_log_debug("%s: n_rx >= n_alloc", __func__);
182
0
                return (-1);
183
0
        }
184
185
118
        if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) {
186
8
                fido_log_debug("%s: decode_template", __func__);
187
8
                return (-1);
188
8
        }
189
190
110
        ta->n_rx++;
191
192
110
        return (0);
193
110
}
194
195
static int
196
bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val,
197
    void *arg)
198
87
{
199
87
        fido_bio_template_array_t *ta = arg;
200
201
87
        if (cbor_isa_uint(key) == false ||
202
87
            cbor_int_get_width(key) != CBOR_INT_8 ||
203
87
            cbor_get_uint8(key) != 7) {
204
54
                fido_log_debug("%s: cbor type", __func__);
205
54
                return (0); /* ignore */
206
54
        }
207
208
33
        if (cbor_isa_array(val) == false ||
209
33
            cbor_array_is_definite(val) == false) {
210
2
                fido_log_debug("%s: cbor type", __func__);
211
2
                return (-1);
212
2
        }
213
214
31
        if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) {
215
0
                fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0",
216
0
                    __func__);
217
0
                return (-1);
218
0
        }
219
220
31
        if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL)
221
31
                return (-1);
222
223
30
        ta->n_alloc = cbor_array_size(val);
224
225
30
        if (cbor_array_iter(val, ta, decode_template_array) < 0) {
226
19
                fido_log_debug("%s: decode_template_array", __func__);
227
19
                return (-1);
228
19
        }
229
230
11
        return (0);
231
11
}
232
233
static int
234
bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int *ms)
235
66
{
236
66
        unsigned char   reply[FIDO_MAXMSG];
237
66
        int             reply_len;
238
66
        int             r;
239
240
66
        bio_reset_template_array(ta);
241
242
66
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
243
66
            ms)) < 0) {
244
4
                fido_log_debug("%s: fido_rx", __func__);
245
4
                return (FIDO_ERR_RX);
246
4
        }
247
248
62
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta,
249
62
            bio_parse_template_array)) != FIDO_OK) {
250
48
                fido_log_debug("%s: bio_parse_template_array" , __func__);
251
48
                return (r);
252
48
        }
253
254
14
        return (FIDO_OK);
255
14
}
256
257
static int
258
bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta,
259
    const char *pin, int *ms)
260
457
{
261
457
        int r;
262
263
457
        if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL, ms)) != FIDO_OK ||
264
457
            (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK)
265
457
                return (r);
266
267
14
        return (FIDO_OK);
268
14
}
269
270
int
271
fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta,
272
    const char *pin)
273
457
{
274
457
        int ms = dev->timeout_ms;
275
276
457
        if (pin == NULL)
277
457
                return (FIDO_ERR_INVALID_ARGUMENT);
278
279
457
        return (bio_get_template_array_wait(dev, ta, pin, &ms));
280
457
}
281
282
static int
283
bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t,
284
    const char *pin, int *ms)
285
445
{
286
445
        cbor_item_t     *argv[2];
287
445
        int              r = FIDO_ERR_INTERNAL;
288
289
445
        memset(&argv, 0, sizeof(argv));
290
291
445
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
292
445
            (argv[1] = cbor_build_string(t->name)) == NULL) {
293
7
                fido_log_debug("%s: cbor encode", __func__);
294
7
                goto fail;
295
7
        }
296
297
438
        if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL,
298
438
            ms)) != FIDO_OK ||
299
438
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
300
436
                fido_log_debug("%s: tx/rx", __func__);
301
436
                goto fail;
302
436
        }
303
304
2
        r = FIDO_OK;
305
445
fail:
306
445
        cbor_vector_free(argv, nitems(argv));
307
308
445
        return (r);
309
2
}
310
311
int
312
fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t,
313
    const char *pin)
314
448
{
315
448
        int ms = dev->timeout_ms;
316
317
448
        if (pin == NULL || t->name == NULL)
318
448
                return (FIDO_ERR_INVALID_ARGUMENT);
319
320
445
        return (bio_set_template_name_wait(dev, t, pin, &ms));
321
445
}
322
323
static void
324
bio_reset_enroll(fido_bio_enroll_t *e)
325
952
{
326
952
        e->remaining_samples = 0;
327
952
        e->last_status = 0;
328
329
952
        if (e->token)
330
315
                fido_blob_free(&e->token);
331
952
}
332
333
static int
334
bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val,
335
    void *arg)
336
826
{
337
826
        fido_bio_enroll_t *e = arg;
338
826
        uint64_t x;
339
340
826
        if (cbor_isa_uint(key) == false ||
341
826
            cbor_int_get_width(key) != CBOR_INT_8) {
342
34
                fido_log_debug("%s: cbor type", __func__);
343
34
                return (0); /* ignore */
344
34
        }
345
346
792
        switch (cbor_get_uint8(key)) {
347
292
        case 5:
348
292
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
349
80
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
350
80
                        return (-1);
351
80
                }
352
212
                e->last_status = (uint8_t)x;
353
212
                break;
354
221
        case 6:
355
221
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
356
81
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
357
81
                        return (-1);
358
81
                }
359
140
                e->remaining_samples = (uint8_t)x;
360
140
                break;
361
279
        default:
362
279
                return (0); /* ignore */
363
352
        }
364
365
352
        return (0);
366
352
}
367
368
static int
369
bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val,
370
    void *arg)
371
276
{
372
276
        fido_blob_t *id = arg;
373
374
276
        if (cbor_isa_uint(key) == false ||
375
276
            cbor_int_get_width(key) != CBOR_INT_8 ||
376
276
            cbor_get_uint8(key) != 4) {
377
195
                fido_log_debug("%s: cbor type", __func__);
378
195
                return (0); /* ignore */
379
195
        }
380
381
81
        return (fido_blob_decode(val, id));
382
81
}
383
384
static int
385
bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
386
    fido_bio_enroll_t *e, int *ms)
387
305
{
388
305
        unsigned char   reply[FIDO_MAXMSG];
389
305
        int             reply_len;
390
305
        int             r;
391
392
305
        bio_reset_template(t);
393
394
305
        e->remaining_samples = 0;
395
305
        e->last_status = 0;
396
397
305
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
398
305
            ms)) < 0) {
399
40
                fido_log_debug("%s: fido_rx", __func__);
400
40
                return (FIDO_ERR_RX);
401
40
        }
402
403
265
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, e,
404
265
            bio_parse_enroll_status)) != FIDO_OK) {
405
174
                fido_log_debug("%s: bio_parse_enroll_status", __func__);
406
174
                return (r);
407
174
        }
408
91
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id,
409
91
            bio_parse_template_id)) != FIDO_OK) {
410
2
                fido_log_debug("%s: bio_parse_template_id", __func__);
411
2
                return (r);
412
2
        }
413
414
89
        return (FIDO_OK);
415
89
}
416
417
static int
418
bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
419
    fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
420
315
{
421
315
        cbor_item_t     *argv[3];
422
315
        const uint8_t    cmd = CMD_ENROLL_BEGIN;
423
315
        int              r = FIDO_ERR_INTERNAL;
424
425
315
        memset(&argv, 0, sizeof(argv));
426
427
315
        if ((argv[2] = cbor_build_uint(timo_ms)) == NULL) {
428
3
                fido_log_debug("%s: cbor encode", __func__);
429
3
                goto fail;
430
3
        }
431
432
312
        if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
433
312
            (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) {
434
223
                fido_log_debug("%s: tx/rx", __func__);
435
223
                goto fail;
436
223
        }
437
438
89
        r = FIDO_OK;
439
315
fail:
440
315
        cbor_vector_free(argv, nitems(argv));
441
442
315
        return (r);
443
89
}
444
445
int
446
fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
447
    fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin)
448
952
{
449
952
        es256_pk_t      *pk = NULL;
450
952
        fido_blob_t     *ecdh = NULL;
451
952
        fido_blob_t     *token = NULL;
452
952
        int              ms = dev->timeout_ms;
453
952
        int              r;
454
455
952
        if (pin == NULL || e->token != NULL)
456
952
                return (FIDO_ERR_INVALID_ARGUMENT);
457
458
952
        if ((token = fido_blob_new()) == NULL) {
459
5
                r = FIDO_ERR_INTERNAL;
460
5
                goto fail;
461
5
        }
462
463
947
        if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
464
524
                fido_log_debug("%s: fido_do_ecdh", __func__);
465
524
                goto fail;
466
524
        }
467
468
423
        if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh,
469
423
            pk, NULL, token, &ms)) != FIDO_OK) {
470
108
                fido_log_debug("%s: fido_dev_get_uv_token", __func__);
471
108
                goto fail;
472
108
        }
473
474
315
        e->token = token;
475
315
        token = NULL;
476
952
fail:
477
952
        es256_pk_free(&pk);
478
952
        fido_blob_free(&ecdh);
479
952
        fido_blob_free(&token);
480
481
952
        if (r != FIDO_OK)
482
952
                return (r);
483
484
315
        return (bio_enroll_begin_wait(dev, t, e, timo_ms, &ms));
485
315
}
486
487
static int
488
bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int *ms)
489
130
{
490
130
        unsigned char   reply[FIDO_MAXMSG];
491
130
        int             reply_len;
492
130
        int             r;
493
494
130
        e->remaining_samples = 0;
495
130
        e->last_status = 0;
496
497
130
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
498
130
            ms)) < 0) {
499
51
                fido_log_debug("%s: fido_rx", __func__);
500
51
                return (FIDO_ERR_RX);
501
51
        }
502
503
79
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, e,
504
79
            bio_parse_enroll_status)) != FIDO_OK) {
505
28
                fido_log_debug("%s: bio_parse_enroll_status", __func__);
506
28
                return (r);
507
28
        }
508
509
51
        return (FIDO_OK);
510
51
}
511
512
static int
513
bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
514
    fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
515
222
{
516
222
        cbor_item_t     *argv[3];
517
222
        const uint8_t    cmd = CMD_ENROLL_NEXT;
518
222
        int              r = FIDO_ERR_INTERNAL;
519
520
222
        memset(&argv, 0, sizeof(argv));
521
522
222
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
523
222
            (argv[2] = cbor_build_uint(timo_ms)) == NULL) {
524
14
                fido_log_debug("%s: cbor encode", __func__);
525
14
                goto fail;
526
14
        }
527
528
208
        if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
529
208
            (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) {
530
157
                fido_log_debug("%s: tx/rx", __func__);
531
157
                goto fail;
532
157
        }
533
534
51
        r = FIDO_OK;
535
222
fail:
536
222
        cbor_vector_free(argv, nitems(argv));
537
538
222
        return (r);
539
51
}
540
541
int
542
fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t,
543
    fido_bio_enroll_t *e, uint32_t timo_ms)
544
222
{
545
222
        int ms = dev->timeout_ms;
546
547
222
        if (e->token == NULL)
548
222
                return (FIDO_ERR_INVALID_ARGUMENT);
549
550
222
        return (bio_enroll_continue_wait(dev, t, e, timo_ms, &ms));
551
222
}
552
553
static int
554
bio_enroll_cancel_wait(fido_dev_t *dev, int *ms)
555
0
{
556
0
        const uint8_t   cmd = CMD_ENROLL_CANCEL;
557
0
        int             r;
558
559
0
        if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL, ms)) != FIDO_OK ||
560
0
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
561
0
                fido_log_debug("%s: tx/rx", __func__);
562
0
                return (r);
563
0
        }
564
565
0
        return (FIDO_OK);
566
0
}
567
568
int
569
fido_bio_dev_enroll_cancel(fido_dev_t *dev)
570
0
{
571
0
        int ms = dev->timeout_ms;
572
573
0
        return (bio_enroll_cancel_wait(dev, &ms));
574
0
}
575
576
static int
577
bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t,
578
    const char *pin, int *ms)
579
322
{
580
322
        cbor_item_t     *argv[1];
581
322
        const uint8_t    cmd = CMD_ENROLL_REMOVE;
582
322
        int              r = FIDO_ERR_INTERNAL;
583
584
322
        memset(&argv, 0, sizeof(argv));
585
586
322
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL) {
587
9
                fido_log_debug("%s: cbor encode", __func__);
588
9
                goto fail;
589
9
        }
590
591
313
        if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL, ms)) != FIDO_OK ||
592
313
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
593
311
                fido_log_debug("%s: tx/rx", __func__);
594
311
                goto fail;
595
311
        }
596
597
2
        r = FIDO_OK;
598
322
fail:
599
322
        cbor_vector_free(argv, nitems(argv));
600
601
322
        return (r);
602
2
}
603
604
int
605
fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t,
606
    const char *pin)
607
322
{
608
322
        int ms = dev->timeout_ms;
609
610
322
        return (bio_enroll_remove_wait(dev, t, pin, &ms));
611
322
}
612
613
static void
614
bio_reset_info(fido_bio_info_t *i)
615
966
{
616
966
        i->type = 0;
617
966
        i->max_samples = 0;
618
966
}
619
620
static int
621
bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg)
622
1.17k
{
623
1.17k
        fido_bio_info_t *i = arg;
624
1.17k
        uint64_t         x;
625
626
1.17k
        if (cbor_isa_uint(key) == false ||
627
1.17k
            cbor_int_get_width(key) != CBOR_INT_8) {
628
504
                fido_log_debug("%s: cbor type", __func__);
629
504
                return (0); /* ignore */
630
504
        }
631
632
671
        switch (cbor_get_uint8(key)) {
633
134
        case 2:
634
134
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
635
104
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
636
104
                        return (-1);
637
104
                }
638
30
                i->type = (uint8_t)x;
639
30
                break;
640
105
        case 3:
641
105
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
642
88
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
643
88
                        return (-1);
644
88
                }
645
17
                i->max_samples = (uint8_t)x;
646
17
                break;
647
432
        default:
648
432
                return (0); /* ignore */
649
47
        }
650
651
47
        return (0);
652
47
}
653
654
static int
655
bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
656
966
{
657
966
        unsigned char   reply[FIDO_MAXMSG];
658
966
        int             reply_len;
659
966
        int             r;
660
661
966
        bio_reset_info(i);
662
663
966
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
664
966
            ms)) < 0) {
665
439
                fido_log_debug("%s: fido_rx", __func__);
666
439
                return (FIDO_ERR_RX);
667
439
        }
668
669
527
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, i,
670
527
            bio_parse_info)) != FIDO_OK) {
671
505
                fido_log_debug("%s: bio_parse_info" , __func__);
672
505
                return (r);
673
505
        }
674
675
22
        return (FIDO_OK);
676
22
}
677
678
static int
679
bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
680
1.00k
{
681
1.00k
        int r;
682
683
1.00k
        if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL,
684
1.00k
            ms)) != FIDO_OK ||
685
1.00k
            (r = bio_rx_info(dev, i, ms)) != FIDO_OK) {
686
986
                fido_log_debug("%s: tx/rx", __func__);
687
986
                return (r);
688
986
        }
689
690
22
        return (FIDO_OK);
691
22
}
692
693
int
694
fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i)
695
1.00k
{
696
1.00k
        int ms = dev->timeout_ms;
697
698
1.00k
        return (bio_get_info_wait(dev, i, &ms));
699
1.00k
}
700
701
const char *
702
fido_bio_template_name(const fido_bio_template_t *t)
703
2.07k
{
704
2.07k
        return (t->name);
705
2.07k
}
706
707
const unsigned char *
708
fido_bio_template_id_ptr(const fido_bio_template_t *t)
709
2.07k
{
710
2.07k
        return (t->id.ptr);
711
2.07k
}
712
713
size_t
714
fido_bio_template_id_len(const fido_bio_template_t *t)
715
2.07k
{
716
2.07k
        return (t->id.len);
717
2.07k
}
718
719
size_t
720
fido_bio_template_array_count(const fido_bio_template_array_t *ta)
721
1.02k
{
722
1.02k
        return (ta->n_rx);
723
1.02k
}
724
725
fido_bio_template_array_t *
726
fido_bio_template_array_new(void)
727
458
{
728
458
        return (calloc(1, sizeof(fido_bio_template_array_t)));
729
458
}
730
731
fido_bio_template_t *
732
fido_bio_template_new(void)
733
1.73k
{
734
1.73k
        return (calloc(1, sizeof(fido_bio_template_t)));
735
1.73k
}
736
737
void
738
fido_bio_template_array_free(fido_bio_template_array_t **tap)
739
2.51k
{
740
2.51k
        fido_bio_template_array_t *ta;
741
742
2.51k
        if (tap == NULL || (ta = *tap) == NULL)
743
2.51k
                return;
744
745
457
        bio_reset_template_array(ta);
746
457
        free(ta);
747
457
        *tap = NULL;
748
457
}
749
750
void
751
fido_bio_template_free(fido_bio_template_t **tp)
752
7.54k
{
753
7.54k
        fido_bio_template_t *t;
754
755
7.54k
        if (tp == NULL || (t = *tp) == NULL)
756
7.54k
                return;
757
758
1.72k
        bio_reset_template(t);
759
1.72k
        free(t);
760
1.72k
        *tp = NULL;
761
1.72k
}
762
763
int
764
fido_bio_template_set_name(fido_bio_template_t *t, const char *name)
765
448
{
766
448
        free(t->name);
767
448
        t->name = NULL;
768
769
448
        if (name && (t->name = strdup(name)) == NULL)
770
448
                return (FIDO_ERR_INTERNAL);
771
772
445
        return (FIDO_OK);
773
445
}
774
775
int
776
fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr,
777
    size_t len)
778
770
{
779
770
        fido_blob_reset(&t->id);
780
781
770
        if (ptr && fido_blob_set(&t->id, ptr, len) < 0)
782
9
                return (FIDO_ERR_INTERNAL);
783
784
761
        return (FIDO_OK);
785
761
}
786
787
const fido_bio_template_t *
788
fido_bio_template(const fido_bio_template_array_t *ta, size_t idx)
789
567
{
790
567
        if (idx >= ta->n_alloc)
791
438
                return (NULL);
792
793
129
        return (&ta->ptr[idx]);
794
129
}
795
796
fido_bio_enroll_t *
797
fido_bio_enroll_new(void)
798
953
{
799
953
        return (calloc(1, sizeof(fido_bio_enroll_t)));
800
953
}
801
802
fido_bio_info_t *
803
fido_bio_info_new(void)
804
1.01k
{
805
1.01k
        return (calloc(1, sizeof(fido_bio_info_t)));
806
1.01k
}
807
808
uint8_t
809
fido_bio_info_type(const fido_bio_info_t *i)
810
1.00k
{
811
1.00k
        return (i->type);
812
1.00k
}
813
814
uint8_t
815
fido_bio_info_max_samples(const fido_bio_info_t *i)
816
1.00k
{
817
1.00k
        return (i->max_samples);
818
1.00k
}
819
820
void
821
fido_bio_enroll_free(fido_bio_enroll_t **ep)
822
2.51k
{
823
2.51k
        fido_bio_enroll_t *e;
824
825
2.51k
        if (ep == NULL || (e = *ep) == NULL)
826
2.51k
                return;
827
828
952
        bio_reset_enroll(e);
829
830
952
        free(e);
831
952
        *ep = NULL;
832
952
}
833
834
void
835
fido_bio_info_free(fido_bio_info_t **ip)
836
2.51k
{
837
2.51k
        fido_bio_info_t *i;
838
839
2.51k
        if (ip == NULL || (i = *ip) == NULL)
840
2.51k
                return;
841
842
1.00k
        free(i);
843
1.00k
        *ip = NULL;
844
1.00k
}
845
846
uint8_t
847
fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e)
848
2.34k
{
849
2.34k
        return (e->remaining_samples);
850
2.34k
}
851
852
uint8_t
853
fido_bio_enroll_last_status(const fido_bio_enroll_t *e)
854
1.17k
{
855
1.17k
        return (e->last_status);
856
1.17k
}