Coverage Report

Created: 2025-03-01 02:43

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