Coverage Report

Created: 2022-07-22 12:05

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