Coverage Report

Created: 2022-01-17 10:46

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