Coverage Report

Created: 2021-07-20 18:14

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