Coverage Report

Created: 2021-03-26 11:35

/libfido2/src/pin.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018 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 <openssl/sha.h>
8
#include "fido.h"
9
#include "fido/es256.h"
10
11
17
#define CTAP21_UV_TOKEN_PERM_MAKECRED   0x01
12
20
#define CTAP21_UV_TOKEN_PERM_ASSERT     0x02
13
19
#define CTAP21_UV_TOKEN_PERM_CRED_MGMT  0x04
14
24
#define CTAP21_UV_TOKEN_PERM_BIO        0x08
15
13
#define CTAP21_UV_TOKEN_PERM_LARGEBLOB  0x10
16
24
#define CTAP21_UV_TOKEN_PERM_CONFIG     0x20
17
18
static int
19
sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest)
20
3.00k
{
21
3.00k
        if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
22
3.00k
                return (-1);
23
2.99k
24
2.99k
        digest->len = SHA256_DIGEST_LENGTH;
25
2.99k
26
2.99k
        if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
27
13
                free(digest->ptr);
28
13
                digest->ptr = NULL;
29
13
                digest->len = 0;
30
13
                return (-1);
31
13
        }
32
2.97k
33
2.97k
        return (0);
34
2.97k
}
35
36
static int
37
pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared,
38
    const fido_blob_t *pin, fido_blob_t **out)
39
3.02k
{
40
3.02k
        fido_blob_t     *ph = NULL;
41
3.02k
        int              r;
42
3.02k
43
3.02k
        if ((*out = fido_blob_new()) == NULL ||
44
3.02k
            (ph = fido_blob_new()) == NULL) {
45
25
                r = FIDO_ERR_INTERNAL;
46
25
                goto fail;
47
25
        }
48
3.00k
49
3.00k
        if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
50
23
                fido_log_debug("%s: SHA256", __func__);
51
23
                r = FIDO_ERR_INTERNAL;
52
23
                goto fail;
53
23
        }
54
2.97k
55
2.97k
        ph->len = 16; /* first 16 bytes */
56
2.97k
57
2.97k
        if (aes256_cbc_enc(dev, shared, ph, *out) < 0) {
58
54
                fido_log_debug("%s: aes256_cbc_enc", __func__);
59
54
                r = FIDO_ERR_INTERNAL;
60
54
                goto fail;
61
54
        }
62
2.92k
63
2.92k
        r = FIDO_OK;
64
3.02k
fail:
65
3.02k
        fido_blob_free(&ph);
66
3.02k
67
3.02k
        return (r);
68
2.92k
}
69
70
static int
71
pad64(const char *pin, fido_blob_t **ppin)
72
131
{
73
131
        size_t  pin_len;
74
131
        size_t  ppin_len;
75
131
76
131
        pin_len = strlen(pin);
77
131
        if (pin_len < 4 || pin_len > 255) {
78
12
                fido_log_debug("%s: invalid pin length", __func__);
79
12
                return (FIDO_ERR_PIN_POLICY_VIOLATION);
80
12
        }
81
119
82
119
        if ((*ppin = fido_blob_new()) == NULL)
83
119
                return (FIDO_ERR_INTERNAL);
84
118
85
118
        ppin_len = (pin_len + 63U) & ~63U;
86
118
        if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
87
1
                fido_blob_free(ppin);
88
1
                return (FIDO_ERR_INTERNAL);
89
1
        }
90
117
91
117
        memcpy((*ppin)->ptr, pin, pin_len);
92
117
        (*ppin)->len = ppin_len;
93
117
94
117
        return (FIDO_OK);
95
117
}
96
97
static int
98
pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared,
99
    const char *pin, fido_blob_t **out)
