## Coverage Report

#### Created: 2023-09-23 17:42

    /libfido2/src/assert.c

    Line
    Count
    Source (jump to first uncovered line)
    1
    /*
    2
     * Copyright (c) 2018-2023 Yubico AB. All rights reserved.
    3
     * Use of this source code is governed by a BSD-style
    4
     * license that can be found in the LICENSE file.
    5
     * SPDX-License-Identifier: BSD-2-Clause
    6
     */
    7
    8
    #include <openssl/sha.h>
    9
    10
    #include "fido.h"
    11
    #include "fido/es256.h"
    12
    #include "fido/rs256.h"
    13
    #include "fido/eddsa.h"
    14
    15
    static int
    16
    adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    17
    892
    {
    18
    892
            fido_assert_t   *assert = arg;
    19
    892
            uint64_t         n;
    20
    21
            /* numberOfCredentials; see section 6.2 */
    22
    892
            if (cbor_isa_uint(key) == false ||
    23
    892
                cbor_int_get_width(key) != CBOR_INT_8 ||
    24
    892
                cbor_get_uint8(key) != 5) {
    25
    760
                    fido_log_debug("%s: cbor_type", __func__);
    26
    760
                    return (0); /* ignore */
    27
    760
            }
    28
    29
    132
            if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
    30
    1
                    fido_log_debug("%s: cbor_decode_uint64", __func__);
    31
    1
                    return (-1);
    32
    1
            }
    33
    34
    131
            if (assert->stmt_len != 0 || assert->stmt_cnt != 1 ||
    35
    131
                (size_t)n < assert->stmt_cnt) {
    36
    1
                    fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu",
    37
    1
                        __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n);
    38
    1
                    return (-1);
    39
    1
            }
    40
    41
    130
            if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) {
    42
    39
                    fido_log_debug("%s: fido_assert_set_count", __func__);
    43
    39
                    return (-1);
    44
    39
            }
    45
    46
    91
            assert->stmt_len = 0; /* XXX */
    47
    48
    91
            return (0);
    49
    130
    }
    50
    51
    static int
    52
    parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    53
    1.62k
    {
    54
    1.62k
            fido_assert_stmt *stmt = arg;
    55
    56
    1.62k
            if (cbor_isa_uint(key) == false ||
    57
    1.62k
                cbor_int_get_width(key) != CBOR_INT_8) {
    58
    66
                    fido_log_debug("%s: cbor type", __func__);
    59
    66
                    return (0); /* ignore */
    60
    66
            }
    61
    62
    1.56k
            switch (cbor_get_uint8(key)) {
    63
    415
            case 1: /* credential id */
    64
    415
                    return (cbor_decode_cred_id(val, &stmt->id));
    65
    371
            case 2: /* authdata */
    66
    371
                    if (fido_blob_decode(val, &stmt->authdata_raw) < 0) {
    67
    3
                            fido_log_debug("%s: fido_blob_decode", __func__);
    68
    3
                            return (-1);
    69
    3
                    }
    70
    368
                    return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor,
    71
    368
                        &stmt->authdata, &stmt->authdata_ext));
    72
    343
            case 3: /* signature */
    73
    343
                    return (fido_blob_decode(val, &stmt->sig));
    74
    311
            case 4: /* user attributes */
    75
    311
                    return (cbor_decode_user(val, &stmt->user));
    76
    1
            case 7: /* large blob key */
    77
    1
                    return (fido_blob_decode(val, &stmt->largeblob_key));
    78
    119
            default: /* ignore */
    79
    119
                    fido_log_debug("%s: cbor type", __func__);
    80
    119
                    return (0);
    81
    1.56k
            }
    82
    1.56k
    }
    83
    84
    static int
    85
    fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
    86
        const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
    87
    615
    {
    88
    615
            fido_blob_t      f;
    89
    615
            fido_opt_t       uv = assert->uv;
    90
    615
            cbor_item_t     *argv[7];
    91
    615
            const uint8_t    cmd = CTAP_CBOR_ASSERT;
    92
    615
            int              r;
    93
    94
    615
            memset(argv, 0, sizeof(argv));
    95
    615
            memset(&f, 0, sizeof(f));
    96
    97
            /* do we have everything we need? */
    98
    615
            if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
    99
    0
                    fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
    100
    0
                        (void *)assert->rp_id, (void *)assert->cdh.ptr);
    101
    0
                    r = FIDO_ERR_INVALID_ARGUMENT;
    102
    0
                    goto fail;
    103
    0
            }
    104
    105
    615
            if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL ||
    106
    615
                (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) {
    107
    3
                    fido_log_debug("%s: cbor encode", __func__);
    108
    3
                    r = FIDO_ERR_INTERNAL;
    109
    3
                    goto fail;
    110
    3
            }
    111
    112
            /* allowed credentials */
    113
    612
            if (assert->allow_list.len) {
    114
    351
                    const fido_blob_array_t *cl = &assert->allow_list;
    115
    351
                    if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) {
    116
    22
                            fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
    117
    22
                            r = FIDO_ERR_INTERNAL;
    118
    22
                            goto fail;
    119
    22
                    }
    120
    351
            }
    121
    122
    590
            if (assert->ext.mask)
    123
    316
                    if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh,
    124
    316
                        pk)) == NULL) {
    125
    23
                            fido_log_debug("%s: cbor_encode_assert_ext", __func__);
    126
    23
                            r = FIDO_ERR_INTERNAL;
    127
    23
                            goto fail;
    128
    23
                    }
    129
    130
            /* user verification */
    131
    567
            if (pin != NULL || (uv == FIDO_OPT_TRUE &&
    132
    380
                fido_dev_supports_permissions(dev))) {
    133
    200
                    if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
    134
    200
                        pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) {
    135
    116
                            fido_log_debug("%s: cbor_add_uv_params", __func__);
    136
    116
                            goto fail;
    137
    116
                    }
    138
    84
                    uv = FIDO_OPT_OMIT;
    139
    84
            }
    140
    141
            /* options */
    142
    451
            if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
    143
    232
                    if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) {
    144
    4
                            fido_log_debug("%s: cbor_encode_assert_opt", __func__);
    145
    4
                            r = FIDO_ERR_INTERNAL;
    146
    4
                            goto fail;
    147
    4
                    }
    148
    149
            /* frame and transmit */
    150
    447
            if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
    151
    447
                fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    152
    100
                    fido_log_debug("%s: fido_tx", __func__);
    153
    100
                    r = FIDO_ERR_TX;
    154
    100
                    goto fail;
    155
    100
            }
    156
    157
    347
            r = FIDO_OK;
    158
    615
    fail:
    159
    615
            cbor_vector_free(argv, nitems(argv));
    160
    615
            free(f.ptr);
    161
    162
    615
            return (r);
    163
    347
    }
    164
    165
    static int
    166
    fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
    167
    347
    {
    168
    347
            unsigned char   *msg;
    169
    347
            int              msglen;
    170
    347
            int              r;
    171
    172
    347
            fido_assert_reset_rx(assert);
    173
    174
    347
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    175
    2
                    r = FIDO_ERR_INTERNAL;
    176
    2
                    goto out;
    177
    2
            }
    178
    179
    345
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    180
    46
                    fido_log_debug("%s: fido_rx", __func__);
    181
    46
                    r = FIDO_ERR_RX;
    182
    46
                    goto out;
    183
    46
            }
    184
    185
            /* start with room for a single assertion */
    186
    299
            if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) {
    187
    1
                    r = FIDO_ERR_INTERNAL;
    188
    1
                    goto out;
    189
    1
            }
    190
    298
            assert->stmt_len = 0;
    191
    298
            assert->stmt_cnt = 1;
    192
    193
            /* adjust as needed */
    194
    298
            if ((r = cbor_parse_reply(msg, (size_t)msglen, assert,
    195
    298
                adjust_assert_count)) != FIDO_OK) {
    196
    75
                    fido_log_debug("%s: adjust_assert_count", __func__);
    197
    75
                    goto out;
    198
    75
            }
    199
    200
            /* parse the first assertion */
    201
    223
            if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[0],
    202
    223
                parse_assert_reply)) != FIDO_OK) {
    203
    30
                    fido_log_debug("%s: parse_assert_reply", __func__);
    204
    30
                    goto out;
    205
    30
            }
    206
    193
            assert->stmt_len = 1;
    207
    208
    193
            r = FIDO_OK;
    209
    347
    out:
    210
    347
            freezero(msg, FIDO_MAXMSG);
    211
    212
    347
            return (r);
    213
    193
    }
    214
    215
    static int
    216
    fido_get_next_assert_tx(fido_dev_t *dev, int *ms)
    217
    263
    {
    218
    263
            const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT };
    219
    220
    263
            if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
    221
    3
                    fido_log_debug("%s: fido_tx", __func__);
    222
    3
                    return (FIDO_ERR_TX);
    223
    3
            }
    224
    225
    260
            return (FIDO_OK);
    226
    263
    }
    227
    228
    static int
    229
    fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
    230
    260
    {
    231
    260
            unsigned char   *msg;
    232
    260
            int              msglen;
    233
    260
            int              r;
    234
    235
    260
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    236
    1
                    r = FIDO_ERR_INTERNAL;
    237
    1
                    goto out;
    238
    1
            }
    239
    240
    259
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    241
    11
                    fido_log_debug("%s: fido_rx", __func__);
    242
    11
                    r = FIDO_ERR_RX;
    243
    11
                    goto out;
    244
    11
            }
    245
    246
            /* sanity check */
    247
    248
            if (assert->stmt_len >= assert->stmt_cnt) {
    248
    0
                    fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__,
    249
    0
                        assert->stmt_len, assert->stmt_cnt);
    250
    0
                    r = FIDO_ERR_INTERNAL;
    251
    0
                    goto out;
    252
    0
            }
    253
    254
    248
            if ((r = cbor_parse_reply(msg, (size_t)msglen,
    255
    248
                &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
    256
    31
                    fido_log_debug("%s: parse_assert_reply", __func__);
    257
    31
                    goto out;
    258
    31
            }
    259
    260
    217
            r = FIDO_OK;
    261
    260
    out:
    262
    260
            freezero(msg, FIDO_MAXMSG);
    263
    264
    260
            return (r);
    265
    217
    }
    266
    267
    static int
    268
    fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
    269
        const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
    270
    615
    {
    271
    615
            int r;
    272
    273
    615
            if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin,
    274
    615
                ms)) != FIDO_OK ||
    275
    615
                (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
    276
    422
                    return (r);
    277
    278
    410
            while (assert->stmt_len < assert->stmt_cnt) {
    279
    263
                    if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK ||
    280
    263
                        (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
    281
    46
                            return (r);
    282
    217
                    assert->stmt_len++;
    283
    217
            }
    284
    285
    147
            return (FIDO_OK);
    286
    193
    }
    287
    288
    static int
    289
    decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert,
    290
        const fido_blob_t *key)
    291
    19
    {
    292
    70
            for (size_t i = 0; i < assert->stmt_cnt; i++) {
    293
    58
                    fido_assert_stmt *stmt = &assert->stmt[i];
    294
    58
                    if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) {
    295
    37
                            if (aes256_cbc_dec(dev, key,
    296
    37
                                &stmt->authdata_ext.hmac_secret_enc,
    297
    37
                                &stmt->hmac_secret) < 0) {
    298
    7
                                    fido_log_debug("%s: aes256_cbc_dec %zu",
    299
    7
                                        __func__, i);
    300
    7
                                    return (-1);
    301
    7
                            }
    302
    37
                    }
    303
    58
            }
    304
    305
    12
            return (0);
    306
    19
    }
    307
    308
    int
    309
    fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
    310
    1.71k
    {
    311
    1.71k
            fido_blob_t     *ecdh = NULL;
    312
    1.71k
            es256_pk_t      *pk = NULL;
    313
    1.71k
            int              ms = dev->timeout_ms;
    314
    1.71k
            int              r;
    315
    316
    #ifdef USE_WINHELLO
    317
            if (dev->flags & FIDO_DEV_WINHELLO)
    318
                    return (fido_winhello_get_assert(dev, assert, pin, ms));
    319
    #endif
    320
    321
    1.71k
            if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
    322
    11
                    fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
    323
    11
                        (void *)assert->rp_id, (void *)assert->cdh.ptr);
    324
    11
                    return (FIDO_ERR_INVALID_ARGUMENT);
    325
    11
            }
    326
    327
    1.70k
            if (fido_dev_is_fido2(dev) == false) {
    328
    928
                    if (pin != NULL || assert->ext.mask != 0)
    329
    226
                            return (FIDO_ERR_UNSUPPORTED_OPTION);
    330
    702
                    return (u2f_authenticate(dev, assert, &ms));
    331
    928
            }
    332
    333
    773
            if (pin != NULL || (assert->uv == FIDO_OPT_TRUE &&
    334
    505
                fido_dev_supports_permissions(dev)) ||
    335
    773
                (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
    336
    413
                    if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
    337
    158
                            fido_log_debug("%s: fido_do_ecdh", __func__);
    338
    158
                            goto fail;
    339
    158
                    }
    340
    413
            }
    341
    342
    615
            r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms);
    343
    615
            if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET))
    344
    19
                    if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) {
    345
    7
                            fido_log_debug("%s: decrypt_hmac_secrets", __func__);
    346
    7
                            r = FIDO_ERR_INTERNAL;
    347
    7
                            goto fail;
    348
    7
                    }
    349
    350
    773
    fail:
    351
    773
            es256_pk_free(&pk);
    352
    773
            fido_blob_free(&ecdh);
    353
    354
    773
            return (r);
    355
    615
    }
    356
    357
    int
    358
    fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv)
    359
    618
    {
    360
    618
            fido_log_debug("%s: flags=%02x", __func__, flags);
    361
    618
            fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv);
    362
    363
    618
            if (up == FIDO_OPT_TRUE &&
    364
    618
                (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) {
    365
    17
                    fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__);
    366
    17
                    return (-1); /* user not present */
    367
    17
            }
    368
    369
    601
            if (uv == FIDO_OPT_TRUE &&
    370
    601
                (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) {
    371
    35
                    fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__);
    372
    35
                    return (-1); /* user not verified */
    373
    35
            }
    374
    375
    566
            return (0);
    376
    601
    }
    377
    378
    static int
    379
    check_extensions(int authdata_ext, int ext)
    380
    381
    {
    381
            /* XXX: largeBlobKey is not part of extensions map */
    382
    381
            ext &= ~FIDO_EXT_LARGEBLOB_KEY;
    383
    381
            if (authdata_ext != ext) {
    384
    47
                    fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
    385
    47
                        authdata_ext, ext);
    386
    47
                    return (-1);
    387
    47
            }
    388
    389
    334
            return (0);
    390
    381
    }
    391
    392
    static int
    393
    get_es256_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
    394
        const fido_blob_t *authdata)
    395
    162
    {
    396
    162
            const EVP_MD    *md;
    397
    162
            EVP_MD_CTX      *ctx = NULL;
    398
    399
    162
            if (dgst->len < SHA256_DIGEST_LENGTH ||
    400
    162
                (md = EVP_sha256()) == NULL ||
    401
    162
                (ctx = EVP_MD_CTX_new()) == NULL ||
    402
    162
                EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
    403
    162
                EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
    404
    162
                EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
    405
    162
                EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
    406
    26
                    EVP_MD_CTX_free(ctx);
    407
    26
                    return (-1);
    408
    26
            }
    409
    136
            dgst->len = SHA256_DIGEST_LENGTH;
    410
    411
    136
            EVP_MD_CTX_free(ctx);
    412
    413
    136
            return (0);
    414
    162
    }
    415
    416
    static int
    417
    get_es384_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
    418
        const fido_blob_t *authdata)
    419
    81
    {
    420
    81
            const EVP_MD    *md;
    421
    81
            EVP_MD_CTX      *ctx = NULL;
    422
    423
    81
            if (dgst->len < SHA384_DIGEST_LENGTH ||
    424
    81
                (md = EVP_sha384()) == NULL ||
    425
    81
                (ctx = EVP_MD_CTX_new()) == NULL ||
    426
    81
                EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
    427
    81
                EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
    428
    81
                EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
    429
    81
                EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
    430
    15
                    EVP_MD_CTX_free(ctx);
    431
    15
                    return (-1);
    432
    15
            }
    433
    66
            dgst->len = SHA384_DIGEST_LENGTH;
    434
    435
    66
            EVP_MD_CTX_free(ctx);
    436
    437
    66
            return (0);
    438
    81
    }
    439
    440
    static int
    441
    get_eddsa_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
    442
        const fido_blob_t *authdata)
    443
    125
    {
    444
    125
            if (SIZE_MAX - authdata->len < clientdata->len ||
    445
    125
                dgst->len < authdata->len + clientdata->len)
    446
    12
                    return (-1);
    447
    448
    113
            memcpy(dgst->ptr, authdata->ptr, authdata->len);
    449
    113
            memcpy(dgst->ptr + authdata->len, clientdata->ptr, clientdata->len);
    450
    113
            dgst->len = authdata->len + clientdata->len;
    451
    452
    113
            return (0);
    453
    125
    }
    454
    455
    int
    456
    fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
    457
        const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor)
    458
    374
    {
    459
    374
            cbor_item_t             *item = NULL;
    460
    374
            fido_blob_t              authdata;
    461
    374
            struct cbor_load_result  cbor;
    462
    374
            int                      ok = -1;
    463
    464
    374
            fido_log_debug("%s: cose_alg=%d", __func__, cose_alg);
    465
    466
    374
            if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
    467
    374
                &cbor)) == NULL || cbor_isa_bytestring(item) == false ||
    468
    374
                cbor_bytestring_is_definite(item) == false) {
    469
    6
                    fido_log_debug("%s: authdata", __func__);
    470
    6
                    goto fail;
    471
    6
            }
    472
    368
            authdata.ptr = cbor_bytestring_handle(item);
    473
    368
            authdata.len = cbor_bytestring_length(item);
    474
    475
    368
            switch (cose_alg) {
    476
    72
            case COSE_ES256:
    477
    162
            case COSE_RS256:
    478
    162
                    ok = get_es256_hash(dgst, clientdata, &authdata);
    479
    162
                    break;
    480
    81
            case COSE_ES384:
    481
    81
                    ok = get_es384_hash(dgst, clientdata, &authdata);
    482
    81
                    break;
    483
    125
            case COSE_EDDSA:
    484
    125
                    ok = get_eddsa_hash(dgst, clientdata, &authdata);
    485
    125
                    break;
    486
    0
            default:
    487
    0
                    fido_log_debug("%s: unknown cose_alg", __func__);
    488
    0
                    break;
    489
    368
            }
    490
    374
    fail:
    491
    374
            if (item != NULL)
    492
    368
                    cbor_decref(&item);
    493
    494
    374
            return (ok);
    495
    368
    }
    496
    497
    int
    498
    fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
    499
        const void *pk)
    500
    37.5k
    {
    501
    37.5k
            unsigned char            buf[1024]; /* XXX */
    502
    37.5k
            fido_blob_t              dgst;
    503
    37.5k
            const fido_assert_stmt  *stmt = NULL;
    504
    37.5k
            int                      ok = -1;
    505
    37.5k
            int                      r;
    506
    507
    37.5k
            dgst.ptr = buf;
    508
    37.5k
            dgst.len = sizeof(buf);
    509
    510
    37.5k
            if (idx >= assert->stmt_len || pk == NULL) {
    511
    119
                    r = FIDO_ERR_INVALID_ARGUMENT;
    512
    119
                    goto out;
    513
    119
            }
    514
    515
    37.4k
            stmt = &assert->stmt[idx];
    516
    517
            /* do we have everything we need? */
    518
    37.4k
            if (assert->cdh.ptr == NULL || assert->rp_id == NULL ||
    519
    37.4k
                stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) {
    520
    36.9k
                    fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p",
    521
    36.9k
                        __func__, (void *)assert->cdh.ptr, assert->rp_id,
    522
    36.9k
                        (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr);
    523
    36.9k
                    r = FIDO_ERR_INVALID_ARGUMENT;
    524
    36.9k
                    goto out;
    525
    36.9k
            }
    526
    527
    429
            if (fido_check_flags(stmt->authdata.flags, assert->up,
    528
    429
                assert->uv) < 0) {
    529
    48
                    fido_log_debug("%s: fido_check_flags", __func__);
    530
    48
                    r = FIDO_ERR_INVALID_PARAM;
    531
    48
                    goto out;
    532
    48
            }
    533
    534
    381
            if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) {
    535
    47
                    fido_log_debug("%s: check_extensions", __func__);
    536
    47
                    r = FIDO_ERR_INVALID_PARAM;
    537
    47
                    goto out;
    538
    47
            }
    539
    540
    334
            if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) {
    541
    65
                    fido_log_debug("%s: fido_check_rp_id", __func__);
    542
    65
                    r = FIDO_ERR_INVALID_PARAM;
    543
    65
                    goto out;
    544
    65
            }
    545
    546
    269
            if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh,
    547
    269
                &stmt->authdata_cbor) < 0) {
    548
    45
                    fido_log_debug("%s: fido_get_signed_hash", __func__);
    549
    45
                    r = FIDO_ERR_INTERNAL;
    550
    45
                    goto out;
    551
    45
            }
    552
    553
    224
            switch (cose_alg) {
    554
    55
            case COSE_ES256:
    555
    55
                    ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig);
    556
    55
                    break;
    557
    48
            case COSE_ES384:
    558
    48
                    ok = es384_pk_verify_sig(&dgst, pk, &stmt->sig);
    559
    48
                    break;
    560
    47
            case COSE_RS256:
    561
    47
                    ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig);
    562
    47
                    break;
    563
    74
            case COSE_EDDSA:
    564
    74
                    ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig);
    565
    74
                    break;
    566
    0
            default:
    567
    0
                    fido_log_debug("%s: unsupported cose_alg %d", __func__,
    568
    0
                        cose_alg);
    569
    0
                    r = FIDO_ERR_UNSUPPORTED_OPTION;
    570
    0
                    goto out;
    571
    224
            }
    572
    573
    224
            if (ok < 0)
    574
    224
                    r = FIDO_ERR_INVALID_SIG;
    575
    0
            else
    576
    0
                    r = FIDO_OK;
    577
    37.5k
    out:
    578
    37.5k
            explicit_bzero(buf, sizeof(buf));
    579
    580
    37.5k
            return (r);
    581
    224
    }
    582
    583
    int
    584
    fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data,
    585
        size_t data_len)
    586
    0
    {
    587
    0
            if (!fido_blob_is_empty(&assert->cdh) ||
    588
    0
                fido_blob_set(&assert->cd, data, data_len) < 0) {
    589
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    590
    0
            }
    591
    0
            if (fido_sha256(&assert->cdh, data, data_len) < 0) {
    592
    0
                    fido_blob_reset(&assert->cd);
    593
    0
                    return (FIDO_ERR_INTERNAL);
    594
    0
            }
    595
    596
    0
            return (FIDO_OK);
    597
    0
    }
    598
    599
    int
    600
    fido_assert_set_clientdata_hash(fido_assert_t *assert,
    601
        const unsigned char *hash, size_t hash_len)
    602
    40.9k
    {
    603
    40.9k
            if (!fido_blob_is_empty(&assert->cd) ||
    604
    40.9k
                fido_blob_set(&assert->cdh, hash, hash_len) < 0)
    605
    541
                    return (FIDO_ERR_INVALID_ARGUMENT);
    606
    607
    40.4k
            return (FIDO_OK);
    608
    40.9k
    }
    609
    610
    int
    611
    fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt,
    612
        size_t salt_len)
    613
    3.42k
    {
    614
    3.42k
            if ((salt_len != 32 && salt_len != 64) ||
    615
    3.42k
                fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0)
    616
    3.28k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    617
    618
    138
            return (FIDO_OK);
    619
    3.42k
    }
    620
    621
    int
    622
    fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx,
    623
        const unsigned char *secret, size_t secret_len)
    624
    0
    {
    625
    0
            if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) ||
    626
    0
                fido_blob_set(&assert->stmt[idx].hmac_secret, secret,
    627
    0
                secret_len) < 0)
    628
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    629
    630
    0
            return (FIDO_OK);
    631
    0
    }
    632
    633
    int
    634
    fido_assert_set_rp(fido_assert_t *assert, const char *id)
    635
    40.9k
    {
    636
    40.9k
            if (assert->rp_id != NULL) {
    637
    1.70k
                    free(assert->rp_id);
    638
    1.70k
                    assert->rp_id = NULL;
    639
    1.70k
            }
    640
    641
    40.9k
            if (id == NULL)
    642
    422
                    return (FIDO_ERR_INVALID_ARGUMENT);
    643
    644
    40.5k
            if ((assert->rp_id = strdup(id)) == NULL)
    645
    122
                    return (FIDO_ERR_INTERNAL);
    646
    647
    40.4k
            return (FIDO_OK);
    648
    40.5k
    }
    649
    650
    #ifdef USE_WINHELLO
    651
    int
    652
    fido_assert_set_winhello_appid(fido_assert_t *assert, const char *id)
    653
    {
    654
            if (assert->appid != NULL) {
    655
                    free(assert->appid);
    656
                    assert->appid = NULL;
    657
            }
    658
    659
            if (id == NULL)
    660
                    return (FIDO_ERR_INVALID_ARGUMENT);
    661
    662
            if ((assert->appid = strdup(id)) == NULL)
    663
                    return (FIDO_ERR_INTERNAL);
    664
    665
            return (FIDO_OK);
    666
    }
    667
    #else
    668
    int
    669
    fido_assert_set_winhello_appid(fido_assert_t *assert, const char *id)
    670
    0
    {
    671
    0
            (void)assert;
    672
    0
            (void)id;
    673
    674
    0
            return (FIDO_ERR_UNSUPPORTED_EXTENSION);
    675
    0
    }
    676
    #endif /* USE_WINHELLO */
    677
    678
    int
    679
    fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr,
    680
        size_t len)
    681
    65.0k
    {
    682
    65.0k
            fido_blob_t      id;
    683
    65.0k
            fido_blob_t     *list_ptr;
    684
    65.0k
            int              r;
    685
    686
    65.0k
            memset(&id, 0, sizeof(id));
    687
    688
    65.0k
            if (assert->allow_list.len == SIZE_MAX) {
    689
    0
                    r = FIDO_ERR_INVALID_ARGUMENT;
    690
    0
                    goto fail;
    691
    0
            }
    692
    693
    65.0k
            if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr =
    694
    64.5k
                recallocarray(assert->allow_list.ptr, assert->allow_list.len,
    695
    64.5k
                assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) {
    696
    641
                    r = FIDO_ERR_INVALID_ARGUMENT;
    697
    641
                    goto fail;
    698
    641
            }
    699
    700
    64.4k
            list_ptr[assert->allow_list.len++] = id;
    701
    64.4k
            assert->allow_list.ptr = list_ptr;
    702
    703
    64.4k
            return (FIDO_OK);
    704
    641
    fail:
    705
    641
            free(id.ptr);
    706
    707
    641
            return (r);
    708
    65.0k
    }
    709
    710
    int
    711
    fido_assert_empty_allow_list(fido_assert_t *assert)
    712
    39.6k
    {
    713
    39.6k
            fido_free_blob_array(&assert->allow_list);
    714
    39.6k
            memset(&assert->allow_list, 0, sizeof(assert->allow_list));
    715
    716
    39.6k
            return (FIDO_OK);
    717
    39.6k
    }
    718
    719
    int
    720
    fido_assert_set_extensions(fido_assert_t *assert, int ext)
    721
    38.5k
    {
    722
    38.5k
            if (ext == 0)
    723
    1.70k
                    assert->ext.mask = 0;
    724
    36.8k
            else {
    725
    36.8k
                    if ((ext & FIDO_EXT_ASSERT_MASK) != ext)
    726
    35.7k
                            return (FIDO_ERR_INVALID_ARGUMENT);
    727
    1.16k
                    assert->ext.mask |= ext;
    728
    1.16k
            }
    729
    730
    2.87k
            return (FIDO_OK);
    731
    38.5k
    }
    732
    733
    int
    734
    fido_assert_set_options(fido_assert_t *assert, bool up, bool uv)
    735
    0
    {
    736
    0
            assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
    737
    0
            assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
    738
    739
    0
            return (FIDO_OK);
    740
    0
    }
    741
    742
    int
    743
    fido_assert_set_up(fido_assert_t *assert, fido_opt_t up)
    744
    17.2k
    {
    745
    17.2k
            assert->up = up;
    746
    747
    17.2k
            return (FIDO_OK);
    748
    17.2k
    }
    749
    750
    int
    751
    fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv)
    752
    1.27k
    {
    753
    1.27k
            assert->uv = uv;
    754
    755
    1.27k
            return (FIDO_OK);
    756
    1.27k
    }
    757
    758
    const unsigned char *
    759
    fido_assert_clientdata_hash_ptr(const fido_assert_t *assert)
    760
    37.6k
    {
    761
    37.6k
            return (assert->cdh.ptr);
    762
    37.6k
    }
    763
    764
    size_t
    765
    fido_assert_clientdata_hash_len(const fido_assert_t *assert)
    766
    37.6k
    {
    767
    37.6k
            return (assert->cdh.len);
    768
    37.6k
    }
    769
    770
    fido_assert_t *
    771
    fido_assert_new(void)
    772
    39.7k
    {
    773
    39.7k
            return (calloc(1, sizeof(fido_assert_t)));
    774
    39.7k
    }
    775
    776
    void
    777
    fido_assert_reset_tx(fido_assert_t *assert)
    778
    39.6k
    {
    779
    39.6k
            free(assert->rp_id);
    780
    39.6k
            free(assert->appid);
    781
    39.6k
            fido_blob_reset(&assert->cd);
    782
    39.6k
            fido_blob_reset(&assert->cdh);
    783
    39.6k
            fido_blob_reset(&assert->ext.hmac_salt);
    784
    39.6k
            fido_assert_empty_allow_list(assert);
    785
    39.6k
            memset(&assert->ext, 0, sizeof(assert->ext));
    786
    39.6k
            assert->rp_id = NULL;
    787
    39.6k
            assert->appid = NULL;
    788
    39.6k
            assert->up = FIDO_OPT_OMIT;
    789
    39.6k
            assert->uv = FIDO_OPT_OMIT;
    790
    39.6k
    }
    791
    792
    static void
    793
    fido_assert_reset_extattr(fido_assert_extattr_t *ext)
    794
    75.4k
    {
    795
    75.4k
            fido_blob_reset(&ext->hmac_secret_enc);
    796
    75.4k
            fido_blob_reset(&ext->blob);
    797
    75.4k
            memset(ext, 0, sizeof(*ext));
    798
    75.4k
    }
    799
    800
    void
    801
    fido_assert_reset_rx(fido_assert_t *assert)
    802
    40.0k
    {
    803
    114k
            for (size_t i = 0; i < assert->stmt_cnt; i++) {
    804
    74.0k
                    free(assert->stmt[i].user.icon);
    805
    74.0k
                    free(assert->stmt[i].user.name);
    806
    74.0k
                    free(assert->stmt[i].user.display_name);
    807
    74.0k
                    fido_blob_reset(&assert->stmt[i].user.id);
    808
    74.0k
                    fido_blob_reset(&assert->stmt[i].id);
    809
    74.0k
                    fido_blob_reset(&assert->stmt[i].hmac_secret);
    810
    74.0k
                    fido_blob_reset(&assert->stmt[i].authdata_cbor);
    811
    74.0k
                    fido_blob_reset(&assert->stmt[i].authdata_raw);
    812
    74.0k
                    fido_blob_reset(&assert->stmt[i].largeblob_key);
    813
    74.0k
                    fido_blob_reset(&assert->stmt[i].sig);
    814
    74.0k
                    fido_assert_reset_extattr(&assert->stmt[i].authdata_ext);
    815
    74.0k
                    memset(&assert->stmt[i], 0, sizeof(assert->stmt[i]));
    816
    74.0k
            }
    817
    40.0k
            free(assert->stmt);
    818
    40.0k
            assert->stmt = NULL;
    819
    40.0k
            assert->stmt_len = 0;
    820
    40.0k
            assert->stmt_cnt = 0;
    821
    40.0k
    }
    822
    823
    void
    824
    fido_assert_free(fido_assert_t **assert_p)
    825
    39.6k
    {
    826
    39.6k
            fido_assert_t *assert;
    827
    828
    39.6k
            if (assert_p == NULL || (assert = *assert_p) == NULL)
    829
    14
                    return;
    830
    39.6k
            fido_assert_reset_tx(assert);
    831
    39.6k
            fido_assert_reset_rx(assert);
    832
    39.6k
            free(assert);
    833
    39.6k
            *assert_p = NULL;
    834
    39.6k
    }
    835
    836
    size_t
    837
    fido_assert_count(const fido_assert_t *assert)
    838
    39.7k
    {
    839
    39.7k
            return (assert->stmt_len);
    840
    39.7k
    }
    841
    842
    const char *
    843
    fido_assert_rp_id(const fido_assert_t *assert)
    844
    37.6k
    {
    845
    37.6k
            return (assert->rp_id);
    846
    37.6k
    }
    847
    848
    uint8_t
    849
    fido_assert_flags(const fido_assert_t *assert, size_t idx)
    850
    37.6k
    {
    851
    37.6k
            if (idx >= assert->stmt_len)
    852
    2.13k
                    return (0);
    853
    854
    35.5k
            return (assert->stmt[idx].authdata.flags);
    855
    37.6k
    }
    856
    857
    uint32_t
    858
    fido_assert_sigcount(const fido_assert_t *assert, size_t idx)
    859
    37.6k
    {
    860
    37.6k
            if (idx >= assert->stmt_len)
    861
    2.13k
                    return (0);
    862
    863
    35.5k
            return (assert->stmt[idx].authdata.sigcount);
    864
    37.6k
    }
    865
    866
    const unsigned char *
    867
    fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx)
    868
    37.6k
    {
    869
    37.6k
            if (idx >= assert->stmt_len)
    870
    2.13k
                    return (NULL);
    871
    872
    35.5k
            return (assert->stmt[idx].authdata_cbor.ptr);
    873
    37.6k
    }
    874
    875
    size_t
    876
    fido_assert_authdata_len(const fido_assert_t *assert, size_t idx)
    877
    37.6k
    {
    878
    37.6k
            if (idx >= assert->stmt_len)
    879
    2.13k
                    return (0);
    880
    881
    35.5k
            return (assert->stmt[idx].authdata_cbor.len);
    882
    37.6k
    }
    883
    884
    const unsigned char *
    885
    fido_assert_authdata_raw_ptr(const fido_assert_t *assert, size_t idx)
    886
    37.6k
    {
    887
    37.6k
            if (idx >= assert->stmt_len)
    888
    2.13k
                    return (NULL);
    889
    890
    35.5k
            return (assert->stmt[idx].authdata_raw.ptr);
    891
    37.6k
    }
    892
    893
    size_t
    894
    fido_assert_authdata_raw_len(const fido_assert_t *assert, size_t idx)
    895
    37.6k
    {
    896
    37.6k
            if (idx >= assert->stmt_len)
    897
    2.13k
                    return (0);
    898
    899
    35.5k
            return (assert->stmt[idx].authdata_raw.len);
    900
    37.6k
    }
    901
    902
    const unsigned char *
    903
    fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx)
    904
    37.6k
    {
    905
    37.6k
            if (idx >= assert->stmt_len)
    906
    2.13k
                    return (NULL);
    907
    908
    35.5k
            return (assert->stmt[idx].sig.ptr);
    909
    37.6k
    }
    910
    911
    size_t
    912
    fido_assert_sig_len(const fido_assert_t *assert, size_t idx)
    913
    37.6k
    {
    914
    37.6k
            if (idx >= assert->stmt_len)
    915
    2.13k
                    return (0);
    916
    917
    35.5k
            return (assert->stmt[idx].sig.len);
    918
    37.6k
    }
    919
    920
    const unsigned char *
    921
    fido_assert_id_ptr(const fido_assert_t *assert, size_t idx)
    922
    37.6k
    {
    923
    37.6k
            if (idx >= assert->stmt_len)
    924
    2.13k
                    return (NULL);
    925
    926
    35.5k
            return (assert->stmt[idx].id.ptr);
    927
    37.6k
    }
    928
    929
    size_t
    930
    fido_assert_id_len(const fido_assert_t *assert, size_t idx)
    931
    37.6k
    {
    932
    37.6k
            if (idx >= assert->stmt_len)
    933
    2.13k
                    return (0);
    934
    935
    35.5k
            return (assert->stmt[idx].id.len);
    936
    37.6k
    }
    937
    938
    const unsigned char *
    939
    fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx)
    940
    37.6k
    {
    941
    37.6k
            if (idx >= assert->stmt_len)
    942
    2.13k
                    return (NULL);
    943
    944
    35.5k
            return (assert->stmt[idx].user.id.ptr);
    945
    37.6k
    }
    946
    947
    size_t
    948
    fido_assert_user_id_len(const fido_assert_t *assert, size_t idx)
    949
    37.6k
    {
    950
    37.6k
            if (idx >= assert->stmt_len)
    951
    2.13k
                    return (0);
    952
    953
    35.5k
            return (assert->stmt[idx].user.id.len);
    954
    37.6k
    }
    955
    956
    const char *
    957
    fido_assert_user_icon(const fido_assert_t *assert, size_t idx)
    958
    37.6k
    {
    959
    37.6k
            if (idx >= assert->stmt_len)
    960
    2.13k
                    return (NULL);
    961
    962
    35.5k
            return (assert->stmt[idx].user.icon);
    963
    37.6k
    }
    964
    965
    const char *
    966
    fido_assert_user_name(const fido_assert_t *assert, size_t idx)
    967
    37.6k
    {
    968
    37.6k
            if (idx >= assert->stmt_len)
    969
    2.13k
                    return (NULL);
    970
    971
    35.5k
            return (assert->stmt[idx].user.name);
    972
    37.6k
    }
    973
    974
    const char *
    975
    fido_assert_user_display_name(const fido_assert_t *assert, size_t idx)
    976
    37.6k
    {
    977
    37.6k
            if (idx >= assert->stmt_len)
    978
    2.13k
                    return (NULL);
    979
    980
    35.5k
            return (assert->stmt[idx].user.display_name);
    981
    37.6k
    }
    982
    983
    const unsigned char *
    984
    fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx)
    985
    37.6k
    {
    986
    37.6k
            if (idx >= assert->stmt_len)
    987
    2.13k
                    return (NULL);
    988
    989
    35.5k
            return (assert->stmt[idx].hmac_secret.ptr);
    990
    37.6k
    }
    991
    992
    size_t
    993
    fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx)
    994
    37.6k
    {
    995
    37.6k
            if (idx >= assert->stmt_len)
    996
    2.13k
                    return (0);
    997
    998
    35.5k
            return (assert->stmt[idx].hmac_secret.len);
    999
    37.6k
    }
    1000
    1001
    const unsigned char *
    1002
    fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx)
    1003
    37.6k
    {
    1004
    37.6k
            if (idx >= assert->stmt_len)
    1005
    2.13k
                    return (NULL);
    1006
    1007
    35.5k
            return (assert->stmt[idx].largeblob_key.ptr);
    1008
    37.6k
    }
    1009
    1010
    size_t
    1011
    fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx)
    1012
    37.6k
    {
    1013
    37.6k
            if (idx >= assert->stmt_len)
    1014
    2.13k
                    return (0);
    1015
    1016
    35.5k
            return (assert->stmt[idx].largeblob_key.len);
    1017
    37.6k
    }
    1018
    1019
    const unsigned char *
    1020
    fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx)
    1021
    37.6k
    {
    1022
    37.6k
            if (idx >= assert->stmt_len)
    1023
    2.13k
                    return (NULL);
    1024
    1025
    35.5k
            return (assert->stmt[idx].authdata_ext.blob.ptr);
    1026
    37.6k
    }
    1027
    1028
    size_t
    1029
    fido_assert_blob_len(const fido_assert_t *assert, size_t idx)
    1030
    37.6k
    {
    1031
    37.6k
            if (idx >= assert->stmt_len)
    1032
    2.13k
                    return (0);
    1033
    1034
    35.5k
            return (assert->stmt[idx].authdata_ext.blob.len);
    1035
    37.6k
    }
    1036
    1037
    static void
    1038
    fido_assert_clean_authdata(fido_assert_stmt *stmt)
    1039
    1.34k
    {
    1040
    1.34k
            fido_blob_reset(&stmt->authdata_cbor);
    1041
    1.34k
            fido_blob_reset(&stmt->authdata_raw);
    1042
    1.34k
            fido_assert_reset_extattr(&stmt->authdata_ext);
    1043
    1.34k
            memset(&stmt->authdata, 0, sizeof(stmt->authdata));
    1044
    1.34k
    }
    1045
    1046
    int
    1047
    fido_assert_set_authdata(fido_assert_t *assert, size_t idx,
    1048
        const unsigned char *ptr, size_t len)
    1049
    75.2k
    {
    1050
    75.2k
            cbor_item_t             *item = NULL;
    1051
    75.2k
            fido_assert_stmt        *stmt = NULL;
    1052
    75.2k
            struct cbor_load_result  cbor;
    1053
    75.2k
            int                      r;
    1054
    1055
    75.2k
            if (idx >= assert->stmt_len || ptr == NULL || len == 0)
    1056
    74.0k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1057
    1058
    1.12k
            stmt = &assert->stmt[idx];
    1059
    1.12k
            fido_assert_clean_authdata(stmt);
    1060
    1061
    1.12k
            if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
    1062
    21
                    fido_log_debug("%s: cbor_load", __func__);
    1063
    21
                    r = FIDO_ERR_INVALID_ARGUMENT;
    1064
    21
                    goto fail;
    1065
    21
            }
    1066
    1067
    1.10k
            if (fido_blob_decode(item, &stmt->authdata_raw) < 0) {
    1068
    16
                fido_log_debug("%s: fido_blob_decode", __func__);
    1069
    16
                r = FIDO_ERR_INTERNAL;
    1070
    16
                goto fail;
    1071
    16
            }
    1072
    1073
    1.08k
            if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
    1074
    1.08k
                &stmt->authdata, &stmt->authdata_ext) < 0) {
    1075
    43
                    fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
    1076
    43
                    r = FIDO_ERR_INVALID_ARGUMENT;
    1077
    43
                    goto fail;
    1078
    43
            }
    1079
    1080
    1.04k
            r = FIDO_OK;
    1081
    1.12k
    fail:
    1082
    1.12k
            if (item != NULL)
    1083
    1.10k
                    cbor_decref(&item);
    1084
    1085
    1.12k
            if (r != FIDO_OK)
    1086
    80
                    fido_assert_clean_authdata(stmt);
    1087
    1088
    1.12k
            return (r);
    1089
    1.04k
    }
    1090
    1091
    int
    1092
    fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx,
    1093
        const unsigned char *ptr, size_t len)
    1094
    74.1k
    {
    1095
    74.1k
            cbor_item_t             *item = NULL;
    1096
    74.1k
            fido_assert_stmt        *stmt = NULL;
    1097
    74.1k
            int                      r;
    1098
    1099
    74.1k
            if (idx >= assert->stmt_len || ptr == NULL || len == 0)
    1100
    74.0k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1101
    1102
    77
            stmt = &assert->stmt[idx];
    1103
    77
            fido_assert_clean_authdata(stmt);
    1104
    1105
    77
            if (fido_blob_set(&stmt->authdata_raw, ptr, len) < 0) {
    1106
    2
                    fido_log_debug("%s: fido_blob_set", __func__);
    1107
    2
                    r = FIDO_ERR_INTERNAL;
    1108
    2
                    goto fail;
    1109
    2
            }
    1110
    1111
    75
            if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
    1112
    2
                    fido_log_debug("%s: cbor_build_bytestring", __func__);
    1113
    2
                    r = FIDO_ERR_INTERNAL;
    1114
    2
                    goto fail;
    1115
    2
            }
    1116
    1117
    73
            if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
    1118
    73
                &stmt->authdata, &stmt->authdata_ext) < 0) {
    1119
    66
                    fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
    1120
    66
                    r = FIDO_ERR_INVALID_ARGUMENT;
    1121
    66
                    goto fail;
    1122
    66
            }
    1123
    1124
    7
            r = FIDO_OK;
    1125
    77
    fail:
    1126
    77
            if (item != NULL)
    1127
    73
                    cbor_decref(&item);
    1128
    1129
    77
            if (r != FIDO_OK)
    1130
    70
                    fido_assert_clean_authdata(stmt);
    1131
    1132
    77
            return (r);
    1133
    7
    }
    1134
    1135
    int
    1136
    fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
    1137
        size_t len)
    1138
    75.2k
    {
    1139
    75.2k
            if (idx >= a->stmt_len || ptr == NULL || len == 0)
    1140
    74.1k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1141
    1.07k
            if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0)
    1142
    13
                    return (FIDO_ERR_INTERNAL);
    1143
    1144
    1.06k
            return (FIDO_OK);
    1145
    1.07k
    }
    1146
    1147
    /* XXX shrinking leaks memory; fortunately that shouldn't happen */
    1148
    int
    1149
    fido_assert_set_count(fido_assert_t *assert, size_t n)
    1150
    38.2k
    {
    1151
    38.2k
            void *new_stmt;
    1152
    1153
    38.2k
    #ifdef FIDO_FUZZ
    1154
    38.2k
            if (n > UINT8_MAX) {
    1155
    39
                    fido_log_debug("%s: n > UINT8_MAX", __func__);
    1156
    39
                    return (FIDO_ERR_INTERNAL);
    1157
    39
            }
    1158
    38.2k
    #endif
    1159
    1160
    38.2k
            new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n,
    1161
    38.2k
                sizeof(fido_assert_stmt));
    1162
    38.2k
            if (new_stmt == NULL)
    1163
    120
                    return (FIDO_ERR_INTERNAL);
    1164
    1165
    38.1k
            assert->stmt = new_stmt;
    1166
    38.1k
            assert->stmt_cnt = n;
    1167
    38.1k
            assert->stmt_len = n;
    1168
    1169
    38.1k
            return (FIDO_OK);
    1170
    38.2k
    }