10afa8e06SEd Maste /* 2*2ccfa855SEd Maste * Copyright (c) 2018-2022 Yubico AB. All rights reserved. 30afa8e06SEd Maste * Use of this source code is governed by a BSD-style 40afa8e06SEd Maste * license that can be found in the LICENSE file. 5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause 60afa8e06SEd Maste */ 70afa8e06SEd Maste 80afa8e06SEd Maste #include <openssl/sha.h> 90afa8e06SEd Maste 100afa8e06SEd Maste #include "fido.h" 110afa8e06SEd Maste #include "fido/es256.h" 120afa8e06SEd Maste #include "fido/rs256.h" 130afa8e06SEd Maste #include "fido/eddsa.h" 140afa8e06SEd Maste 150afa8e06SEd Maste static int 160afa8e06SEd Maste adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) 170afa8e06SEd Maste { 180afa8e06SEd Maste fido_assert_t *assert = arg; 190afa8e06SEd Maste uint64_t n; 200afa8e06SEd Maste 210afa8e06SEd Maste /* numberOfCredentials; see section 6.2 */ 220afa8e06SEd Maste if (cbor_isa_uint(key) == false || 230afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8 || 240afa8e06SEd Maste cbor_get_uint8(key) != 5) { 250afa8e06SEd Maste fido_log_debug("%s: cbor_type", __func__); 260afa8e06SEd Maste return (0); /* ignore */ 270afa8e06SEd Maste } 280afa8e06SEd Maste 290afa8e06SEd Maste if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { 300afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__); 310afa8e06SEd Maste return (-1); 320afa8e06SEd Maste } 330afa8e06SEd Maste 340afa8e06SEd Maste if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || 350afa8e06SEd Maste (size_t)n < assert->stmt_cnt) { 360afa8e06SEd Maste fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", 370afa8e06SEd Maste __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); 380afa8e06SEd Maste return (-1); 390afa8e06SEd Maste } 400afa8e06SEd Maste 410afa8e06SEd Maste if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { 420afa8e06SEd Maste fido_log_debug("%s: fido_assert_set_count", __func__); 430afa8e06SEd Maste return (-1); 440afa8e06SEd Maste } 450afa8e06SEd Maste 460afa8e06SEd Maste assert->stmt_len = 0; /* XXX */ 470afa8e06SEd Maste 480afa8e06SEd Maste return (0); 490afa8e06SEd Maste } 500afa8e06SEd Maste 510afa8e06SEd Maste static int 520afa8e06SEd Maste parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) 530afa8e06SEd Maste { 540afa8e06SEd Maste fido_assert_stmt *stmt = arg; 550afa8e06SEd Maste 560afa8e06SEd Maste if (cbor_isa_uint(key) == false || 570afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8) { 580afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__); 590afa8e06SEd Maste return (0); /* ignore */ 600afa8e06SEd Maste } 610afa8e06SEd Maste 620afa8e06SEd Maste switch (cbor_get_uint8(key)) { 630afa8e06SEd Maste case 1: /* credential id */ 640afa8e06SEd Maste return (cbor_decode_cred_id(val, &stmt->id)); 650afa8e06SEd Maste case 2: /* authdata */ 660afa8e06SEd Maste return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, 670afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext)); 680afa8e06SEd Maste case 3: /* signature */ 690afa8e06SEd Maste return (fido_blob_decode(val, &stmt->sig)); 700afa8e06SEd Maste case 4: /* user attributes */ 710afa8e06SEd Maste return (cbor_decode_user(val, &stmt->user)); 720afa8e06SEd Maste case 7: /* large blob key */ 730afa8e06SEd Maste return (fido_blob_decode(val, &stmt->largeblob_key)); 740afa8e06SEd Maste default: /* ignore */ 750afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__); 760afa8e06SEd Maste return (0); 770afa8e06SEd Maste } 780afa8e06SEd Maste } 790afa8e06SEd Maste 800afa8e06SEd Maste static int 810afa8e06SEd Maste fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, 82f540a430SEd Maste const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) 830afa8e06SEd Maste { 840afa8e06SEd Maste fido_blob_t f; 850afa8e06SEd Maste fido_opt_t uv = assert->uv; 860afa8e06SEd Maste cbor_item_t *argv[7]; 870afa8e06SEd Maste const uint8_t cmd = CTAP_CBOR_ASSERT; 880afa8e06SEd Maste int r; 890afa8e06SEd Maste 900afa8e06SEd Maste memset(argv, 0, sizeof(argv)); 910afa8e06SEd Maste memset(&f, 0, sizeof(f)); 920afa8e06SEd Maste 930afa8e06SEd Maste /* do we have everything we need? */ 940afa8e06SEd Maste if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 950afa8e06SEd Maste fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 960afa8e06SEd Maste (void *)assert->rp_id, (void *)assert->cdh.ptr); 970afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 980afa8e06SEd Maste goto fail; 990afa8e06SEd Maste } 1000afa8e06SEd Maste 1010afa8e06SEd Maste if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || 1020afa8e06SEd Maste (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { 1030afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__); 1040afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1050afa8e06SEd Maste goto fail; 1060afa8e06SEd Maste } 1070afa8e06SEd Maste 1080afa8e06SEd Maste /* allowed credentials */ 1090afa8e06SEd Maste if (assert->allow_list.len) { 1100afa8e06SEd Maste const fido_blob_array_t *cl = &assert->allow_list; 1110afa8e06SEd Maste if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { 1120afa8e06SEd Maste fido_log_debug("%s: cbor_encode_pubkey_list", __func__); 1130afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1140afa8e06SEd Maste goto fail; 1150afa8e06SEd Maste } 1160afa8e06SEd Maste } 1170afa8e06SEd Maste 1180afa8e06SEd Maste if (assert->ext.mask) 1190afa8e06SEd Maste if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh, 1200afa8e06SEd Maste pk)) == NULL) { 1210afa8e06SEd Maste fido_log_debug("%s: cbor_encode_assert_ext", __func__); 1220afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1230afa8e06SEd Maste goto fail; 1240afa8e06SEd Maste } 1250afa8e06SEd Maste 1260afa8e06SEd Maste /* user verification */ 1270afa8e06SEd Maste if (pin != NULL || (uv == FIDO_OPT_TRUE && 1280afa8e06SEd Maste fido_dev_supports_permissions(dev))) { 1290afa8e06SEd Maste if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh, 130f540a430SEd Maste pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) { 1310afa8e06SEd Maste fido_log_debug("%s: cbor_add_uv_params", __func__); 1320afa8e06SEd Maste goto fail; 1330afa8e06SEd Maste } 1340afa8e06SEd Maste uv = FIDO_OPT_OMIT; 1350afa8e06SEd Maste } 1360afa8e06SEd Maste 1370afa8e06SEd Maste /* options */ 1380afa8e06SEd Maste if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT) 1390afa8e06SEd Maste if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) { 1400afa8e06SEd Maste fido_log_debug("%s: cbor_encode_assert_opt", __func__); 1410afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1420afa8e06SEd Maste goto fail; 1430afa8e06SEd Maste } 1440afa8e06SEd Maste 1450afa8e06SEd Maste /* frame and transmit */ 1460afa8e06SEd Maste if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || 147f540a430SEd Maste fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 1480afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__); 1490afa8e06SEd Maste r = FIDO_ERR_TX; 1500afa8e06SEd Maste goto fail; 1510afa8e06SEd Maste } 1520afa8e06SEd Maste 1530afa8e06SEd Maste r = FIDO_OK; 1540afa8e06SEd Maste fail: 1550afa8e06SEd Maste cbor_vector_free(argv, nitems(argv)); 1560afa8e06SEd Maste free(f.ptr); 1570afa8e06SEd Maste 1580afa8e06SEd Maste return (r); 1590afa8e06SEd Maste } 1600afa8e06SEd Maste 1610afa8e06SEd Maste static int 162f540a430SEd Maste fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) 1630afa8e06SEd Maste { 164*2ccfa855SEd Maste unsigned char *msg; 165*2ccfa855SEd Maste int msglen; 1660afa8e06SEd Maste int r; 1670afa8e06SEd Maste 1680afa8e06SEd Maste fido_assert_reset_rx(assert); 1690afa8e06SEd Maste 170*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) { 171*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL; 172*2ccfa855SEd Maste goto out; 173*2ccfa855SEd Maste } 174*2ccfa855SEd Maste 175*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { 1760afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 177*2ccfa855SEd Maste r = FIDO_ERR_RX; 178*2ccfa855SEd Maste goto out; 1790afa8e06SEd Maste } 1800afa8e06SEd Maste 1810afa8e06SEd Maste /* start with room for a single assertion */ 182*2ccfa855SEd Maste if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) { 183*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL; 184*2ccfa855SEd Maste goto out; 185*2ccfa855SEd Maste } 1860afa8e06SEd Maste assert->stmt_len = 0; 1870afa8e06SEd Maste assert->stmt_cnt = 1; 1880afa8e06SEd Maste 1890afa8e06SEd Maste /* adjust as needed */ 190*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, assert, 1910afa8e06SEd Maste adjust_assert_count)) != FIDO_OK) { 1920afa8e06SEd Maste fido_log_debug("%s: adjust_assert_count", __func__); 193*2ccfa855SEd Maste goto out; 1940afa8e06SEd Maste } 1950afa8e06SEd Maste 1960afa8e06SEd Maste /* parse the first assertion */ 197*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[0], 198*2ccfa855SEd Maste parse_assert_reply)) != FIDO_OK) { 1990afa8e06SEd Maste fido_log_debug("%s: parse_assert_reply", __func__); 200*2ccfa855SEd Maste goto out; 2010afa8e06SEd Maste } 202*2ccfa855SEd Maste assert->stmt_len = 1; 2030afa8e06SEd Maste 204*2ccfa855SEd Maste r = FIDO_OK; 205*2ccfa855SEd Maste out: 206*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG); 2070afa8e06SEd Maste 208*2ccfa855SEd Maste return (r); 2090afa8e06SEd Maste } 2100afa8e06SEd Maste 2110afa8e06SEd Maste static int 212f540a430SEd Maste fido_get_next_assert_tx(fido_dev_t *dev, int *ms) 2130afa8e06SEd Maste { 2140afa8e06SEd Maste const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; 2150afa8e06SEd Maste 216f540a430SEd Maste if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { 2170afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__); 2180afa8e06SEd Maste return (FIDO_ERR_TX); 2190afa8e06SEd Maste } 2200afa8e06SEd Maste 2210afa8e06SEd Maste return (FIDO_OK); 2220afa8e06SEd Maste } 2230afa8e06SEd Maste 2240afa8e06SEd Maste static int 225f540a430SEd Maste fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) 2260afa8e06SEd Maste { 227*2ccfa855SEd Maste unsigned char *msg; 228*2ccfa855SEd Maste int msglen; 2290afa8e06SEd Maste int r; 2300afa8e06SEd Maste 231*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) { 232*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL; 233*2ccfa855SEd Maste goto out; 234*2ccfa855SEd Maste } 235*2ccfa855SEd Maste 236*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { 2370afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 238*2ccfa855SEd Maste r = FIDO_ERR_RX; 239*2ccfa855SEd Maste goto out; 2400afa8e06SEd Maste } 2410afa8e06SEd Maste 2420afa8e06SEd Maste /* sanity check */ 2430afa8e06SEd Maste if (assert->stmt_len >= assert->stmt_cnt) { 2440afa8e06SEd Maste fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, 2450afa8e06SEd Maste assert->stmt_len, assert->stmt_cnt); 246*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL; 247*2ccfa855SEd Maste goto out; 2480afa8e06SEd Maste } 2490afa8e06SEd Maste 250*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, 2510afa8e06SEd Maste &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { 2520afa8e06SEd Maste fido_log_debug("%s: parse_assert_reply", __func__); 253*2ccfa855SEd Maste goto out; 2540afa8e06SEd Maste } 2550afa8e06SEd Maste 256*2ccfa855SEd Maste r = FIDO_OK; 257*2ccfa855SEd Maste out: 258*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG); 259*2ccfa855SEd Maste 260*2ccfa855SEd Maste return (r); 2610afa8e06SEd Maste } 2620afa8e06SEd Maste 2630afa8e06SEd Maste static int 2640afa8e06SEd Maste fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, 265f540a430SEd Maste const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) 2660afa8e06SEd Maste { 2670afa8e06SEd Maste int r; 2680afa8e06SEd Maste 269f540a430SEd Maste if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin, 270f540a430SEd Maste ms)) != FIDO_OK || 2710afa8e06SEd Maste (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) 2720afa8e06SEd Maste return (r); 2730afa8e06SEd Maste 2740afa8e06SEd Maste while (assert->stmt_len < assert->stmt_cnt) { 275f540a430SEd Maste if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK || 2760afa8e06SEd Maste (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) 2770afa8e06SEd Maste return (r); 2780afa8e06SEd Maste assert->stmt_len++; 2790afa8e06SEd Maste } 2800afa8e06SEd Maste 2810afa8e06SEd Maste return (FIDO_OK); 2820afa8e06SEd Maste } 2830afa8e06SEd Maste 2840afa8e06SEd Maste static int 2850afa8e06SEd Maste decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert, 2860afa8e06SEd Maste const fido_blob_t *key) 2870afa8e06SEd Maste { 2880afa8e06SEd Maste for (size_t i = 0; i < assert->stmt_cnt; i++) { 2890afa8e06SEd Maste fido_assert_stmt *stmt = &assert->stmt[i]; 2900afa8e06SEd Maste if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) { 2910afa8e06SEd Maste if (aes256_cbc_dec(dev, key, 2920afa8e06SEd Maste &stmt->authdata_ext.hmac_secret_enc, 2930afa8e06SEd Maste &stmt->hmac_secret) < 0) { 2940afa8e06SEd Maste fido_log_debug("%s: aes256_cbc_dec %zu", 2950afa8e06SEd Maste __func__, i); 2960afa8e06SEd Maste return (-1); 2970afa8e06SEd Maste } 2980afa8e06SEd Maste } 2990afa8e06SEd Maste } 3000afa8e06SEd Maste 3010afa8e06SEd Maste return (0); 3020afa8e06SEd Maste } 3030afa8e06SEd Maste 3040afa8e06SEd Maste int 3050afa8e06SEd Maste fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) 3060afa8e06SEd Maste { 3070afa8e06SEd Maste fido_blob_t *ecdh = NULL; 3080afa8e06SEd Maste es256_pk_t *pk = NULL; 309f540a430SEd Maste int ms = dev->timeout_ms; 3100afa8e06SEd Maste int r; 3110afa8e06SEd Maste 3120afa8e06SEd Maste #ifdef USE_WINHELLO 3130afa8e06SEd Maste if (dev->flags & FIDO_DEV_WINHELLO) 314f540a430SEd Maste return (fido_winhello_get_assert(dev, assert, pin, ms)); 3150afa8e06SEd Maste #endif 3160afa8e06SEd Maste 3170afa8e06SEd Maste if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 3180afa8e06SEd Maste fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 3190afa8e06SEd Maste (void *)assert->rp_id, (void *)assert->cdh.ptr); 3200afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 3210afa8e06SEd Maste } 3220afa8e06SEd Maste 3230afa8e06SEd Maste if (fido_dev_is_fido2(dev) == false) { 3240afa8e06SEd Maste if (pin != NULL || assert->ext.mask != 0) 3250afa8e06SEd Maste return (FIDO_ERR_UNSUPPORTED_OPTION); 326f540a430SEd Maste return (u2f_authenticate(dev, assert, &ms)); 3270afa8e06SEd Maste } 3280afa8e06SEd Maste 3290afa8e06SEd Maste if (pin != NULL || (assert->uv == FIDO_OPT_TRUE && 3300afa8e06SEd Maste fido_dev_supports_permissions(dev)) || 3310afa8e06SEd Maste (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) { 332f540a430SEd Maste if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) { 3330afa8e06SEd Maste fido_log_debug("%s: fido_do_ecdh", __func__); 3340afa8e06SEd Maste goto fail; 3350afa8e06SEd Maste } 3360afa8e06SEd Maste } 3370afa8e06SEd Maste 338f540a430SEd Maste r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms); 3390afa8e06SEd Maste if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) 3400afa8e06SEd Maste if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) { 3410afa8e06SEd Maste fido_log_debug("%s: decrypt_hmac_secrets", __func__); 3420afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 3430afa8e06SEd Maste goto fail; 3440afa8e06SEd Maste } 3450afa8e06SEd Maste 3460afa8e06SEd Maste fail: 3470afa8e06SEd Maste es256_pk_free(&pk); 3480afa8e06SEd Maste fido_blob_free(&ecdh); 3490afa8e06SEd Maste 3500afa8e06SEd Maste return (r); 3510afa8e06SEd Maste } 3520afa8e06SEd Maste 3530afa8e06SEd Maste int 3540afa8e06SEd Maste fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) 3550afa8e06SEd Maste { 3560afa8e06SEd Maste fido_log_debug("%s: flags=%02x", __func__, flags); 3570afa8e06SEd Maste fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); 3580afa8e06SEd Maste 3590afa8e06SEd Maste if (up == FIDO_OPT_TRUE && 3600afa8e06SEd Maste (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { 3610afa8e06SEd Maste fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); 3620afa8e06SEd Maste return (-1); /* user not present */ 3630afa8e06SEd Maste } 3640afa8e06SEd Maste 3650afa8e06SEd Maste if (uv == FIDO_OPT_TRUE && 3660afa8e06SEd Maste (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { 3670afa8e06SEd Maste fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); 3680afa8e06SEd Maste return (-1); /* user not verified */ 3690afa8e06SEd Maste } 3700afa8e06SEd Maste 3710afa8e06SEd Maste return (0); 3720afa8e06SEd Maste } 3730afa8e06SEd Maste 3740afa8e06SEd Maste static int 3750afa8e06SEd Maste check_extensions(int authdata_ext, int ext) 3760afa8e06SEd Maste { 3770afa8e06SEd Maste /* XXX: largeBlobKey is not part of extensions map */ 3780afa8e06SEd Maste ext &= ~FIDO_EXT_LARGEBLOB_KEY; 3790afa8e06SEd Maste if (authdata_ext != ext) { 3800afa8e06SEd Maste fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, 3810afa8e06SEd Maste authdata_ext, ext); 3820afa8e06SEd Maste return (-1); 3830afa8e06SEd Maste } 3840afa8e06SEd Maste 3850afa8e06SEd Maste return (0); 3860afa8e06SEd Maste } 3870afa8e06SEd Maste 388*2ccfa855SEd Maste static int 389*2ccfa855SEd Maste get_es256_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, 390*2ccfa855SEd Maste const fido_blob_t *authdata) 391*2ccfa855SEd Maste { 392*2ccfa855SEd Maste const EVP_MD *md; 393*2ccfa855SEd Maste EVP_MD_CTX *ctx = NULL; 394*2ccfa855SEd Maste 395*2ccfa855SEd Maste if (dgst->len < SHA256_DIGEST_LENGTH || 396*2ccfa855SEd Maste (md = EVP_sha256()) == NULL || 397*2ccfa855SEd Maste (ctx = EVP_MD_CTX_new()) == NULL || 398*2ccfa855SEd Maste EVP_DigestInit_ex(ctx, md, NULL) != 1 || 399*2ccfa855SEd Maste EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 || 400*2ccfa855SEd Maste EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || 401*2ccfa855SEd Maste EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { 402*2ccfa855SEd Maste EVP_MD_CTX_free(ctx); 403*2ccfa855SEd Maste return (-1); 404*2ccfa855SEd Maste } 405*2ccfa855SEd Maste dgst->len = SHA256_DIGEST_LENGTH; 406*2ccfa855SEd Maste 407*2ccfa855SEd Maste EVP_MD_CTX_free(ctx); 408*2ccfa855SEd Maste 409*2ccfa855SEd Maste return (0); 410*2ccfa855SEd Maste } 411*2ccfa855SEd Maste 412*2ccfa855SEd Maste static int 413*2ccfa855SEd Maste get_es384_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, 414*2ccfa855SEd Maste const fido_blob_t *authdata) 415*2ccfa855SEd Maste { 416*2ccfa855SEd Maste const EVP_MD *md; 417*2ccfa855SEd Maste EVP_MD_CTX *ctx = NULL; 418*2ccfa855SEd Maste 419*2ccfa855SEd Maste if (dgst->len < SHA384_DIGEST_LENGTH || 420*2ccfa855SEd Maste (md = EVP_sha384()) == NULL || 421*2ccfa855SEd Maste (ctx = EVP_MD_CTX_new()) == NULL || 422*2ccfa855SEd Maste EVP_DigestInit_ex(ctx, md, NULL) != 1 || 423*2ccfa855SEd Maste EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 || 424*2ccfa855SEd Maste EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || 425*2ccfa855SEd Maste EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { 426*2ccfa855SEd Maste EVP_MD_CTX_free(ctx); 427*2ccfa855SEd Maste return (-1); 428*2ccfa855SEd Maste } 429*2ccfa855SEd Maste dgst->len = SHA384_DIGEST_LENGTH; 430*2ccfa855SEd Maste 431*2ccfa855SEd Maste EVP_MD_CTX_free(ctx); 432*2ccfa855SEd Maste 433*2ccfa855SEd Maste return (0); 434*2ccfa855SEd Maste } 435*2ccfa855SEd Maste 436*2ccfa855SEd Maste static int 437*2ccfa855SEd Maste get_eddsa_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, 438*2ccfa855SEd Maste const fido_blob_t *authdata) 439*2ccfa855SEd Maste { 440*2ccfa855SEd Maste if (SIZE_MAX - authdata->len < clientdata->len || 441*2ccfa855SEd Maste dgst->len < authdata->len + clientdata->len) 442*2ccfa855SEd Maste return (-1); 443*2ccfa855SEd Maste 444*2ccfa855SEd Maste memcpy(dgst->ptr, authdata->ptr, authdata->len); 445*2ccfa855SEd Maste memcpy(dgst->ptr + authdata->len, clientdata->ptr, clientdata->len); 446*2ccfa855SEd Maste dgst->len = authdata->len + clientdata->len; 447*2ccfa855SEd Maste 448*2ccfa855SEd Maste return (0); 449*2ccfa855SEd Maste } 450*2ccfa855SEd Maste 4510afa8e06SEd Maste int 4520afa8e06SEd Maste fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, 4530afa8e06SEd Maste const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) 4540afa8e06SEd Maste { 4550afa8e06SEd Maste cbor_item_t *item = NULL; 456*2ccfa855SEd Maste fido_blob_t authdata; 4570afa8e06SEd Maste struct cbor_load_result cbor; 4580afa8e06SEd Maste int ok = -1; 4590afa8e06SEd Maste 460*2ccfa855SEd Maste fido_log_debug("%s: cose_alg=%d", __func__, cose_alg); 461*2ccfa855SEd Maste 4620afa8e06SEd Maste if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, 4630afa8e06SEd Maste &cbor)) == NULL || cbor_isa_bytestring(item) == false || 4640afa8e06SEd Maste cbor_bytestring_is_definite(item) == false) { 4650afa8e06SEd Maste fido_log_debug("%s: authdata", __func__); 4660afa8e06SEd Maste goto fail; 4670afa8e06SEd Maste } 468*2ccfa855SEd Maste authdata.ptr = cbor_bytestring_handle(item); 469*2ccfa855SEd Maste authdata.len = cbor_bytestring_length(item); 4700afa8e06SEd Maste 471*2ccfa855SEd Maste switch (cose_alg) { 472*2ccfa855SEd Maste case COSE_ES256: 473*2ccfa855SEd Maste case COSE_RS256: 474*2ccfa855SEd Maste ok = get_es256_hash(dgst, clientdata, &authdata); 475*2ccfa855SEd Maste break; 476*2ccfa855SEd Maste case COSE_ES384: 477*2ccfa855SEd Maste ok = get_es384_hash(dgst, clientdata, &authdata); 478*2ccfa855SEd Maste break; 479*2ccfa855SEd Maste case COSE_EDDSA: 480*2ccfa855SEd Maste ok = get_eddsa_hash(dgst, clientdata, &authdata); 481*2ccfa855SEd Maste break; 482*2ccfa855SEd Maste default: 483*2ccfa855SEd Maste fido_log_debug("%s: unknown cose_alg", __func__); 484*2ccfa855SEd Maste break; 4850afa8e06SEd Maste } 4860afa8e06SEd Maste fail: 4870afa8e06SEd Maste if (item != NULL) 4880afa8e06SEd Maste cbor_decref(&item); 4890afa8e06SEd Maste 4900afa8e06SEd Maste return (ok); 4910afa8e06SEd Maste } 4920afa8e06SEd Maste 4930afa8e06SEd Maste int 4940afa8e06SEd Maste fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, 4950afa8e06SEd Maste const void *pk) 4960afa8e06SEd Maste { 4970afa8e06SEd Maste unsigned char buf[1024]; /* XXX */ 4980afa8e06SEd Maste fido_blob_t dgst; 4990afa8e06SEd Maste const fido_assert_stmt *stmt = NULL; 5000afa8e06SEd Maste int ok = -1; 5010afa8e06SEd Maste int r; 5020afa8e06SEd Maste 5030afa8e06SEd Maste dgst.ptr = buf; 5040afa8e06SEd Maste dgst.len = sizeof(buf); 5050afa8e06SEd Maste 5060afa8e06SEd Maste if (idx >= assert->stmt_len || pk == NULL) { 5070afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 5080afa8e06SEd Maste goto out; 5090afa8e06SEd Maste } 5100afa8e06SEd Maste 5110afa8e06SEd Maste stmt = &assert->stmt[idx]; 5120afa8e06SEd Maste 5130afa8e06SEd Maste /* do we have everything we need? */ 5140afa8e06SEd Maste if (assert->cdh.ptr == NULL || assert->rp_id == NULL || 5150afa8e06SEd Maste stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { 5160afa8e06SEd Maste fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", 5170afa8e06SEd Maste __func__, (void *)assert->cdh.ptr, assert->rp_id, 5180afa8e06SEd Maste (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); 5190afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 5200afa8e06SEd Maste goto out; 5210afa8e06SEd Maste } 5220afa8e06SEd Maste 5230afa8e06SEd Maste if (fido_check_flags(stmt->authdata.flags, assert->up, 5240afa8e06SEd Maste assert->uv) < 0) { 5250afa8e06SEd Maste fido_log_debug("%s: fido_check_flags", __func__); 5260afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 5270afa8e06SEd Maste goto out; 5280afa8e06SEd Maste } 5290afa8e06SEd Maste 5300afa8e06SEd Maste if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) { 5310afa8e06SEd Maste fido_log_debug("%s: check_extensions", __func__); 5320afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 5330afa8e06SEd Maste goto out; 5340afa8e06SEd Maste } 5350afa8e06SEd Maste 5360afa8e06SEd Maste if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { 5370afa8e06SEd Maste fido_log_debug("%s: fido_check_rp_id", __func__); 5380afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 5390afa8e06SEd Maste goto out; 5400afa8e06SEd Maste } 5410afa8e06SEd Maste 5420afa8e06SEd Maste if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh, 5430afa8e06SEd Maste &stmt->authdata_cbor) < 0) { 5440afa8e06SEd Maste fido_log_debug("%s: fido_get_signed_hash", __func__); 5450afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 5460afa8e06SEd Maste goto out; 5470afa8e06SEd Maste } 5480afa8e06SEd Maste 5490afa8e06SEd Maste switch (cose_alg) { 5500afa8e06SEd Maste case COSE_ES256: 551f540a430SEd Maste ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig); 5520afa8e06SEd Maste break; 553*2ccfa855SEd Maste case COSE_ES384: 554*2ccfa855SEd Maste ok = es384_pk_verify_sig(&dgst, pk, &stmt->sig); 555*2ccfa855SEd Maste break; 5560afa8e06SEd Maste case COSE_RS256: 557f540a430SEd Maste ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig); 5580afa8e06SEd Maste break; 5590afa8e06SEd Maste case COSE_EDDSA: 560f540a430SEd Maste ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig); 5610afa8e06SEd Maste break; 5620afa8e06SEd Maste default: 5630afa8e06SEd Maste fido_log_debug("%s: unsupported cose_alg %d", __func__, 5640afa8e06SEd Maste cose_alg); 5650afa8e06SEd Maste r = FIDO_ERR_UNSUPPORTED_OPTION; 5660afa8e06SEd Maste goto out; 5670afa8e06SEd Maste } 5680afa8e06SEd Maste 5690afa8e06SEd Maste if (ok < 0) 5700afa8e06SEd Maste r = FIDO_ERR_INVALID_SIG; 5710afa8e06SEd Maste else 5720afa8e06SEd Maste r = FIDO_OK; 5730afa8e06SEd Maste out: 5740afa8e06SEd Maste explicit_bzero(buf, sizeof(buf)); 5750afa8e06SEd Maste 5760afa8e06SEd Maste return (r); 5770afa8e06SEd Maste } 5780afa8e06SEd Maste 5790afa8e06SEd Maste int 5800afa8e06SEd Maste fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data, 5810afa8e06SEd Maste size_t data_len) 5820afa8e06SEd Maste { 5830afa8e06SEd Maste if (!fido_blob_is_empty(&assert->cdh) || 5840afa8e06SEd Maste fido_blob_set(&assert->cd, data, data_len) < 0) { 5850afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5860afa8e06SEd Maste } 5870afa8e06SEd Maste if (fido_sha256(&assert->cdh, data, data_len) < 0) { 5880afa8e06SEd Maste fido_blob_reset(&assert->cd); 5890afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 5900afa8e06SEd Maste } 5910afa8e06SEd Maste 5920afa8e06SEd Maste return (FIDO_OK); 5930afa8e06SEd Maste } 5940afa8e06SEd Maste 5950afa8e06SEd Maste int 5960afa8e06SEd Maste fido_assert_set_clientdata_hash(fido_assert_t *assert, 5970afa8e06SEd Maste const unsigned char *hash, size_t hash_len) 5980afa8e06SEd Maste { 5990afa8e06SEd Maste if (!fido_blob_is_empty(&assert->cd) || 6000afa8e06SEd Maste fido_blob_set(&assert->cdh, hash, hash_len) < 0) 6010afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6020afa8e06SEd Maste 6030afa8e06SEd Maste return (FIDO_OK); 6040afa8e06SEd Maste } 6050afa8e06SEd Maste 6060afa8e06SEd Maste int 6070afa8e06SEd Maste fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, 6080afa8e06SEd Maste size_t salt_len) 6090afa8e06SEd Maste { 6100afa8e06SEd Maste if ((salt_len != 32 && salt_len != 64) || 6110afa8e06SEd Maste fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0) 6120afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6130afa8e06SEd Maste 6140afa8e06SEd Maste return (FIDO_OK); 6150afa8e06SEd Maste } 6160afa8e06SEd Maste 6170afa8e06SEd Maste int 6180afa8e06SEd Maste fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx, 6190afa8e06SEd Maste const unsigned char *secret, size_t secret_len) 6200afa8e06SEd Maste { 6210afa8e06SEd Maste if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) || 6220afa8e06SEd Maste fido_blob_set(&assert->stmt[idx].hmac_secret, secret, 6230afa8e06SEd Maste secret_len) < 0) 6240afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6250afa8e06SEd Maste 6260afa8e06SEd Maste return (FIDO_OK); 6270afa8e06SEd Maste } 6280afa8e06SEd Maste 6290afa8e06SEd Maste int 6300afa8e06SEd Maste fido_assert_set_rp(fido_assert_t *assert, const char *id) 6310afa8e06SEd Maste { 6320afa8e06SEd Maste if (assert->rp_id != NULL) { 6330afa8e06SEd Maste free(assert->rp_id); 6340afa8e06SEd Maste assert->rp_id = NULL; 6350afa8e06SEd Maste } 6360afa8e06SEd Maste 6370afa8e06SEd Maste if (id == NULL) 6380afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6390afa8e06SEd Maste 6400afa8e06SEd Maste if ((assert->rp_id = strdup(id)) == NULL) 6410afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 6420afa8e06SEd Maste 6430afa8e06SEd Maste return (FIDO_OK); 6440afa8e06SEd Maste } 6450afa8e06SEd Maste 6460afa8e06SEd Maste int 6470afa8e06SEd Maste fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, 6480afa8e06SEd Maste size_t len) 6490afa8e06SEd Maste { 6500afa8e06SEd Maste fido_blob_t id; 6510afa8e06SEd Maste fido_blob_t *list_ptr; 6520afa8e06SEd Maste int r; 6530afa8e06SEd Maste 6540afa8e06SEd Maste memset(&id, 0, sizeof(id)); 6550afa8e06SEd Maste 6560afa8e06SEd Maste if (assert->allow_list.len == SIZE_MAX) { 6570afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 6580afa8e06SEd Maste goto fail; 6590afa8e06SEd Maste } 6600afa8e06SEd Maste 6610afa8e06SEd Maste if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = 6620afa8e06SEd Maste recallocarray(assert->allow_list.ptr, assert->allow_list.len, 6630afa8e06SEd Maste assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { 6640afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 6650afa8e06SEd Maste goto fail; 6660afa8e06SEd Maste } 6670afa8e06SEd Maste 6680afa8e06SEd Maste list_ptr[assert->allow_list.len++] = id; 6690afa8e06SEd Maste assert->allow_list.ptr = list_ptr; 6700afa8e06SEd Maste 6710afa8e06SEd Maste return (FIDO_OK); 6720afa8e06SEd Maste fail: 6730afa8e06SEd Maste free(id.ptr); 6740afa8e06SEd Maste 6750afa8e06SEd Maste return (r); 676*2ccfa855SEd Maste } 6770afa8e06SEd Maste 678*2ccfa855SEd Maste int 679*2ccfa855SEd Maste fido_assert_empty_allow_list(fido_assert_t *assert) 680*2ccfa855SEd Maste { 681*2ccfa855SEd Maste fido_free_blob_array(&assert->allow_list); 682*2ccfa855SEd Maste memset(&assert->allow_list, 0, sizeof(assert->allow_list)); 683*2ccfa855SEd Maste 684*2ccfa855SEd Maste return (FIDO_OK); 6850afa8e06SEd Maste } 6860afa8e06SEd Maste 6870afa8e06SEd Maste int 6880afa8e06SEd Maste fido_assert_set_extensions(fido_assert_t *assert, int ext) 6890afa8e06SEd Maste { 6900afa8e06SEd Maste if (ext == 0) 6910afa8e06SEd Maste assert->ext.mask = 0; 6920afa8e06SEd Maste else { 6930afa8e06SEd Maste if ((ext & FIDO_EXT_ASSERT_MASK) != ext) 6940afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6950afa8e06SEd Maste assert->ext.mask |= ext; 6960afa8e06SEd Maste } 6970afa8e06SEd Maste 6980afa8e06SEd Maste return (FIDO_OK); 6990afa8e06SEd Maste } 7000afa8e06SEd Maste 7010afa8e06SEd Maste int 7020afa8e06SEd Maste fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) 7030afa8e06SEd Maste { 7040afa8e06SEd Maste assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 7050afa8e06SEd Maste assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 7060afa8e06SEd Maste 7070afa8e06SEd Maste return (FIDO_OK); 7080afa8e06SEd Maste } 7090afa8e06SEd Maste 7100afa8e06SEd Maste int 7110afa8e06SEd Maste fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) 7120afa8e06SEd Maste { 7130afa8e06SEd Maste assert->up = up; 7140afa8e06SEd Maste 7150afa8e06SEd Maste return (FIDO_OK); 7160afa8e06SEd Maste } 7170afa8e06SEd Maste 7180afa8e06SEd Maste int 7190afa8e06SEd Maste fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) 7200afa8e06SEd Maste { 7210afa8e06SEd Maste assert->uv = uv; 7220afa8e06SEd Maste 7230afa8e06SEd Maste return (FIDO_OK); 7240afa8e06SEd Maste } 7250afa8e06SEd Maste 7260afa8e06SEd Maste const unsigned char * 7270afa8e06SEd Maste fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) 7280afa8e06SEd Maste { 7290afa8e06SEd Maste return (assert->cdh.ptr); 7300afa8e06SEd Maste } 7310afa8e06SEd Maste 7320afa8e06SEd Maste size_t 7330afa8e06SEd Maste fido_assert_clientdata_hash_len(const fido_assert_t *assert) 7340afa8e06SEd Maste { 7350afa8e06SEd Maste return (assert->cdh.len); 7360afa8e06SEd Maste } 7370afa8e06SEd Maste 7380afa8e06SEd Maste fido_assert_t * 7390afa8e06SEd Maste fido_assert_new(void) 7400afa8e06SEd Maste { 7410afa8e06SEd Maste return (calloc(1, sizeof(fido_assert_t))); 7420afa8e06SEd Maste } 7430afa8e06SEd Maste 7440afa8e06SEd Maste void 7450afa8e06SEd Maste fido_assert_reset_tx(fido_assert_t *assert) 7460afa8e06SEd Maste { 7470afa8e06SEd Maste free(assert->rp_id); 7480afa8e06SEd Maste fido_blob_reset(&assert->cd); 7490afa8e06SEd Maste fido_blob_reset(&assert->cdh); 7500afa8e06SEd Maste fido_blob_reset(&assert->ext.hmac_salt); 751*2ccfa855SEd Maste fido_assert_empty_allow_list(assert); 7520afa8e06SEd Maste memset(&assert->ext, 0, sizeof(assert->ext)); 7530afa8e06SEd Maste assert->rp_id = NULL; 7540afa8e06SEd Maste assert->up = FIDO_OPT_OMIT; 7550afa8e06SEd Maste assert->uv = FIDO_OPT_OMIT; 7560afa8e06SEd Maste } 7570afa8e06SEd Maste 758*2ccfa855SEd Maste static void 759*2ccfa855SEd Maste fido_assert_reset_extattr(fido_assert_extattr_t *ext) 7600afa8e06SEd Maste { 7610afa8e06SEd Maste fido_blob_reset(&ext->hmac_secret_enc); 7620afa8e06SEd Maste fido_blob_reset(&ext->blob); 7630afa8e06SEd Maste memset(ext, 0, sizeof(*ext)); 7640afa8e06SEd Maste } 7650afa8e06SEd Maste 7660afa8e06SEd Maste void 7670afa8e06SEd Maste fido_assert_reset_rx(fido_assert_t *assert) 7680afa8e06SEd Maste { 7690afa8e06SEd Maste for (size_t i = 0; i < assert->stmt_cnt; i++) { 7700afa8e06SEd Maste free(assert->stmt[i].user.icon); 7710afa8e06SEd Maste free(assert->stmt[i].user.name); 7720afa8e06SEd Maste free(assert->stmt[i].user.display_name); 7730afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].user.id); 7740afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].id); 7750afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].hmac_secret); 7760afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].authdata_cbor); 7770afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].largeblob_key); 7780afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].sig); 7790afa8e06SEd Maste fido_assert_reset_extattr(&assert->stmt[i].authdata_ext); 7800afa8e06SEd Maste memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); 7810afa8e06SEd Maste } 7820afa8e06SEd Maste free(assert->stmt); 7830afa8e06SEd Maste assert->stmt = NULL; 7840afa8e06SEd Maste assert->stmt_len = 0; 7850afa8e06SEd Maste assert->stmt_cnt = 0; 7860afa8e06SEd Maste } 7870afa8e06SEd Maste 7880afa8e06SEd Maste void 7890afa8e06SEd Maste fido_assert_free(fido_assert_t **assert_p) 7900afa8e06SEd Maste { 7910afa8e06SEd Maste fido_assert_t *assert; 7920afa8e06SEd Maste 7930afa8e06SEd Maste if (assert_p == NULL || (assert = *assert_p) == NULL) 7940afa8e06SEd Maste return; 7950afa8e06SEd Maste fido_assert_reset_tx(assert); 7960afa8e06SEd Maste fido_assert_reset_rx(assert); 7970afa8e06SEd Maste free(assert); 7980afa8e06SEd Maste *assert_p = NULL; 7990afa8e06SEd Maste } 8000afa8e06SEd Maste 8010afa8e06SEd Maste size_t 8020afa8e06SEd Maste fido_assert_count(const fido_assert_t *assert) 8030afa8e06SEd Maste { 8040afa8e06SEd Maste return (assert->stmt_len); 8050afa8e06SEd Maste } 8060afa8e06SEd Maste 8070afa8e06SEd Maste const char * 8080afa8e06SEd Maste fido_assert_rp_id(const fido_assert_t *assert) 8090afa8e06SEd Maste { 8100afa8e06SEd Maste return (assert->rp_id); 8110afa8e06SEd Maste } 8120afa8e06SEd Maste 8130afa8e06SEd Maste uint8_t 8140afa8e06SEd Maste fido_assert_flags(const fido_assert_t *assert, size_t idx) 8150afa8e06SEd Maste { 8160afa8e06SEd Maste if (idx >= assert->stmt_len) 8170afa8e06SEd Maste return (0); 8180afa8e06SEd Maste 8190afa8e06SEd Maste return (assert->stmt[idx].authdata.flags); 8200afa8e06SEd Maste } 8210afa8e06SEd Maste 8220afa8e06SEd Maste uint32_t 8230afa8e06SEd Maste fido_assert_sigcount(const fido_assert_t *assert, size_t idx) 8240afa8e06SEd Maste { 8250afa8e06SEd Maste if (idx >= assert->stmt_len) 8260afa8e06SEd Maste return (0); 8270afa8e06SEd Maste 8280afa8e06SEd Maste return (assert->stmt[idx].authdata.sigcount); 8290afa8e06SEd Maste } 8300afa8e06SEd Maste 8310afa8e06SEd Maste const unsigned char * 8320afa8e06SEd Maste fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) 8330afa8e06SEd Maste { 8340afa8e06SEd Maste if (idx >= assert->stmt_len) 8350afa8e06SEd Maste return (NULL); 8360afa8e06SEd Maste 8370afa8e06SEd Maste return (assert->stmt[idx].authdata_cbor.ptr); 8380afa8e06SEd Maste } 8390afa8e06SEd Maste 8400afa8e06SEd Maste size_t 8410afa8e06SEd Maste fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) 8420afa8e06SEd Maste { 8430afa8e06SEd Maste if (idx >= assert->stmt_len) 8440afa8e06SEd Maste return (0); 8450afa8e06SEd Maste 8460afa8e06SEd Maste return (assert->stmt[idx].authdata_cbor.len); 8470afa8e06SEd Maste } 8480afa8e06SEd Maste 8490afa8e06SEd Maste const unsigned char * 8500afa8e06SEd Maste fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) 8510afa8e06SEd Maste { 8520afa8e06SEd Maste if (idx >= assert->stmt_len) 8530afa8e06SEd Maste return (NULL); 8540afa8e06SEd Maste 8550afa8e06SEd Maste return (assert->stmt[idx].sig.ptr); 8560afa8e06SEd Maste } 8570afa8e06SEd Maste 8580afa8e06SEd Maste size_t 8590afa8e06SEd Maste fido_assert_sig_len(const fido_assert_t *assert, size_t idx) 8600afa8e06SEd Maste { 8610afa8e06SEd Maste if (idx >= assert->stmt_len) 8620afa8e06SEd Maste return (0); 8630afa8e06SEd Maste 8640afa8e06SEd Maste return (assert->stmt[idx].sig.len); 8650afa8e06SEd Maste } 8660afa8e06SEd Maste 8670afa8e06SEd Maste const unsigned char * 8680afa8e06SEd Maste fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) 8690afa8e06SEd Maste { 8700afa8e06SEd Maste if (idx >= assert->stmt_len) 8710afa8e06SEd Maste return (NULL); 8720afa8e06SEd Maste 8730afa8e06SEd Maste return (assert->stmt[idx].id.ptr); 8740afa8e06SEd Maste } 8750afa8e06SEd Maste 8760afa8e06SEd Maste size_t 8770afa8e06SEd Maste fido_assert_id_len(const fido_assert_t *assert, size_t idx) 8780afa8e06SEd Maste { 8790afa8e06SEd Maste if (idx >= assert->stmt_len) 8800afa8e06SEd Maste return (0); 8810afa8e06SEd Maste 8820afa8e06SEd Maste return (assert->stmt[idx].id.len); 8830afa8e06SEd Maste } 8840afa8e06SEd Maste 8850afa8e06SEd Maste const unsigned char * 8860afa8e06SEd Maste fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) 8870afa8e06SEd Maste { 8880afa8e06SEd Maste if (idx >= assert->stmt_len) 8890afa8e06SEd Maste return (NULL); 8900afa8e06SEd Maste 8910afa8e06SEd Maste return (assert->stmt[idx].user.id.ptr); 8920afa8e06SEd Maste } 8930afa8e06SEd Maste 8940afa8e06SEd Maste size_t 8950afa8e06SEd Maste fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) 8960afa8e06SEd Maste { 8970afa8e06SEd Maste if (idx >= assert->stmt_len) 8980afa8e06SEd Maste return (0); 8990afa8e06SEd Maste 9000afa8e06SEd Maste return (assert->stmt[idx].user.id.len); 9010afa8e06SEd Maste } 9020afa8e06SEd Maste 9030afa8e06SEd Maste const char * 9040afa8e06SEd Maste fido_assert_user_icon(const fido_assert_t *assert, size_t idx) 9050afa8e06SEd Maste { 9060afa8e06SEd Maste if (idx >= assert->stmt_len) 9070afa8e06SEd Maste return (NULL); 9080afa8e06SEd Maste 9090afa8e06SEd Maste return (assert->stmt[idx].user.icon); 9100afa8e06SEd Maste } 9110afa8e06SEd Maste 9120afa8e06SEd Maste const char * 9130afa8e06SEd Maste fido_assert_user_name(const fido_assert_t *assert, size_t idx) 9140afa8e06SEd Maste { 9150afa8e06SEd Maste if (idx >= assert->stmt_len) 9160afa8e06SEd Maste return (NULL); 9170afa8e06SEd Maste 9180afa8e06SEd Maste return (assert->stmt[idx].user.name); 9190afa8e06SEd Maste } 9200afa8e06SEd Maste 9210afa8e06SEd Maste const char * 9220afa8e06SEd Maste fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) 9230afa8e06SEd Maste { 9240afa8e06SEd Maste if (idx >= assert->stmt_len) 9250afa8e06SEd Maste return (NULL); 9260afa8e06SEd Maste 9270afa8e06SEd Maste return (assert->stmt[idx].user.display_name); 9280afa8e06SEd Maste } 9290afa8e06SEd Maste 9300afa8e06SEd Maste const unsigned char * 9310afa8e06SEd Maste fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) 9320afa8e06SEd Maste { 9330afa8e06SEd Maste if (idx >= assert->stmt_len) 9340afa8e06SEd Maste return (NULL); 9350afa8e06SEd Maste 9360afa8e06SEd Maste return (assert->stmt[idx].hmac_secret.ptr); 9370afa8e06SEd Maste } 9380afa8e06SEd Maste 9390afa8e06SEd Maste size_t 9400afa8e06SEd Maste fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) 9410afa8e06SEd Maste { 9420afa8e06SEd Maste if (idx >= assert->stmt_len) 9430afa8e06SEd Maste return (0); 9440afa8e06SEd Maste 9450afa8e06SEd Maste return (assert->stmt[idx].hmac_secret.len); 9460afa8e06SEd Maste } 9470afa8e06SEd Maste 9480afa8e06SEd Maste const unsigned char * 9490afa8e06SEd Maste fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx) 9500afa8e06SEd Maste { 9510afa8e06SEd Maste if (idx >= assert->stmt_len) 9520afa8e06SEd Maste return (NULL); 9530afa8e06SEd Maste 9540afa8e06SEd Maste return (assert->stmt[idx].largeblob_key.ptr); 9550afa8e06SEd Maste } 9560afa8e06SEd Maste 9570afa8e06SEd Maste size_t 9580afa8e06SEd Maste fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx) 9590afa8e06SEd Maste { 9600afa8e06SEd Maste if (idx >= assert->stmt_len) 9610afa8e06SEd Maste return (0); 9620afa8e06SEd Maste 9630afa8e06SEd Maste return (assert->stmt[idx].largeblob_key.len); 9640afa8e06SEd Maste } 9650afa8e06SEd Maste 9660afa8e06SEd Maste const unsigned char * 9670afa8e06SEd Maste fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx) 9680afa8e06SEd Maste { 9690afa8e06SEd Maste if (idx >= assert->stmt_len) 9700afa8e06SEd Maste return (NULL); 9710afa8e06SEd Maste 9720afa8e06SEd Maste return (assert->stmt[idx].authdata_ext.blob.ptr); 9730afa8e06SEd Maste } 9740afa8e06SEd Maste 9750afa8e06SEd Maste size_t 9760afa8e06SEd Maste fido_assert_blob_len(const fido_assert_t *assert, size_t idx) 9770afa8e06SEd Maste { 9780afa8e06SEd Maste if (idx >= assert->stmt_len) 9790afa8e06SEd Maste return (0); 9800afa8e06SEd Maste 9810afa8e06SEd Maste return (assert->stmt[idx].authdata_ext.blob.len); 9820afa8e06SEd Maste } 9830afa8e06SEd Maste 9840afa8e06SEd Maste static void 9850afa8e06SEd Maste fido_assert_clean_authdata(fido_assert_stmt *stmt) 9860afa8e06SEd Maste { 9870afa8e06SEd Maste fido_blob_reset(&stmt->authdata_cbor); 9880afa8e06SEd Maste fido_assert_reset_extattr(&stmt->authdata_ext); 9890afa8e06SEd Maste memset(&stmt->authdata, 0, sizeof(stmt->authdata)); 9900afa8e06SEd Maste } 9910afa8e06SEd Maste 9920afa8e06SEd Maste int 9930afa8e06SEd Maste fido_assert_set_authdata(fido_assert_t *assert, size_t idx, 9940afa8e06SEd Maste const unsigned char *ptr, size_t len) 9950afa8e06SEd Maste { 9960afa8e06SEd Maste cbor_item_t *item = NULL; 9970afa8e06SEd Maste fido_assert_stmt *stmt = NULL; 9980afa8e06SEd Maste struct cbor_load_result cbor; 9990afa8e06SEd Maste int r; 10000afa8e06SEd Maste 10010afa8e06SEd Maste if (idx >= assert->stmt_len || ptr == NULL || len == 0) 10020afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 10030afa8e06SEd Maste 10040afa8e06SEd Maste stmt = &assert->stmt[idx]; 10050afa8e06SEd Maste fido_assert_clean_authdata(stmt); 10060afa8e06SEd Maste 10070afa8e06SEd Maste if ((item = cbor_load(ptr, len, &cbor)) == NULL) { 10080afa8e06SEd Maste fido_log_debug("%s: cbor_load", __func__); 10090afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 10100afa8e06SEd Maste goto fail; 10110afa8e06SEd Maste } 10120afa8e06SEd Maste 10130afa8e06SEd Maste if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 10140afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext) < 0) { 10150afa8e06SEd Maste fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 10160afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 10170afa8e06SEd Maste goto fail; 10180afa8e06SEd Maste } 10190afa8e06SEd Maste 10200afa8e06SEd Maste r = FIDO_OK; 10210afa8e06SEd Maste fail: 10220afa8e06SEd Maste if (item != NULL) 10230afa8e06SEd Maste cbor_decref(&item); 10240afa8e06SEd Maste 10250afa8e06SEd Maste if (r != FIDO_OK) 10260afa8e06SEd Maste fido_assert_clean_authdata(stmt); 10270afa8e06SEd Maste 10280afa8e06SEd Maste return (r); 10290afa8e06SEd Maste } 10300afa8e06SEd Maste 10310afa8e06SEd Maste int 10320afa8e06SEd Maste fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, 10330afa8e06SEd Maste const unsigned char *ptr, size_t len) 10340afa8e06SEd Maste { 10350afa8e06SEd Maste cbor_item_t *item = NULL; 10360afa8e06SEd Maste fido_assert_stmt *stmt = NULL; 10370afa8e06SEd Maste int r; 10380afa8e06SEd Maste 10390afa8e06SEd Maste if (idx >= assert->stmt_len || ptr == NULL || len == 0) 10400afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 10410afa8e06SEd Maste 10420afa8e06SEd Maste stmt = &assert->stmt[idx]; 10430afa8e06SEd Maste fido_assert_clean_authdata(stmt); 10440afa8e06SEd Maste 10450afa8e06SEd Maste if ((item = cbor_build_bytestring(ptr, len)) == NULL) { 10460afa8e06SEd Maste fido_log_debug("%s: cbor_build_bytestring", __func__); 10470afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 10480afa8e06SEd Maste goto fail; 10490afa8e06SEd Maste } 10500afa8e06SEd Maste 10510afa8e06SEd Maste if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 10520afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext) < 0) { 10530afa8e06SEd Maste fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 10540afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 10550afa8e06SEd Maste goto fail; 10560afa8e06SEd Maste } 10570afa8e06SEd Maste 10580afa8e06SEd Maste r = FIDO_OK; 10590afa8e06SEd Maste fail: 10600afa8e06SEd Maste if (item != NULL) 10610afa8e06SEd Maste cbor_decref(&item); 10620afa8e06SEd Maste 10630afa8e06SEd Maste if (r != FIDO_OK) 10640afa8e06SEd Maste fido_assert_clean_authdata(stmt); 10650afa8e06SEd Maste 10660afa8e06SEd Maste return (r); 10670afa8e06SEd Maste } 10680afa8e06SEd Maste 10690afa8e06SEd Maste int 10700afa8e06SEd Maste fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, 10710afa8e06SEd Maste size_t len) 10720afa8e06SEd Maste { 10730afa8e06SEd Maste if (idx >= a->stmt_len || ptr == NULL || len == 0) 10740afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 10750afa8e06SEd Maste if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0) 10760afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 10770afa8e06SEd Maste 10780afa8e06SEd Maste return (FIDO_OK); 10790afa8e06SEd Maste } 10800afa8e06SEd Maste 10810afa8e06SEd Maste /* XXX shrinking leaks memory; fortunately that shouldn't happen */ 10820afa8e06SEd Maste int 10830afa8e06SEd Maste fido_assert_set_count(fido_assert_t *assert, size_t n) 10840afa8e06SEd Maste { 10850afa8e06SEd Maste void *new_stmt; 10860afa8e06SEd Maste 10870afa8e06SEd Maste #ifdef FIDO_FUZZ 10880afa8e06SEd Maste if (n > UINT8_MAX) { 10890afa8e06SEd Maste fido_log_debug("%s: n > UINT8_MAX", __func__); 10900afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 10910afa8e06SEd Maste } 10920afa8e06SEd Maste #endif 10930afa8e06SEd Maste 10940afa8e06SEd Maste new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, 10950afa8e06SEd Maste sizeof(fido_assert_stmt)); 10960afa8e06SEd Maste if (new_stmt == NULL) 10970afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 10980afa8e06SEd Maste 10990afa8e06SEd Maste assert->stmt = new_stmt; 11000afa8e06SEd Maste assert->stmt_cnt = n; 11010afa8e06SEd Maste assert->stmt_len = n; 11020afa8e06SEd Maste 11030afa8e06SEd Maste return (FIDO_OK); 11040afa8e06SEd Maste } 1105