Coverage Report

Created: 2021-03-26 11:35

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