Coverage Report

Created: 2021-07-20 18:14

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