Coverage Report

Created: 2023-09-23 17:42

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