Coverage Report

Created: 2024-02-05 19:20

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