Coverage Report

Created: 2024-06-03 09:43

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