100
131
{
101
131
        fido_blob_t *ppin = NULL;
102
131
        int          r;
103
131
104
131
        if ((r = pad64(pin, &ppin)) != FIDO_OK) {
105
14
                fido_log_debug("%s: pad64", __func__);
106
14
                    goto fail;
107
14
        }
108
117
109
117
        if ((*out = fido_blob_new()) == NULL) {
110
1
                r = FIDO_ERR_INTERNAL;
111
1
                goto fail;
112
1
        }
113
116
114
116
        if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) {
115
7
                fido_log_debug("%s: aes256_cbc_enc", __func__);
116
7
                r = FIDO_ERR_INTERNAL;
117
7
                goto fail;
118
7
        }
119
109
120
109
        r = FIDO_OK;
121
131
fail:
122
131
        fido_blob_free(&ppin);
123
131
124
131
        return (r);
125
109
}
126
127
static cbor_item_t *
128
encode_uv_permission(uint8_t cmd)
129
117
{
130
117
        switch (cmd) {
131
20
        case CTAP_CBOR_ASSERT:
132
20
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT));
133
24
        case CTAP_CBOR_BIO_ENROLL_PRE:
134
24
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO));
135
24
        case CTAP_CBOR_CONFIG:
136
24
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG));
137
17
        case CTAP_CBOR_MAKECRED:
138
17
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED));
139
19
        case CTAP_CBOR_CRED_MGMT_PRE:
140
19
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT));
141
13
        case CTAP_CBOR_LARGEBLOB:
142
13
                return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB));
143
0
        default:
144
0
                fido_log_debug("%s: cmd 0x%02x", __func__, cmd);
145
0
                return (NULL);
146
117
        }
147
117
}
148
149
static int
150
ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
151
    const es256_pk_t *pk)
152
2.86k
{
153
2.86k
        fido_blob_t      f;
154
2.86k
        fido_blob_t     *p = NULL;
155
2.86k
        fido_blob_t     *phe = NULL;
156
2.86k
        cbor_item_t     *argv[6];
157
2.86k
        int              r;
158
2.86k
159
2.86k
        memset(&f, 0, sizeof(f));
160
2.86k
        memset(argv, 0, sizeof(argv));
161
2.86k
162
2.86k
        if (pin == NULL || (p = fido_blob_new()) == NULL || fido_blob_set(p,
163
2.85k
            (const unsigned char *)pin, strlen(pin)) < 0) {
164
47
                fido_log_debug("%s: fido_blob_set", __func__);
165
47
                r = FIDO_ERR_INVALID_ARGUMENT;
166
47
                goto fail;
167
47
        }
168
2.81k
169
2.81k
        if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
170
89
                fido_log_debug("%s: pin_sha256_enc", __func__);
171
89
                goto fail;
172
89
        }
173
2.72k
174
2.72k
        if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
175
2.72k
            (argv[1] = cbor_build_uint8(5)) == NULL ||
176
2.72k
            (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
177
2.72k
            (argv[5] = fido_blob_encode(phe)) == NULL) {
178
173
                fido_log_debug("%s: cbor encode", __func__);
179
173
                r = FIDO_ERR_INTERNAL;
180
173
                goto fail;
181
173
        }
182
2.55k
183
2.55k
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
184
2.55k
            &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
185
51
                fido_log_debug("%s: fido_tx", __func__);
186
51
                r = FIDO_ERR_TX;
187
51
                goto fail;
188
51
        }
189
2.50k
190
2.50k
        r = FIDO_OK;
191
2.86k
fail:
192
2.86k
        cbor_vector_free(argv, nitems(argv));
193
2.86k
        fido_blob_free(&p);
194
2.86k
        fido_blob_free(&phe);
195
2.86k
        free(f.ptr);
196
2.86k
197
2.86k
        return (r);
198
2.50k
}
199
200
static int
201
ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
202
    const es256_pk_t *pk, uint8_t cmd, const char *rpid)
