Coverage Report

Created: 2021-07-20 18:14

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