Coverage Report

Created: 2022-04-27 14:33

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