203
174
{
204
174
        fido_blob_t      f;
205
174
        fido_blob_t     *p = NULL;
206
174
        fido_blob_t     *phe = NULL;
207
174
        cbor_item_t     *argv[10];
208
174
        uint8_t          subcmd = 6;
209
174
        int              r;
210
174
211
174
        memset(&f, 0, sizeof(f));
212
174
        memset(argv, 0, sizeof(argv));
213
174
214
174
        if (pin != NULL) {
215
156
                if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
216
150
                    (const unsigned char *)pin, strlen(pin)) < 0) {
217
12
                        fido_log_debug("%s: fido_blob_set", __func__);
218
12
                        r = FIDO_ERR_INVALID_ARGUMENT;
219
12
                        goto fail;
220
12
                }
221
144
                if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
222
11
                        fido_log_debug("%s: pin_sha256_enc", __func__);
223
11
                        goto fail;
224
11
                }
225
133
                subcmd = 9;
226
133
        }
227
174
228
174
        if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
229
151
            (argv[1] = cbor_build_uint8(subcmd)) == NULL ||
230
151
            (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
231
151
            (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) ||
232
151
            (argv[8] = encode_uv_permission(cmd)) == NULL ||
233
151
            (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) {
234
43
                fido_log_debug("%s: cbor encode", __func__);
235
43
                r = FIDO_ERR_INTERNAL;
236
43
                goto fail;
237
43
        }
238
108
239
108
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
240
108
            &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
241
28
                fido_log_debug("%s:  fido_tx", __func__);
242
28
                r = FIDO_ERR_TX;
243
28
                goto fail;
244
28
        }
245
80
246
80
        r = FIDO_OK;
247
174
fail:
248
174
        cbor_vector_free(argv, nitems(argv));
249
174
        fido_blob_free(&p);
250
174
        fido_blob_free(&phe);
251
174
        free(f.ptr);
252
174
253
174
        return (r);
254
80
}
255
256
static int
257
parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg)
258
2.43k
{
259
2.43k
        fido_blob_t *token = arg;
260
2.43k
261
2.43k
        if (cbor_isa_uint(key) == false ||
262
2.43k
            cbor_int_get_width(key) != CBOR_INT_8 ||
263
2.43k
            cbor_get_uint8(key) != 2) {
264
203
                fido_log_debug("%s: cbor type", __func__);
265
203
                return (0); /* ignore */
266
203
        }
267
2.23k
268
2.23k
        return (fido_blob_decode(val, token));
269
2.23k
}
270
271
static int
272
uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
273
    int ms)
274
2.58k
{
275
2.58k
        fido_blob_t     *aes_token = NULL;
276
2.58k
        unsigned char    reply[FIDO_MAXMSG];
277
2.58k
        int              reply_len;
278
2.58k
        int              r;
279
2.58k
280
2.58k
        if ((aes_token = fido_blob_new()) == NULL) {
281
13
                r = FIDO_ERR_INTERNAL;
282
13
                goto fail;
283
13
        }
284
2.57k
285
2.57k
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
286
2.57k
            ms)) < 0) {
287
128
                fido_log_debug("%s: fido_rx", __func__);
288
128
                r = FIDO_ERR_RX;
289
128
                goto fail;
290
128
        }
291
2.44k
292
2.44k
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token,
293
2.44k
            parse_uv_token)) != FIDO_OK) {
294
168
                fido_log_debug("%s: parse_uv_token", __func__);
295
168
                goto fail;
296
168
        }
297
2.27k
298
2.27k
        if  (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) {
299
169
                fido_log_debug("%s: aes256_cbc_dec", __func__);
300
169
                r = FIDO_ERR_RX;
301
169
                goto fail;
302
169
        }
303
2.10k
304
2.10k
        r = FIDO_OK;
305
2.58k
fail:
306
2.58k
        fido_blob_free(&aes_token);
307
2.58k
308
2.58k
        return (r);
309
2.10k
}
310
311
static int
312
uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
313
    const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
314
    fido_blob_t *token, int ms)
315
3.03k
{
316
3.03k
        int r;
317
3.03k
318
3.03k
        if (ecdh == NULL || pk == NULL)
319
3.03k
                return (FIDO_ERR_INVALID_ARGUMENT);
320
3.03k
        if (fido_dev_supports_permissions(dev))
321
174
                r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid);
