Coverage Report

Created: 2026-04-08 06:32

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