Coverage Report

Created: 2022-07-22 12:05

/libfido2/src/credman.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019-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
9
#include "fido.h"
10
#include "fido/credman.h"
11
#include "fido/es256.h"
12
13
267
#define CMD_CRED_METADATA       0x01
14
200
#define CMD_RP_BEGIN            0x02
15
153
#define CMD_RP_NEXT             0x03
16
380
#define CMD_RK_BEGIN            0x04
17
74
#define CMD_RK_NEXT             0x05
18
852
#define CMD_DELETE_CRED         0x06
19
902
#define CMD_UPDATE_CRED         0x07
20
21
static int
22
credman_grow_array(void **ptr, size_t *n_alloc, const size_t *n_rx, size_t n,
23
    size_t size)
24
97
{
25
97
        void *new_ptr;
26
27
97
#ifdef FIDO_FUZZ
28
97
        if (n > UINT8_MAX) {
29
4
                fido_log_debug("%s: n > UINT8_MAX", __func__);
30
4
                return (-1);
31
4
        }
32
93
#endif
33
34
93
        if (n < *n_alloc)
35
0
                return (0);
36
37
        /* sanity check */
38
93
        if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) {
39
0
                fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n,
40
0
                    *n_rx, *n_alloc);
41
0
                return (-1);
42
0
        }
43
44
93
        if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL)
45
1
                return (-1);
46
47
92
        *ptr = new_ptr;
48
92
        *n_alloc = n;
49
50
92
        return (0);
51
93
}
52
53
static int
54
credman_prepare_hmac(uint8_t cmd, const void *body, cbor_item_t **param,
55
    fido_blob_t *hmac_data)
56
620
{
57
620
        cbor_item_t *param_cbor[3];
58
620
        const fido_cred_t *cred;
59
620
        size_t n;
60
620
        int ok = -1;
61
62
620
        memset(&param_cbor, 0, sizeof(param_cbor));
63
64
620
        if (body == NULL)
65
196
                return (fido_blob_set(hmac_data, &cmd, sizeof(cmd)));
66
67
424
        switch (cmd) {
68
139
        case CMD_RK_BEGIN:
69
139
                n = 1;
70
139
                if ((param_cbor[0] = fido_blob_encode(body)) == NULL) {
71
1
                        fido_log_debug("%s: cbor encode", __func__);
72
1
                        goto fail;
73
1
                }
74
138
                break;
75
142
        case CMD_DELETE_CRED:
76
142
                n = 2;
77
142
                if ((param_cbor[1] = cbor_encode_pubkey(body)) == NULL) {
78
5
                        fido_log_debug("%s: cbor encode", __func__);
79
5
                        goto fail;
80
5
                }
81
137
                break;
82
143
        case CMD_UPDATE_CRED:
83
143
                n = 3;
84
143
                cred = body;
85
143
                param_cbor[1] = cbor_encode_pubkey(&cred->attcred.id);
86
143
                param_cbor[2] = cbor_encode_user_entity(&cred->user);
87
143
                if (param_cbor[1] == NULL || param_cbor[2] == NULL) {
88
12
                        fido_log_debug("%s: cbor encode", __func__);
89
12
                        goto fail;
90
12
                }
91
131
                break;
92
131
        default:
93
0
                fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd);
94
0
                return (-1);
95
424
        }
96
97
406
        if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) {
98
6
                fido_log_debug("%s: cbor_flatten_vector", __func__);
99
6
                goto fail;
100
6
        }
101
400
        if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) {
102
9
                fido_log_debug("%s: cbor_build_frame", __func__);
103
9
                goto fail;
104
9
        }
105
106
391
        ok = 0;
107
424
fail:
108
424
        cbor_vector_free(param_cbor, nitems(param_cbor));
109
110
424
        return (ok);
111
391
}
112
113
static int
114
credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
115
    const char *rp_id, fido_opt_t uv, int *ms)