322
2.86k
        else
323
2.86k
                r = ctap20_uv_token_tx(dev, pin, ecdh, pk);
324
3.03k
        if (r != FIDO_OK)
325
3.03k
                return (r);
326
2.58k
327
2.58k
        return (uv_token_rx(dev, ecdh, token, ms));
328
2.58k
}
329
330
int
331
fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin,
332
    const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
333
    fido_blob_t *token)
334
3.03k
{
335
3.03k
        return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, -1));
336
3.03k
}
337
338
static int
339
fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
340
314
{
341
314
        fido_blob_t      f;
342
314
        fido_blob_t     *ppine = NULL;
343
314
        fido_blob_t     *ecdh = NULL;
344
314
        fido_blob_t     *opin = NULL;
345
314
        fido_blob_t     *opinhe = NULL;
346
314
        cbor_item_t     *argv[6];
347
314
        es256_pk_t      *pk = NULL;
348
314
        int r;
349
314
350
314
        memset(&f, 0, sizeof(f));
351
314
        memset(argv, 0, sizeof(argv));
352
314
353
314
        if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin,
354
312
            (const unsigned char *)oldpin, strlen(oldpin)) < 0) {
355
64
                fido_log_debug("%s: fido_blob_set", __func__);
356
64
                r = FIDO_ERR_INVALID_ARGUMENT;
357
64
                goto fail;
358
64
        }
359
250
360
250
        if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
361
170
                fido_log_debug("%s: fido_do_ecdh", __func__);
362
170
                goto fail;
363
170
        }
364
80
365
80
        /* pad and encrypt new pin */
366
80
        if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
367
14
                fido_log_debug("%s: pin_pad64_enc", __func__);
368
14
                goto fail;
369
14
        }
370
66
371
66
        /* hash and encrypt old pin */
372
66
        if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) {
373
2
                fido_log_debug("%s: pin_sha256_enc", __func__);
374
2
                goto fail;
375
2
        }
376
64
377
64
        if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
378
64
            (argv[1] = cbor_build_uint8(4)) == NULL ||
379
64
            (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
380
64
            (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL ||
381
64
            (argv[4] = fido_blob_encode(ppine)) == NULL ||
382
64
            (argv[5] = fido_blob_encode(opinhe)) == NULL) {
383
21
                fido_log_debug("%s: cbor encode", __func__);
384
21
                r = FIDO_ERR_INTERNAL;
385
21
                goto fail;
386
21
        }
387
43
388
43
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
389
43
            &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
390
4
                fido_log_debug("%s: fido_tx", __func__);
391
4
                r = FIDO_ERR_TX;
392
4
                goto fail;
393
4
        }
394
39
395
39
        r = FIDO_OK;
396
314
fail:
397
314
        cbor_vector_free(argv, nitems(argv));
398
314
        es256_pk_free(&pk);
399
314
        fido_blob_free(&ppine);
400
314
        fido_blob_free(&ecdh);
401
314
        fido_blob_free(&opin);
402
314
        fido_blob_free(&opinhe);
403
314
        free(f.ptr);
404
314
405
314
        return (r);
406
39
407
39
}
408
409
static int
410
fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
411
394
{
412
394
        fido_blob_t      f;
413
394
        fido_blob_t     *ppine = NULL;
414
394
        fido_blob_t     *ecdh = NULL;
415
394
        cbor_item_t     *argv[5];
416
394
        es256_pk_t      *pk = NULL;
417
394
        int              r;
418
394
419
394
        memset(&f, 0, sizeof(f));
420
394
        memset(argv, 0, sizeof(argv));
421
394
422
394
        if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
423
343
                fido_log_debug("%s: fido_do_ecdh", __func__);
424
343
                goto fail;
425
343
        }
426
51
427
51
        if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
428
8
                fido_log_debug("%s: pin_pad64_enc", __func__);
429
8
                goto fail;
430
8
        }
431
43
432
43
        if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
433
43
            (argv[1] = cbor_build_uint8(3)) == NULL ||
