## Coverage Report

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

    /libfido2/src/largeblob.c

    Line
    Count
    Source (jump to first uncovered line)
    1
    /*
    2
     * Copyright (c) 2020-2022 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
    13
    1.42k
    #define LARGEBLOB_DIGEST_LENGTH 16
    14
    648
    #define LARGEBLOB_NONCE_LENGTH  12
    15
    657
    #define LARGEBLOB_TAG_LENGTH    16
    16
    17
    typedef struct largeblob {
    18
            size_t origsiz;
    19
            fido_blob_t ciphertext;
    20
            fido_blob_t nonce;
    21
    } largeblob_t;
    22
    23
    static largeblob_t *
    24
    largeblob_new(void)
    25
    636
    {
    26
    636
            return calloc(1, sizeof(largeblob_t));
    27
    636
    }
    28
    29
    static void
    30
    largeblob_reset(largeblob_t *blob)
    31
    1.29k
    {
    32
    1.29k
            fido_blob_reset(&blob->ciphertext);
    33
    1.29k
            fido_blob_reset(&blob->nonce);
    34
    1.29k
            blob->origsiz = 0;
    35
    1.29k
    }
    36
    37
    static void
    38
    largeblob_free(largeblob_t **blob_ptr)
    39
    636
    {
    40
    636
            largeblob_t *blob;
    41
    42
    636
            if (blob_ptr == NULL || (blob = *blob_ptr) == NULL)
    43
    6
                    return;
    44
    630
            largeblob_reset(blob);
    45
    630
            free(blob);
    46
    630
            *blob_ptr = NULL;
    47
    630
    }
    48
    49
    static int
    50
    largeblob_aad(fido_blob_t *aad, uint64_t size)
    51
    1.25k
    {
    52
    1.25k
            uint8_t buf[4 + sizeof(uint64_t)];
    53
    54
    1.25k
            buf[0] = 0x62; /* b */
    55
    1.25k
            buf[1] = 0x6c; /* l */
    56
    1.25k
            buf[2] = 0x6f; /* o */
    57
    1.25k
            buf[3] = 0x62; /* b */
    58
    1.25k
            size = htole64(size);
    59
    1.25k
            memcpy(&buf[4], &size, sizeof(uint64_t));
    60
    61
    1.25k
            return fido_blob_set(aad, buf, sizeof(buf));
    62
    1.25k
    }
    63
    64
    static fido_blob_t *
    65
    largeblob_decrypt(const largeblob_t *blob, const fido_blob_t *key)
    66
    648
    {
    67
    648
            fido_blob_t *plaintext = NULL, *aad = NULL;
    68
    648
            int ok = -1;
    69
    70
    648
            if ((plaintext = fido_blob_new()) == NULL ||
    71
    648
                (aad = fido_blob_new()) == NULL) {
    72
    15
                    fido_log_debug("%s: fido_blob_new", __func__);
    73
    15
                    goto fail;
    74
    15
            }
    75
    633
            if (largeblob_aad(aad, blob->origsiz) < 0) {
    76
    11
                    fido_log_debug("%s: largeblob_aad", __func__);
    77
    11
                    goto fail;
    78
    11
            }
    79
    622
            if (aes256_gcm_dec(key, &blob->nonce, aad, &blob->ciphertext,
    80
    622
                plaintext) < 0) {
    81
    301
                    fido_log_debug("%s: aes256_gcm_dec", __func__);
    82
    301
                    goto fail;
    83
    301
            }
    84
    85
    321
            ok = 0;
    86
    648
    fail:
    87
    648
            fido_blob_free(&aad);
    88
    89
    648
            if (ok < 0)
    90
    327
                    fido_blob_free(&plaintext);
    91
    92
    648
            return plaintext;
    93
    321
    }
    94
    95
    static int
    96
    largeblob_get_nonce(largeblob_t *blob)
    97
    621
    {
    98
    621
            uint8_t buf[LARGEBLOB_NONCE_LENGTH];
    99
    621
            int ok = -1;
    100
    101
    621
            if (fido_get_random(buf, sizeof(buf)) < 0) {
    102
    4
                    fido_log_debug("%s: fido_get_random", __func__);
    103
    4
                    goto fail;
    104
    4
            }
    105
    617
            if (fido_blob_set(&blob->nonce, buf, sizeof(buf)) < 0) {
    106
    2
                    fido_log_debug("%s: fido_blob_set", __func__);
    107
    2
                    goto fail;
    108
    2
            }
    109
    110
    615
            ok = 0;
    111
    621
    fail:
    112
    621
            explicit_bzero(buf, sizeof(buf));
    113
    114
    621
            return ok;
    115
    615
    }
    116
    117
    static int
    118
    largeblob_seal(largeblob_t *blob, const fido_blob_t *body,
    119
        const fido_blob_t *key)
    120
    630
    {
    121
    630
            fido_blob_t *plaintext = NULL, *aad = NULL;
    122
    630
            int ok = -1;
    123
    124
    630
            if ((plaintext = fido_blob_new()) == NULL ||
    125
    630
                (aad = fido_blob_new()) == NULL) {
    126
    2
                    fido_log_debug("%s: fido_blob_new", __func__);
    127
    2
                    goto fail;
    128
    2
            }
    129
    628
            if (fido_compress(plaintext, body) != FIDO_OK) {
    130
    5
                    fido_log_debug("%s: fido_compress", __func__);
    131
    5
                    goto fail;
    132
    5
            }
    133
    623
            if (largeblob_aad(aad, body->len) < 0) {
    134
    2
                    fido_log_debug("%s: largeblob_aad", __func__);
    135
    2
                    goto fail;
    136
    2
            }
    137
    621
            if (largeblob_get_nonce(blob) < 0) {
    138
    6
                    fido_log_debug("%s: largeblob_get_nonce", __func__);
    139
    6
                    goto fail;
    140
    6
            }
    141
    615
            if (aes256_gcm_enc(key, &blob->nonce, aad, plaintext,
    142
    615
                &blob->ciphertext) < 0) {
    143
    142
                    fido_log_debug("%s: aes256_gcm_enc", __func__);
    144
    142
                    goto fail;
    145
    142
            }
    146
    473
            blob->origsiz = body->len;
    147
    148
    473
            ok = 0;
    149
    630
    fail:
    150
    630
            fido_blob_free(&plaintext);
    151
    630
            fido_blob_free(&aad);
    152
    153
    630
            return ok;
    154
    473
    }
    155
    156
    static int
    157
    largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count, int *ms)
    158
    844
    {
    159
    844
            fido_blob_t f;
    160
    844
            cbor_item_t *argv[3];
    161
    844
            int r;
    162
    163
    844
            memset(argv, 0, sizeof(argv));
    164
    844
            memset(&f, 0, sizeof(f));
    165
    166
    844
            if ((argv[0] = cbor_build_uint(count)) == NULL ||
    167
    844
                (argv[2] = cbor_build_uint(offset)) == NULL) {
    168
    10
                    fido_log_debug("%s: cbor encode", __func__);
    169
    10
                    r = FIDO_ERR_INTERNAL;
    170
    10
                    goto fail;
    171
    10
            }
    172
    834
            if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 ||
    173
    834
                fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    174
    24
                    fido_log_debug("%s: fido_tx", __func__);
    175
    24
                    r = FIDO_ERR_TX;
    176
    24
                    goto fail;
    177
    24
            }
    178
    179
    810
            r = FIDO_OK;
    180
    844
    fail:
    181
    844
            cbor_vector_free(argv, nitems(argv));
    182
    844
            free(f.ptr);
    183
    184
    844
            return r;
    185
    810
    }
    186
    187
    static int
    188
    parse_largeblob_reply(const cbor_item_t *key, const cbor_item_t *val,
    189
        void *arg)
    190
    843
    {
    191
    843
            if (cbor_isa_uint(key) == false ||
    192
    843
                cbor_int_get_width(key) != CBOR_INT_8 ||
    193
    843
                cbor_get_uint8(key) != 1) {
    194
    183
                    fido_log_debug("%s: cbor type", __func__);
    195
    183
                    return 0; /* ignore */
    196
    183
            }
    197
    198
    660
            return fido_blob_decode(val, arg);
    199
    843
    }
    200
    201
    static int
    202
    largeblob_get_rx(fido_dev_t *dev, fido_blob_t **chunk, int *ms)
    203
    810
    {
    204
    810
            unsigned char *msg;
    205
    810
            int msglen, r;
    206
    207
    810
            *chunk = NULL;
    208
    810
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    209
    3
                    r = FIDO_ERR_INTERNAL;
    210
    3
                    goto out;
    211
    3
            }
    212
    807
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    213
    65
                    fido_log_debug("%s: fido_rx", __func__);
    214
    65
                    r = FIDO_ERR_RX;
    215
    65
                    goto out;
    216
    65
            }
    217
    742
            if ((*chunk = fido_blob_new()) == NULL) {
    218
    3
                    fido_log_debug("%s: fido_blob_new", __func__);
    219
    3
                    r = FIDO_ERR_INTERNAL;
    220
    3
                    goto out;
    221
    3
            }
    222
    739
            if ((r = cbor_parse_reply(msg, (size_t)msglen, *chunk,
    223
    739
                parse_largeblob_reply)) != FIDO_OK) {
    224
    70
                    fido_log_debug("%s: parse_largeblob_reply", __func__);
    225
    70
                    goto out;
    226
    70
            }
    227
    228
    669
            r = FIDO_OK;
    229
    810
    out:
    230
    810
            if (r != FIDO_OK)
    231
    141
                    fido_blob_free(chunk);
    232
    233
    810
            freezero(msg, FIDO_MAXMSG);
    234
    235
    810
            return r;
    236
    669
    }
    237
    238
    static cbor_item_t *
    239
    largeblob_array_load(const uint8_t *ptr, size_t len)
    240
    409
    {
    241
    409
            struct cbor_load_result cbor;
    242
    409
            cbor_item_t *item;
    243
    244
    409
            if (len < LARGEBLOB_DIGEST_LENGTH) {
    245
    0
                    fido_log_debug("%s: len", __func__);
    246
    0
                    return NULL;
    247
    0
            }
    248
    409
            len -= LARGEBLOB_DIGEST_LENGTH;
    249
    409
            if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
    250
    3
                    fido_log_debug("%s: cbor_load", __func__);
    251
    3
                    return NULL;
    252
    3
            }
    253
    406
            if (!cbor_isa_array(item) || !cbor_array_is_definite(item)) {
    254
    0
                    fido_log_debug("%s: cbor type", __func__);
    255
    0
                    cbor_decref(&item);
    256
    0
                    return NULL;
    257
    0
            }
    258
    259
    406
            return item;
    260
    406
    }
    261
    262
    static size_t
    263
    get_chunklen(fido_dev_t *dev)
    264
    2.87k
    {
    265
    2.87k
            uint64_t maxchunklen;
    266
    267
    2.87k
            if ((maxchunklen = fido_dev_maxmsgsize(dev)) > SIZE_MAX)
    268
    0
                    maxchunklen = SIZE_MAX;
    269
    2.87k
            if (maxchunklen > FIDO_MAXMSG)
    270
    412
                    maxchunklen = FIDO_MAXMSG;
    271
    2.87k
            maxchunklen = maxchunklen > 64 ? maxchunklen - 64 : 0;
    272
    273
    2.87k
            return (size_t)maxchunklen;
    274
    2.87k
    }
    275
    276
    static int
    277
    largeblob_do_decode(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    278
    1.97k
    {
    279
    1.97k
            largeblob_t *blob = arg;
    280
    1.97k
            uint64_t origsiz;
    281
    282
    1.97k
            if (cbor_isa_uint(key) == false ||
    283
    1.97k
                cbor_int_get_width(key) != CBOR_INT_8) {
    284
    0
                    fido_log_debug("%s: cbor type", __func__);
    285
    0
                    return 0; /* ignore */
    286
    0
            }
    287
    288
    1.97k
            switch (cbor_get_uint8(key)) {
    289
    665
            case 1: /* ciphertext */
    290
    665
                    if (fido_blob_decode(val, &blob->ciphertext) < 0 ||
    291
    665
                        blob->ciphertext.len < LARGEBLOB_TAG_LENGTH)
    292
    8
                            return -1;
    293
    657
                    return 0;
    294
    657
            case 2: /* nonce */
    295
    657
                    if (fido_blob_decode(val, &blob->nonce) < 0 ||
    296
    657
                        blob->nonce.len != LARGEBLOB_NONCE_LENGTH)
    297
    9
                            return -1;
    298
    648
                    return 0;
    299
    648
            case 3: /* origSize */
    300
    648
                    if (!cbor_isa_uint(val) ||
    301
    648
                        (origsiz = cbor_get_int(val)) > SIZE_MAX)
    302
    0
                            return -1;
    303
    648
                    blob->origsiz = (size_t)origsiz;
    304
    648
                    return 0;
    305
    0
            default: /* ignore */
    306
    0
                    fido_log_debug("%s: cbor type", __func__);
    307
    0
                    return 0;
    308
    1.97k
            }
    309
    1.97k
    }
    310
    311
    static int
    312
    largeblob_decode(largeblob_t *blob, const cbor_item_t *item)
    313
    668
    {
    314
    668
            if (!cbor_isa_map(item) || !cbor_map_is_definite(item)) {
    315
    0
                    fido_log_debug("%s: cbor type", __func__);
    316
    0
                    return -1;
    317
    0
            }
    318
    668
            if (cbor_map_iter(item, blob, largeblob_do_decode) < 0) {
    319
    20
                    fido_log_debug("%s: cbor_map_iter", __func__);
    320
    20
                    return -1;
    321
    20
            }
    322
    648
            if (fido_blob_is_empty(&blob->ciphertext) ||
    323
    648
                fido_blob_is_empty(&blob->nonce) || blob->origsiz == 0) {
    324
    0
                    fido_log_debug("%s: incomplete blob", __func__);
    325
    0
                    return -1;
    326
    0
            }
    327
    328
    648
            return 0;
    329
    648
    }
    330
    331
    static cbor_item_t *
    332
    largeblob_encode(const fido_blob_t *body, const fido_blob_t *key)
    333
    636
    {
    334
    636
            largeblob_t *blob;
    335
    636
            cbor_item_t *argv[3], *item = NULL;
    336
    337
    636
            memset(argv, 0, sizeof(argv));
    338
    636
            if ((blob = largeblob_new()) == NULL ||
    339
    636
                largeblob_seal(blob, body, key) < 0) {
    340
    163
                    fido_log_debug("%s: largeblob_seal", __func__);
    341
    163
                    goto fail;
    342
    163
            }
    343
    473
            if ((argv[0] = fido_blob_encode(&blob->ciphertext)) == NULL ||
    344
    473
                (argv[1] = fido_blob_encode(&blob->nonce)) == NULL ||
    345
    473
                (argv[2] = cbor_build_uint(blob->origsiz)) == NULL) {
    346
    3
                    fido_log_debug("%s: cbor encode", __func__);
    347
    3
                    goto fail;
    348
    3
            }
    349
    470
            item = cbor_flatten_vector(argv, nitems(argv));
    350
    636
    fail:
    351
    636
            cbor_vector_free(argv, nitems(argv));
    352
    636
            largeblob_free(&blob);
    353
    354
    636
            return item;
    355
    470
    }
    356
    357
    static int
    358
    largeblob_array_lookup(fido_blob_t *out, size_t *idx, const cbor_item_t *item,
    359
        const fido_blob_t *key)
    360
    594
    {
    361
    594
            cbor_item_t **v;
    362
    594
            fido_blob_t *plaintext = NULL;
    363
    594
            largeblob_t blob;
    364
    594
            int r;
    365
    366
    594
            memset(&blob, 0, sizeof(blob));
    367
    594
            if (idx != NULL)
    368
    566
                    *idx = 0;
    369
    594
            if ((v = cbor_array_handle(item)) == NULL)
    370
    5
                    return FIDO_ERR_INVALID_ARGUMENT;
    371
    936
            for (size_t i = 0; i < cbor_array_size(item); i++) {
    372
    668
                    if (largeblob_decode(&blob, v[i]) < 0 ||
    373
    668
                        (plaintext = largeblob_decrypt(&blob, key)) == NULL) {
    374
    347
                            fido_log_debug("%s: largeblob_decode", __func__);
    375
    347
                            largeblob_reset(&blob);
    376
    347
                            continue;
    377
    347
                    }
    378
    321
                    if (idx != NULL)
    379
    313
                            *idx = i;
    380
    321
                    break;
    381
    668
            }
    382
    589
            if (plaintext == NULL) {
    383
    268
                    fido_log_debug("%s: not found", __func__);
    384
    268
                    return FIDO_ERR_NOTFOUND;
    385
    268
            }
    386
    321
            if (out != NULL)
    387
    8
                    r = fido_uncompress(out, plaintext, blob.origsiz);
    388
    313
            else
    389
    313
                    r = FIDO_OK;
    390
    391
    321
            fido_blob_free(&plaintext);
    392
    321
            largeblob_reset(&blob);
    393
    394
    321
            return r;
    395
    589
    }
    396
    397
    static int
    398
    largeblob_array_digest(u_char out[LARGEBLOB_DIGEST_LENGTH], const u_char *data,
    399
        size_t len)
    400
    610
    {
    401
    610
            u_char dgst[SHA256_DIGEST_LENGTH];
    402
    403
    610
            if (data == NULL || len == 0)
    404
    3
                    return -1;
    405
    607
            if (SHA256(data, len, dgst) != dgst)
    406
    3
                    return -1;
    407
    604
            memcpy(out, dgst, LARGEBLOB_DIGEST_LENGTH);
    408
    409
    604
            return 0;
    410
    607
    }
    411
    412
    static int
    413
    largeblob_array_check(const fido_blob_t *array)
    414
    618
    {
    415
    618
            u_char expected_hash[LARGEBLOB_DIGEST_LENGTH];
    416
    618
            size_t body_len;
    417
    418
    618
            fido_log_xxd(array->ptr, array->len, __func__);
    419
    618
            if (array->len < sizeof(expected_hash)) {
    420
    8
                    fido_log_debug("%s: len %zu", __func__, array->len);
    421
    8
                    return -1;
    422
    8
            }
    423
    610
            body_len = array->len - sizeof(expected_hash);
    424
    610
            if (largeblob_array_digest(expected_hash, array->ptr, body_len) < 0) {
    425
    6
                    fido_log_debug("%s: largeblob_array_digest", __func__);
    426
    6
                    return -1;
    427
    6
            }
    428
    429
    604
            return timingsafe_bcmp(expected_hash, array->ptr + body_len,
    430
    604
                sizeof(expected_hash));
    431
    610
    }
    432
    433
    static int
    434
    largeblob_get_array(fido_dev_t *dev, cbor_item_t **item, int *ms)
    435
    1.60k
    {
    436
    1.60k
            fido_blob_t *array, *chunk = NULL;
    437
    1.60k
            size_t n;
    438
    1.60k
            int r;
    439
    440
    1.60k
            *item = NULL;
    441
    1.60k
            if ((n = get_chunklen(dev)) == 0)
    442
    785
                    return FIDO_ERR_INVALID_ARGUMENT;
    443
    818
            if ((array = fido_blob_new()) == NULL)
    444
    3
                    return FIDO_ERR_INTERNAL;
    445
    844
            do {
    446
    844
                    fido_blob_free(&chunk);
    447
    844
                    if ((r = largeblob_get_tx(dev, array->len, n, ms)) != FIDO_OK ||
    448
    844
                        (r = largeblob_get_rx(dev, &chunk, ms)) != FIDO_OK) {
    449
    175
                            fido_log_debug("%s: largeblob_get_wait %zu/%zu",
    450
    175
                                __func__, array->len, n);
    451
    175
                            goto fail;
    452
    175
                    }
    453
    669
                    if (fido_blob_append(array, chunk->ptr, chunk->len) < 0) {
    454
    22
                            fido_log_debug("%s: fido_blob_append", __func__);
    455
    22
                            r = FIDO_ERR_INTERNAL;
    456
    22
                            goto fail;
    457
    22
                    }
    458
    669
            } while (chunk->len == n);
    459
    460
    618
            if (largeblob_array_check(array) != 0)
    461
    209
                    *item = cbor_new_definite_array(0); /* per spec */
    462
    409
            else
    463
    409
                    *item = largeblob_array_load(array->ptr, array->len);
    464
    618
            if (*item == NULL)
    465
    6
                    r = FIDO_ERR_INTERNAL;
    466
    612
            else
    467
    612
                    r = FIDO_OK;
    468
    815
    fail:
    469
    815
            fido_blob_free(&array);
    470
    815
            fido_blob_free(&chunk);
    471
    472
    815
            return r;
    473
    618
    }
    474
    475
    static int
    476
    prepare_hmac(size_t offset, const u_char *data, size_t len, fido_blob_t *hmac)
    477
    63
    {
    478
    63
            uint8_t buf[32 + 2 + sizeof(uint32_t) + SHA256_DIGEST_LENGTH];
    479
    63
            uint32_t u32_offset;
    480
    481
    63
            if (data == NULL || len == 0) {
    482
    0
                    fido_log_debug("%s: invalid data=%p, len=%zu", __func__,
    483
    0
                        (const void *)data, len);
    484
    0
                    return -1;
    485
    0
            }
    486
    63
            if (offset > UINT32_MAX) {
    487
    0
                    fido_log_debug("%s: invalid offset=%zu", __func__, offset);
    488
    0
                    return -1;
    489
    0
            }
    490
    491
    63
            memset(buf, 0xff, 32);
    492
    63
            buf[32] = CTAP_CBOR_LARGEBLOB;
    493
    63
            buf[33] = 0x00;
    494
    63
            u32_offset = htole32((uint32_t)offset);
    495
    63
            memcpy(&buf[34], &u32_offset, sizeof(uint32_t));
    496
    63
            if (SHA256(data, len, &buf[38]) != &buf[38]) {
    497
    2
                    fido_log_debug("%s: SHA256", __func__);
    498
    2
                    return -1;
    499
    2
            }
    500
    501
    61
            return fido_blob_set(hmac, buf, sizeof(buf));
    502
    63
    }
    503
    504
    static int
    505
    largeblob_set_tx(fido_dev_t *dev, const fido_blob_t *token, const u_char *chunk,
    506
        size_t chunk_len, size_t offset, size_t totalsiz, int *ms)
    507
    357
    {
    508
    357
            fido_blob_t *hmac = NULL, f;
    509
    357
            cbor_item_t *argv[6];
    510
    357
            int r;
    511
    512
    357
            memset(argv, 0, sizeof(argv));
    513
    357
            memset(&f, 0, sizeof(f));
    514
    515
    357
            if ((argv[1] = cbor_build_bytestring(chunk, chunk_len)) == NULL ||
    516
    357
                (argv[2] = cbor_build_uint(offset)) == NULL ||
    517
    357
                (offset == 0 && (argv[3] = cbor_build_uint(totalsiz)) == NULL)) {
    518
    4
                    fido_log_debug("%s: cbor encode", __func__);
    519
    4
                    r = FIDO_ERR_INTERNAL;
    520
    4
                    goto fail;
    521
    4
            }
    522
    353
            if (token != NULL) {
    523
    64
                    if ((hmac = fido_blob_new()) == NULL ||
    524
    64
                        prepare_hmac(offset, chunk, chunk_len, hmac) < 0 ||
    525
    64
                        (argv[4] = cbor_encode_pin_auth(dev, token, hmac)) == NULL ||
    526
    64
                        (argv[5] = cbor_encode_pin_opt(dev)) == NULL) {
    527
    7
                            fido_log_debug("%s: cbor_encode_pin_auth", __func__);
    528
    7
                            r = FIDO_ERR_INTERNAL;
    529
    7
                            goto fail;
    530
    7
                    }
    531
    64
            }
    532
    346
            if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 ||
    533
    346
                fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    534
    44
                    fido_log_debug("%s: fido_tx", __func__);
    535
    44
                    r = FIDO_ERR_TX;
    536
    44
                    goto fail;
    537
    44
            }
    538
    539
    302
            r = FIDO_OK;
    540
    357
    fail:
    541
    357
            cbor_vector_free(argv, nitems(argv));
    542
    357
            fido_blob_free(&hmac);
    543
    357
            free(f.ptr);
    544
    545
    357
            return r;
    546
    302
    }
    547
    548
    static int
    549
    largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token,
    550
        int *ms)
    551
    547
    {
    552
    547
            es256_pk_t *pk = NULL;
    553
    547
            fido_blob_t *ecdh = NULL;
    554
    547
            int r;
    555
    556
    547
            if ((*token = fido_blob_new()) == NULL)
    557
    3
                    return FIDO_ERR_INTERNAL;
    558
    544
            if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
    559
    318
                    fido_log_debug("%s: fido_do_ecdh", __func__);
    560
    318
                    goto fail;
    561
    318
            }
    562
    226
            if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_LARGEBLOB, pin, ecdh, pk,
    563
    226
                NULL, *token, ms)) != FIDO_OK) {
    564
    181
                    fido_log_debug("%s: fido_dev_get_uv_token", __func__);
    565
    181
                    goto fail;
    566
    181
            }
    567
    568
    45
            r = FIDO_OK;
    569
    544
    fail:
    570
    544
            if (r != FIDO_OK)
    571
    499
                    fido_blob_free(token);
    572
    573
    544
            fido_blob_free(&ecdh);
    574
    544
            es256_pk_free(&pk);
    575
    576
    544
            return r;
    577
    45
    }
    578
    579
    static int
    580
    largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin,
    581
        int *ms)
    582
    1.27k
    {
    583
    1.27k
            unsigned char dgst[SHA256_DIGEST_LENGTH];
    584
    1.27k
            fido_blob_t cbor, *token = NULL;
    585
    1.27k
            size_t chunklen, maxchunklen, totalsize;
    586
    1.27k
            int r;
    587
    588
    1.27k
            memset(&cbor, 0, sizeof(cbor));
    589
    590
    1.27k
            if ((maxchunklen = get_chunklen(dev)) == 0) {
    591
    405
                    fido_log_debug("%s: maxchunklen=%zu", __func__, maxchunklen);
    592
    405
                    r = FIDO_ERR_INVALID_ARGUMENT;
    593
    405
                    goto fail;
    594
    405
            }
    595
    866
            if (!cbor_isa_array(item) || !cbor_array_is_definite(item)) {
    596
    88
                    fido_log_debug("%s: cbor type", __func__);
    597
    88
                    r = FIDO_ERR_INVALID_ARGUMENT;
    598
    88
                    goto fail;
    599
    88
            }
    600
    778
            if ((fido_blob_serialise(&cbor, item)) < 0) {
    601
    4
                    fido_log_debug("%s: fido_blob_serialise", __func__);
    602
    4
                    r = FIDO_ERR_INTERNAL;
    603
    4
                    goto fail;
    604
    4
            }
    605
    774
            if (cbor.len > SIZE_MAX - sizeof(dgst)) {
    606
    0
                    fido_log_debug("%s: cbor.len=%zu", __func__, cbor.len);
    607
    0
                    r = FIDO_ERR_INVALID_ARGUMENT;
    608
    0
                    goto fail;
    609
    0
            }
    610
    774
            if (SHA256(cbor.ptr, cbor.len, dgst) != dgst) {
    611
    4
                    fido_log_debug("%s: SHA256", __func__);
    612
    4
                    r = FIDO_ERR_INTERNAL;
    613
    4
                    goto fail;
    614
    4
            }
    615
    770
            totalsize = cbor.len + sizeof(dgst) - 16; /* the first 16 bytes only */
    616
    770
            if (pin != NULL || fido_dev_supports_permissions(dev)) {
    617
    547
                    if ((r = largeblob_get_uv_token(dev, pin, &token,
    618
    547
                        ms)) != FIDO_OK) {
    619
    502
                            fido_log_debug("%s: largeblob_get_uv_token", __func__);
    620
    502
                            goto fail;
    621
    502
                    }
    622
    547
            }
    623
    357
            for (size_t offset = 0; offset < cbor.len; offset += chunklen) {
    624
    296
                    if ((chunklen = cbor.len - offset) > maxchunklen)
    625
    54
                            chunklen = maxchunklen;
    626
    296
                    if ((r = largeblob_set_tx(dev, token, cbor.ptr + offset,
    627
    296
                        chunklen, offset, totalsize, ms)) != FIDO_OK ||
    628
    296
                        (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
    629
    207
                            fido_log_debug("%s: body", __func__);
    630
    207
                            goto fail;
    631
    207
                    }
    632
    296
            }
    633
    61
            if ((r = largeblob_set_tx(dev, token, dgst, sizeof(dgst) - 16, cbor.len,
    634
    61
                totalsize, ms)) != FIDO_OK ||
    635
    61
                (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
    636
    53
                    fido_log_debug("%s: dgst", __func__);
    637
    53
                    goto fail;
    638
    53
            }
    639
    640
    8
            r = FIDO_OK;
    641
    1.27k
    fail:
    642
    1.27k
            fido_blob_free(&token);
    643
    1.27k
            fido_blob_reset(&cbor);
    644
    645
    1.27k
            return r;
    646
    8
    }
    647
    648
    static int
    649
    largeblob_add(fido_dev_t *dev, const fido_blob_t *key, cbor_item_t *item,
    650
        const char *pin, int *ms)
    651
    463
    {
    652
    463
            cbor_item_t *array = NULL;
    653
    463
            size_t idx;
    654
    463
            int r;
    655
    656
    463
            if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) {
    657
    137
                    fido_log_debug("%s: largeblob_get_array", __func__);
    658
    137
                    goto fail;
    659
    137
            }
    660
    661
    326
            switch (r = largeblob_array_lookup(NULL, &idx, array, key)) {
    662
    121
            case FIDO_OK:
    663
    121
                    if (!cbor_array_replace(array, idx, item)) {
    664
    0
                            r = FIDO_ERR_INTERNAL;
    665
    0
                            goto fail;
    666
    0
                    }
    667
    121
                    break;
    668
    204
            case FIDO_ERR_NOTFOUND:
    669
    204
                    if (cbor_array_append(&array, item) < 0) {
    670
    7
                            r = FIDO_ERR_INTERNAL;
    671
    7
                            goto fail;
    672
    7
                    }
    673
    197
                    break;
    674
    197
            default:
    675
    1
                    fido_log_debug("%s: largeblob_array_lookup", __func__);
    676
    1
                    goto fail;
    677
    326
            }
    678
    679
    318
            if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) {
    680
    316
                    fido_log_debug("%s: largeblob_set_array", __func__);
    681
    316
                    goto fail;
    682
    316
            }
    683
    684
    2
            r = FIDO_OK;
    685
    463
    fail:
    686
    463
            if (array != NULL)
    687
    326
                    cbor_decref(&array);
    688
    689
    463
            return r;
    690
    2
    }
    691
    692
    static int
    693
    largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin,
    694
        int *ms)
    695
    543
    {
    696
    543
            cbor_item_t *array = NULL;
    697
    543
            size_t idx;
    698
    543
            int r;
    699
    700
    543
            if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) {
    701
    303
                    fido_log_debug("%s: largeblob_get_array", __func__);
    702
    303
                    goto fail;
    703
    303
            }
    704
    240
            if ((r = largeblob_array_lookup(NULL, &idx, array, key)) != FIDO_OK) {
    705
    48
                    fido_log_debug("%s: largeblob_array_lookup", __func__);
    706
    48
                    goto fail;
    707
    48
            }
    708
    192
            if (cbor_array_drop(&array, idx) < 0) {
    709
    6
                    fido_log_debug("%s: cbor_array_drop", __func__);
    710
    6
                    r = FIDO_ERR_INTERNAL;
    711
    6
                    goto fail;
    712
    6
            }
    713
    186
            if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) {
    714
    183
                    fido_log_debug("%s: largeblob_set_array", __func__);
    715
    183
                    goto fail;
    716
    183
            }
    717
    718
    3
            r = FIDO_OK;
    719
    543
    fail:
    720
    543
            if (array != NULL)
    721
    240
                    cbor_decref(&array);
    722
    723
    543
            return r;
    724
    3
    }
    725
    726
    int
    727
    fido_dev_largeblob_get(fido_dev_t *dev, const unsigned char *key_ptr,
    728
        size_t key_len, unsigned char **blob_ptr, size_t *blob_len)
    729
    365
    {
    730
    365
            cbor_item_t *item = NULL;
    731
    365
            fido_blob_t key, body;
    732
    365
            int ms = dev->timeout_ms;
    733
    365
            int r;
    734
    735
    365
            memset(&key, 0, sizeof(key));
    736
    365
            memset(&body, 0, sizeof(body));
    737
    738
    365
            if (key_len != 32) {
    739
    123
                    fido_log_debug("%s: invalid key len %zu", __func__, key_len);
    740
    123
                    return FIDO_ERR_INVALID_ARGUMENT;
    741
    123
            }
    742
    242
            if (blob_ptr == NULL || blob_len == NULL) {
    743
    0
                    fido_log_debug("%s: invalid blob_ptr=%p, blob_len=%p", __func__,
    744
    0
                        (const void *)blob_ptr, (const void *)blob_len);
    745
    0
                    return FIDO_ERR_INVALID_ARGUMENT;
    746
    0
            }
    747
    242
            *blob_ptr = NULL;
    748
    242
            *blob_len = 0;
    749
    242
            if (fido_blob_set(&key, key_ptr, key_len) < 0) {
    750
    2
                    fido_log_debug("%s: fido_blob_set", __func__);
    751
    2
                    return FIDO_ERR_INTERNAL;
    752
    2
            }
    753
    240
            if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) {
    754
    212
                    fido_log_debug("%s: largeblob_get_array", __func__);
    755
    212
                    goto fail;
    756
    212
            }
    757
    28
            if ((r = largeblob_array_lookup(&body, NULL, item, &key)) != FIDO_OK)
    758
    22
                    fido_log_debug("%s: largeblob_array_lookup", __func__);
    759
    6
            else {
    760
    6
                    *blob_ptr = body.ptr;
    761
    6
                    *blob_len = body.len;
    762
    6
            }
    763
    240
    fail:
    764
    240
            if (item != NULL)
    765
    28
                    cbor_decref(&item);
    766
    767
    240
            fido_blob_reset(&key);
    768
    769
    240
            return r;
    770
    28
    }
    771
    772
    int
    773
    fido_dev_largeblob_set(fido_dev_t *dev, const unsigned char *key_ptr,
    774
        size_t key_len, const unsigned char *blob_ptr, size_t blob_len,
    775
        const char *pin)
    776
    1.62k
    {
    777
    1.62k
            cbor_item_t *item = NULL;
    778
    1.62k
            fido_blob_t key, body;
    779
    1.62k
            int ms = dev->timeout_ms;
    780
    1.62k
            int r;
    781
    782
    1.62k
            memset(&key, 0, sizeof(key));
    783
    1.62k
            memset(&body, 0, sizeof(body));
    784
    785
    1.62k
            if (key_len != 32) {
    786
    988
                    fido_log_debug("%s: invalid key len %zu", __func__, key_len);
    787
    988
                    return FIDO_ERR_INVALID_ARGUMENT;
    788
    988
            }
    789
    641
            if (blob_ptr == NULL || blob_len == 0) {
    790
    2
                    fido_log_debug("%s: invalid blob_ptr=%p, blob_len=%zu", __func__,
    791
    2
                        (const void *)blob_ptr, blob_len);
    792
    2
                    return FIDO_ERR_INVALID_ARGUMENT;
    793
    2
            }
    794
    639
            if (fido_blob_set(&key, key_ptr, key_len) < 0 ||
    795
    639
                fido_blob_set(&body, blob_ptr, blob_len) < 0) {
    796
    3
                    fido_log_debug("%s: fido_blob_set", __func__);
    797
    3
                    r = FIDO_ERR_INTERNAL;
    798
    3
                    goto fail;
    799
    3
            }
    800
    636
            if ((item = largeblob_encode(&body, &key)) == NULL) {
    801
    173
                    fido_log_debug("%s: largeblob_encode", __func__);
    802
    173
                    r = FIDO_ERR_INTERNAL;
    803
    173
                    goto fail;
    804
    173
            }
    805
    463
            if ((r = largeblob_add(dev, &key, item, pin, &ms)) != FIDO_OK)
    806
    461
                    fido_log_debug("%s: largeblob_add", __func__);
    807
    639
    fail:
    808
    639
            if (item != NULL)
    809
    463
                    cbor_decref(&item);
    810
    811
    639
            fido_blob_reset(&key);
    812
    639
            fido_blob_reset(&body);
    813
    814
    639
            return r;
    815
    463
    }
    816
    817
    int
    818
    fido_dev_largeblob_remove(fido_dev_t *dev, const unsigned char *key_ptr,
    819
        size_t key_len, const char *pin)
    820
    1.54k
    {
    821
    1.54k
            fido_blob_t key;
    822
    1.54k
            int ms = dev->timeout_ms;
    823
    1.54k
            int r;
    824
    825
    1.54k
            memset(&key, 0, sizeof(key));
    826
    827
    1.54k
            if (key_len != 32) {
    828
    998
                    fido_log_debug("%s: invalid key len %zu", __func__, key_len);
    829
    998
                    return FIDO_ERR_INVALID_ARGUMENT;
    830
    998
            }
    831
    546
            if (fido_blob_set(&key, key_ptr, key_len) < 0) {
    832
    3
                    fido_log_debug("%s: fido_blob_set", __func__);
    833
    3
                    return FIDO_ERR_INTERNAL;
    834
    3
            }
    835
    543
            if ((r = largeblob_drop(dev, &key, pin, &ms)) != FIDO_OK)
    836
    540
                    fido_log_debug("%s: largeblob_drop", __func__);
    837
    838
    543
            fido_blob_reset(&key);
    839
    840
    543
            return r;
    841
    546
    }
    842
    843
    int
    844
    fido_dev_largeblob_get_array(fido_dev_t *dev, unsigned char **cbor_ptr,
    845
        size_t *cbor_len)
    846
    357
    {
    847
    357
            cbor_item_t *item = NULL;
    848
    357
            fido_blob_t cbor;
    849
    357
            int ms = dev->timeout_ms;
    850
    357
            int r;
    851
    852
    357
            memset(&cbor, 0, sizeof(cbor));
    853
    854
    357
            if (cbor_ptr == NULL || cbor_len == NULL) {
    855
    0
                    fido_log_debug("%s: invalid cbor_ptr=%p, cbor_len=%p", __func__,
    856
    0
                        (const void *)cbor_ptr, (const void *)cbor_len);
    857
    0
                    return FIDO_ERR_INVALID_ARGUMENT;
    858
    0
            }
    859
    357
            *cbor_ptr = NULL;
    860
    357
            *cbor_len = 0;
    861
    357
            if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) {
    862
    339
                    fido_log_debug("%s: largeblob_get_array", __func__);
    863
    339
                    return r;
    864
    339
            }
    865
    18
            if (fido_blob_serialise(&cbor, item) < 0) {
    866
    2
                    fido_log_debug("%s: fido_blob_serialise", __func__);
    867
    2
                    r = FIDO_ERR_INTERNAL;
    868
    16
            } else {
    869
    16
                    *cbor_ptr = cbor.ptr;
    870
    16
                    *cbor_len = cbor.len;
    871
    16
            }
    872
    873
    18
            cbor_decref(&item);
    874
    875
    18
            return r;
    876
    357
    }
    877
    878
    int
    879
    fido_dev_largeblob_set_array(fido_dev_t *dev, const unsigned char *cbor_ptr,
    880
        size_t cbor_len, const char *pin)
    881
    1.59k
    {
    882
    1.59k
            cbor_item_t *item = NULL;
    883
    1.59k
            struct cbor_load_result cbor_result;
    884
    1.59k
            int ms = dev->timeout_ms;
    885
    1.59k
            int r;
    886
    887
    1.59k
            if (cbor_ptr == NULL || cbor_len == 0) {
    888
    2
                    fido_log_debug("%s: invalid cbor_ptr=%p, cbor_len=%zu", __func__,
    889
    2
                        (const void *)cbor_ptr, cbor_len);
    890
    2
                    return FIDO_ERR_INVALID_ARGUMENT;
    891
    2
            }
    892
    1.58k
            if ((item = cbor_load(cbor_ptr, cbor_len, &cbor_result)) == NULL) {
    893
    822
                    fido_log_debug("%s: cbor_load", __func__);
    894
    822
                    return FIDO_ERR_INVALID_ARGUMENT;
    895
    822
            }
    896
    767
            if ((r = largeblob_set_array(dev, item, pin, &ms)) != FIDO_OK)
    897
    764
                    fido_log_debug("%s: largeblob_set_array", __func__);
    898
    899
    767
            cbor_decref(&item);
    900
    901
    767
            return r;
    902
    1.58k
    }