116
2.40k
{
117
2.40k
        fido_blob_t      f;
118
2.40k
        fido_blob_t     *ecdh = NULL;
119
2.40k
        fido_blob_t      hmac;
120
2.40k
        es256_pk_t      *pk = NULL;
121
2.40k
        cbor_item_t     *argv[4];
122
2.40k
        const uint8_t    cmd = CTAP_CBOR_CRED_MGMT_PRE;
123
2.40k
        int              r = FIDO_ERR_INTERNAL;
124
125
2.40k
        memset(&f, 0, sizeof(f));
126
2.40k
        memset(&hmac, 0, sizeof(hmac));
127
2.40k
        memset(&argv, 0, sizeof(argv));
128
129
2.40k
        if (fido_dev_is_fido2(dev) == false) {
130
1.55k
                fido_log_debug("%s: fido_dev_is_fido2", __func__);
131
1.55k
                r = FIDO_ERR_INVALID_COMMAND;
132
1.55k
                goto fail;
133
1.55k
        }
134
135
        /* subCommand */
136
848
        if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
137
3
                fido_log_debug("%s: cbor encode", __func__);
138
3
                goto fail;
139
3
        }
140
141
        /* pinProtocol, pinAuth */
142
845
        if (pin != NULL || uv == FIDO_OPT_TRUE) {
143
620
                if (credman_prepare_hmac(subcmd, param, &argv[1], &hmac) < 0) {
144
33
                        fido_log_debug("%s: credman_prepare_hmac", __func__);
145
33
                        goto fail;
146
33
                }
147
587
                if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
148
269
                        fido_log_debug("%s: fido_do_ecdh", __func__);
149
269
                        goto fail;
150
269
                }
151
318
                if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
152
318
                    rp_id, &argv[3], &argv[2], ms)) != FIDO_OK) {
153
142
                        fido_log_debug("%s: cbor_add_uv_params", __func__);
154
142
                        goto fail;
155
142
                }
156
318
        }
157
158
        /* framing and transmission */
159
401
        if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
160
401
            fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
161
17
                fido_log_debug("%s: fido_tx", __func__);
162
17
                r = FIDO_ERR_TX;
163
17
                goto fail;
164
17
        }
165
166
384
        r = FIDO_OK;
167
2.40k
fail:
168
2.40k
        es256_pk_free(&pk);
169
2.40k
        fido_blob_free(&ecdh);
170
2.40k
        cbor_vector_free(argv, nitems(argv));
171
2.40k
        free(f.ptr);
172
2.40k
        free(hmac.ptr);
173
174
2.40k
        return (r);
175
384
}
176
177
static int
178
credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val,
179
    void *arg)
180
26
{
181
26
        fido_credman_metadata_t *metadata = arg;
182
183
26
        if (cbor_isa_uint(key) == false ||
184
26
            cbor_int_get_width(key) != CBOR_INT_8) {
185
11
                fido_log_debug("%s: cbor type", __func__);
186
11
                return (0); /* ignore */
187
11
        }
188
189
15
        switch (cbor_get_uint8(key)) {
190
1
        case 1:
191
1
                return (cbor_decode_uint64(val, &metadata->rk_existing));
192
1
        case 2:
193
1
                return (cbor_decode_uint64(val, &metadata->rk_remaining));
194
13
        default:
195
13
                fido_log_debug("%s: cbor type", __func__);
196
13
                return (0); /* ignore */
197
15
        }
198
15
}
199
200
static int
201
credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int *ms)
202
19
{
203
19
        unsigned char   *msg;
204
19
        int              msglen;
205
19
        int              r;
206
207
19
        memset(metadata, 0, sizeof(*metadata));
208
209
19
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
210
1
                r = FIDO_ERR_INTERNAL;
211
1
                goto out;
212
1
        }
213
214
18
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
215
1
                fido_log_debug("%s: fido_rx", __func__);
216
1
                r = FIDO_ERR_RX;
217
1
                goto out;
218
1
        }
219
220
17
        if ((r = cbor_parse_reply(msg, (size_t)msglen, metadata,
221
17
            credman_parse_metadata)) != FIDO_OK) {
222
14
                fido_log_debug("%s: credman_parse_metadata", __func__);
223
14
                goto out;
224
14
        }
225
226
3
        r = FIDO_OK;
227
19
out:
228
19
        freezero(msg, FIDO_MAXMSG);
229
230
19
        return (r);
231
3
}
232
233
static int
234
credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
235
    const char *pin, int *ms)
236
267
{
237
267
        int r;
238
239
267
        if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL,
240
267
            FIDO_OPT_TRUE, ms)) != FIDO_OK ||
241
267
            (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
242
264
                return (r);
243
244
3
        return (FIDO_OK);
245
267
}
246
247
int
248
fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
249
    const char *pin)