434
43
            (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
435
43
            (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL ||
436
43
            (argv[4] = fido_blob_encode(ppine)) == NULL) {
437
15
                fido_log_debug("%s: cbor encode", __func__);
438
15
                r = FIDO_ERR_INTERNAL;
439
15
                goto fail;
440
15
        }
441
28
442
28
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
443
28
            &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
444
2
                fido_log_debug("%s: fido_tx", __func__);
445
2
                r = FIDO_ERR_TX;
446
2
                goto fail;
447
2
        }
448
26
449
26
        r = FIDO_OK;
450
394
fail:
451
394
        cbor_vector_free(argv, nitems(argv));
452
394
        es256_pk_free(&pk);
453
394
        fido_blob_free(&ppine);
454
394
        fido_blob_free(&ecdh);
455
394
        free(f.ptr);
456
394
457
394
        return (r);
458
26
}
459
460
static int
461
fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
462
    int ms)
463
708
{
464
708
        int r;
465
708
466
708
        if (oldpin != NULL) {
467
314
                if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) {
468
275
                        fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
469
275
                        return (r);
470
275
                }
471
394
        } else {
472
394
                if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) {
473
368
                        fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
474
368
                        return (r);
475
368
                }
476
65
        }
477
65
478
65
        if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
479
59
                fido_log_debug("%s: fido_rx_cbor_status", __func__);
480
59
                return (r);
481
59
        }
482
6
483
6
        if (dev->flags & FIDO_DEV_PIN_UNSET) {
484
3
                dev->flags &= ~FIDO_DEV_PIN_UNSET;
485
3
                dev->flags |= FIDO_DEV_PIN_SET;
486
3
        }
487
6
488
6
        return (FIDO_OK);
489
6
}
490
491
int
492
fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
493
708
{
494
708
        return (fido_dev_set_pin_wait(dev, pin, oldpin, -1));
495
708
}
496
497
static int
498
parse_retry_count(const uint8_t keyval, const cbor_item_t *key,
499
    const cbor_item_t *val, void *arg)
500
334
{
501
334
        int             *retries = arg;
502
334
        uint64_t         n;
503
334
504
334
        if (cbor_isa_uint(key) == false ||
505
334
            cbor_int_get_width(key) != CBOR_INT_8 ||
506
334
            cbor_get_uint8(key) != keyval) {
507
232
                fido_log_debug("%s: cbor type", __func__);
508
232
                return (0); /* ignore */
509
232
        }
510
102
511
102
        if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) {
512
61
                fido_log_debug("%s: cbor_decode_uint64", __func__);
513
61
                return (-1);
514
61
        }
515
41
516
41
        *retries = (int)n;
517
41
518
41
        return (0);
519
41
}
520
521
static int
522
parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
523
241
{
524
241
        return (parse_retry_count(3, key, val, arg));
525
241
}
526
527
static int
528
parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
529
93
{
530
93
        return (parse_retry_count(5, key, val, arg));
531
93
}
532
533
static int
534
fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd)
535
811
{
536
811
        fido_blob_t      f;
537
811
        cbor_item_t     *argv[2];
538
811
        int              r;
539
811
540
811
        memset(&f, 0, sizeof(f));
541
811
        memset(argv, 0, sizeof(argv));
542
811
543
811
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
544
811
            (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
545
12
                r = FIDO_ERR_INTERNAL;
546
12
                goto fail;
547
12
        }
548
799
549
799
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
550
799
            &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
551
46
                fido_log_debug("%s: fido_tx", __func__);
552
46
                r = FIDO_ERR_TX;
553
46
                goto fail;
554
46
        }
555
753
556
753
        r = FIDO_OK;
557
811
fail:
558
811
        cbor_vector_free(argv, nitems(argv));
559
811
        free(f.ptr);
560
811
561
811
        return (r);
