Coverage Report

Created: 2023-09-23 17:42

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