250
267
{
251
267
        int ms = dev->timeout_ms;
252
253
267
        return (credman_get_metadata_wait(dev, metadata, pin, &ms));
254
267
}
255
256
static int
257
credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
258
455
{
259
455
        fido_cred_t     *cred = arg;
260
455
        uint64_t         prot;
261
262
455
        if (cbor_isa_uint(key) == false ||
263
455
            cbor_int_get_width(key) != CBOR_INT_8) {
264
17
                fido_log_debug("%s: cbor type", __func__);
265
17
                return (0); /* ignore */
266
17
        }
267
268
438
        switch (cbor_get_uint8(key)) {
269
102
        case 6:
270
102
                return (cbor_decode_user(val, &cred->user));
271
96
        case 7:
272
96
                return (cbor_decode_cred_id(val, &cred->attcred.id));
273
95
        case 8:
274
95
                if (cbor_decode_pubkey(val, &cred->attcred.type,
275
95
                    &cred->attcred.pubkey) < 0)
276
19
                        return (-1);
277
76
                cred->type = cred->attcred.type; /* XXX */
278
76
                return (0);
279
72
        case 10:
280
72
                if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
281
72
                    fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
282
4
                        return (-1);
283
68
                return (0);
284
1
        case 11:
285
1
                return (fido_blob_decode(val, &cred->largeblob_key));
286
72
        default:
287
72
                fido_log_debug("%s: cbor type", __func__);
288
72
                return (0); /* ignore */
289
438
        }
290
438
}
291
292
static void
293
credman_reset_rk(fido_credman_rk_t *rk)
294
325
{
295
899
        for (size_t i = 0; i < rk->n_alloc; i++) {
296
574
                fido_cred_reset_tx(&rk->ptr[i]);
297
574
                fido_cred_reset_rx(&rk->ptr[i]);
298
574
        }
299
300
325
        free(rk->ptr);
301
325
        rk->ptr = NULL;
302
325
        memset(rk, 0, sizeof(*rk));
303
325
}
304
305
static int
306
credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
307
    void *arg)
308
315
{
309
315
        fido_credman_rk_t *rk = arg;
310
315
        uint64_t n;
311
312
        /* totalCredentials */
313
315
        if (cbor_isa_uint(key) == false ||
314
315
            cbor_int_get_width(key) != CBOR_INT_8 ||
315
315
            cbor_get_uint8(key) != 9) {
316
254
                fido_log_debug("%s: cbor_type", __func__);
317
254
                return (0); /* ignore */
318
254
        }
319
320
61
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
321
1
                fido_log_debug("%s: cbor_decode_uint64", __func__);
322
1
                return (-1);
323
1
        }
324
325
60
        if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx,
326
60
            (size_t)n, sizeof(*rk->ptr)) < 0) {
327
2
                fido_log_debug("%s: credman_grow_array", __func__);
328
2
                return (-1);
329
2
        }
330
331
58
        return (0);
332
60
}
333
334
static int
335
credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
336
82
{
337
82
        unsigned char   *msg;
338
82
        int              msglen;
339
82
        int              r;
340
341
82
        credman_reset_rk(rk);
342
343
82
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
344
1
                r = FIDO_ERR_INTERNAL;
345
1
                goto out;
346
1
        }
347
348
81
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
349
15
                fido_log_debug("%s: fido_rx", __func__);
350
15
                r = FIDO_ERR_RX;
351
15
                goto out;
352
15
        }
353
354
        /* adjust as needed */
355
66
        if ((r = cbor_parse_reply(msg, (size_t)msglen, rk,
356
66
            credman_parse_rk_count)) != FIDO_OK) {
357
8
                fido_log_debug("%s: credman_parse_rk_count", __func__);
358
8
                goto out;
359
8
        }
360
361
58
        if (rk->n_alloc == 0) {
362
1
                fido_log_debug("%s: n_alloc=0", __func__);
363
1
                r = FIDO_OK;
364
1
                goto out;
365
1
        }
366
367
        /* parse the first rk */
368
57
        if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[0],
369
57
            credman_parse_rk)) != FIDO_OK) {
370
13
                fido_log_debug("%s: credman_parse_rk", __func__);
371
13
                goto out;
372
13
        }
373
44
        rk->n_rx = 1;
374
375
44
        r = FIDO_OK;
376
82
out:
377
82
        freezero(msg, FIDO_MAXMSG);
378
379
82
        return (r);
