Coverage Report

Created: 2021-03-26 11:35

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