Coverage Report

Created: 2021-10-21 13:35

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