380
44
}
381
382
static int
383
credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
384
70
{
385
70
        unsigned char   *msg;
386
70
        int              msglen;
387
70
        int              r;
388
389
70
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
390
1
                r = FIDO_ERR_INTERNAL;
391
1
                goto out;
392
1
        }
393
394
69
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
395
4
                fido_log_debug("%s: fido_rx", __func__);
396
4
                r = FIDO_ERR_RX;
397
4
                goto out;
398
4
        }
399
400
        /* sanity check */
401
65
        if (rk->n_rx >= rk->n_alloc) {
402
0
                fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx,
403
0
                    rk->n_alloc);
404
0
                r = FIDO_ERR_INTERNAL;
405
0
                goto out;
406
0
        }
407
408
65
        if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[rk->n_rx],
409
65
            credman_parse_rk)) != FIDO_OK) {
410
32
                fido_log_debug("%s: credman_parse_rk", __func__);
411
32
                goto out;
412
32
        }
413
414
33
        r = FIDO_OK;
415
70
out:
416
70
        freezero(msg, FIDO_MAXMSG);
417
418
70
        return (r);
419
33
}
420
421
static int
422
credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
423
    const char *pin, int *ms)
424
243
{
425
243
        fido_blob_t     rp_dgst;
426
243
        uint8_t         dgst[SHA256_DIGEST_LENGTH];
427
243
        int             r;
428
429
243
        if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) {
430
2
                fido_log_debug("%s: sha256", __func__);
431
2
                return (FIDO_ERR_INTERNAL);
432
2
        }
433
434
241
        rp_dgst.ptr = dgst;
435
241
        rp_dgst.len = sizeof(dgst);
436
437
241
        if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
438
241
            FIDO_OPT_TRUE, ms)) != FIDO_OK ||
439
241
            (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
440
196
                return (r);
441
442
78
        while (rk->n_rx < rk->n_alloc) {
443
74
                if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
444
74
                    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
445
74
                    (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
446
41
                        return (r);
447
33
                rk->n_rx++;
448
33
        }
449
450
4
        return (FIDO_OK);
451
45
}
452
453
int
454
fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
455
    fido_credman_rk_t *rk, const char *pin)
456
243
{
457
243
        int ms = dev->timeout_ms;
458
459
243
        return (credman_get_rk_wait(dev, rp_id, rk, pin, &ms));
460
243
}
461
462
static int
463
credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
464
    size_t cred_id_len, const char *pin, int *ms)
465
715
{
466
715
        fido_blob_t cred;
467
715
        int r;
468
469
715
        memset(&cred, 0, sizeof(cred));
470
471
715
        if (fido_blob_set(&cred, cred_id, cred_id_len) < 0)
472
5
                return (FIDO_ERR_INVALID_ARGUMENT);
473
474
710
        if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
475
710
            FIDO_OPT_TRUE, ms)) != FIDO_OK ||
476
710
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
477
709
                goto fail;
478
479
1
        r = FIDO_OK;
480
710
fail:
481
710
        free(cred.ptr);
482
483
710
        return (r);
484
1
}
485
486
int
487
fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
488
    size_t cred_id_len, const char *pin)
489
715
{
490
715
        int ms = dev->timeout_ms;
491
492
715
        return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, &ms));
493
715
}
494
495
static int
496
credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg)
497
342
{
498
342
        struct fido_credman_single_rp *rp = arg;
499
500
342
        if (cbor_isa_uint(key) == false ||
501
342
            cbor_int_get_width(key) != CBOR_INT_8) {
502
59
                fido_log_debug("%s: cbor type", __func__);
503
59
                return (0); /* ignore */
504
59
        }
505
506
283
        switch (cbor_get_uint8(key)) {
507
123
        case 3:
508
123
                return (cbor_decode_rp_entity(val, &rp->rp_entity));
509
89
        case 4:
510
89
                return (fido_blob_decode(val, &rp->rp_id_hash));
511
71
        default:
512
71
                fido_log_debug("%s: cbor type", __func__);
513
71
                return (0); /* ignore */
514
283
        }
515
283
}
516
517
static void
518
credman_reset_rp(fido_credman_rp_t *rp)
519
245
{
520
2.56k
        for (size_t i = 0; i < rp->n_alloc; i++) {
521
2.32k
                free(rp->ptr[i].rp_entity.id);
522
2.32k
                free(rp->ptr[i].rp_entity.name);
523
2.32k
                rp->ptr[i].rp_entity.id = NULL;
524
2.32k
                rp->ptr[i].rp_entity.name = NULL;
525
2.32k
                fido_blob_reset(&rp->ptr[i].rp_id_hash);
526
2.32k
        }
527
528
245
        free(rp->ptr);
529
245
        rp->ptr = NULL;
530
245
        memset(rp, 0, sizeof(*rp));
531
245
}
532
533
static int
534
credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
535
    void *arg)
