2 * Copyright (c) 2018-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.
7 #include <openssl/ecdsa.h>
8 #include <openssl/sha.h>
11 #include "fido/es256.h"
12 #include "fido/rs256.h"
13 #include "fido/eddsa.h"
16 adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
18 fido_assert_t *assert = arg;
21 /* numberOfCredentials; see section 6.2 */
22 if (cbor_isa_uint(key) == false ||
23 cbor_int_get_width(key) != CBOR_INT_8 ||
24 cbor_get_uint8(key) != 5) {
25 fido_log_debug("%s: cbor_type", __func__);
26 return (0); /* ignore */
29 if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
30 fido_log_debug("%s: cbor_decode_uint64", __func__);
34 if (assert->stmt_len != 0 || assert->stmt_cnt != 1 ||
35 (size_t)n < assert->stmt_cnt) {
36 fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu",
37 __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n);
41 if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) {
42 fido_log_debug("%s: fido_assert_set_count", __func__);
46 assert->stmt_len = 0; /* XXX */
52 parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
54 fido_assert_stmt *stmt = arg;
56 if (cbor_isa_uint(key) == false ||
57 cbor_int_get_width(key) != CBOR_INT_8) {
58 fido_log_debug("%s: cbor type", __func__);
59 return (0); /* ignore */
62 switch (cbor_get_uint8(key)) {
63 case 1: /* credential id */
64 return (cbor_decode_cred_id(val, &stmt->id));
65 case 2: /* authdata */
66 return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor,
67 &stmt->authdata, &stmt->authdata_ext));
68 case 3: /* signature */
69 return (fido_blob_decode(val, &stmt->sig));
70 case 4: /* user attributes */
71 return (cbor_decode_user(val, &stmt->user));
72 case 7: /* large blob key */
73 return (fido_blob_decode(val, &stmt->largeblob_key));
75 fido_log_debug("%s: cbor type", __func__);
81 fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
82 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin)
85 fido_opt_t uv = assert->uv;
87 const uint8_t cmd = CTAP_CBOR_ASSERT;
90 memset(argv, 0, sizeof(argv));
91 memset(&f, 0, sizeof(f));
93 /* do we have everything we need? */
94 if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
95 fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
96 (void *)assert->rp_id, (void *)assert->cdh.ptr);
97 r = FIDO_ERR_INVALID_ARGUMENT;
101 if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL ||
102 (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) {
103 fido_log_debug("%s: cbor encode", __func__);
104 r = FIDO_ERR_INTERNAL;
108 /* allowed credentials */
109 if (assert->allow_list.len) {
110 const fido_blob_array_t *cl = &assert->allow_list;
111 if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) {
112 fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
113 r = FIDO_ERR_INTERNAL;
118 if (assert->ext.mask)
119 if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh,
121 fido_log_debug("%s: cbor_encode_assert_ext", __func__);
122 r = FIDO_ERR_INTERNAL;
126 /* user verification */
127 if (pin != NULL || (uv == FIDO_OPT_TRUE &&
128 fido_dev_supports_permissions(dev))) {
129 if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
130 pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) {
131 fido_log_debug("%s: cbor_add_uv_params", __func__);
138 if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
139 if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) {
140 fido_log_debug("%s: cbor_encode_assert_opt", __func__);
141 r = FIDO_ERR_INTERNAL;
145 /* frame and transmit */
146 if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
147 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
148 fido_log_debug("%s: fido_tx", __func__);
155 cbor_vector_free(argv, nitems(argv));
162 fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
164 unsigned char reply[FIDO_MAXMSG];
168 fido_assert_reset_rx(assert);
170 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
172 fido_log_debug("%s: fido_rx", __func__);
173 return (FIDO_ERR_RX);
176 /* start with room for a single assertion */
177 if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL)
178 return (FIDO_ERR_INTERNAL);
180 assert->stmt_len = 0;
181 assert->stmt_cnt = 1;
183 /* adjust as needed */
184 if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert,
185 adjust_assert_count)) != FIDO_OK) {
186 fido_log_debug("%s: adjust_assert_count", __func__);
190 /* parse the first assertion */
191 if ((r = cbor_parse_reply(reply, (size_t)reply_len,
192 &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
193 fido_log_debug("%s: parse_assert_reply", __func__);
203 fido_get_next_assert_tx(fido_dev_t *dev)
205 const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT };
207 if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
208 fido_log_debug("%s: fido_tx", __func__);
209 return (FIDO_ERR_TX);
216 fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
218 unsigned char reply[FIDO_MAXMSG];
222 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
224 fido_log_debug("%s: fido_rx", __func__);
225 return (FIDO_ERR_RX);
229 if (assert->stmt_len >= assert->stmt_cnt) {
230 fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__,
231 assert->stmt_len, assert->stmt_cnt);
232 return (FIDO_ERR_INTERNAL);
235 if ((r = cbor_parse_reply(reply, (size_t)reply_len,
236 &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
237 fido_log_debug("%s: parse_assert_reply", __func__);
245 fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
246 const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms)
250 if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK ||
251 (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
254 while (assert->stmt_len < assert->stmt_cnt) {
255 if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK ||
256 (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
265 decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert,
266 const fido_blob_t *key)
268 for (size_t i = 0; i < assert->stmt_cnt; i++) {
269 fido_assert_stmt *stmt = &assert->stmt[i];
270 if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) {
271 if (aes256_cbc_dec(dev, key,
272 &stmt->authdata_ext.hmac_secret_enc,
273 &stmt->hmac_secret) < 0) {
274 fido_log_debug("%s: aes256_cbc_dec %zu",
285 fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
287 fido_blob_t *ecdh = NULL;
288 es256_pk_t *pk = NULL;
292 if (dev->flags & FIDO_DEV_WINHELLO)
293 return (fido_winhello_get_assert(dev, assert, pin));
296 if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
297 fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
298 (void *)assert->rp_id, (void *)assert->cdh.ptr);
299 return (FIDO_ERR_INVALID_ARGUMENT);
302 if (fido_dev_is_fido2(dev) == false) {
303 if (pin != NULL || assert->ext.mask != 0)
304 return (FIDO_ERR_UNSUPPORTED_OPTION);
305 return (u2f_authenticate(dev, assert, -1));
308 if (pin != NULL || (assert->uv == FIDO_OPT_TRUE &&
309 fido_dev_supports_permissions(dev)) ||
310 (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
311 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
312 fido_log_debug("%s: fido_do_ecdh", __func__);
317 r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
318 if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET))
319 if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) {
320 fido_log_debug("%s: decrypt_hmac_secrets", __func__);
321 r = FIDO_ERR_INTERNAL;
327 fido_blob_free(&ecdh);
333 fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv)
335 fido_log_debug("%s: flags=%02x", __func__, flags);
336 fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv);
338 if (up == FIDO_OPT_TRUE &&
339 (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) {
340 fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__);
341 return (-1); /* user not present */
344 if (uv == FIDO_OPT_TRUE &&
345 (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) {
346 fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__);
347 return (-1); /* user not verified */
354 check_extensions(int authdata_ext, int ext)
356 /* XXX: largeBlobKey is not part of extensions map */
357 ext &= ~FIDO_EXT_LARGEBLOB_KEY;
358 if (authdata_ext != ext) {
359 fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
368 fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
369 const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor)
371 cbor_item_t *item = NULL;
372 unsigned char *authdata_ptr = NULL;
374 struct cbor_load_result cbor;
378 if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
379 &cbor)) == NULL || cbor_isa_bytestring(item) == false ||
380 cbor_bytestring_is_definite(item) == false) {
381 fido_log_debug("%s: authdata", __func__);
385 authdata_ptr = cbor_bytestring_handle(item);
386 authdata_len = cbor_bytestring_length(item);
388 if (cose_alg != COSE_EDDSA) {
389 if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
390 SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
391 SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
392 SHA256_Final(dgst->ptr, &ctx) == 0) {
393 fido_log_debug("%s: sha256", __func__);
396 dgst->len = SHA256_DIGEST_LENGTH;
398 if (SIZE_MAX - authdata_len < clientdata->len ||
399 dgst->len < authdata_len + clientdata->len) {
400 fido_log_debug("%s: memcpy", __func__);
403 memcpy(dgst->ptr, authdata_ptr, authdata_len);
404 memcpy(dgst->ptr + authdata_len, clientdata->ptr,
406 dgst->len = authdata_len + clientdata->len;
418 fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
419 const fido_blob_t *sig)
421 EVP_PKEY *pkey = NULL;
425 /* ECDSA_verify needs ints */
426 if (dgst->len > INT_MAX || sig->len > INT_MAX) {
427 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
428 dgst->len, sig->len);
432 if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
433 (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
434 fido_log_debug("%s: pk -> ec", __func__);
438 if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
439 (int)sig->len, ec) != 1) {
440 fido_log_debug("%s: ECDSA_verify", __func__);
453 fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
454 const fido_blob_t *sig)
456 EVP_PKEY *pkey = NULL;
460 /* RSA_verify needs unsigned ints */
461 if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
462 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
463 dgst->len, sig->len);
467 if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
468 (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
469 fido_log_debug("%s: pk -> ec", __func__);
473 if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
474 (unsigned int)sig->len, rsa) != 1) {
475 fido_log_debug("%s: RSA_verify", __func__);
488 fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
489 const fido_blob_t *sig)
491 EVP_PKEY *pkey = NULL;
492 EVP_MD_CTX *mdctx = NULL;
495 /* EVP_DigestVerify needs ints */
496 if (dgst->len > INT_MAX || sig->len > INT_MAX) {
497 fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
498 dgst->len, sig->len);
502 if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
503 fido_log_debug("%s: pk -> pkey", __func__);
507 if ((mdctx = EVP_MD_CTX_new()) == NULL) {
508 fido_log_debug("%s: EVP_MD_CTX_new", __func__);
512 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
513 fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
517 if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
519 fido_log_debug("%s: EVP_DigestVerify", __func__);
526 EVP_MD_CTX_free(mdctx);
535 fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
538 unsigned char buf[1024]; /* XXX */
540 const fido_assert_stmt *stmt = NULL;
545 dgst.len = sizeof(buf);
547 if (idx >= assert->stmt_len || pk == NULL) {
548 r = FIDO_ERR_INVALID_ARGUMENT;
552 stmt = &assert->stmt[idx];
554 /* do we have everything we need? */
555 if (assert->cdh.ptr == NULL || assert->rp_id == NULL ||
556 stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) {
557 fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p",
558 __func__, (void *)assert->cdh.ptr, assert->rp_id,
559 (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr);
560 r = FIDO_ERR_INVALID_ARGUMENT;
564 if (fido_check_flags(stmt->authdata.flags, assert->up,
566 fido_log_debug("%s: fido_check_flags", __func__);
567 r = FIDO_ERR_INVALID_PARAM;
571 if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) {
572 fido_log_debug("%s: check_extensions", __func__);
573 r = FIDO_ERR_INVALID_PARAM;
577 if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) {
578 fido_log_debug("%s: fido_check_rp_id", __func__);
579 r = FIDO_ERR_INVALID_PARAM;
583 if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh,
584 &stmt->authdata_cbor) < 0) {
585 fido_log_debug("%s: fido_get_signed_hash", __func__);
586 r = FIDO_ERR_INTERNAL;
592 ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig);
595 ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig);
598 ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig);
601 fido_log_debug("%s: unsupported cose_alg %d", __func__,
603 r = FIDO_ERR_UNSUPPORTED_OPTION;
608 r = FIDO_ERR_INVALID_SIG;
612 explicit_bzero(buf, sizeof(buf));
618 fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data,
621 if (!fido_blob_is_empty(&assert->cdh) ||
622 fido_blob_set(&assert->cd, data, data_len) < 0) {
623 return (FIDO_ERR_INVALID_ARGUMENT);
625 if (fido_sha256(&assert->cdh, data, data_len) < 0) {
626 fido_blob_reset(&assert->cd);
627 return (FIDO_ERR_INTERNAL);
634 fido_assert_set_clientdata_hash(fido_assert_t *assert,
635 const unsigned char *hash, size_t hash_len)
637 if (!fido_blob_is_empty(&assert->cd) ||
638 fido_blob_set(&assert->cdh, hash, hash_len) < 0)
639 return (FIDO_ERR_INVALID_ARGUMENT);
645 fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt,
648 if ((salt_len != 32 && salt_len != 64) ||
649 fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0)
650 return (FIDO_ERR_INVALID_ARGUMENT);
656 fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx,
657 const unsigned char *secret, size_t secret_len)
659 if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) ||
660 fido_blob_set(&assert->stmt[idx].hmac_secret, secret,
662 return (FIDO_ERR_INVALID_ARGUMENT);
668 fido_assert_set_rp(fido_assert_t *assert, const char *id)
670 if (assert->rp_id != NULL) {
672 assert->rp_id = NULL;
676 return (FIDO_ERR_INVALID_ARGUMENT);
678 if ((assert->rp_id = strdup(id)) == NULL)
679 return (FIDO_ERR_INTERNAL);
685 fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr,
689 fido_blob_t *list_ptr;
692 memset(&id, 0, sizeof(id));
694 if (assert->allow_list.len == SIZE_MAX) {
695 r = FIDO_ERR_INVALID_ARGUMENT;
699 if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr =
700 recallocarray(assert->allow_list.ptr, assert->allow_list.len,
701 assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) {
702 r = FIDO_ERR_INVALID_ARGUMENT;
706 list_ptr[assert->allow_list.len++] = id;
707 assert->allow_list.ptr = list_ptr;
718 fido_assert_set_extensions(fido_assert_t *assert, int ext)
721 assert->ext.mask = 0;
723 if ((ext & FIDO_EXT_ASSERT_MASK) != ext)
724 return (FIDO_ERR_INVALID_ARGUMENT);
725 assert->ext.mask |= ext;
732 fido_assert_set_options(fido_assert_t *assert, bool up, bool uv)
734 assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
735 assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
741 fido_assert_set_up(fido_assert_t *assert, fido_opt_t up)
749 fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv)
756 const unsigned char *
757 fido_assert_clientdata_hash_ptr(const fido_assert_t *assert)
759 return (assert->cdh.ptr);
763 fido_assert_clientdata_hash_len(const fido_assert_t *assert)
765 return (assert->cdh.len);
769 fido_assert_new(void)
771 return (calloc(1, sizeof(fido_assert_t)));
775 fido_assert_reset_tx(fido_assert_t *assert)
778 fido_blob_reset(&assert->cd);
779 fido_blob_reset(&assert->cdh);
780 fido_blob_reset(&assert->ext.hmac_salt);
781 fido_free_blob_array(&assert->allow_list);
782 memset(&assert->ext, 0, sizeof(assert->ext));
783 memset(&assert->allow_list, 0, sizeof(assert->allow_list));
784 assert->rp_id = NULL;
785 assert->up = FIDO_OPT_OMIT;
786 assert->uv = FIDO_OPT_OMIT;
789 static void fido_assert_reset_extattr(fido_assert_extattr_t *ext)
791 fido_blob_reset(&ext->hmac_secret_enc);
792 fido_blob_reset(&ext->blob);
793 memset(ext, 0, sizeof(*ext));
797 fido_assert_reset_rx(fido_assert_t *assert)
799 for (size_t i = 0; i < assert->stmt_cnt; i++) {
800 free(assert->stmt[i].user.icon);
801 free(assert->stmt[i].user.name);
802 free(assert->stmt[i].user.display_name);
803 fido_blob_reset(&assert->stmt[i].user.id);
804 fido_blob_reset(&assert->stmt[i].id);
805 fido_blob_reset(&assert->stmt[i].hmac_secret);
806 fido_blob_reset(&assert->stmt[i].authdata_cbor);
807 fido_blob_reset(&assert->stmt[i].largeblob_key);
808 fido_blob_reset(&assert->stmt[i].sig);
809 fido_assert_reset_extattr(&assert->stmt[i].authdata_ext);
810 memset(&assert->stmt[i], 0, sizeof(assert->stmt[i]));
814 assert->stmt_len = 0;
815 assert->stmt_cnt = 0;
819 fido_assert_free(fido_assert_t **assert_p)
821 fido_assert_t *assert;
823 if (assert_p == NULL || (assert = *assert_p) == NULL)
825 fido_assert_reset_tx(assert);
826 fido_assert_reset_rx(assert);
832 fido_assert_count(const fido_assert_t *assert)
834 return (assert->stmt_len);
838 fido_assert_rp_id(const fido_assert_t *assert)
840 return (assert->rp_id);
844 fido_assert_flags(const fido_assert_t *assert, size_t idx)
846 if (idx >= assert->stmt_len)
849 return (assert->stmt[idx].authdata.flags);
853 fido_assert_sigcount(const fido_assert_t *assert, size_t idx)
855 if (idx >= assert->stmt_len)
858 return (assert->stmt[idx].authdata.sigcount);
861 const unsigned char *
862 fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx)
864 if (idx >= assert->stmt_len)
867 return (assert->stmt[idx].authdata_cbor.ptr);
871 fido_assert_authdata_len(const fido_assert_t *assert, size_t idx)
873 if (idx >= assert->stmt_len)
876 return (assert->stmt[idx].authdata_cbor.len);
879 const unsigned char *
880 fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx)
882 if (idx >= assert->stmt_len)
885 return (assert->stmt[idx].sig.ptr);
889 fido_assert_sig_len(const fido_assert_t *assert, size_t idx)
891 if (idx >= assert->stmt_len)
894 return (assert->stmt[idx].sig.len);
897 const unsigned char *
898 fido_assert_id_ptr(const fido_assert_t *assert, size_t idx)
900 if (idx >= assert->stmt_len)
903 return (assert->stmt[idx].id.ptr);
907 fido_assert_id_len(const fido_assert_t *assert, size_t idx)
909 if (idx >= assert->stmt_len)
912 return (assert->stmt[idx].id.len);
915 const unsigned char *
916 fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx)
918 if (idx >= assert->stmt_len)
921 return (assert->stmt[idx].user.id.ptr);
925 fido_assert_user_id_len(const fido_assert_t *assert, size_t idx)
927 if (idx >= assert->stmt_len)
930 return (assert->stmt[idx].user.id.len);
934 fido_assert_user_icon(const fido_assert_t *assert, size_t idx)
936 if (idx >= assert->stmt_len)
939 return (assert->stmt[idx].user.icon);
943 fido_assert_user_name(const fido_assert_t *assert, size_t idx)
945 if (idx >= assert->stmt_len)
948 return (assert->stmt[idx].user.name);
952 fido_assert_user_display_name(const fido_assert_t *assert, size_t idx)
954 if (idx >= assert->stmt_len)
957 return (assert->stmt[idx].user.display_name);
960 const unsigned char *
961 fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx)
963 if (idx >= assert->stmt_len)
966 return (assert->stmt[idx].hmac_secret.ptr);
970 fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx)
972 if (idx >= assert->stmt_len)
975 return (assert->stmt[idx].hmac_secret.len);
978 const unsigned char *
979 fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx)
981 if (idx >= assert->stmt_len)
984 return (assert->stmt[idx].largeblob_key.ptr);
988 fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx)
990 if (idx >= assert->stmt_len)
993 return (assert->stmt[idx].largeblob_key.len);
996 const unsigned char *
997 fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx)
999 if (idx >= assert->stmt_len)
1002 return (assert->stmt[idx].authdata_ext.blob.ptr);
1006 fido_assert_blob_len(const fido_assert_t *assert, size_t idx)
1008 if (idx >= assert->stmt_len)
1011 return (assert->stmt[idx].authdata_ext.blob.len);
1015 fido_assert_clean_authdata(fido_assert_stmt *stmt)
1017 fido_blob_reset(&stmt->authdata_cbor);
1018 fido_assert_reset_extattr(&stmt->authdata_ext);
1019 memset(&stmt->authdata, 0, sizeof(stmt->authdata));
1023 fido_assert_set_authdata(fido_assert_t *assert, size_t idx,
1024 const unsigned char *ptr, size_t len)
1026 cbor_item_t *item = NULL;
1027 fido_assert_stmt *stmt = NULL;
1028 struct cbor_load_result cbor;
1031 if (idx >= assert->stmt_len || ptr == NULL || len == 0)
1032 return (FIDO_ERR_INVALID_ARGUMENT);
1034 stmt = &assert->stmt[idx];
1035 fido_assert_clean_authdata(stmt);
1037 if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
1038 fido_log_debug("%s: cbor_load", __func__);
1039 r = FIDO_ERR_INVALID_ARGUMENT;
1043 if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
1044 &stmt->authdata, &stmt->authdata_ext) < 0) {
1045 fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
1046 r = FIDO_ERR_INVALID_ARGUMENT;
1056 fido_assert_clean_authdata(stmt);
1062 fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx,
1063 const unsigned char *ptr, size_t len)
1065 cbor_item_t *item = NULL;
1066 fido_assert_stmt *stmt = NULL;
1069 if (idx >= assert->stmt_len || ptr == NULL || len == 0)
1070 return (FIDO_ERR_INVALID_ARGUMENT);
1072 stmt = &assert->stmt[idx];
1073 fido_assert_clean_authdata(stmt);
1075 if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
1076 fido_log_debug("%s: cbor_build_bytestring", __func__);
1077 r = FIDO_ERR_INTERNAL;
1081 if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
1082 &stmt->authdata, &stmt->authdata_ext) < 0) {
1083 fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
1084 r = FIDO_ERR_INVALID_ARGUMENT;
1094 fido_assert_clean_authdata(stmt);
1100 fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
1103 if (idx >= a->stmt_len || ptr == NULL || len == 0)
1104 return (FIDO_ERR_INVALID_ARGUMENT);
1105 if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0)
1106 return (FIDO_ERR_INTERNAL);
1111 /* XXX shrinking leaks memory; fortunately that shouldn't happen */
1113 fido_assert_set_count(fido_assert_t *assert, size_t n)
1118 if (n > UINT8_MAX) {
1119 fido_log_debug("%s: n > UINT8_MAX", __func__);
1120 return (FIDO_ERR_INTERNAL);
1124 new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n,
1125 sizeof(fido_assert_stmt));
1126 if (new_stmt == NULL)
1127 return (FIDO_ERR_INTERNAL);
1129 assert->stmt = new_stmt;
1130 assert->stmt_cnt = n;
1131 assert->stmt_len = n;