Coverage Report

Created: 2020-03-07 10:10

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