536
136
{
537
136
        fido_credman_rp_t *rp = arg;
538
136
        uint64_t n;
539
540
        /* totalRPs */
541
136
        if (cbor_isa_uint(key) == false ||
542
136
            cbor_int_get_width(key) != CBOR_INT_8 ||
543
136
            cbor_get_uint8(key) != 5) {
544
98
                fido_log_debug("%s: cbor_type", __func__);
545
98
                return (0); /* ignore */
546
98
        }
547
548
38
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
549
1
                fido_log_debug("%s: cbor_decode_uint64", __func__);
550
1
                return (-1);
551
1
        }
552
553
37
        if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx,
554
37
            (size_t)n, sizeof(*rp->ptr)) < 0) {
555
3
                fido_log_debug("%s: credman_grow_array", __func__);
556
3
                return (-1);
557
3
        }
558
559
34
        return (0);
560
37
}
561
562
static int
563
credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
564
45
{
565
45
        unsigned char   *msg;
566
45
        int              msglen;
567
45
        int              r;
568
569
45
        credman_reset_rp(rp);
570
571
45
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
572
1
                r = FIDO_ERR_INTERNAL;
573
1
                goto out;
574
1
        }
575
576
44
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
577
1
                fido_log_debug("%s: fido_rx", __func__);
578
1
                r = FIDO_ERR_RX;
579
1
                goto out;
580
1
        }
581
582
        /* adjust as needed */
583
43
        if ((r = cbor_parse_reply(msg, (size_t)msglen, rp,
584
43
            credman_parse_rp_count)) != FIDO_OK) {
585
7
                fido_log_debug("%s: credman_parse_rp_count", __func__);
586
7
                goto out;
587
7
        }
588
589
36
        if (rp->n_alloc == 0) {
590
2
                fido_log_debug("%s: n_alloc=0", __func__);
591
2
                r = FIDO_OK;
592
2
                goto out;
593
2
        }
594
595
        /* parse the first rp */
596
34
        if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[0],
597
34
            credman_parse_rp)) != FIDO_OK) {
598
3
                fido_log_debug("%s: credman_parse_rp", __func__);
599
3
                goto out;
600
3
        }
601
31
        rp->n_rx = 1;
602
603
31
        r = FIDO_OK;
604
45
out:
605
45
        freezero(msg, FIDO_MAXMSG);
606
607
45
        return (r);
608
31
}
609
610
static int
611
credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
612
150
{
613
150
        unsigned char   *msg;
614
150
        int              msglen;
615
150
        int              r;
616
617
150
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
618
1
                r = FIDO_ERR_INTERNAL;
619
1
                goto out;
620
1
        }
621
622
149
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
623
16
                fido_log_debug("%s: fido_rx", __func__);
624
16
                r = FIDO_ERR_RX;
625
16
                goto out;
626
16
        }
627
628
        /* sanity check */
629
133
        if (rp->n_rx >= rp->n_alloc) {
630
0
                fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx,
631
0
                    rp->n_alloc);
632
0
                r = FIDO_ERR_INTERNAL;
633
0
                goto out;
634
0
        }
635
636
133
        if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[rp->n_rx],
637
133
            credman_parse_rp)) != FIDO_OK) {
638
8
                fido_log_debug("%s: credman_parse_rp", __func__);
639
8
                goto out;
640
8
        }
641
642
125
        r = FIDO_OK;
643
150
out:
644
150
        freezero(msg, FIDO_MAXMSG);
645
646
150
        return (r);
647
125
}
648
649
static int
650
credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
651
    int *ms)
652
200
{
653
200
        int r;
654
655
200
        if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
656
200
            FIDO_OPT_TRUE, ms)) != FIDO_OK ||
