10afa8e06SEd Maste /* 20afa8e06SEd Maste * Copyright (c) 2018-2021 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. 50afa8e06SEd Maste */ 60afa8e06SEd Maste 70afa8e06SEd Maste #include <openssl/sha.h> 80afa8e06SEd Maste 90afa8e06SEd Maste #include "fido.h" 100afa8e06SEd Maste #include "fido/es256.h" 110afa8e06SEd Maste #include "fido/rs256.h" 120afa8e06SEd Maste #include "fido/eddsa.h" 130afa8e06SEd Maste 140afa8e06SEd Maste static int 150afa8e06SEd Maste adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) 160afa8e06SEd Maste { 170afa8e06SEd Maste fido_assert_t *assert = arg; 180afa8e06SEd Maste uint64_t n; 190afa8e06SEd Maste 200afa8e06SEd Maste /* numberOfCredentials; see section 6.2 */ 210afa8e06SEd Maste if (cbor_isa_uint(key) == false || 220afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8 || 230afa8e06SEd Maste cbor_get_uint8(key) != 5) { 240afa8e06SEd Maste fido_log_debug("%s: cbor_type", __func__); 250afa8e06SEd Maste return (0); /* ignore */ 260afa8e06SEd Maste } 270afa8e06SEd Maste 280afa8e06SEd Maste if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { 290afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__); 300afa8e06SEd Maste return (-1); 310afa8e06SEd Maste } 320afa8e06SEd Maste 330afa8e06SEd Maste if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || 340afa8e06SEd Maste (size_t)n < assert->stmt_cnt) { 350afa8e06SEd Maste fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", 360afa8e06SEd Maste __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); 370afa8e06SEd Maste return (-1); 380afa8e06SEd Maste } 390afa8e06SEd Maste 400afa8e06SEd Maste if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { 410afa8e06SEd Maste fido_log_debug("%s: fido_assert_set_count", __func__); 420afa8e06SEd Maste return (-1); 430afa8e06SEd Maste } 440afa8e06SEd Maste 450afa8e06SEd Maste assert->stmt_len = 0; /* XXX */ 460afa8e06SEd Maste 470afa8e06SEd Maste return (0); 480afa8e06SEd Maste } 490afa8e06SEd Maste 500afa8e06SEd Maste static int 510afa8e06SEd Maste parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) 520afa8e06SEd Maste { 530afa8e06SEd Maste fido_assert_stmt *stmt = arg; 540afa8e06SEd Maste 550afa8e06SEd Maste if (cbor_isa_uint(key) == false || 560afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8) { 570afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__); 580afa8e06SEd Maste return (0); /* ignore */ 590afa8e06SEd Maste } 600afa8e06SEd Maste 610afa8e06SEd Maste switch (cbor_get_uint8(key)) { 620afa8e06SEd Maste case 1: /* credential id */ 630afa8e06SEd Maste return (cbor_decode_cred_id(val, &stmt->id)); 640afa8e06SEd Maste case 2: /* authdata */ 650afa8e06SEd Maste return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, 660afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext)); 670afa8e06SEd Maste case 3: /* signature */ 680afa8e06SEd Maste return (fido_blob_decode(val, &stmt->sig)); 690afa8e06SEd Maste case 4: /* user attributes */ 700afa8e06SEd Maste return (cbor_decode_user(val, &stmt->user)); 710afa8e06SEd Maste case 7: /* large blob key */ 720afa8e06SEd Maste return (fido_blob_decode(val, &stmt->largeblob_key)); 730afa8e06SEd Maste default: /* ignore */ 740afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__); 750afa8e06SEd Maste return (0); 760afa8e06SEd Maste } 770afa8e06SEd Maste } 780afa8e06SEd Maste 790afa8e06SEd Maste static int 800afa8e06SEd Maste fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, 81*f540a430SEd Maste const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) 820afa8e06SEd Maste { 830afa8e06SEd Maste fido_blob_t f; 840afa8e06SEd Maste fido_opt_t uv = assert->uv; 850afa8e06SEd Maste cbor_item_t *argv[7]; 860afa8e06SEd Maste const uint8_t cmd = CTAP_CBOR_ASSERT; 870afa8e06SEd Maste int r; 880afa8e06SEd Maste 890afa8e06SEd Maste memset(argv, 0, sizeof(argv)); 900afa8e06SEd Maste memset(&f, 0, sizeof(f)); 910afa8e06SEd Maste 920afa8e06SEd Maste /* do we have everything we need? */ 930afa8e06SEd Maste if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 940afa8e06SEd Maste fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 950afa8e06SEd Maste (void *)assert->rp_id, (void *)assert->cdh.ptr); 960afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 970afa8e06SEd Maste goto fail; 980afa8e06SEd Maste } 990afa8e06SEd Maste 1000afa8e06SEd Maste if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || 1010afa8e06SEd Maste (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { 1020afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__); 1030afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1040afa8e06SEd Maste goto fail; 1050afa8e06SEd Maste } 1060afa8e06SEd Maste 1070afa8e06SEd Maste /* allowed credentials */ 1080afa8e06SEd Maste if (assert->allow_list.len) { 1090afa8e06SEd Maste const fido_blob_array_t *cl = &assert->allow_list; 1100afa8e06SEd Maste if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { 1110afa8e06SEd Maste fido_log_debug("%s: cbor_encode_pubkey_list", __func__); 1120afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1130afa8e06SEd Maste goto fail; 1140afa8e06SEd Maste } 1150afa8e06SEd Maste } 1160afa8e06SEd Maste 1170afa8e06SEd Maste if (assert->ext.mask) 1180afa8e06SEd Maste if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh, 1190afa8e06SEd Maste pk)) == NULL) { 1200afa8e06SEd Maste fido_log_debug("%s: cbor_encode_assert_ext", __func__); 1210afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1220afa8e06SEd Maste goto fail; 1230afa8e06SEd Maste } 1240afa8e06SEd Maste 1250afa8e06SEd Maste /* user verification */ 1260afa8e06SEd Maste if (pin != NULL || (uv == FIDO_OPT_TRUE && 1270afa8e06SEd Maste fido_dev_supports_permissions(dev))) { 1280afa8e06SEd Maste if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh, 129*f540a430SEd Maste pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) { 1300afa8e06SEd Maste fido_log_debug("%s: cbor_add_uv_params", __func__); 1310afa8e06SEd Maste goto fail; 1320afa8e06SEd Maste } 1330afa8e06SEd Maste uv = FIDO_OPT_OMIT; 1340afa8e06SEd Maste } 1350afa8e06SEd Maste 1360afa8e06SEd Maste /* options */ 1370afa8e06SEd Maste if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT) 1380afa8e06SEd Maste if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) { 1390afa8e06SEd Maste fido_log_debug("%s: cbor_encode_assert_opt", __func__); 1400afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1410afa8e06SEd Maste goto fail; 1420afa8e06SEd Maste } 1430afa8e06SEd Maste 1440afa8e06SEd Maste /* frame and transmit */ 1450afa8e06SEd Maste if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || 146*f540a430SEd Maste fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 1470afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__); 1480afa8e06SEd Maste r = FIDO_ERR_TX; 1490afa8e06SEd Maste goto fail; 1500afa8e06SEd Maste } 1510afa8e06SEd Maste 1520afa8e06SEd Maste r = FIDO_OK; 1530afa8e06SEd Maste fail: 1540afa8e06SEd Maste cbor_vector_free(argv, nitems(argv)); 1550afa8e06SEd Maste free(f.ptr); 1560afa8e06SEd Maste 1570afa8e06SEd Maste return (r); 1580afa8e06SEd Maste } 1590afa8e06SEd Maste 1600afa8e06SEd Maste static int 161*f540a430SEd Maste fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) 1620afa8e06SEd Maste { 1630afa8e06SEd Maste unsigned char reply[FIDO_MAXMSG]; 1640afa8e06SEd Maste int reply_len; 1650afa8e06SEd Maste int r; 1660afa8e06SEd Maste 1670afa8e06SEd Maste fido_assert_reset_rx(assert); 1680afa8e06SEd Maste 1690afa8e06SEd Maste if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 1700afa8e06SEd Maste ms)) < 0) { 1710afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 1720afa8e06SEd Maste return (FIDO_ERR_RX); 1730afa8e06SEd Maste } 1740afa8e06SEd Maste 1750afa8e06SEd Maste /* start with room for a single assertion */ 1760afa8e06SEd Maste if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) 1770afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 1780afa8e06SEd Maste 1790afa8e06SEd Maste assert->stmt_len = 0; 1800afa8e06SEd Maste assert->stmt_cnt = 1; 1810afa8e06SEd Maste 1820afa8e06SEd Maste /* adjust as needed */ 1830afa8e06SEd Maste if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, 1840afa8e06SEd Maste adjust_assert_count)) != FIDO_OK) { 1850afa8e06SEd Maste fido_log_debug("%s: adjust_assert_count", __func__); 1860afa8e06SEd Maste return (r); 1870afa8e06SEd Maste } 1880afa8e06SEd Maste 1890afa8e06SEd Maste /* parse the first assertion */ 1900afa8e06SEd Maste if ((r = cbor_parse_reply(reply, (size_t)reply_len, 1910afa8e06SEd Maste &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { 1920afa8e06SEd Maste fido_log_debug("%s: parse_assert_reply", __func__); 1930afa8e06SEd Maste return (r); 1940afa8e06SEd Maste } 1950afa8e06SEd Maste 1960afa8e06SEd Maste assert->stmt_len++; 1970afa8e06SEd Maste 1980afa8e06SEd Maste return (FIDO_OK); 1990afa8e06SEd Maste } 2000afa8e06SEd Maste 2010afa8e06SEd Maste static int 202*f540a430SEd Maste fido_get_next_assert_tx(fido_dev_t *dev, int *ms) 2030afa8e06SEd Maste { 2040afa8e06SEd Maste const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; 2050afa8e06SEd Maste 206*f540a430SEd Maste if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { 2070afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__); 2080afa8e06SEd Maste return (FIDO_ERR_TX); 2090afa8e06SEd Maste } 2100afa8e06SEd Maste 2110afa8e06SEd Maste return (FIDO_OK); 2120afa8e06SEd Maste } 2130afa8e06SEd Maste 2140afa8e06SEd Maste static int 215*f540a430SEd Maste fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) 2160afa8e06SEd Maste { 2170afa8e06SEd Maste unsigned char reply[FIDO_MAXMSG]; 2180afa8e06SEd Maste int reply_len; 2190afa8e06SEd Maste int r; 2200afa8e06SEd Maste 2210afa8e06SEd Maste if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 2220afa8e06SEd Maste ms)) < 0) { 2230afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 2240afa8e06SEd Maste return (FIDO_ERR_RX); 2250afa8e06SEd Maste } 2260afa8e06SEd Maste 2270afa8e06SEd Maste /* sanity check */ 2280afa8e06SEd Maste if (assert->stmt_len >= assert->stmt_cnt) { 2290afa8e06SEd Maste fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, 2300afa8e06SEd Maste assert->stmt_len, assert->stmt_cnt); 2310afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 2320afa8e06SEd Maste } 2330afa8e06SEd Maste 2340afa8e06SEd Maste if ((r = cbor_parse_reply(reply, (size_t)reply_len, 2350afa8e06SEd Maste &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { 2360afa8e06SEd Maste fido_log_debug("%s: parse_assert_reply", __func__); 2370afa8e06SEd Maste return (r); 2380afa8e06SEd Maste } 2390afa8e06SEd Maste 2400afa8e06SEd Maste return (FIDO_OK); 2410afa8e06SEd Maste } 2420afa8e06SEd Maste 2430afa8e06SEd Maste static int 2440afa8e06SEd Maste fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, 245*f540a430SEd Maste const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) 2460afa8e06SEd Maste { 2470afa8e06SEd Maste int r; 2480afa8e06SEd Maste 249*f540a430SEd Maste if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin, 250*f540a430SEd Maste ms)) != FIDO_OK || 2510afa8e06SEd Maste (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) 2520afa8e06SEd Maste return (r); 2530afa8e06SEd Maste 2540afa8e06SEd Maste while (assert->stmt_len < assert->stmt_cnt) { 255*f540a430SEd Maste if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK || 2560afa8e06SEd Maste (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) 2570afa8e06SEd Maste return (r); 2580afa8e06SEd Maste assert->stmt_len++; 2590afa8e06SEd Maste } 2600afa8e06SEd Maste 2610afa8e06SEd Maste return (FIDO_OK); 2620afa8e06SEd Maste } 2630afa8e06SEd Maste 2640afa8e06SEd Maste static int 2650afa8e06SEd Maste decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert, 2660afa8e06SEd Maste const fido_blob_t *key) 2670afa8e06SEd Maste { 2680afa8e06SEd Maste for (size_t i = 0; i < assert->stmt_cnt; i++) { 2690afa8e06SEd Maste fido_assert_stmt *stmt = &assert->stmt[i]; 2700afa8e06SEd Maste if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) { 2710afa8e06SEd Maste if (aes256_cbc_dec(dev, key, 2720afa8e06SEd Maste &stmt->authdata_ext.hmac_secret_enc, 2730afa8e06SEd Maste &stmt->hmac_secret) < 0) { 2740afa8e06SEd Maste fido_log_debug("%s: aes256_cbc_dec %zu", 2750afa8e06SEd Maste __func__, i); 2760afa8e06SEd Maste return (-1); 2770afa8e06SEd Maste } 2780afa8e06SEd Maste } 2790afa8e06SEd Maste } 2800afa8e06SEd Maste 2810afa8e06SEd Maste return (0); 2820afa8e06SEd Maste } 2830afa8e06SEd Maste 2840afa8e06SEd Maste int 2850afa8e06SEd Maste fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) 2860afa8e06SEd Maste { 2870afa8e06SEd Maste fido_blob_t *ecdh = NULL; 2880afa8e06SEd Maste es256_pk_t *pk = NULL; 289*f540a430SEd Maste int ms = dev->timeout_ms; 2900afa8e06SEd Maste int r; 2910afa8e06SEd Maste 2920afa8e06SEd Maste #ifdef USE_WINHELLO 2930afa8e06SEd Maste if (dev->flags & FIDO_DEV_WINHELLO) 294*f540a430SEd Maste return (fido_winhello_get_assert(dev, assert, pin, ms)); 2950afa8e06SEd Maste #endif 2960afa8e06SEd Maste 2970afa8e06SEd Maste if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { 2980afa8e06SEd Maste fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, 2990afa8e06SEd Maste (void *)assert->rp_id, (void *)assert->cdh.ptr); 3000afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 3010afa8e06SEd Maste } 3020afa8e06SEd Maste 3030afa8e06SEd Maste if (fido_dev_is_fido2(dev) == false) { 3040afa8e06SEd Maste if (pin != NULL || assert->ext.mask != 0) 3050afa8e06SEd Maste return (FIDO_ERR_UNSUPPORTED_OPTION); 306*f540a430SEd Maste return (u2f_authenticate(dev, assert, &ms)); 3070afa8e06SEd Maste } 3080afa8e06SEd Maste 3090afa8e06SEd Maste if (pin != NULL || (assert->uv == FIDO_OPT_TRUE && 3100afa8e06SEd Maste fido_dev_supports_permissions(dev)) || 3110afa8e06SEd Maste (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) { 312*f540a430SEd Maste if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) { 3130afa8e06SEd Maste fido_log_debug("%s: fido_do_ecdh", __func__); 3140afa8e06SEd Maste goto fail; 3150afa8e06SEd Maste } 3160afa8e06SEd Maste } 3170afa8e06SEd Maste 318*f540a430SEd Maste r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms); 3190afa8e06SEd Maste if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) 3200afa8e06SEd Maste if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) { 3210afa8e06SEd Maste fido_log_debug("%s: decrypt_hmac_secrets", __func__); 3220afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 3230afa8e06SEd Maste goto fail; 3240afa8e06SEd Maste } 3250afa8e06SEd Maste 3260afa8e06SEd Maste fail: 3270afa8e06SEd Maste es256_pk_free(&pk); 3280afa8e06SEd Maste fido_blob_free(&ecdh); 3290afa8e06SEd Maste 3300afa8e06SEd Maste return (r); 3310afa8e06SEd Maste } 3320afa8e06SEd Maste 3330afa8e06SEd Maste int 3340afa8e06SEd Maste fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) 3350afa8e06SEd Maste { 3360afa8e06SEd Maste fido_log_debug("%s: flags=%02x", __func__, flags); 3370afa8e06SEd Maste fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); 3380afa8e06SEd Maste 3390afa8e06SEd Maste if (up == FIDO_OPT_TRUE && 3400afa8e06SEd Maste (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { 3410afa8e06SEd Maste fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); 3420afa8e06SEd Maste return (-1); /* user not present */ 3430afa8e06SEd Maste } 3440afa8e06SEd Maste 3450afa8e06SEd Maste if (uv == FIDO_OPT_TRUE && 3460afa8e06SEd Maste (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { 3470afa8e06SEd Maste fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); 3480afa8e06SEd Maste return (-1); /* user not verified */ 3490afa8e06SEd Maste } 3500afa8e06SEd Maste 3510afa8e06SEd Maste return (0); 3520afa8e06SEd Maste } 3530afa8e06SEd Maste 3540afa8e06SEd Maste static int 3550afa8e06SEd Maste check_extensions(int authdata_ext, int ext) 3560afa8e06SEd Maste { 3570afa8e06SEd Maste /* XXX: largeBlobKey is not part of extensions map */ 3580afa8e06SEd Maste ext &= ~FIDO_EXT_LARGEBLOB_KEY; 3590afa8e06SEd Maste if (authdata_ext != ext) { 3600afa8e06SEd Maste fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, 3610afa8e06SEd Maste authdata_ext, ext); 3620afa8e06SEd Maste return (-1); 3630afa8e06SEd Maste } 3640afa8e06SEd Maste 3650afa8e06SEd Maste return (0); 3660afa8e06SEd Maste } 3670afa8e06SEd Maste 3680afa8e06SEd Maste int 3690afa8e06SEd Maste fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, 3700afa8e06SEd Maste const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) 3710afa8e06SEd Maste { 3720afa8e06SEd Maste cbor_item_t *item = NULL; 3730afa8e06SEd Maste unsigned char *authdata_ptr = NULL; 3740afa8e06SEd Maste size_t authdata_len; 3750afa8e06SEd Maste struct cbor_load_result cbor; 376*f540a430SEd Maste const EVP_MD *md = NULL; 377*f540a430SEd Maste EVP_MD_CTX *ctx = NULL; 3780afa8e06SEd Maste int ok = -1; 3790afa8e06SEd Maste 3800afa8e06SEd Maste if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, 3810afa8e06SEd Maste &cbor)) == NULL || cbor_isa_bytestring(item) == false || 3820afa8e06SEd Maste cbor_bytestring_is_definite(item) == false) { 3830afa8e06SEd Maste fido_log_debug("%s: authdata", __func__); 3840afa8e06SEd Maste goto fail; 3850afa8e06SEd Maste } 3860afa8e06SEd Maste 3870afa8e06SEd Maste authdata_ptr = cbor_bytestring_handle(item); 3880afa8e06SEd Maste authdata_len = cbor_bytestring_length(item); 3890afa8e06SEd Maste 3900afa8e06SEd Maste if (cose_alg != COSE_EDDSA) { 391*f540a430SEd Maste if (dgst->len < SHA256_DIGEST_LENGTH || 392*f540a430SEd Maste (md = EVP_sha256()) == NULL || 393*f540a430SEd Maste (ctx = EVP_MD_CTX_new()) == NULL || 394*f540a430SEd Maste EVP_DigestInit_ex(ctx, md, NULL) != 1 || 395*f540a430SEd Maste EVP_DigestUpdate(ctx, authdata_ptr, authdata_len) != 1 || 396*f540a430SEd Maste EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || 397*f540a430SEd Maste EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { 3980afa8e06SEd Maste fido_log_debug("%s: sha256", __func__); 3990afa8e06SEd Maste goto fail; 4000afa8e06SEd Maste } 4010afa8e06SEd Maste dgst->len = SHA256_DIGEST_LENGTH; 4020afa8e06SEd Maste } else { 4030afa8e06SEd Maste if (SIZE_MAX - authdata_len < clientdata->len || 4040afa8e06SEd Maste dgst->len < authdata_len + clientdata->len) { 4050afa8e06SEd Maste fido_log_debug("%s: memcpy", __func__); 4060afa8e06SEd Maste goto fail; 4070afa8e06SEd Maste } 4080afa8e06SEd Maste memcpy(dgst->ptr, authdata_ptr, authdata_len); 4090afa8e06SEd Maste memcpy(dgst->ptr + authdata_len, clientdata->ptr, 4100afa8e06SEd Maste clientdata->len); 4110afa8e06SEd Maste dgst->len = authdata_len + clientdata->len; 4120afa8e06SEd Maste } 4130afa8e06SEd Maste 4140afa8e06SEd Maste ok = 0; 4150afa8e06SEd Maste fail: 4160afa8e06SEd Maste if (item != NULL) 4170afa8e06SEd Maste cbor_decref(&item); 4180afa8e06SEd Maste 419*f540a430SEd Maste EVP_MD_CTX_free(ctx); 4200afa8e06SEd Maste 4210afa8e06SEd Maste return (ok); 4220afa8e06SEd Maste } 4230afa8e06SEd Maste 4240afa8e06SEd Maste int 4250afa8e06SEd Maste fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, 4260afa8e06SEd Maste const void *pk) 4270afa8e06SEd Maste { 4280afa8e06SEd Maste unsigned char buf[1024]; /* XXX */ 4290afa8e06SEd Maste fido_blob_t dgst; 4300afa8e06SEd Maste const fido_assert_stmt *stmt = NULL; 4310afa8e06SEd Maste int ok = -1; 4320afa8e06SEd Maste int r; 4330afa8e06SEd Maste 4340afa8e06SEd Maste dgst.ptr = buf; 4350afa8e06SEd Maste dgst.len = sizeof(buf); 4360afa8e06SEd Maste 4370afa8e06SEd Maste if (idx >= assert->stmt_len || pk == NULL) { 4380afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 4390afa8e06SEd Maste goto out; 4400afa8e06SEd Maste } 4410afa8e06SEd Maste 4420afa8e06SEd Maste stmt = &assert->stmt[idx]; 4430afa8e06SEd Maste 4440afa8e06SEd Maste /* do we have everything we need? */ 4450afa8e06SEd Maste if (assert->cdh.ptr == NULL || assert->rp_id == NULL || 4460afa8e06SEd Maste stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { 4470afa8e06SEd Maste fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", 4480afa8e06SEd Maste __func__, (void *)assert->cdh.ptr, assert->rp_id, 4490afa8e06SEd Maste (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); 4500afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 4510afa8e06SEd Maste goto out; 4520afa8e06SEd Maste } 4530afa8e06SEd Maste 4540afa8e06SEd Maste if (fido_check_flags(stmt->authdata.flags, assert->up, 4550afa8e06SEd Maste assert->uv) < 0) { 4560afa8e06SEd Maste fido_log_debug("%s: fido_check_flags", __func__); 4570afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 4580afa8e06SEd Maste goto out; 4590afa8e06SEd Maste } 4600afa8e06SEd Maste 4610afa8e06SEd Maste if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) { 4620afa8e06SEd Maste fido_log_debug("%s: check_extensions", __func__); 4630afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 4640afa8e06SEd Maste goto out; 4650afa8e06SEd Maste } 4660afa8e06SEd Maste 4670afa8e06SEd Maste if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { 4680afa8e06SEd Maste fido_log_debug("%s: fido_check_rp_id", __func__); 4690afa8e06SEd Maste r = FIDO_ERR_INVALID_PARAM; 4700afa8e06SEd Maste goto out; 4710afa8e06SEd Maste } 4720afa8e06SEd Maste 4730afa8e06SEd Maste if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh, 4740afa8e06SEd Maste &stmt->authdata_cbor) < 0) { 4750afa8e06SEd Maste fido_log_debug("%s: fido_get_signed_hash", __func__); 4760afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 4770afa8e06SEd Maste goto out; 4780afa8e06SEd Maste } 4790afa8e06SEd Maste 4800afa8e06SEd Maste switch (cose_alg) { 4810afa8e06SEd Maste case COSE_ES256: 482*f540a430SEd Maste ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig); 4830afa8e06SEd Maste break; 4840afa8e06SEd Maste case COSE_RS256: 485*f540a430SEd Maste ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig); 4860afa8e06SEd Maste break; 4870afa8e06SEd Maste case COSE_EDDSA: 488*f540a430SEd Maste ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig); 4890afa8e06SEd Maste break; 4900afa8e06SEd Maste default: 4910afa8e06SEd Maste fido_log_debug("%s: unsupported cose_alg %d", __func__, 4920afa8e06SEd Maste cose_alg); 4930afa8e06SEd Maste r = FIDO_ERR_UNSUPPORTED_OPTION; 4940afa8e06SEd Maste goto out; 4950afa8e06SEd Maste } 4960afa8e06SEd Maste 4970afa8e06SEd Maste if (ok < 0) 4980afa8e06SEd Maste r = FIDO_ERR_INVALID_SIG; 4990afa8e06SEd Maste else 5000afa8e06SEd Maste r = FIDO_OK; 5010afa8e06SEd Maste out: 5020afa8e06SEd Maste explicit_bzero(buf, sizeof(buf)); 5030afa8e06SEd Maste 5040afa8e06SEd Maste return (r); 5050afa8e06SEd Maste } 5060afa8e06SEd Maste 5070afa8e06SEd Maste int 5080afa8e06SEd Maste fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data, 5090afa8e06SEd Maste size_t data_len) 5100afa8e06SEd Maste { 5110afa8e06SEd Maste if (!fido_blob_is_empty(&assert->cdh) || 5120afa8e06SEd Maste fido_blob_set(&assert->cd, data, data_len) < 0) { 5130afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5140afa8e06SEd Maste } 5150afa8e06SEd Maste if (fido_sha256(&assert->cdh, data, data_len) < 0) { 5160afa8e06SEd Maste fido_blob_reset(&assert->cd); 5170afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 5180afa8e06SEd Maste } 5190afa8e06SEd Maste 5200afa8e06SEd Maste return (FIDO_OK); 5210afa8e06SEd Maste } 5220afa8e06SEd Maste 5230afa8e06SEd Maste int 5240afa8e06SEd Maste fido_assert_set_clientdata_hash(fido_assert_t *assert, 5250afa8e06SEd Maste const unsigned char *hash, size_t hash_len) 5260afa8e06SEd Maste { 5270afa8e06SEd Maste if (!fido_blob_is_empty(&assert->cd) || 5280afa8e06SEd Maste fido_blob_set(&assert->cdh, hash, hash_len) < 0) 5290afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5300afa8e06SEd Maste 5310afa8e06SEd Maste return (FIDO_OK); 5320afa8e06SEd Maste } 5330afa8e06SEd Maste 5340afa8e06SEd Maste int 5350afa8e06SEd Maste fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, 5360afa8e06SEd Maste size_t salt_len) 5370afa8e06SEd Maste { 5380afa8e06SEd Maste if ((salt_len != 32 && salt_len != 64) || 5390afa8e06SEd Maste fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0) 5400afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5410afa8e06SEd Maste 5420afa8e06SEd Maste return (FIDO_OK); 5430afa8e06SEd Maste } 5440afa8e06SEd Maste 5450afa8e06SEd Maste int 5460afa8e06SEd Maste fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx, 5470afa8e06SEd Maste const unsigned char *secret, size_t secret_len) 5480afa8e06SEd Maste { 5490afa8e06SEd Maste if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) || 5500afa8e06SEd Maste fido_blob_set(&assert->stmt[idx].hmac_secret, secret, 5510afa8e06SEd Maste secret_len) < 0) 5520afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5530afa8e06SEd Maste 5540afa8e06SEd Maste return (FIDO_OK); 5550afa8e06SEd Maste } 5560afa8e06SEd Maste 5570afa8e06SEd Maste int 5580afa8e06SEd Maste fido_assert_set_rp(fido_assert_t *assert, const char *id) 5590afa8e06SEd Maste { 5600afa8e06SEd Maste if (assert->rp_id != NULL) { 5610afa8e06SEd Maste free(assert->rp_id); 5620afa8e06SEd Maste assert->rp_id = NULL; 5630afa8e06SEd Maste } 5640afa8e06SEd Maste 5650afa8e06SEd Maste if (id == NULL) 5660afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 5670afa8e06SEd Maste 5680afa8e06SEd Maste if ((assert->rp_id = strdup(id)) == NULL) 5690afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 5700afa8e06SEd Maste 5710afa8e06SEd Maste return (FIDO_OK); 5720afa8e06SEd Maste } 5730afa8e06SEd Maste 5740afa8e06SEd Maste int 5750afa8e06SEd Maste fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, 5760afa8e06SEd Maste size_t len) 5770afa8e06SEd Maste { 5780afa8e06SEd Maste fido_blob_t id; 5790afa8e06SEd Maste fido_blob_t *list_ptr; 5800afa8e06SEd Maste int r; 5810afa8e06SEd Maste 5820afa8e06SEd Maste memset(&id, 0, sizeof(id)); 5830afa8e06SEd Maste 5840afa8e06SEd Maste if (assert->allow_list.len == SIZE_MAX) { 5850afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 5860afa8e06SEd Maste goto fail; 5870afa8e06SEd Maste } 5880afa8e06SEd Maste 5890afa8e06SEd Maste if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = 5900afa8e06SEd Maste recallocarray(assert->allow_list.ptr, assert->allow_list.len, 5910afa8e06SEd Maste assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { 5920afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 5930afa8e06SEd Maste goto fail; 5940afa8e06SEd Maste } 5950afa8e06SEd Maste 5960afa8e06SEd Maste list_ptr[assert->allow_list.len++] = id; 5970afa8e06SEd Maste assert->allow_list.ptr = list_ptr; 5980afa8e06SEd Maste 5990afa8e06SEd Maste return (FIDO_OK); 6000afa8e06SEd Maste fail: 6010afa8e06SEd Maste free(id.ptr); 6020afa8e06SEd Maste 6030afa8e06SEd Maste return (r); 6040afa8e06SEd Maste 6050afa8e06SEd Maste } 6060afa8e06SEd Maste 6070afa8e06SEd Maste int 6080afa8e06SEd Maste fido_assert_set_extensions(fido_assert_t *assert, int ext) 6090afa8e06SEd Maste { 6100afa8e06SEd Maste if (ext == 0) 6110afa8e06SEd Maste assert->ext.mask = 0; 6120afa8e06SEd Maste else { 6130afa8e06SEd Maste if ((ext & FIDO_EXT_ASSERT_MASK) != ext) 6140afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 6150afa8e06SEd Maste assert->ext.mask |= ext; 6160afa8e06SEd Maste } 6170afa8e06SEd Maste 6180afa8e06SEd Maste return (FIDO_OK); 6190afa8e06SEd Maste } 6200afa8e06SEd Maste 6210afa8e06SEd Maste int 6220afa8e06SEd Maste fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) 6230afa8e06SEd Maste { 6240afa8e06SEd Maste assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 6250afa8e06SEd Maste assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; 6260afa8e06SEd Maste 6270afa8e06SEd Maste return (FIDO_OK); 6280afa8e06SEd Maste } 6290afa8e06SEd Maste 6300afa8e06SEd Maste int 6310afa8e06SEd Maste fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) 6320afa8e06SEd Maste { 6330afa8e06SEd Maste assert->up = up; 6340afa8e06SEd Maste 6350afa8e06SEd Maste return (FIDO_OK); 6360afa8e06SEd Maste } 6370afa8e06SEd Maste 6380afa8e06SEd Maste int 6390afa8e06SEd Maste fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) 6400afa8e06SEd Maste { 6410afa8e06SEd Maste assert->uv = uv; 6420afa8e06SEd Maste 6430afa8e06SEd Maste return (FIDO_OK); 6440afa8e06SEd Maste } 6450afa8e06SEd Maste 6460afa8e06SEd Maste const unsigned char * 6470afa8e06SEd Maste fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) 6480afa8e06SEd Maste { 6490afa8e06SEd Maste return (assert->cdh.ptr); 6500afa8e06SEd Maste } 6510afa8e06SEd Maste 6520afa8e06SEd Maste size_t 6530afa8e06SEd Maste fido_assert_clientdata_hash_len(const fido_assert_t *assert) 6540afa8e06SEd Maste { 6550afa8e06SEd Maste return (assert->cdh.len); 6560afa8e06SEd Maste } 6570afa8e06SEd Maste 6580afa8e06SEd Maste fido_assert_t * 6590afa8e06SEd Maste fido_assert_new(void) 6600afa8e06SEd Maste { 6610afa8e06SEd Maste return (calloc(1, sizeof(fido_assert_t))); 6620afa8e06SEd Maste } 6630afa8e06SEd Maste 6640afa8e06SEd Maste void 6650afa8e06SEd Maste fido_assert_reset_tx(fido_assert_t *assert) 6660afa8e06SEd Maste { 6670afa8e06SEd Maste free(assert->rp_id); 6680afa8e06SEd Maste fido_blob_reset(&assert->cd); 6690afa8e06SEd Maste fido_blob_reset(&assert->cdh); 6700afa8e06SEd Maste fido_blob_reset(&assert->ext.hmac_salt); 6710afa8e06SEd Maste fido_free_blob_array(&assert->allow_list); 6720afa8e06SEd Maste memset(&assert->ext, 0, sizeof(assert->ext)); 6730afa8e06SEd Maste memset(&assert->allow_list, 0, sizeof(assert->allow_list)); 6740afa8e06SEd Maste assert->rp_id = NULL; 6750afa8e06SEd Maste assert->up = FIDO_OPT_OMIT; 6760afa8e06SEd Maste assert->uv = FIDO_OPT_OMIT; 6770afa8e06SEd Maste } 6780afa8e06SEd Maste 6790afa8e06SEd Maste static void fido_assert_reset_extattr(fido_assert_extattr_t *ext) 6800afa8e06SEd Maste { 6810afa8e06SEd Maste fido_blob_reset(&ext->hmac_secret_enc); 6820afa8e06SEd Maste fido_blob_reset(&ext->blob); 6830afa8e06SEd Maste memset(ext, 0, sizeof(*ext)); 6840afa8e06SEd Maste } 6850afa8e06SEd Maste 6860afa8e06SEd Maste void 6870afa8e06SEd Maste fido_assert_reset_rx(fido_assert_t *assert) 6880afa8e06SEd Maste { 6890afa8e06SEd Maste for (size_t i = 0; i < assert->stmt_cnt; i++) { 6900afa8e06SEd Maste free(assert->stmt[i].user.icon); 6910afa8e06SEd Maste free(assert->stmt[i].user.name); 6920afa8e06SEd Maste free(assert->stmt[i].user.display_name); 6930afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].user.id); 6940afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].id); 6950afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].hmac_secret); 6960afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].authdata_cbor); 6970afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].largeblob_key); 6980afa8e06SEd Maste fido_blob_reset(&assert->stmt[i].sig); 6990afa8e06SEd Maste fido_assert_reset_extattr(&assert->stmt[i].authdata_ext); 7000afa8e06SEd Maste memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); 7010afa8e06SEd Maste } 7020afa8e06SEd Maste free(assert->stmt); 7030afa8e06SEd Maste assert->stmt = NULL; 7040afa8e06SEd Maste assert->stmt_len = 0; 7050afa8e06SEd Maste assert->stmt_cnt = 0; 7060afa8e06SEd Maste } 7070afa8e06SEd Maste 7080afa8e06SEd Maste void 7090afa8e06SEd Maste fido_assert_free(fido_assert_t **assert_p) 7100afa8e06SEd Maste { 7110afa8e06SEd Maste fido_assert_t *assert; 7120afa8e06SEd Maste 7130afa8e06SEd Maste if (assert_p == NULL || (assert = *assert_p) == NULL) 7140afa8e06SEd Maste return; 7150afa8e06SEd Maste fido_assert_reset_tx(assert); 7160afa8e06SEd Maste fido_assert_reset_rx(assert); 7170afa8e06SEd Maste free(assert); 7180afa8e06SEd Maste *assert_p = NULL; 7190afa8e06SEd Maste } 7200afa8e06SEd Maste 7210afa8e06SEd Maste size_t 7220afa8e06SEd Maste fido_assert_count(const fido_assert_t *assert) 7230afa8e06SEd Maste { 7240afa8e06SEd Maste return (assert->stmt_len); 7250afa8e06SEd Maste } 7260afa8e06SEd Maste 7270afa8e06SEd Maste const char * 7280afa8e06SEd Maste fido_assert_rp_id(const fido_assert_t *assert) 7290afa8e06SEd Maste { 7300afa8e06SEd Maste return (assert->rp_id); 7310afa8e06SEd Maste } 7320afa8e06SEd Maste 7330afa8e06SEd Maste uint8_t 7340afa8e06SEd Maste fido_assert_flags(const fido_assert_t *assert, size_t idx) 7350afa8e06SEd Maste { 7360afa8e06SEd Maste if (idx >= assert->stmt_len) 7370afa8e06SEd Maste return (0); 7380afa8e06SEd Maste 7390afa8e06SEd Maste return (assert->stmt[idx].authdata.flags); 7400afa8e06SEd Maste } 7410afa8e06SEd Maste 7420afa8e06SEd Maste uint32_t 7430afa8e06SEd Maste fido_assert_sigcount(const fido_assert_t *assert, size_t idx) 7440afa8e06SEd Maste { 7450afa8e06SEd Maste if (idx >= assert->stmt_len) 7460afa8e06SEd Maste return (0); 7470afa8e06SEd Maste 7480afa8e06SEd Maste return (assert->stmt[idx].authdata.sigcount); 7490afa8e06SEd Maste } 7500afa8e06SEd Maste 7510afa8e06SEd Maste const unsigned char * 7520afa8e06SEd Maste fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) 7530afa8e06SEd Maste { 7540afa8e06SEd Maste if (idx >= assert->stmt_len) 7550afa8e06SEd Maste return (NULL); 7560afa8e06SEd Maste 7570afa8e06SEd Maste return (assert->stmt[idx].authdata_cbor.ptr); 7580afa8e06SEd Maste } 7590afa8e06SEd Maste 7600afa8e06SEd Maste size_t 7610afa8e06SEd Maste fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) 7620afa8e06SEd Maste { 7630afa8e06SEd Maste if (idx >= assert->stmt_len) 7640afa8e06SEd Maste return (0); 7650afa8e06SEd Maste 7660afa8e06SEd Maste return (assert->stmt[idx].authdata_cbor.len); 7670afa8e06SEd Maste } 7680afa8e06SEd Maste 7690afa8e06SEd Maste const unsigned char * 7700afa8e06SEd Maste fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) 7710afa8e06SEd Maste { 7720afa8e06SEd Maste if (idx >= assert->stmt_len) 7730afa8e06SEd Maste return (NULL); 7740afa8e06SEd Maste 7750afa8e06SEd Maste return (assert->stmt[idx].sig.ptr); 7760afa8e06SEd Maste } 7770afa8e06SEd Maste 7780afa8e06SEd Maste size_t 7790afa8e06SEd Maste fido_assert_sig_len(const fido_assert_t *assert, size_t idx) 7800afa8e06SEd Maste { 7810afa8e06SEd Maste if (idx >= assert->stmt_len) 7820afa8e06SEd Maste return (0); 7830afa8e06SEd Maste 7840afa8e06SEd Maste return (assert->stmt[idx].sig.len); 7850afa8e06SEd Maste } 7860afa8e06SEd Maste 7870afa8e06SEd Maste const unsigned char * 7880afa8e06SEd Maste fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) 7890afa8e06SEd Maste { 7900afa8e06SEd Maste if (idx >= assert->stmt_len) 7910afa8e06SEd Maste return (NULL); 7920afa8e06SEd Maste 7930afa8e06SEd Maste return (assert->stmt[idx].id.ptr); 7940afa8e06SEd Maste } 7950afa8e06SEd Maste 7960afa8e06SEd Maste size_t 7970afa8e06SEd Maste fido_assert_id_len(const fido_assert_t *assert, size_t idx) 7980afa8e06SEd Maste { 7990afa8e06SEd Maste if (idx >= assert->stmt_len) 8000afa8e06SEd Maste return (0); 8010afa8e06SEd Maste 8020afa8e06SEd Maste return (assert->stmt[idx].id.len); 8030afa8e06SEd Maste } 8040afa8e06SEd Maste 8050afa8e06SEd Maste const unsigned char * 8060afa8e06SEd Maste fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) 8070afa8e06SEd Maste { 8080afa8e06SEd Maste if (idx >= assert->stmt_len) 8090afa8e06SEd Maste return (NULL); 8100afa8e06SEd Maste 8110afa8e06SEd Maste return (assert->stmt[idx].user.id.ptr); 8120afa8e06SEd Maste } 8130afa8e06SEd Maste 8140afa8e06SEd Maste size_t 8150afa8e06SEd Maste fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) 8160afa8e06SEd Maste { 8170afa8e06SEd Maste if (idx >= assert->stmt_len) 8180afa8e06SEd Maste return (0); 8190afa8e06SEd Maste 8200afa8e06SEd Maste return (assert->stmt[idx].user.id.len); 8210afa8e06SEd Maste } 8220afa8e06SEd Maste 8230afa8e06SEd Maste const char * 8240afa8e06SEd Maste fido_assert_user_icon(const fido_assert_t *assert, size_t idx) 8250afa8e06SEd Maste { 8260afa8e06SEd Maste if (idx >= assert->stmt_len) 8270afa8e06SEd Maste return (NULL); 8280afa8e06SEd Maste 8290afa8e06SEd Maste return (assert->stmt[idx].user.icon); 8300afa8e06SEd Maste } 8310afa8e06SEd Maste 8320afa8e06SEd Maste const char * 8330afa8e06SEd Maste fido_assert_user_name(const fido_assert_t *assert, size_t idx) 8340afa8e06SEd Maste { 8350afa8e06SEd Maste if (idx >= assert->stmt_len) 8360afa8e06SEd Maste return (NULL); 8370afa8e06SEd Maste 8380afa8e06SEd Maste return (assert->stmt[idx].user.name); 8390afa8e06SEd Maste } 8400afa8e06SEd Maste 8410afa8e06SEd Maste const char * 8420afa8e06SEd Maste fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) 8430afa8e06SEd Maste { 8440afa8e06SEd Maste if (idx >= assert->stmt_len) 8450afa8e06SEd Maste return (NULL); 8460afa8e06SEd Maste 8470afa8e06SEd Maste return (assert->stmt[idx].user.display_name); 8480afa8e06SEd Maste } 8490afa8e06SEd Maste 8500afa8e06SEd Maste const unsigned char * 8510afa8e06SEd Maste fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) 8520afa8e06SEd Maste { 8530afa8e06SEd Maste if (idx >= assert->stmt_len) 8540afa8e06SEd Maste return (NULL); 8550afa8e06SEd Maste 8560afa8e06SEd Maste return (assert->stmt[idx].hmac_secret.ptr); 8570afa8e06SEd Maste } 8580afa8e06SEd Maste 8590afa8e06SEd Maste size_t 8600afa8e06SEd Maste fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) 8610afa8e06SEd Maste { 8620afa8e06SEd Maste if (idx >= assert->stmt_len) 8630afa8e06SEd Maste return (0); 8640afa8e06SEd Maste 8650afa8e06SEd Maste return (assert->stmt[idx].hmac_secret.len); 8660afa8e06SEd Maste } 8670afa8e06SEd Maste 8680afa8e06SEd Maste const unsigned char * 8690afa8e06SEd Maste fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx) 8700afa8e06SEd Maste { 8710afa8e06SEd Maste if (idx >= assert->stmt_len) 8720afa8e06SEd Maste return (NULL); 8730afa8e06SEd Maste 8740afa8e06SEd Maste return (assert->stmt[idx].largeblob_key.ptr); 8750afa8e06SEd Maste } 8760afa8e06SEd Maste 8770afa8e06SEd Maste size_t 8780afa8e06SEd Maste fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx) 8790afa8e06SEd Maste { 8800afa8e06SEd Maste if (idx >= assert->stmt_len) 8810afa8e06SEd Maste return (0); 8820afa8e06SEd Maste 8830afa8e06SEd Maste return (assert->stmt[idx].largeblob_key.len); 8840afa8e06SEd Maste } 8850afa8e06SEd Maste 8860afa8e06SEd Maste const unsigned char * 8870afa8e06SEd Maste fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx) 8880afa8e06SEd Maste { 8890afa8e06SEd Maste if (idx >= assert->stmt_len) 8900afa8e06SEd Maste return (NULL); 8910afa8e06SEd Maste 8920afa8e06SEd Maste return (assert->stmt[idx].authdata_ext.blob.ptr); 8930afa8e06SEd Maste } 8940afa8e06SEd Maste 8950afa8e06SEd Maste size_t 8960afa8e06SEd Maste fido_assert_blob_len(const fido_assert_t *assert, size_t idx) 8970afa8e06SEd Maste { 8980afa8e06SEd Maste if (idx >= assert->stmt_len) 8990afa8e06SEd Maste return (0); 9000afa8e06SEd Maste 9010afa8e06SEd Maste return (assert->stmt[idx].authdata_ext.blob.len); 9020afa8e06SEd Maste } 9030afa8e06SEd Maste 9040afa8e06SEd Maste static void 9050afa8e06SEd Maste fido_assert_clean_authdata(fido_assert_stmt *stmt) 9060afa8e06SEd Maste { 9070afa8e06SEd Maste fido_blob_reset(&stmt->authdata_cbor); 9080afa8e06SEd Maste fido_assert_reset_extattr(&stmt->authdata_ext); 9090afa8e06SEd Maste memset(&stmt->authdata, 0, sizeof(stmt->authdata)); 9100afa8e06SEd Maste } 9110afa8e06SEd Maste 9120afa8e06SEd Maste int 9130afa8e06SEd Maste fido_assert_set_authdata(fido_assert_t *assert, size_t idx, 9140afa8e06SEd Maste const unsigned char *ptr, size_t len) 9150afa8e06SEd Maste { 9160afa8e06SEd Maste cbor_item_t *item = NULL; 9170afa8e06SEd Maste fido_assert_stmt *stmt = NULL; 9180afa8e06SEd Maste struct cbor_load_result cbor; 9190afa8e06SEd Maste int r; 9200afa8e06SEd Maste 9210afa8e06SEd Maste if (idx >= assert->stmt_len || ptr == NULL || len == 0) 9220afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 9230afa8e06SEd Maste 9240afa8e06SEd Maste stmt = &assert->stmt[idx]; 9250afa8e06SEd Maste fido_assert_clean_authdata(stmt); 9260afa8e06SEd Maste 9270afa8e06SEd Maste if ((item = cbor_load(ptr, len, &cbor)) == NULL) { 9280afa8e06SEd Maste fido_log_debug("%s: cbor_load", __func__); 9290afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 9300afa8e06SEd Maste goto fail; 9310afa8e06SEd Maste } 9320afa8e06SEd Maste 9330afa8e06SEd Maste if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 9340afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext) < 0) { 9350afa8e06SEd Maste fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 9360afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 9370afa8e06SEd Maste goto fail; 9380afa8e06SEd Maste } 9390afa8e06SEd Maste 9400afa8e06SEd Maste r = FIDO_OK; 9410afa8e06SEd Maste fail: 9420afa8e06SEd Maste if (item != NULL) 9430afa8e06SEd Maste cbor_decref(&item); 9440afa8e06SEd Maste 9450afa8e06SEd Maste if (r != FIDO_OK) 9460afa8e06SEd Maste fido_assert_clean_authdata(stmt); 9470afa8e06SEd Maste 9480afa8e06SEd Maste return (r); 9490afa8e06SEd Maste } 9500afa8e06SEd Maste 9510afa8e06SEd Maste int 9520afa8e06SEd Maste fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, 9530afa8e06SEd Maste const unsigned char *ptr, size_t len) 9540afa8e06SEd Maste { 9550afa8e06SEd Maste cbor_item_t *item = NULL; 9560afa8e06SEd Maste fido_assert_stmt *stmt = NULL; 9570afa8e06SEd Maste int r; 9580afa8e06SEd Maste 9590afa8e06SEd Maste if (idx >= assert->stmt_len || ptr == NULL || len == 0) 9600afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 9610afa8e06SEd Maste 9620afa8e06SEd Maste stmt = &assert->stmt[idx]; 9630afa8e06SEd Maste fido_assert_clean_authdata(stmt); 9640afa8e06SEd Maste 9650afa8e06SEd Maste if ((item = cbor_build_bytestring(ptr, len)) == NULL) { 9660afa8e06SEd Maste fido_log_debug("%s: cbor_build_bytestring", __func__); 9670afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 9680afa8e06SEd Maste goto fail; 9690afa8e06SEd Maste } 9700afa8e06SEd Maste 9710afa8e06SEd Maste if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, 9720afa8e06SEd Maste &stmt->authdata, &stmt->authdata_ext) < 0) { 9730afa8e06SEd Maste fido_log_debug("%s: cbor_decode_assert_authdata", __func__); 9740afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 9750afa8e06SEd Maste goto fail; 9760afa8e06SEd Maste } 9770afa8e06SEd Maste 9780afa8e06SEd Maste r = FIDO_OK; 9790afa8e06SEd Maste fail: 9800afa8e06SEd Maste if (item != NULL) 9810afa8e06SEd Maste cbor_decref(&item); 9820afa8e06SEd Maste 9830afa8e06SEd Maste if (r != FIDO_OK) 9840afa8e06SEd Maste fido_assert_clean_authdata(stmt); 9850afa8e06SEd Maste 9860afa8e06SEd Maste return (r); 9870afa8e06SEd Maste } 9880afa8e06SEd Maste 9890afa8e06SEd Maste int 9900afa8e06SEd Maste fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, 9910afa8e06SEd Maste size_t len) 9920afa8e06SEd Maste { 9930afa8e06SEd Maste if (idx >= a->stmt_len || ptr == NULL || len == 0) 9940afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT); 9950afa8e06SEd Maste if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0) 9960afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 9970afa8e06SEd Maste 9980afa8e06SEd Maste return (FIDO_OK); 9990afa8e06SEd Maste } 10000afa8e06SEd Maste 10010afa8e06SEd Maste /* XXX shrinking leaks memory; fortunately that shouldn't happen */ 10020afa8e06SEd Maste int 10030afa8e06SEd Maste fido_assert_set_count(fido_assert_t *assert, size_t n) 10040afa8e06SEd Maste { 10050afa8e06SEd Maste void *new_stmt; 10060afa8e06SEd Maste 10070afa8e06SEd Maste #ifdef FIDO_FUZZ 10080afa8e06SEd Maste if (n > UINT8_MAX) { 10090afa8e06SEd Maste fido_log_debug("%s: n > UINT8_MAX", __func__); 10100afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 10110afa8e06SEd Maste } 10120afa8e06SEd Maste #endif 10130afa8e06SEd Maste 10140afa8e06SEd Maste new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, 10150afa8e06SEd Maste sizeof(fido_assert_stmt)); 10160afa8e06SEd Maste if (new_stmt == NULL) 10170afa8e06SEd Maste return (FIDO_ERR_INTERNAL); 10180afa8e06SEd Maste 10190afa8e06SEd Maste assert->stmt = new_stmt; 10200afa8e06SEd Maste assert->stmt_cnt = n; 10210afa8e06SEd Maste assert->stmt_len = n; 10220afa8e06SEd Maste 10230afa8e06SEd Maste return (FIDO_OK); 10240afa8e06SEd Maste } 1025