Coverage Report

Created: 2020-09-01 07:05

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