Coverage Report

Created: 2021-10-21 13:35

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