562
753
}
563
564
static int
565
fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
566
397
{
567
397
        unsigned char   reply[FIDO_MAXMSG];
568
397
        int             reply_len;
569
397
        int             r;
570
397
571
397
        *retries = 0;
572
397
573
397
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
574
397
            ms)) < 0) {
575
224
                fido_log_debug("%s: fido_rx", __func__);
576
224
                return (FIDO_ERR_RX);
577
224
        }
578
173
579
173
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries,
580
173
            parse_pin_retry_count)) != FIDO_OK) {
581
128
                fido_log_debug("%s: parse_pin_retry_count", __func__);
582
128
                return (r);
583
128
        }
584
45
585
45
        return (FIDO_OK);
586
45
}
587
588
static int
589
fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
590
424
{
591
424
        int r;
592
424
593
424
        if ((r = fido_dev_get_retry_count_tx(dev, 1)) != FIDO_OK ||
594
424
            (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK)
595
424
                return (r);
596
45
597
45
        return (FIDO_OK);
598
45
}
599
600
int
601
fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
602
424
{
603
424
        return (fido_dev_get_pin_retry_count_wait(dev, retries, -1));
604
424
}
605
606
static int
607
fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
608
356
{
609
356
        unsigned char   reply[FIDO_MAXMSG];
610
356
        int             reply_len;
611
356
        int             r;
612
356
613
356
        *retries = 0;
614
356
615
356
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
616
356
            ms)) < 0) {
617
283
                fido_log_debug("%s: fido_rx", __func__);
618
283
                return (FIDO_ERR_RX);
619
283
        }
620
73
621
73
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries,
622
73
            parse_uv_retry_count)) != FIDO_OK) {
623
63
                fido_log_debug("%s: parse_uv_retry_count", __func__);
624
63
                return (r);
625
63
        }
626
10
627
10
        return (FIDO_OK);
628
10
}
629
630
static int
631
fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
632
387
{
633
387
        int r;
634
387
635
387
        if ((r = fido_dev_get_retry_count_tx(dev, 7)) != FIDO_OK ||
636
387
            (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK)
637
387
                return (r);
638
10
639
10
        return (FIDO_OK);
640
10
}
641
642
int
643
fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries)
644
387
{
645
387
        return (fido_dev_get_uv_retry_count_wait(dev, retries, -1));
646
387
}
647
648
int
649
cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
650
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
651
    const char *rpid, cbor_item_t **auth, cbor_item_t **opt)
652
2.42k
{
653
2.42k
        fido_blob_t     *token = NULL;
654
2.42k
        int              r;
655
2.42k
656
2.42k
        if ((token = fido_blob_new()) == NULL) {
657
6
                r = FIDO_ERR_INTERNAL;
658
6
                goto fail;
659
6
        }
660
2.41k
661
2.41k
        if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid,
662
2.41k
            token)) != FIDO_OK) {
663
655
                fido_log_debug("%s: fido_dev_get_uv_token", __func__);
664
655
                goto fail;
665
655
        }
666
1.76k
667
1.76k
        if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL ||
668
1.76k
            (*opt = cbor_encode_pin_opt(dev)) == NULL) {
669
16
                fido_log_debug("%s: cbor encode", __func__);
670
16
                r = FIDO_ERR_INTERNAL;
671
16
                goto fail;
672
16
        }
673
1.74k
674
1.74k
        r = FIDO_OK;
675
2.42k
fail:
676
2.42k
        fido_blob_free(&token);
677
2.42k
678
2.42k
        return (r);
679
1.74k
}
680
681
bool
682
fido_dev_can_get_uv_token(const fido_dev_t *dev, const char *pin, fido_opt_t uv)
683
6.50k
{
684
6.50k
        if (pin != NULL)
685
6.50k
                return (true);
686
2.11k
        if (fido_dev_supports_permissions(dev)) {
687
45
                if (uv != FIDO_OPT_OMIT)
688
15
                        return (uv == FIDO_OPT_TRUE);
689
30
                return (fido_dev_has_uv(dev));
690
30
        }
691
2.06k
692
2.06k
        return (false);
693
2.06k
}