Coverage Report

Created: 2025-10-04 18:33

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