Coverage Report

Created: 2022-07-22 12:05

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