Coverage Report

Created: 2023-09-23 17:42

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