## Coverage Report

#### Created: 2025-03-01 02:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /libfido2/src/cred.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 2018-2024 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
    #include <openssl/x509.h>
    10
    11
    #include "fido.h"
    12
    #include "fido/es256.h"
    13
    14
    #ifndef FIDO_MAXMSG_CRED
    15
    7.99k
    #define FIDO_MAXMSG_CRED        4096
    16
    #endif
    17
    18
    static int
    19
    parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    20
    9.85k
    {
    21
    9.85k
            fido_cred_t *cred = arg;
    22
    23
    9.85k
            if (cbor_isa_uint(key) == false ||
    24
    9.85k
                cbor_int_get_width(key) != CBOR_INT_8) {
    25
    91
                    fido_log_debug("%s: cbor type", __func__);
    26
    91
                    return (0); /* ignore */
    27
    91
            }
    28
    29
    9.75k
            switch (cbor_get_uint8(key)) {
    30
    3.57k
            case 1: /* fmt */
    31
    3.57k
                    return (cbor_decode_fmt(val, &cred->fmt));
    32
    3.36k
            case 2: /* authdata */
    33
    3.36k
                    if (fido_blob_decode(val, &cred->authdata_raw) < 0) {
    34
    1
                            fido_log_debug("%s: fido_blob_decode", __func__);
    35
    1
                            return (-1);
    36
    1
                    }
    37
    3.36k
                    return (cbor_decode_cred_authdata(val, cred->type,
    38
    3.36k
                        &cred->authdata_cbor, &cred->authdata, &cred->attcred,
    39
    3.36k
                        &cred->authdata_ext));
    40
    2.69k
            case 3: /* attestation statement */
    41
    2.69k
                    return (cbor_decode_attstmt(val, &cred->attstmt));
    42
    6
            case 4: /* enterprise attestation */
    43
    6
                    return (cbor_decode_bool(val, &cred->ea.att));
    44
    4
            case 5: /* large blob key */
    45
    4
                    return (fido_blob_decode(val, &cred->largeblob_key));
    46
    121
            default: /* ignore */
    47
    121
                    fido_log_debug("%s: cbor type", __func__);
    48
    121
                    return (0);
    49
    9.75k
            }
    50
    9.75k
    }
    51
    52
    static int
    53
    fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
    54
        int *ms)
    55
    6.24k
    {
    56
    6.24k
            fido_blob_t      f;
    57
    6.24k
            fido_blob_t     *ecdh = NULL;
    58
    6.24k
            fido_opt_t       uv = cred->uv;
    59
    6.24k
            es256_pk_t      *pk = NULL;
    60
    6.24k
            cbor_item_t     *argv[10];
    61
    6.24k
            const uint8_t    cmd = CTAP_CBOR_MAKECRED;
    62
    6.24k
            int              r;
    63
    64
    6.24k
            memset(&f, 0, sizeof(f));
    65
    6.24k
            memset(argv, 0, sizeof(argv));
    66
    67
    6.24k
            if (cred->cdh.ptr == NULL || cred->type == 0) {
    68
    7
                    fido_log_debug("%s: cdh=%p, type=%d", __func__,
    69
    7
                        (void *)cred->cdh.ptr, cred->type);
    70
    7
                    r = FIDO_ERR_INVALID_ARGUMENT;
    71
    7
                    goto fail;
    72
    7
            }
    73
    74
    6.24k
            if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
    75
    6.24k
                (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
    76
    6.24k
                (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
    77
    6.24k
                (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
    78
    189
                    fido_log_debug("%s: cbor encode", __func__);
    79
    189
                    r = FIDO_ERR_INTERNAL;
    80
    189
                    goto fail;
    81
    189
            }
    82
    83
            /* excluded credentials */
    84
    6.05k
            if (cred->excl.len)
    85
    3.91k
                    if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
    86
    237
                            fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
    87
    237
                            r = FIDO_ERR_INTERNAL;
    88
    237
                            goto fail;
    89
    237
                    }
    90
    91
            /* extensions */
    92
    5.81k
            if (cred->ext.mask)
    93
    4.15k
                    if ((argv[5] = cbor_encode_cred_ext(&cred->ext,
    94
    4.15k
                        &cred->blob)) == NULL) {
    95
    47
                            fido_log_debug("%s: cbor_encode_cred_ext", __func__);
    96
    47
                            r = FIDO_ERR_INTERNAL;
    97
    47
                            goto fail;
    98
    47
                    }
    99
    100
            /* user verification */
    101
    5.76k
            if (pin != NULL || (uv == FIDO_OPT_TRUE &&
    102
    4.41k
                fido_dev_supports_permissions(dev))) {
    103
    4.41k
                    if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
    104
    832
                            fido_log_debug("%s: fido_do_ecdh", __func__);
    105
    832
                            goto fail;
    106
    832
                    }
    107
    3.58k
                    if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
    108
    3.58k
                        pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
    109
    450
                            fido_log_debug("%s: cbor_add_uv_params", __func__);
    110
    450
                            goto fail;
    111
    450
                    }
    112
    3.13k
                    uv = FIDO_OPT_OMIT;
    113
    3.13k
            }
    114
    115
            /* options */
    116
    4.48k
            if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT)
    117
    1.31k
                    if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) {
    118
    15
                            fido_log_debug("%s: cbor_encode_cred_opt", __func__);
    119
    15
                            r = FIDO_ERR_INTERNAL;
    120
    15
                            goto fail;
    121
    15
                    }
    122
    123
            /* enterprise attestation */
    124
    4.47k
            if (cred->ea.mode != 0)
    125
    1.78k
                    if ((argv[9] = cbor_build_uint8((uint8_t)cred->ea.mode)) ==
    126
    1.78k
                        NULL) {
    127
    4
                            fido_log_debug("%s: cbor_build_uint8", __func__);
    128
    4
                            r = FIDO_ERR_INTERNAL;
    129
    4
                            goto fail;
    130
    4
                    }
    131
    132
            /* framing and transmission */
    133
    4.46k
            if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
    134
    4.46k
                fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    135
    466
                    fido_log_debug("%s: fido_tx", __func__);
    136
    466
                    r = FIDO_ERR_TX;
    137
    466
                    goto fail;
    138
    466
            }
    139
    140
    4.00k
            r = FIDO_OK;
    141
    6.24k
    fail:
    142
    6.24k
            es256_pk_free(&pk);
    143
    6.24k
            fido_blob_free(&ecdh);
    144
    6.24k
            cbor_vector_free(argv, nitems(argv));
    145
    6.24k
            free(f.ptr);
    146
    147
    6.24k
            return (r);
    148
    4.00k
    }
    149
    150
    static int
    151
    fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
    152
    4.00k
    {
    153
    4.00k
            unsigned char   *reply;
    154
    4.00k
            int              reply_len;
    155
    4.00k
            int              r;
    156
    157
    4.00k
            fido_cred_reset_rx(cred);
    158
    159
    4.00k
            if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
    160
    3
                    r = FIDO_ERR_INTERNAL;
    161
    3
                    goto fail;
    162
    3
            }
    163
    164
    3.99k
            if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
    165
    3.99k
                ms)) < 0) {
    166
    211
                    fido_log_debug("%s: fido_rx", __func__);
    167
    211
                    r = FIDO_ERR_RX;
    168
    211
                    goto fail;
    169
    211
            }
    170
    171
    3.78k
            if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
    172
    3.78k
                parse_makecred_reply)) != FIDO_OK) {
    173
    1.28k
                    fido_log_debug("%s: parse_makecred_reply", __func__);
    174
    1.28k
                    goto fail;
    175
    1.28k
            }
    176
    177
    2.50k
            if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
    178
    2.50k
                fido_blob_is_empty(&cred->attcred.id)) {
    179
    86
                    r = FIDO_ERR_INVALID_CBOR;
    180
    86
                    goto fail;
    181
    86
            }
    182
    183
    2.41k
            r = FIDO_OK;
    184
    4.00k
    fail:
    185
    4.00k
            free(reply);
    186
    187
    4.00k
            if (r != FIDO_OK)
    188
    1.58k
                    fido_cred_reset_rx(cred);
    189
    190
    4.00k
            return (r);
    191
    2.41k
    }
    192
    193
    static int
    194
    fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
    195
        int *ms)
    196
    6.24k
    {
    197
    6.24k
            int  r;
    198
    199
    6.24k
            if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
    200
    6.24k
                (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
    201
    3.83k
                    return (r);
    202
    203
    2.41k
            return (FIDO_OK);
    204
    6.24k
    }
    205
    206
    int
    207
    fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
    208
    12.0k
    {
    209
    12.0k
            int ms = dev->timeout_ms;
    210
    211
    #ifdef USE_WINHELLO
    212
            if (dev->flags & FIDO_DEV_WINHELLO)
    213
                    return (fido_winhello_make_cred(dev, cred, pin, ms));
    214
    #endif
    215
    12.0k
            if (fido_dev_is_fido2(dev) == false) {
    216
    5.79k
                    if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
    217
    5.79k
                        cred->ext.mask != 0)
    218
    2.70k
                            return (FIDO_ERR_UNSUPPORTED_OPTION);
    219
    3.08k
                    return (u2f_register(dev, cred, &ms));
    220
    5.79k
            }
    221
    222
    6.24k
            return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
    223
    12.0k
    }
    224
    225
    static int
    226
    check_extensions(const fido_cred_ext_t *authdata_ext,
    227
        const fido_cred_ext_t *ext)
    228
    5.36k
    {
    229
    5.36k
            fido_cred_ext_t  tmp;
    230
    231
            /* XXX: largeBlobKey is not part of the extensions map */
    232
    5.36k
            memcpy(&tmp, ext, sizeof(tmp));
    233
    5.36k
            tmp.mask &= ~FIDO_EXT_LARGEBLOB_KEY;
    234
    235
    5.36k
            return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext)));
    236
    5.36k
    }
    237
    238
    int
    239
    fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
    240
    9.16k
    {
    241
    9.16k
            unsigned char expected_hash[SHA256_DIGEST_LENGTH];
    242
    243
    9.16k
            explicit_bzero(expected_hash, sizeof(expected_hash));
    244
    245
    9.16k
            if (SHA256((const unsigned char *)id, strlen(id),
    246
    9.16k
                expected_hash) != expected_hash) {
    247
    41
                    fido_log_debug("%s: sha256", __func__);
    248
    41
                    return (-1);
    249
    41
            }
    250
    251
    9.12k
            return (timingsafe_bcmp(expected_hash, obtained_hash,
    252
    9.12k
                SHA256_DIGEST_LENGTH));
    253
    9.16k
    }
    254
    255
    static int
    256
    get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
    257
        size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
    258
        const es256_pk_t *pk)
    259
    581
    {
    260
    581
            const uint8_t    zero = 0;
    261
    581
            const uint8_t    four = 4; /* uncompressed point */
    262
    581
            const EVP_MD    *md = NULL;
    263
    581
            EVP_MD_CTX      *ctx = NULL;
    264
    581
            int              ok = -1;
    265
    266
    581
            if (dgst->len < SHA256_DIGEST_LENGTH ||
    267
    581
                (md = EVP_sha256()) == NULL ||
    268
    581
                (ctx = EVP_MD_CTX_new()) == NULL ||
    269
    581
                EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
    270
    581
                EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
    271
    581
                EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
    272
    581
                EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
    273
    581
                EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
    274
    581
                EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
    275
    581
                EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
    276
    581
                EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
    277
    581
                EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
    278
    50
                    fido_log_debug("%s: sha256", __func__);
    279
    50
                    goto fail;
    280
    50
            }
    281
    531
            dgst->len = SHA256_DIGEST_LENGTH;
    282
    283
    531
            ok = 0;
    284
    581
    fail:
    285
    581
            EVP_MD_CTX_free(ctx);
    286
    287
    581
            return (ok);
    288
    531
    }
    289
    290
    static int
    291
    verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
    292
    4.57k
    {
    293
    4.57k
            BIO             *rawcert = NULL;
    294
    4.57k
            X509            *cert = NULL;
    295
    4.57k
            EVP_PKEY        *pkey = NULL;
    296
    4.57k
            int              ok = -1;
    297
    298
    4.57k
            if (!attstmt->x5c.len) {
    299
    0
                    fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
    300
    0
                    return (-1);
    301
    0
            }
    302
    303
            /* openssl needs ints */
    304
    4.57k
            if (attstmt->x5c.ptr[0].len > INT_MAX) {
    305
    0
                    fido_log_debug("%s: x5c[0].len=%zu", __func__,
    306
    0
                        attstmt->x5c.ptr[0].len);
    307
    0
                    return (-1);
    308
    0
            }
    309
    310
            /* fetch key from x509 */
    311
    4.57k
            if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr[0].ptr,
    312
    4.57k
                (int)attstmt->x5c.ptr[0].len)) == NULL ||
    313
    4.57k
                (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
    314
    4.57k
                (pkey = X509_get_pubkey(cert)) == NULL) {
    315
    2.95k
                    fido_log_debug("%s: x509 key", __func__);
    316
    2.95k
                    goto fail;
    317
    2.95k
            }
    318
    319
    1.62k
            switch (attstmt->alg) {
    320
    25
            case COSE_UNSPEC:
    321
    1.11k
            case COSE_ES256:
    322
    1.11k
                    ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
    323
    1.11k
                    break;
    324
    9
            case COSE_ES384:
    325
    9
                    ok = es384_verify_sig(dgst, pkey, &attstmt->sig);
    326
    9
                    break;
    327
    4
            case COSE_RS256:
    328
    4
                    ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
    329
    4
                    break;
    330
    481
            case COSE_RS1:
    331
    481
                    ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
    332
    481
                    break;
    333
    13
            case COSE_EDDSA:
    334
    13
                    ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
    335
    13
                    break;
    336
    0
            default:
    337
    0
                    fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
    338
    0
                    break;
    339
    1.62k
            }
    340
    341
    4.57k
    fail:
    342
    4.57k
            BIO_free(rawcert);
    343
    4.57k
            X509_free(cert);
    344
    4.57k
            EVP_PKEY_free(pkey);
    345
    346
    4.57k
            return (ok);
    347
    1.62k
    }
    348
    349
    int
    350
    fido_cred_verify(const fido_cred_t *cred)
    351
    19.5k
    {
    352
    19.5k
            unsigned char   buf[1024]; /* XXX */
    353
    19.5k
            fido_blob_t     dgst;
    354
    19.5k
            int             cose_alg;
    355
    19.5k
            int             r;
    356
    357
    19.5k
            dgst.ptr = buf;
    358
    19.5k
            dgst.len = sizeof(buf);
    359
    360
            /* do we have everything we need? */
    361
    19.5k
            if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
    362
    19.5k
                cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
    363
    19.5k
                cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
    364
    19.5k
                cred->rp.id == NULL) {
    365
    14.4k
                    fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
    366
    14.4k
                        "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
    367
    14.4k
                        (void *)cred->authdata_cbor.ptr,
    368
    14.4k
                        (void *)cred->attstmt.x5c.ptr,
    369
    14.4k
                        (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
    370
    14.4k
                        (void *)cred->attcred.id.ptr, cred->rp.id);
    371
    14.4k
                    r = FIDO_ERR_INVALID_ARGUMENT;
    372
    14.4k
                    goto out;
    373
    14.4k
            }
    374
    375
    5.12k
            if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
    376
    330
                    fido_log_debug("%s: fido_check_rp_id", __func__);
    377
    330
                    r = FIDO_ERR_INVALID_PARAM;
    378
    330
                    goto out;
    379
    330
            }
    380
    381
    4.79k
            if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
    382
    4.79k
                cred->uv) < 0) {
    383
    7
                    fido_log_debug("%s: fido_check_flags", __func__);
    384
    7
                    r = FIDO_ERR_INVALID_PARAM;
    385
    7
                    goto out;
    386
    7
            }
    387
    388
    4.78k
            if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
    389
    8
                    fido_log_debug("%s: check_extensions", __func__);
    390
    8
                    r = FIDO_ERR_INVALID_PARAM;
    391
    8
                    goto out;
    392
    8
            }
    393
    394
    4.77k
            if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC)
    395
    137
                    cose_alg = COSE_ES256; /* backwards compat */
    396
    397
    4.77k
            if (!strcmp(cred->fmt, "packed")) {
    398
    3.47k
                    if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh,
    399
    3.47k
                        &cred->authdata_cbor) < 0) {
    400
    72
                            fido_log_debug("%s: fido_get_signed_hash", __func__);
    401
    72
                            r = FIDO_ERR_INTERNAL;
    402
    72
                            goto out;
    403
    72
                    }
    404
    3.47k
            } else if (!strcmp(cred->fmt, "fido-u2f")) {
    405
    510
                    if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
    406
    510
                        sizeof(cred->authdata.rp_id_hash), &cred->cdh,
    407
    510
                        &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
    408
    46
                            fido_log_debug("%s: get_signed_hash_u2f", __func__);
    409
    46
                            r = FIDO_ERR_INTERNAL;
    410
    46
                            goto out;
    411
    46
                    }
    412
    789
            } else if (!strcmp(cred->fmt, "tpm")) {
    413
    786
                    if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
    414
    786
                        &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
    415
    80
                            fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
    416
    80
                            r = FIDO_ERR_INTERNAL;
    417
    80
                            goto out;
    418
    80
                    }
    419
    786
            } else {
    420
    3
                    fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
    421
    3
                    r = FIDO_ERR_INVALID_ARGUMENT;
    422
    3
                    goto out;
    423
    3
            }
    424
    425
    4.57k
            if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
    426
    4.57k
                    fido_log_debug("%s: verify_attstmt", __func__);
    427
    4.57k
                    r = FIDO_ERR_INVALID_SIG;
    428
    4.57k
                    goto out;
    429
    4.57k
            }
    430
    431
    4
            r = FIDO_OK;
    432
    19.5k
    out:
    433
    19.5k
            explicit_bzero(buf, sizeof(buf));
    434
    435
    19.5k
            return (r);
    436
    4
    }
    437
    438
    int
    439
    fido_cred_verify_self(const fido_cred_t *cred)
    440
    13.1k
    {
    441
    13.1k
            unsigned char   buf[1024]; /* XXX */
    442
    13.1k
            fido_blob_t     dgst;
    443
    13.1k
            int             ok = -1;
    444
    13.1k
            int             r;
    445
    446
    13.1k
            dgst.ptr = buf;
    447
    13.1k
            dgst.len = sizeof(buf);
    448
    449
            /* do we have everything we need? */
    450
    13.1k
            if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
    451
    13.1k
                cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
    452
    13.1k
                cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
    453
    13.1k
                cred->rp.id == NULL) {
    454
    12.2k
                    fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
    455
    12.2k
                        "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
    456
    12.2k
                        (void *)cred->authdata_cbor.ptr,
    457
    12.2k
                        (void *)cred->attstmt.x5c.ptr,
    458
    12.2k
                        (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
    459
    12.2k
                        (void *)cred->attcred.id.ptr, cred->rp.id);
    460
    12.2k
                    r = FIDO_ERR_INVALID_ARGUMENT;
    461
    12.2k
                    goto out;
    462
    12.2k
            }
    463
    464
    866
            if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
    465
    280
                    fido_log_debug("%s: fido_check_rp_id", __func__);
    466
    280
                    r = FIDO_ERR_INVALID_PARAM;
    467
    280
                    goto out;
    468
    280
            }
    469
    470
    586
            if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
    471
    586
                cred->uv) < 0) {
    472
    6
                    fido_log_debug("%s: fido_check_flags", __func__);
    473
    6
                    r = FIDO_ERR_INVALID_PARAM;
    474
    6
                    goto out;
    475
    6
            }
    476
    477
    580
            if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) {
    478
    5
                    fido_log_debug("%s: check_extensions", __func__);
    479
    5
                    r = FIDO_ERR_INVALID_PARAM;
    480
    5
                    goto out;
    481
    5
            }
    482
    483
    575
            if (!strcmp(cred->fmt, "packed")) {
    484
    500
                    if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
    485
    500
                        &cred->authdata_cbor) < 0) {
    486
    28
                            fido_log_debug("%s: fido_get_signed_hash", __func__);
    487
    28
                            r = FIDO_ERR_INTERNAL;
    488
    28
                            goto out;
    489
    28
                    }
    490
    500
            } else if (!strcmp(cred->fmt, "fido-u2f")) {
    491
    71
                    if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
    492
    71
                        sizeof(cred->authdata.rp_id_hash), &cred->cdh,
    493
    71
                        &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
    494
    4
                            fido_log_debug("%s: get_signed_hash_u2f", __func__);
    495
    4
                            r = FIDO_ERR_INTERNAL;
    496
    4
                            goto out;
    497
    4
                    }
    498
    71
            } else {
    499
    4
                    fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
    500
    4
                    r = FIDO_ERR_INVALID_ARGUMENT;
    501
    4
                    goto out;
    502
    4
            }
    503
    504
    539
            switch (cred->attcred.type) {
    505
    113
            case COSE_ES256:
    506
    113
                    ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
    507
    113
                        &cred->attstmt.sig);
    508
    113
                    break;
    509
    187
            case COSE_ES384:
    510
    187
                    ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384,
    511
    187
                        &cred->attstmt.sig);
    512
    187
                    break;
    513
    57
            case COSE_RS256:
    514
    57
                    ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
    515
    57
                        &cred->attstmt.sig);
    516
    57
                    break;
    517
    182
            case COSE_EDDSA:
    518
    182
                    ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
    519
    182
                        &cred->attstmt.sig);
    520
    182
                    break;
    521
    0
            default:
    522
    0
                    fido_log_debug("%s: unsupported cose_alg %d", __func__,
    523
    0
                        cred->attcred.type);
    524
    0
                    r = FIDO_ERR_UNSUPPORTED_OPTION;
    525
    0
                    goto out;
    526
    539
            }
    527
    528
    539
            if (ok < 0)
    529
    539
                    r = FIDO_ERR_INVALID_SIG;
    530
    0
            else
    531
    0
                    r = FIDO_OK;
    532
    533
    13.1k
    out:
    534
    13.1k
            explicit_bzero(buf, sizeof(buf));
    535
    536
    13.1k
            return (r);
    537
    539
    }
    538
    539
    fido_cred_t *
    540
    fido_cred_new(void)
    541
    55.5k
    {
    542
    55.5k
            return (calloc(1, sizeof(fido_cred_t)));
    543
    55.5k
    }
    544
    545
    static void
    546
    fido_cred_clean_authdata(fido_cred_t *cred)
    547
    228k
    {
    548
    228k
            fido_blob_reset(&cred->authdata_cbor);
    549
    228k
            fido_blob_reset(&cred->authdata_raw);
    550
    228k
            fido_blob_reset(&cred->attcred.id);
    551
    552
    228k
            memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
    553
    228k
            memset(&cred->authdata, 0, sizeof(cred->authdata));
    554
    228k
            memset(&cred->attcred, 0, sizeof(cred->attcred));
    555
    228k
    }
    556
    557
    static void
    558
    fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
    559
    187k
    {
    560
    187k
            fido_blob_reset(&attstmt->certinfo);
    561
    187k
            fido_blob_reset(&attstmt->pubarea);
    562
    187k
            fido_blob_reset(&attstmt->cbor);
    563
    187k
            fido_free_blob_array(&attstmt->x5c);
    564
    187k
            fido_blob_reset(&attstmt->sig);
    565
    566
    187k
            memset(attstmt, 0, sizeof(*attstmt));
    567
    187k
    }
    568
    569
    static void
    570
    fido_cred_clean_attobj(fido_cred_t *cred)
    571
    139k
    {
    572
    139k
            free(cred->fmt);
    573
    139k
            cred->fmt = NULL;
    574
    139k
            fido_cred_clean_authdata(cred);
    575
    139k
            fido_cred_clean_attstmt(&cred->attstmt);
    576
    139k
    }
    577
    578
    void
    579
    fido_cred_reset_tx(fido_cred_t *cred)
    580
    127k
    {
    581
    127k
            fido_blob_reset(&cred->cd);
    582
    127k
            fido_blob_reset(&cred->cdh);
    583
    127k
            fido_blob_reset(&cred->user.id);
    584
    127k
            fido_blob_reset(&cred->blob);
    585
    586
    127k
            free(cred->rp.id);
    587
    127k
            free(cred->rp.name);
    588
    127k
            free(cred->user.icon);
    589
    127k
            free(cred->user.name);
    590
    127k
            free(cred->user.display_name);
    591
    127k
            fido_cred_empty_exclude_list(cred);
    592
    593
    127k
            memset(&cred->rp, 0, sizeof(cred->rp));
    594
    127k
            memset(&cred->user, 0, sizeof(cred->user));
    595
    127k
            memset(&cred->ext, 0, sizeof(cred->ext));
    596
    597
    127k
            cred->type = 0;
    598
    127k
            cred->rk = FIDO_OPT_OMIT;
    599
    127k
            cred->uv = FIDO_OPT_OMIT;
    600
    127k
            cred->ea.mode = 0;
    601
    127k
    }
    602
    603
    void
    604
    fido_cred_reset_rx(fido_cred_t *cred)
    605
    133k
    {
    606
    133k
            fido_cred_clean_attobj(cred);
    607
    133k
            fido_blob_reset(&cred->largeblob_key);
    608
    133k
            cred->ea.att = false;
    609
    133k
    }
    610
    611
    void
    612
    fido_cred_free(fido_cred_t **cred_p)
    613
    55.3k
    {
    614
    55.3k
            fido_cred_t *cred;
    615
    616
    55.3k
            if (cred_p == NULL || (cred = *cred_p) == NULL)
    617
    13
                    return;
    618
    55.3k
            fido_cred_reset_tx(cred);
    619
    55.3k
            fido_cred_reset_rx(cred);
    620
    55.3k
            free(cred);
    621
    55.3k
            *cred_p = NULL;
    622
    55.3k
    }
    623
    624
    int
    625
    fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    626
    26.8k
    {
    627
    26.8k
            cbor_item_t             *item = NULL;
    628
    26.8k
            struct cbor_load_result  cbor;
    629
    26.8k
            int                      r = FIDO_ERR_INVALID_ARGUMENT;
    630
    631
    26.8k
            fido_cred_clean_authdata(cred);
    632
    633
    26.8k
            if (ptr == NULL || len == 0)
    634
    20.1k
                    goto fail;
    635
    636
    6.70k
            if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
    637
    276
                    fido_log_debug("%s: cbor_load", __func__);
    638
    276
                    goto fail;
    639
    276
            }
    640
    641
    6.42k
            if (fido_blob_decode(item, &cred->authdata_raw) < 0) {
    642
    28
                    fido_log_debug("%s: fido_blob_decode", __func__);
    643
    28
                    goto fail;
    644
    28
            }
    645
    646
    6.39k
            if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
    647
    6.39k
                &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
    648
    268
                    fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
    649
    268
                    goto fail;
    650
    268
            }
    651
    652
    6.13k
            r = FIDO_OK;
    653
    26.8k
    fail:
    654
    26.8k
            if (item != NULL)
    655
    6.42k
                    cbor_decref(&item);
    656
    657
    26.8k
            if (r != FIDO_OK)
    658
    20.7k
                    fido_cred_clean_authdata(cred);
    659
    660
    26.8k
            return (r);
    661
    6.13k
    }
    662
    663
    int
    664
    fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
    665
        size_t len)
    666
    20.7k
    {
    667
    20.7k
            cbor_item_t     *item = NULL;
    668
    20.7k
            int              r = FIDO_ERR_INVALID_ARGUMENT;
    669
    670
    20.7k
            fido_cred_clean_authdata(cred);
    671
    672
    20.7k
            if (ptr == NULL || len == 0)
    673
    20.1k
                    goto fail;
    674
    675
    559
            if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) {
    676
    1
                    fido_log_debug("%s: fido_blob_set", __func__);
    677
    1
                    r = FIDO_ERR_INTERNAL;
    678
    1
                    goto fail;
    679
    1
            }
    680
    681
    558
            if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
    682
    8
                    fido_log_debug("%s: cbor_build_bytestring", __func__);
    683
    8
                    r = FIDO_ERR_INTERNAL;
    684
    8
                    goto fail;
    685
    8
            }
    686
    687
    550
            if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
    688
    550
                &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
    689
    243
                    fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
    690
    243
                    goto fail;
    691
    243
            }
    692
    693
    307
            r = FIDO_OK;
    694
    20.7k
    fail:
    695
    20.7k
            if (item != NULL)
    696
    550
                    cbor_decref(&item);
    697
    698
    20.7k
            if (r != FIDO_OK)
    699
    20.4k
                    fido_cred_clean_authdata(cred);
    700
    701
    20.7k
            return (r);
    702
    307
    }
    703
    704
    int
    705
    fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    706
    22.5k
    {
    707
    22.5k
            if (fido_blob_set(&cred->attcred.id, ptr, len) < 0)
    708
    172
                    return (FIDO_ERR_INVALID_ARGUMENT);
    709
    710
    22.4k
            return (FIDO_OK);
    711
    22.5k
    }
    712
    713
    int
    714
    fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    715
    33.7k
    {
    716
    33.7k
            fido_blob_t x5c_blob;
    717
    33.7k
            fido_blob_t *list_ptr = NULL;
    718
    719
    33.7k
            memset(&x5c_blob, 0, sizeof(x5c_blob));
    720
    33.7k
            fido_free_blob_array(&cred->attstmt.x5c);
    721
    722
    33.7k
            if (fido_blob_set(&x5c_blob, ptr, len) < 0)
    723
    31.7k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    724
    725
    2.06k
            if (cred->attstmt.x5c.len == SIZE_MAX) {
    726
    0
                    fido_blob_reset(&x5c_blob);
    727
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    728
    0
            }
    729
    730
    2.06k
            if ((list_ptr = recallocarray(cred->attstmt.x5c.ptr,
    731
    2.06k
                cred->attstmt.x5c.len, cred->attstmt.x5c.len + 1,
    732
    2.06k
                sizeof(x5c_blob))) == NULL) {
    733
    29
                    fido_blob_reset(&x5c_blob);
    734
    29
                    return (FIDO_ERR_INTERNAL);
    735
    29
            }
    736
    737
    2.03k
            list_ptr[cred->attstmt.x5c.len++] = x5c_blob;
    738
    2.03k
            cred->attstmt.x5c.ptr = list_ptr;
    739
    740
    2.03k
            return (FIDO_OK);
    741
    2.06k
    }
    742
    743
    int
    744
    fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    745
    33.7k
    {
    746
    33.7k
            if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0)
    747
    30.8k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    748
    749
    2.97k
            return (FIDO_OK);
    750
    33.7k
    }
    751
    752
    int
    753
    fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    754
    26.8k
    {
    755
    26.8k
            cbor_item_t             *item = NULL;
    756
    26.8k
            struct cbor_load_result  cbor;
    757
    26.8k
            int                      r = FIDO_ERR_INVALID_ARGUMENT;
    758
    759
    26.8k
            fido_cred_clean_attstmt(&cred->attstmt);
    760
    761
    26.8k
            if (ptr == NULL || len == 0)
    762
    20.3k
                    goto fail;
    763
    764
    6.56k
            if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
    765
    37
                    fido_log_debug("%s: cbor_load", __func__);
    766
    37
                    goto fail;
    767
    37
            }
    768
    769
    6.53k
            if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
    770
    322
                    fido_log_debug("%s: cbor_decode_attstmt", __func__);
    771
    322
                    goto fail;
    772
    322
            }
    773
    774
    6.20k
            r = FIDO_OK;
    775
    26.8k
    fail:
    776
    26.8k
            if (item != NULL)
    777
    6.53k
                    cbor_decref(&item);
    778
    779
    26.8k
            if (r != FIDO_OK)
    780
    20.6k
                    fido_cred_clean_attstmt(&cred->attstmt);
    781
    782
    26.8k
            return (r);
    783
    6.20k
    }
    784
    785
    int
    786
    fido_cred_set_attobj(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    787
    6.45k
    {
    788
    6.45k
            cbor_item_t             *item = NULL;
    789
    6.45k
            struct cbor_load_result  cbor;
    790
    6.45k
            int                      r = FIDO_ERR_INVALID_ARGUMENT;
    791
    792
    6.45k
            fido_cred_clean_attobj(cred);
    793
    794
    6.45k
            if (ptr == NULL || len == 0)
    795
    9
                    goto fail;
    796
    797
    6.44k
            if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
    798
    178
                    fido_log_debug("%s: cbor_load", __func__);
    799
    178
                    goto fail;
    800
    178
            }
    801
    6.26k
            if (cbor_decode_attobj(item, cred) != 0) {
    802
    5.35k
                    fido_log_debug("%s: cbor_decode_attobj", __func__);
    803
    5.35k
                    goto fail;
    804
    5.35k
            }
    805
    806
    910
            r = FIDO_OK;
    807
    6.45k
    fail:
    808
    6.45k
            if (item != NULL)
    809
    6.26k
                    cbor_decref(&item);
    810
    811
    6.45k
            return (r);
    812
    910
    }
    813
    814
    int
    815
    fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
    816
    337k
    {
    817
    337k
            fido_blob_t id_blob;
    818
    337k
            fido_blob_t *list_ptr;
    819
    820
    337k
            memset(&id_blob, 0, sizeof(id_blob));
    821
    822
    337k
            if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
    823
    2.00k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    824
    825
    335k
            if (cred->excl.len == SIZE_MAX) {
    826
    0
                    free(id_blob.ptr);
    827
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    828
    0
            }
    829
    830
    335k
            if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
    831
    335k
                cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
    832
    891
                    free(id_blob.ptr);
    833
    891
                    return (FIDO_ERR_INTERNAL);
    834
    891
            }
    835
    836
    334k
            list_ptr[cred->excl.len++] = id_blob;
    837
    334k
            cred->excl.ptr = list_ptr;
    838
    839
    334k
            return (FIDO_OK);
    840
    335k
    }
    841
    842
    int
    843
    fido_cred_empty_exclude_list(fido_cred_t *cred)
    844
    127k
    {
    845
    127k
            fido_free_blob_array(&cred->excl);
    846
    127k
            memset(&cred->excl, 0, sizeof(cred->excl));
    847
    848
    127k
            return (FIDO_OK);
    849
    127k
    }
    850
    851
    int
    852
    fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
    853
        size_t data_len)
    854
    0
    {
    855
    0
            if (!fido_blob_is_empty(&cred->cdh) ||
    856
    0
                fido_blob_set(&cred->cd, data, data_len) < 0) {
    857
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    858
    0
            }
    859
    0
            if (fido_sha256(&cred->cdh, data, data_len) < 0) {
    860
    0
                    fido_blob_reset(&cred->cd);
    861
    0
                    return (FIDO_ERR_INTERNAL);
    862
    0
            }
    863
    864
    0
            return (FIDO_OK);
    865
    0
    }
    866
    867
    int
    868
    fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
    869
        size_t hash_len)
    870
    43.6k
    {
    871
    43.6k
            if (!fido_blob_is_empty(&cred->cd) ||
    872
    43.6k
                fido_blob_set(&cred->cdh, hash, hash_len) < 0)
    873
    2.82k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    874
    875
    40.8k
            return (FIDO_OK);
    876
    43.6k
    }
    877
    878
    int
    879
    fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
    880
    43.6k
    {
    881
    43.6k
            fido_rp_t *rp = &cred->rp;
    882
    883
    43.6k
            if (rp->id != NULL) {
    884
    11.9k
                    free(rp->id);
    885
    11.9k
                    rp->id = NULL;
    886
    11.9k
            }
    887
    43.6k
            if (rp->name != NULL) {
    888
    11.9k
                    free(rp->name);
    889
    11.9k
                    rp->name = NULL;
    890
    11.9k
            }
    891
    892
    43.6k
            if (id != NULL && (rp->id = strdup(id)) == NULL)
    893
    172
                    goto fail;
    894
    43.4k
            if (name != NULL && (rp->name = strdup(name)) == NULL)
    895
    111
                    goto fail;
    896
    897
    43.3k
            return (FIDO_OK);
    898
    283
    fail:
    899
    283
            free(rp->id);
    900
    283
            free(rp->name);
    901
    283
            rp->id = NULL;
    902
    283
            rp->name = NULL;
    903
    904
    283
            return (FIDO_ERR_INTERNAL);
    905
    43.4k
    }
    906
    907
    int
    908
    fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
    909
        size_t user_id_len, const char *name, const char *display_name,
    910
        const char *icon)
    911
    33.4k
    {
    912
    33.4k
            fido_user_t *up = &cred->user;
    913
    914
    33.4k
            if (up->id.ptr != NULL) {
    915
    11.8k
                    free(up->id.ptr);
    916
    11.8k
                    up->id.ptr = NULL;
    917
    11.8k
                    up->id.len = 0;
    918
    11.8k
            }
    919
    33.4k
            if (up->name != NULL) {
    920
    11.8k
                    free(up->name);
    921
    11.8k
                    up->name = NULL;
    922
    11.8k
            }
    923
    33.4k
            if (up->display_name != NULL) {
    924
    11.8k
                    free(up->display_name);
    925
    11.8k
                    up->display_name = NULL;
    926
    11.8k
            }
    927
    33.4k
            if (up->icon != NULL) {
    928
    11.8k
                    free(up->icon);
    929
    11.8k
                    up->icon = NULL;
    930
    11.8k
            }
    931
    932
    33.4k
            if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0)
    933
    202
                    goto fail;
    934
    33.2k
            if (name != NULL && (up->name = strdup(name)) == NULL)
    935
    116
                    goto fail;
    936
    33.0k
            if (display_name != NULL &&
    937
    33.0k
                (up->display_name = strdup(display_name)) == NULL)
    938
    107
                    goto fail;
    939
    32.9k
            if (icon != NULL && (up->icon = strdup(icon)) == NULL)
    940
    67
                    goto fail;
    941
    942
    32.9k
            return (FIDO_OK);
    943
    492
    fail:
    944
    492
            free(up->id.ptr);
    945
    492
            free(up->name);
    946
    492
            free(up->display_name);
    947
    492
            free(up->icon);
    948
    949
    492
            up->id.ptr = NULL;
    950
    492
            up->id.len = 0;
    951
    492
            up->name = NULL;
    952
    492
            up->display_name = NULL;
    953
    492
            up->icon = NULL;
    954
    955
    492
            return (FIDO_ERR_INTERNAL);
    956
    32.9k
    }
    957
    958
    int
    959
    fido_cred_set_extensions(fido_cred_t *cred, int ext)
    960
    19.0k
    {
    961
    19.0k
            if (ext == 0)
    962
    1.12k
                    cred->ext.mask = 0;
    963
    17.9k
            else {
    964
    17.9k
                    if ((ext & FIDO_EXT_CRED_MASK) != ext)
    965
    11.8k
                            return (FIDO_ERR_INVALID_ARGUMENT);
    966
    6.05k
                    cred->ext.mask |= ext;
    967
    6.05k
            }
    968
    969
    7.18k
            return (FIDO_OK);
    970
    19.0k
    }
    971
    972
    int
    973
    fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
    974
    0
    {
    975
    0
            cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
    976
    0
            cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
    977
    978
    0
            return (FIDO_OK);
    979
    0
    }
    980
    981
    int
    982
    fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
    983
    6.19k
    {
    984
    6.19k
            cred->rk = rk;
    985
    986
    6.19k
            return (FIDO_OK);
    987
    6.19k
    }
    988
    989
    int
    990
    fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
    991
    6.37k
    {
    992
    6.37k
            cred->uv = uv;
    993
    994
    6.37k
            return (FIDO_OK);
    995
    6.37k
    }
    996
    997
    int
    998
    fido_cred_set_entattest(fido_cred_t *cred, int ea)
    999
    11.2k
    {
    1000
    11.2k
            if (ea != 0 && ea != FIDO_ENTATTEST_VENDOR &&
    1001
    11.2k
                ea != FIDO_ENTATTEST_PLATFORM)
    1002
    2.01k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1003
    1004
    9.20k
            cred->ea.mode = ea;
    1005
    1006
    9.20k
            return (FIDO_OK);
    1007
    11.2k
    }
    1008
    1009
    int
    1010
    fido_cred_set_prot(fido_cred_t *cred, int prot)
    1011
    29.0k
    {
    1012
    29.0k
            if (prot == 0) {
    1013
    16.9k
                    cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT;
    1014
    16.9k
                    cred->ext.prot = 0;
    1015
    16.9k
            } else {
    1016
    12.1k
                    if (prot != FIDO_CRED_PROT_UV_OPTIONAL &&
    1017
    12.1k
                        prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID &&
    1018
    12.1k
                        prot != FIDO_CRED_PROT_UV_REQUIRED)
    1019
    176
                            return (FIDO_ERR_INVALID_ARGUMENT);
    1020
    1021
    11.9k
                    cred->ext.mask |= FIDO_EXT_CRED_PROTECT;
    1022
    11.9k
                    cred->ext.prot = prot;
    1023
    11.9k
            }
    1024
    1025
    28.8k
            return (FIDO_OK);
    1026
    29.0k
    }
    1027
    1028
    int
    1029
    fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
    1030
    16.0k
    {
    1031
    16.0k
            if (len == 0)
    1032
    12.6k
                    cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
    1033
    3.34k
            else
    1034
    3.34k
                    cred->ext.mask |= FIDO_EXT_MINPINLEN;
    1035
    1036
    16.0k
            cred->ext.minpinlen = len;
    1037
    1038
    16.0k
            return (FIDO_OK);
    1039
    16.0k
    }
    1040
    1041
    int
    1042
    fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
    1043
    2.63k
    {
    1044
    2.63k
            if (ptr == NULL || len == 0)
    1045
    5
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1046
    2.62k
            if (fido_blob_set(&cred->blob, ptr, len) < 0)
    1047
    6
                    return (FIDO_ERR_INTERNAL);
    1048
    1049
    2.62k
            cred->ext.mask |= FIDO_EXT_CRED_BLOB;
    1050
    1051
    2.62k
            return (FIDO_OK);
    1052
    2.62k
    }
    1053
    1054
    int
    1055
    fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
    1056
    3.68k
    {
    1057
    3.68k
            free(cred->fmt);
    1058
    3.68k
            cred->fmt = NULL;
    1059
    1060
    3.68k
            if (fmt == NULL)
    1061
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1062
    1063
    3.68k
            if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
    1064
    3.68k
                strcmp(fmt, "none") && strcmp(fmt, "tpm"))
    1065
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1066
    1067
    3.68k
            if ((cred->fmt = strdup(fmt)) == NULL)
    1068
    36
                    return (FIDO_ERR_INTERNAL);
    1069
    1070
    3.65k
            return (FIDO_OK);
    1071
    3.68k
    }
    1072
    1073
    int
    1074
    fido_cred_set_type(fido_cred_t *cred, int cose_alg)
    1075
    43.6k
    {
    1076
    43.6k
            if (cred->type != 0)
    1077
    12.0k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1078
    31.6k
            if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 &&
    1079
    31.6k
                cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA)
    1080
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    1081
    1082
    31.6k
            cred->type = cose_alg;
    1083
    1084
    31.6k
            return (FIDO_OK);
    1085
    31.6k
    }
    1086
    1087
    int
    1088
    fido_cred_type(const fido_cred_t *cred)
    1089
    24.3k
    {
    1090
    24.3k
            return (cred->type);
    1091
    24.3k
    }
    1092
    1093
    uint8_t
    1094
    fido_cred_flags(const fido_cred_t *cred)
    1095
    13.1k
    {
    1096
    13.1k
            return (cred->authdata.flags);
    1097
    13.1k
    }
    1098
    1099
    uint32_t
    1100
    fido_cred_sigcount(const fido_cred_t *cred)
    1101
    13.1k
    {
    1102
    13.1k
            return (cred->authdata.sigcount);
    1103
    13.1k
    }
    1104
    1105
    const unsigned char *
    1106
    fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
    1107
    13.1k
    {
    1108
    13.1k
            return (cred->cdh.ptr);
    1109
    13.1k
    }
    1110
    1111
    size_t
    1112
    fido_cred_clientdata_hash_len(const fido_cred_t *cred)
    1113
    13.1k
    {
    1114
    13.1k
            return (cred->cdh.len);
    1115
    13.1k
    }
    1116
    1117
    const unsigned char *
    1118
    fido_cred_x5c_ptr(const fido_cred_t *cred)
    1119
    13.1k
    {
    1120
    13.1k
            return (fido_cred_x5c_list_ptr(cred, 0));
    1121
    13.1k
    }
    1122
    1123
    size_t
    1124
    fido_cred_x5c_len(const fido_cred_t *cred)
    1125
    13.1k
    {
    1126
    13.1k
            return (fido_cred_x5c_list_len(cred, 0));
    1127
    13.1k
    }
    1128
    1129
    size_t
    1130
    fido_cred_x5c_list_count(const fido_cred_t *cred)
    1131
    28.3k
    {
    1132
    28.3k
            return (cred->attstmt.x5c.len);
    1133
    28.3k
    }
    1134
    1135
    const unsigned char *
    1136
    fido_cred_x5c_list_ptr(const fido_cred_t *cred, size_t i)
    1137
    28.4k
    {
    1138
    28.4k
            if (i >= cred->attstmt.x5c.len)
    1139
    24.3k
                    return (NULL);
    1140
    1141
    4.08k
            return (cred->attstmt.x5c.ptr[i].ptr);
    1142
    28.4k
    }
    1143
    1144
    size_t
    1145
    fido_cred_x5c_list_len(const fido_cred_t *cred, size_t i)
    1146
    28.4k
    {
    1147
    28.4k
            if (i >= cred->attstmt.x5c.len)
    1148
    24.3k
                    return (0);
    1149
    1150
    4.08k
            return (cred->attstmt.x5c.ptr[i].len);
    1151
    28.4k
    }
    1152
    1153
    const unsigned char *
    1154
    fido_cred_sig_ptr(const fido_cred_t *cred)
    1155
    13.1k
    {
    1156
    13.1k
            return (cred->attstmt.sig.ptr);
    1157
    13.1k
    }
    1158
    1159
    size_t
    1160
    fido_cred_sig_len(const fido_cred_t *cred)
    1161
    13.1k
    {
    1162
    13.1k
            return (cred->attstmt.sig.len);
    1163
    13.1k
    }
    1164
    1165
    const unsigned char *
    1166
    fido_cred_authdata_ptr(const fido_cred_t *cred)
    1167
    19.6k
    {
    1168
    19.6k
            return (cred->authdata_cbor.ptr);
    1169
    19.6k
    }
    1170
    1171
    size_t
    1172
    fido_cred_authdata_len(const fido_cred_t *cred)
    1173
    19.6k
    {
    1174
    19.6k
            return (cred->authdata_cbor.len);
    1175
    19.6k
    }
    1176
    1177
    const unsigned char *
    1178
    fido_cred_authdata_raw_ptr(const fido_cred_t *cred)
    1179
    13.1k
    {
    1180
    13.1k
            return (cred->authdata_raw.ptr);
    1181
    13.1k
    }
    1182
    1183
    size_t
    1184
    fido_cred_authdata_raw_len(const fido_cred_t *cred)
    1185
    13.1k
    {
    1186
    13.1k
            return (cred->authdata_raw.len);
    1187
    13.1k
    }
    1188
    1189
    const unsigned char *
    1190
    fido_cred_attstmt_ptr(const fido_cred_t *cred)
    1191
    19.6k
    {
    1192
    19.6k
            return (cred->attstmt.cbor.ptr);
    1193
    19.6k
    }
    1194
    1195
    size_t
    1196
    fido_cred_attstmt_len(const fido_cred_t *cred)
    1197
    19.6k
    {
    1198
    19.6k
            return (cred->attstmt.cbor.len);
    1199
    19.6k
    }
    1200
    1201
    const unsigned char *
    1202
    fido_cred_pubkey_ptr(const fido_cred_t *cred)
    1203
    24.3k
    {
    1204
    24.3k
            const void *ptr;
    1205
    1206
    24.3k
            switch (cred->attcred.type) {
    1207
    6.45k
            case COSE_ES256:
    1208
    6.45k
                    ptr = &cred->attcred.pubkey.es256;
    1209
    6.45k
                    break;
    1210
    260
            case COSE_ES384:
    1211
    260
                    ptr = &cred->attcred.pubkey.es384;
    1212
    260
                    break;
    1213
    243
            case COSE_RS256:
    1214
    243
                    ptr = &cred->attcred.pubkey.rs256;
    1215
    243
                    break;
    1216
    1.14k
            case COSE_EDDSA:
    1217
    1.14k
                    ptr = &cred->attcred.pubkey.eddsa;
    1218
    1.14k
                    break;
    1219
    16.2k
            default:
    1220
    16.2k
                    ptr = NULL;
    1221
    16.2k
                    break;
    1222
    24.3k
            }
    1223
    1224
    24.3k
            return (ptr);
    1225
    24.3k
    }
    1226
    1227
    size_t
    1228
    fido_cred_pubkey_len(const fido_cred_t *cred)
    1229
    24.3k
    {
    1230
    24.3k
            size_t len;
    1231
    1232
    24.3k
            switch (cred->attcred.type) {
    1233
    6.45k
            case COSE_ES256:
    1234
    6.45k
                    len = sizeof(cred->attcred.pubkey.es256);
    1235
    6.45k
                    break;
    1236
    260
            case COSE_ES384:
    1237
    260
                    len = sizeof(cred->attcred.pubkey.es384);
    1238
    260
                    break;
    1239
    243
            case COSE_RS256:
    1240
    243
                    len = sizeof(cred->attcred.pubkey.rs256);
    1241
    243
                    break;
    1242
    1.14k
            case COSE_EDDSA:
    1243
    1.14k
                    len = sizeof(cred->attcred.pubkey.eddsa);
    1244
    1.14k
                    break;
    1245
    16.2k
            default:
    1246
    16.2k
                    len = 0;
    1247
    16.2k
                    break;
    1248
    24.3k
            }
    1249
    1250
    24.3k
            return (len);
    1251
    24.3k
    }
    1252
    1253
    const unsigned char *
    1254
    fido_cred_id_ptr(const fido_cred_t *cred)
    1255
    37.5k
    {
    1256
    37.5k
            return (cred->attcred.id.ptr);
    1257
    37.5k
    }
    1258
    1259
    size_t
    1260
    fido_cred_id_len(const fido_cred_t *cred)
    1261
    37.5k
    {
    1262
    37.5k
            return (cred->attcred.id.len);
    1263
    37.5k
    }
    1264
    1265
    const unsigned char *
    1266
    fido_cred_aaguid_ptr(const fido_cred_t *cred)
    1267
    13.1k
    {
    1268
    13.1k
            return (cred->attcred.aaguid);
    1269
    13.1k
    }
    1270
    1271
    size_t
    1272
    fido_cred_aaguid_len(const fido_cred_t *cred)
    1273
    13.1k
    {
    1274
    13.1k
            return (sizeof(cred->attcred.aaguid));
    1275
    13.1k
    }
    1276
    1277
    int
    1278
    fido_cred_prot(const fido_cred_t *cred)
    1279
    24.4k
    {
    1280
    24.4k
            return (cred->ext.prot);
    1281
    24.4k
    }
    1282
    1283
    size_t
    1284
    fido_cred_pin_minlen(const fido_cred_t *cred)
    1285
    26.3k
    {
    1286
    26.3k
            return (cred->ext.minpinlen);
    1287
    26.3k
    }
    1288
    1289
    const char *
    1290
    fido_cred_fmt(const fido_cred_t *cred)
    1291
    19.6k
    {
    1292
    19.6k
            return (cred->fmt);
    1293
    19.6k
    }
    1294
    1295
    const char *
    1296
    fido_cred_rp_id(const fido_cred_t *cred)
    1297
    13.1k
    {
    1298
    13.1k
            return (cred->rp.id);
    1299
    13.1k
    }
    1300
    1301
    const char *
    1302
    fido_cred_rp_name(const fido_cred_t *cred)
    1303
    13.1k
    {
    1304
    13.1k
            return (cred->rp.name);
    1305
    13.1k
    }
    1306
    1307
    const char *
    1308
    fido_cred_user_name(const fido_cred_t *cred)
    1309
    24.3k
    {
    1310
    24.3k
            return (cred->user.name);
    1311
    24.3k
    }
    1312
    1313
    const char *
    1314
    fido_cred_display_name(const fido_cred_t *cred)
    1315
    24.3k
    {
    1316
    24.3k
            return (cred->user.display_name);
    1317
    24.3k
    }
    1318
    1319
    const unsigned char *
    1320
    fido_cred_user_id_ptr(const fido_cred_t *cred)
    1321
    24.3k
    {
    1322
    24.3k
            return (cred->user.id.ptr);
    1323
    24.3k
    }
    1324
    1325
    size_t
    1326
    fido_cred_user_id_len(const fido_cred_t *cred)
    1327
    24.3k
    {
    1328
    24.3k
            return (cred->user.id.len);
    1329
    24.3k
    }
    1330
    1331
    const unsigned char *
    1332
    fido_cred_largeblob_key_ptr(const fido_cred_t *cred)
    1333
    13.1k
    {
    1334
    13.1k
            return (cred->largeblob_key.ptr);
    1335
    13.1k
    }
    1336
    1337
    size_t
    1338
    fido_cred_largeblob_key_len(const fido_cred_t *cred)
    1339
    13.1k
    {
    1340
    13.1k
            return (cred->largeblob_key.len);
    1341
    13.1k
    }
    1342
    1343
    bool
    1344
    fido_cred_entattest(const fido_cred_t *cred)
    1345
    13.1k
    {
    1346
    13.1k
            return (cred->ea.att);
    1347
    13.1k
    }