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