657
200
            (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
658
167
                return (r);
659
660
158
        while (rp->n_rx < rp->n_alloc) {
661
153
                if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
662
153
                    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
663
153
                    (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
664
28
                        return (r);
665
125
                rp->n_rx++;
666
125
        }
667
668
5
        return (FIDO_OK);
669
33
}
670
671
int
672
fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
673
200
{
674
200
        int ms = dev->timeout_ms;
675
676
200
        return (credman_get_rp_wait(dev, rp, pin, &ms));
677
200
}
678
679
static int
680
credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
681
    int *ms)
682
759
{
683
759
        int r;
684
685
759
        if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL,
686
759
            FIDO_OPT_TRUE, ms)) != FIDO_OK ||
687
759
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
688
758
                return (r);
689
690
1
        return (FIDO_OK);
691
759
}
692
693
int
694
fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
695
759
{
696
759
        int ms = dev->timeout_ms;
697
698
759
        return (credman_set_dev_rk_wait(dev, cred, pin, &ms));
699
759
}
700
701
fido_credman_rk_t *
702
fido_credman_rk_new(void)
703
245
{
704
245
        return (calloc(1, sizeof(fido_credman_rk_t)));
705
245
}
706
707
void
708
fido_credman_rk_free(fido_credman_rk_t **rk_p)
709
243
{
710
243
        fido_credman_rk_t *rk;
711
712
243
        if (rk_p == NULL || (rk = *rk_p) == NULL)
713
0
                return;
714
715
243
        credman_reset_rk(rk);
716
243
        free(rk);
717
243
        *rk_p = NULL;
718
243
}
719
720
size_t
721
fido_credman_rk_count(const fido_credman_rk_t *rk)
722
751
{
723
751
        return (rk->n_rx);
724
751
}
725
726
const fido_cred_t *
727
fido_credman_rk(const fido_credman_rk_t *rk, size_t idx)
728
320
{
729
320
        if (idx >= rk->n_alloc)
730
188
                return (NULL);
731
732
132
        return (&rk->ptr[idx]);
733
320
}
734
735
fido_credman_metadata_t *
736
fido_credman_metadata_new(void)
737
268
{
738
268
        return (calloc(1, sizeof(fido_credman_metadata_t)));
739
268
}
740
741
void
742
fido_credman_metadata_free(fido_credman_metadata_t **metadata_p)
743
267
{
744
267
        fido_credman_metadata_t *metadata;
745
746
267
        if (metadata_p == NULL || (metadata = *metadata_p) == NULL)
747
0
                return;
748
749
267
        free(metadata);
750
267
        *metadata_p = NULL;
751
267
}
752
753
uint64_t
754
fido_credman_rk_existing(const fido_credman_metadata_t *metadata)
755
267
{
756
267
        return (metadata->rk_existing);
757
267
}
758
759
uint64_t
760
fido_credman_rk_remaining(const fido_credman_metadata_t *metadata)
761
267
{
762
267
        return (metadata->rk_remaining);
763
267
}
764
765
fido_credman_rp_t *
766
fido_credman_rp_new(void)
767
201
{
768
201
        return (calloc(1, sizeof(fido_credman_rp_t)));
769
201
}
770
771
void
772
fido_credman_rp_free(fido_credman_rp_t **rp_p)
773
200
{
774
200
        fido_credman_rp_t *rp;
775
776
200
        if (rp_p == NULL || (rp = *rp_p) == NULL)
777
0
                return;
778
779
200
        credman_reset_rp(rp);
780
200
        free(rp);
781
200
        *rp_p = NULL;
782
200
}
783
784
size_t
785
fido_credman_rp_count(const fido_credman_rp_t *rp)
786
556
{
787
556
        return (rp->n_rx);
788
556
}
789
790
const char *
791
fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx)
792
356
{
793
356
        if (idx >= rp->n_alloc)
794
169
                return (NULL);
795
796
187
        return (rp->ptr[idx].rp_entity.id);
797
356
}
798
799
const char *
800
fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx)
801
356
{
802
356
        if (idx >= rp->n_alloc)
803
169
                return (NULL);
804
805
187
        return (rp->ptr[idx].rp_entity.name);
806
356
}
807
808
size_t
809
fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx)
810
356
{
811
356
        if (idx >= rp->n_alloc)
812
169
                return (0);
813
814
187
        return (rp->ptr[idx].rp_id_hash.len);
815
356
}
816
817
const unsigned char *
818
fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx)
819
356
{
820
356
        if (idx >= rp->n_alloc)
821
169
                return (NULL);
822
823
187
        return (rp->ptr[idx].rp_id_hash.ptr);
824
356
}