Coverage Report

Created: 2020-12-02 17:02

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