## Coverage Report

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

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

    /libfido2/src/u2f.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 2018-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
    #include <openssl/x509.h>
    10
    11
    #ifdef HAVE_UNISTD_H
    12
    #include <unistd.h>
    13
    #endif
    14
    #include <errno.h>
    15
    16
    #include "fido.h"
    17
    #include "fido/es256.h"
    18
    #include "fallthrough.h"
    19
    20
    7.64k
    #define U2F_PACE_MS (100)
    21
    22
    #if defined(_MSC_VER)
    23
    static int
    24
    usleep(unsigned int usec)
    25
    {
    26
            Sleep(usec / 1000);
    27
    28
            return (0);
    29
    }
    30
    #endif
    31
    32
    static int
    33
    delay_ms(unsigned int ms, int *ms_remain)
    34
    7.64k
    {
    35
    7.64k
            if (*ms_remain > -1 && (unsigned int)*ms_remain < ms)
    36
    4.90k
                    ms = (unsigned int)*ms_remain;
    37
    38
    7.64k
            if (ms > UINT_MAX / 1000) {
    39
    0
                    fido_log_debug("%s: ms=%u", __func__, ms);
    40
    0
                    return (-1);
    41
    0
            }
    42
    43
    7.64k
            if (usleep(ms * 1000) < 0) {
    44
    12
                    fido_log_error(errno, "%s: usleep", __func__);
    45
    12
                    return (-1);
    46
    12
            }
    47
    48
    7.63k
            if (*ms_remain > -1)
    49
    7.63k
                    *ms_remain -= (int)ms;
    50
    51
    7.63k
            return (0);
    52
    7.64k
    }
    53
    54
    static int
    55
    sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
    56
    2.74k
    {
    57
    2.74k
            sig->len = *len; /* consume the whole buffer */
    58
    2.74k
            if ((sig->ptr = calloc(1, sig->len)) == NULL ||
    59
    2.74k
                fido_buf_read(buf, len, sig->ptr, sig->len) < 0) {
    60
    4
                    fido_log_debug("%s: fido_buf_read", __func__);
    61
    4
                    fido_blob_reset(sig);
    62
    4
                    return (-1);
    63
    4
            }
    64
    65
    2.73k
            return (0);
    66
    2.74k
    }
    67
    68
    static int
    69
    x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len)
    70
    1.92k
    {
    71
    1.92k
            X509    *cert = NULL;
    72
    1.92k
            int      ok = -1;
    73
    74
    1.92k
            if (*len > LONG_MAX) {
    75
    0
                    fido_log_debug("%s: invalid len %zu", __func__, *len);
    76
    0
                    goto fail;
    77
    0
            }
    78
    79
            /* find out the certificate's length */
    80
    1.92k
            const unsigned char *end = *buf;
    81
    1.92k
            if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf ||
    82
    1.92k
                (x5c->len = (size_t)(end - *buf)) >= *len) {
    83
    1.16k
                    fido_log_debug("%s: d2i_X509", __func__);
    84
    1.16k
                    goto fail;
    85
    1.16k
            }
    86
    87
            /* read accordingly */
    88
    756
            if ((x5c->ptr = calloc(1, x5c->len)) == NULL ||
    89
    756
                fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) {
    90
    2
                    fido_log_debug("%s: fido_buf_read", __func__);
    91
    2
                    goto fail;
    92
    2
            }
    93
    94
    754
            ok = 0;
    95
    1.92k
    fail:
    96
    1.92k
            if (cert != NULL)
    97
    756
                    X509_free(cert);
    98
    99
    1.92k
            if (ok < 0)
    100
    1.16k
                    fido_blob_reset(x5c);
    101
    102
    1.92k
            return (ok);
    103
    754
    }
    104
    105
    static int
    106
    authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
    107
        fido_blob_t *fake_cbor_ad)
    108
    1.98k
    {
    109
    1.98k
            fido_authdata_t  ad;
    110
    1.98k
            cbor_item_t     *item = NULL;
    111
    1.98k
            size_t           alloc_len;
    112
    113
    1.98k
            memset(&ad, 0, sizeof(ad));
    114
    115
    1.98k
            if (SHA256((const void *)rp_id, strlen(rp_id),
    116
    1.98k
                ad.rp_id_hash) != ad.rp_id_hash) {
    117
    7
                    fido_log_debug("%s: sha256", __func__);
    118
    7
                    return (-1);
    119
    7
            }
    120
    121
    1.97k
            ad.flags = flags; /* XXX translate? */
    122
    1.97k
            ad.sigcount = sigcount;
    123
    124
    1.97k
            if ((item = cbor_build_bytestring((const unsigned char *)&ad,
    125
    1.97k
                sizeof(ad))) == NULL) {
    126
    4
                    fido_log_debug("%s: cbor_build_bytestring", __func__);
    127
    4
                    return (-1);
    128
    4
            }
    129
    130
    1.97k
            if (fake_cbor_ad->ptr != NULL ||
    131
    1.97k
                (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr,
    132
    1.97k
                &alloc_len)) == 0) {
    133
    3
                    fido_log_debug("%s: cbor_serialize_alloc", __func__);
    134
    3
                    cbor_decref(&item);
    135
    3
                    return (-1);
    136
    3
            }
    137
    138
    1.97k
            cbor_decref(&item);
    139
    140
    1.97k
            return (0);
    141
    1.97k
    }
    142
    143
    /* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
    144
    static int
    145
    send_dummy_register(fido_dev_t *dev, int *ms)
    146
    180
    {
    147
    180
            iso7816_apdu_t  *apdu = NULL;
    148
    180
            unsigned char   *reply = NULL;
    149
    180
            unsigned char    challenge[SHA256_DIGEST_LENGTH];
    150
    180
            unsigned char    application[SHA256_DIGEST_LENGTH];
    151
    180
            int              r;
    152
    153
            /* dummy challenge & application */
    154
    180
            memset(&challenge, 0xff, sizeof(challenge));
    155
    180
            memset(&application, 0xff, sizeof(application));
    156
    157
    180
            if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
    158
    180
                SHA256_DIGEST_LENGTH)) == NULL ||
    159
    180
                iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
    160
    180
                iso7816_add(apdu, &application, sizeof(application)) < 0) {
    161
    4
                    fido_log_debug("%s: iso7816", __func__);
    162
    4
                    r = FIDO_ERR_INTERNAL;
    163
    4
                    goto fail;
    164
    4
            }
    165
    166
    176
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    167
    6
                    fido_log_debug("%s: malloc", __func__);
    168
    6
                    r = FIDO_ERR_INTERNAL;
    169
    6
                    goto fail;
    170
    6
            }
    171
    172
    586
            do {
    173
    586
                    if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
    174
    586
                        iso7816_len(apdu), ms) < 0) {
    175
    13
                            fido_log_debug("%s: fido_tx", __func__);
    176
    13
                            r = FIDO_ERR_TX;
    177
    13
                            goto fail;
    178
    13
                    }
    179
    573
                    if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) < 2) {
    180
    76
                            fido_log_debug("%s: fido_rx", __func__);
    181
    76
                            r = FIDO_ERR_RX;
    182
    76
                            goto fail;
    183
    76
                    }
    184
    497
                    if (delay_ms(U2F_PACE_MS, ms) != 0) {
    185
    5
                            fido_log_debug("%s: delay_ms", __func__);
    186
    5
                            r = FIDO_ERR_RX;
    187
    5
                            goto fail;
    188
    5
                    }
    189
    497
            } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
    190
    191
    76
            r = FIDO_OK;
    192
    180
    fail:
    193
    180
            iso7816_free(&apdu);
    194
    180
            freezero(reply, FIDO_MAXMSG);
    195
    196
    180
            return (r);
    197
    76
    }
    198
    199
    static int
    200
    key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
    201
        int *found, int *ms)
    202
    5.63k
    {
    203
    5.63k
            iso7816_apdu_t  *apdu = NULL;
    204
    5.63k
            unsigned char   *reply = NULL;
    205
    5.63k
            unsigned char    challenge[SHA256_DIGEST_LENGTH];
    206
    5.63k
            unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
    207
    5.63k
            uint8_t          key_id_len;
    208
    5.63k
            int              r;
    209
    210
    5.63k
            if (key_id->len > UINT8_MAX || rp_id == NULL) {
    211
    62
                    fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__,
    212
    62
                        key_id->len, (const void *)rp_id);
    213
    62
                    r = FIDO_ERR_INVALID_ARGUMENT;
    214
    62
                    goto fail;
    215
    62
            }
    216
    217
    5.57k
            memset(&challenge, 0xff, sizeof(challenge));
    218
    5.57k
            memset(&rp_id_hash, 0, sizeof(rp_id_hash));
    219
    220
    5.57k
            if (SHA256((const void *)rp_id, strlen(rp_id),
    221
    5.57k
                rp_id_hash) != rp_id_hash) {
    222
    21
                    fido_log_debug("%s: sha256", __func__);
    223
    21
                    r = FIDO_ERR_INTERNAL;
    224
    21
                    goto fail;
    225
    21
            }
    226
    227
    5.55k
            key_id_len = (uint8_t)key_id->len;
    228
    229
    5.55k
            if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
    230
    5.55k
                SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
    231
    5.55k
                iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
    232
    5.55k
                iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
    233
    5.55k
                iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
    234
    5.55k
                iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
    235
    9
                    fido_log_debug("%s: iso7816", __func__);
    236
    9
                    r = FIDO_ERR_INTERNAL;
    237
    9
                    goto fail;
    238
    9
            }
    239
    240
    5.54k
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    241
    26
                    fido_log_debug("%s: malloc", __func__);
    242
    26
                    r = FIDO_ERR_INTERNAL;
    243
    26
                    goto fail;
    244
    26
            }
    245
    246
    5.51k
            if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
    247
    5.51k
                iso7816_len(apdu), ms) < 0) {
    248
    225
                    fido_log_debug("%s: fido_tx", __func__);
    249
    225
                    r = FIDO_ERR_TX;
    250
    225
                    goto fail;
    251
    225
            }
    252
    5.29k
            if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) != 2) {
    253
    1.87k
                    fido_log_debug("%s: fido_rx", __func__);
    254
    1.87k
                    r = FIDO_ERR_RX;
    255
    1.87k
                    goto fail;
    256
    1.87k
            }
    257
    258
    3.41k
            switch ((reply[0] << 8) | reply[1]) {
    259
    2.95k
            case SW_CONDITIONS_NOT_SATISFIED:
    260
    2.95k
                    *found = 1; /* key exists */
    261
    2.95k
                    break;
    262
    67
            case SW_WRONG_DATA:
    263
    72
            case SW_WRONG_LENGTH:
    264
    72
                    *found = 0; /* key does not exist */
    265
    72
                    break;
    266
    390
            default:
    267
                    /* unexpected sw */
    268
    390
                    r = FIDO_ERR_INTERNAL;
    269
    390
                    goto fail;
    270
    3.41k
            }
    271
    272
    3.02k
            r = FIDO_OK;
    273
    5.63k
    fail:
    274
    5.63k
            iso7816_free(&apdu);
    275
    5.63k
            freezero(reply, FIDO_MAXMSG);
    276
    277
    5.63k
            return (r);
    278
    3.02k
    }
    279
    280
    static int
    281
    parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id,
    282
        const unsigned char *reply, size_t len)
    283
    2.13k
    {
    284
    2.13k
            uint8_t         flags;
    285
    2.13k
            uint32_t        sigcount;
    286
    287
    2.13k
            if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
    288
    143
                    fido_log_debug("%s: unexpected sw", __func__);
    289
    143
                    return (FIDO_ERR_RX);
    290
    143
            }
    291
    292
    1.99k
            len -= 2;
    293
    294
    1.99k
            if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 ||
    295
    1.99k
                fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) {
    296
    8
                    fido_log_debug("%s: fido_buf_read", __func__);
    297
    8
                    return (FIDO_ERR_RX);
    298
    8
            }
    299
    300
    1.98k
            if (sig_get(sig, &reply, &len) < 0) {
    301
    2
                    fido_log_debug("%s: sig_get", __func__);
    302
    2
                    return (FIDO_ERR_RX);
    303
    2
            }
    304
    305
    1.98k
            if (authdata_fake(rp_id, flags, sigcount, ad) < 0) {
    306
    14
                    fido_log_debug("%s; authdata_fake", __func__);
    307
    14
                    return (FIDO_ERR_RX);
    308
    14
            }
    309
    310
    1.97k
            return (FIDO_OK);
    311
    1.98k
    }
    312
    313
    static int
    314
    do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
    315
        const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms)
    316
    2.34k
    {
    317
    2.34k
            iso7816_apdu_t  *apdu = NULL;
    318
    2.34k
            unsigned char   *reply = NULL;
    319
    2.34k
            unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
    320
    2.34k
            int              reply_len;
    321
    2.34k
            uint8_t          key_id_len;
    322
    2.34k
            int              r;
    323
    324
    2.34k
    #ifdef FIDO_FUZZ
    325
    2.34k
            *ms = 0; /* XXX */
    326
    2.34k
    #endif
    327
    328
    2.34k
            if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
    329
    2.34k
                rp_id == NULL) {
    330
    54
                    r = FIDO_ERR_INVALID_ARGUMENT;
    331
    54
                    goto fail;
    332
    54
            }
    333
    334
    2.29k
            memset(&rp_id_hash, 0, sizeof(rp_id_hash));
    335
    336
    2.29k
            if (SHA256((const void *)rp_id, strlen(rp_id),
    337
    2.29k
                rp_id_hash) != rp_id_hash) {
    338
    3
                    fido_log_debug("%s: sha256", __func__);
    339
    3
                    r = FIDO_ERR_INTERNAL;
    340
    3
                    goto fail;
    341
    3
            }
    342
    343
    2.28k
            key_id_len = (uint8_t)key_id->len;
    344
    345
    2.28k
            if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
    346
    2.28k
                SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
    347
    2.28k
                iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
    348
    2.28k
                iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
    349
    2.28k
                iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
    350
    2.28k
                iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
    351
    3
                    fido_log_debug("%s: iso7816", __func__);
    352
    3
                    r = FIDO_ERR_INTERNAL;
    353
    3
                    goto fail;
    354
    3
            }
    355
    356
    2.28k
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    357
    3
                    fido_log_debug("%s: malloc", __func__);
    358
    3
                    r = FIDO_ERR_INTERNAL;
    359
    3
                    goto fail;
    360
    3
            }
    361
    362
    3.35k
            do {
    363
    3.35k
                    if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
    364
    3.35k
                        iso7816_len(apdu), ms) < 0) {
    365
    15
                            fido_log_debug("%s: fido_tx", __func__);
    366
    15
                            r = FIDO_ERR_TX;
    367
    15
                            goto fail;
    368
    15
                    }
    369
    3.33k
                    if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
    370
    3.33k
                        FIDO_MAXMSG, ms)) < 2) {
    371
    125
                            fido_log_debug("%s: fido_rx", __func__);
    372
    125
                            r = FIDO_ERR_RX;
    373
    125
                            goto fail;
    374
    125
                    }
    375
    3.21k
                    if (delay_ms(U2F_PACE_MS, ms) != 0) {
    376
    3
                            fido_log_debug("%s: delay_ms", __func__);
    377
    3
                            r = FIDO_ERR_RX;
    378
    3
                            goto fail;
    379
    3
                    }
    380
    3.21k
            } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
    381
    382
    2.13k
            if ((r = parse_auth_reply(sig, ad, rp_id, reply,
    383
    2.13k
                (size_t)reply_len)) != FIDO_OK) {
    384
    167
                    fido_log_debug("%s: parse_auth_reply", __func__);
    385
    167
                    goto fail;
    386
    167
            }
    387
    388
    2.34k
    fail:
    389
    2.34k
            iso7816_free(&apdu);
    390
    2.34k
            freezero(reply, FIDO_MAXMSG);
    391
    392
    2.34k
            return (r);
    393
    2.13k
    }
    394
    395
    static int
    396
    cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len,
    397
        fido_blob_t *cbor_blob)
    398
    693
    {
    399
    693
            es256_pk_t      *pk = NULL;
    400
    693
            cbor_item_t     *pk_cbor = NULL;
    401
    693
            size_t           alloc_len;
    402
    693
            int              ok = -1;
    403
    404
            /* only handle uncompressed points */
    405
    693
            if (ec_point_len != 65 || ec_point[0] != 0x04) {
    406
    20
                    fido_log_debug("%s: unexpected format", __func__);
    407
    20
                    goto fail;
    408
    20
            }
    409
    410
    673
            if ((pk = es256_pk_new()) == NULL ||
    411
    673
                es256_pk_set_x(pk, &ec_point[1]) < 0 ||
    412
    673
                es256_pk_set_y(pk, &ec_point[33]) < 0) {
    413
    3
                    fido_log_debug("%s: es256_pk_set", __func__);
    414
    3
                    goto fail;
    415
    3
            }
    416
    417
    670
            if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) {
    418
    7
                    fido_log_debug("%s: es256_pk_encode", __func__);
    419
    7
                    goto fail;
    420
    7
            }
    421
    422
    663
            if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr,
    423
    663
                &alloc_len)) != 77) {
    424
    5
                    fido_log_debug("%s: cbor_serialize_alloc", __func__);
    425
    5
                    goto fail;
    426
    5
            }
    427
    428
    658
            ok = 0;
    429
    693
    fail:
    430
    693
            es256_pk_free(&pk);
    431
    432
    693
            if (pk_cbor)
    433
    663
                    cbor_decref(&pk_cbor);
    434
    435
    693
            return (ok);
    436
    658
    }
    437
    438
    static int
    439
    encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c,
    440
        const fido_blob_t *sig, fido_blob_t *out)
    441
    752
    {
    442
    752
            cbor_item_t             *item = NULL;
    443
    752
            cbor_item_t             *x5c_cbor = NULL;
    444
    752
            const uint8_t            alg_cbor = (uint8_t)(-cose_alg - 1);
    445
    752
            struct cbor_pair         kv[3];
    446
    752
            size_t                   alloc_len;
    447
    752
            int                      ok = -1;
    448
    449
    752
            memset(&kv, 0, sizeof(kv));
    450
    752
            memset(out, 0, sizeof(*out));
    451
    452
    752
            if ((item = cbor_new_definite_map(3)) == NULL) {
    453
    4
                    fido_log_debug("%s: cbor_new_definite_map", __func__);
    454
    4
                    goto fail;
    455
    4
            }
    456
    457
    748
            if ((kv[0].key = cbor_build_string("alg")) == NULL ||
    458
    748
                (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL ||
    459
    748
                !cbor_map_add(item, kv[0])) {
    460
    17
                    fido_log_debug("%s: alg", __func__);
    461
    17
                    goto fail;
    462
    17
            }
    463
    464
    731
            if ((kv[1].key = cbor_build_string("sig")) == NULL ||
    465
    731
                (kv[1].value = fido_blob_encode(sig)) == NULL ||
    466
    731
                !cbor_map_add(item, kv[1])) {
    467
    13
                    fido_log_debug("%s: sig", __func__);
    468
    13
                    goto fail;
    469
    13
            }
    470
    471
    718
            if ((kv[2].key = cbor_build_string("x5c")) == NULL ||
    472
    718
                (kv[2].value = cbor_new_definite_array(1)) == NULL ||
    473
    718
                (x5c_cbor = fido_blob_encode(x5c)) == NULL ||
    474
    718
                !cbor_array_push(kv[2].value, x5c_cbor) ||
    475
    718
                !cbor_map_add(item, kv[2])) {
    476
    21
                    fido_log_debug("%s: x5c", __func__);
    477
    21
                    goto fail;
    478
    21
            }
    479
    480
    697
            if ((out->len = cbor_serialize_alloc(item, &out->ptr,
    481
    697
                &alloc_len)) == 0) {
    482
    4
                    fido_log_debug("%s: cbor_serialize_alloc", __func__);
    483
    4
                    goto fail;
    484
    4
            }
    485
    486
    693
            ok = 0;
    487
    752
    fail:
    488
    752
            if (item != NULL)
    489
    748
                    cbor_decref(&item);
    490
    752
            if (x5c_cbor != NULL)
    491
    706
                    cbor_decref(&x5c_cbor);
    492
    493
    3.00k
            for (size_t i = 0; i < nitems(kv); i++) {
    494
    2.25k
                    if (kv[i].key)
    495
    2.18k
                            cbor_decref(&kv[i].key);
    496
    2.25k
                    if (kv[i].value)
    497
    2.16k
                            cbor_decref(&kv[i].value);
    498
    2.25k
            }
    499
    500
    752
            return (ok);
    501
    693
    }
    502
    503
    static int
    504
    encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
    505
        const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out)
    506
    693
    {
    507
    693
            fido_authdata_t          authdata;
    508
    693
            fido_attcred_raw_t       attcred_raw;
    509
    693
            fido_blob_t              pk_blob;
    510
    693
            fido_blob_t              authdata_blob;
    511
    693
            cbor_item_t             *authdata_cbor = NULL;
    512
    693
            unsigned char           *ptr;
    513
    693
            size_t                   len;
    514
    693
            size_t                   alloc_len;
    515
    693
            int                      ok = -1;
    516
    517
    693
            memset(&pk_blob, 0, sizeof(pk_blob));
    518
    693
            memset(&authdata, 0, sizeof(authdata));
    519
    693
            memset(&authdata_blob, 0, sizeof(authdata_blob));
    520
    693
            memset(out, 0, sizeof(*out));
    521
    522
    693
            if (rp_id == NULL) {
    523
    0
                    fido_log_debug("%s: NULL rp_id", __func__);
    524
    0
                    goto fail;
    525
    0
            }
    526
    527
    693
            if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) {
    528
    35
                    fido_log_debug("%s: cbor_blob_from_ec_point", __func__);
    529
    35
                    goto fail;
    530
    35
            }
    531
    532
    658
            if (SHA256((const void *)rp_id, strlen(rp_id),
    533
    658
                authdata.rp_id_hash) != authdata.rp_id_hash) {
    534
    4
                    fido_log_debug("%s: sha256", __func__);
    535
    4
                    goto fail;
    536
    4
            }
    537
    538
    654
            authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT);
    539
    654
            authdata.sigcount = 0;
    540
    541
    654
            memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
    542
    654
            attcred_raw.id_len = htobe16(kh_len);
    543
    544
    654
            len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
    545
    654
                kh_len + pk_blob.len;
    546
    654
            ptr = authdata_blob.ptr = calloc(1, authdata_blob.len);
    547
    548
    654
            fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len);
    549
    550
    654
            if (authdata_blob.ptr == NULL)
    551
    4
                    goto fail;
    552
    553
    650
            if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 ||
    554
    650
                fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 ||
    555
    650
                fido_buf_write(&ptr, &len, kh, kh_len) < 0 ||
    556
    650
                fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) {
    557
    0
                    fido_log_debug("%s: fido_buf_write", __func__);
    558
    0
                    goto fail;
    559
    0
            }
    560
    561
    650
            if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) {
    562
    4
                    fido_log_debug("%s: fido_blob_encode", __func__);
    563
    4
                    goto fail;
    564
    4
            }
    565
    566
    646
            if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr,
    567
    646
                &alloc_len)) == 0) {
    568
    4
                    fido_log_debug("%s: cbor_serialize_alloc", __func__);
    569
    4
                    goto fail;
    570
    4
            }
    571
    572
    642
            ok = 0;
    573
    693
    fail:
    574
    693
            if (authdata_cbor)
    575
    646
                    cbor_decref(&authdata_cbor);
    576
    577
    693
            fido_blob_reset(&pk_blob);
    578
    693
            fido_blob_reset(&authdata_blob);
    579
    580
    693
            return (ok);
    581
    642
    }
    582
    583
    static int
    584
    parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
    585
    2.08k
    {
    586
    2.08k
            fido_blob_t      x5c;
    587
    2.08k
            fido_blob_t      sig;
    588
    2.08k
            fido_blob_t      ad;
    589
    2.08k
            fido_blob_t      stmt;
    590
    2.08k
            uint8_t          dummy;
    591
    2.08k
            uint8_t          pubkey[65];
    592
    2.08k
            uint8_t          kh_len = 0;
    593
    2.08k
            uint8_t         *kh = NULL;
    594
    2.08k
            int              r;
    595
    596
    2.08k
            memset(&x5c, 0, sizeof(x5c));
    597
    2.08k
            memset(&sig, 0, sizeof(sig));
    598
    2.08k
            memset(&ad, 0, sizeof(ad));
    599
    2.08k
            memset(&stmt, 0, sizeof(stmt));
    600
    2.08k
            r = FIDO_ERR_RX;
    601
    602
            /* status word */
    603
    2.08k
            if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
    604
    141
                    fido_log_debug("%s: unexpected sw", __func__);
    605
    141
                    goto fail;
    606
    141
            }
    607
    608
    1.94k
            len -= 2;
    609
    610
            /* reserved byte */
    611
    1.94k
            if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 ||
    612
    1.94k
                dummy != 0x05) {
    613
    8
                    fido_log_debug("%s: reserved byte", __func__);
    614
    8
                    goto fail;
    615
    8
            }
    616
    617
            /* pubkey + key handle */
    618
    1.93k
            if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 ||
    619
    1.93k
                fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 ||
    620
    1.93k
                (kh = calloc(1, kh_len)) == NULL ||
    621
    1.93k
                fido_buf_read(&reply, &len, kh, kh_len) < 0) {
    622
    13
                    fido_log_debug("%s: fido_buf_read", __func__);
    623
    13
                    goto fail;
    624
    13
            }
    625
    626
            /* x5c + sig */
    627
    1.92k
            if (x5c_get(&x5c, &reply, &len) < 0 ||
    628
    1.92k
                sig_get(&sig, &reply, &len) < 0) {
    629
    1.17k
                    fido_log_debug("%s: x5c || sig", __func__);
    630
    1.17k
                    goto fail;
    631
    1.17k
            }
    632
    633
            /* attstmt */
    634
    752
            if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) {
    635
    59
                    fido_log_debug("%s: encode_cred_attstmt", __func__);
    636
    59
                    goto fail;
    637
    59
            }
    638
    639
            /* authdata */
    640
    693
            if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
    641
    693
                sizeof(pubkey), &ad) < 0) {
    642
    51
                    fido_log_debug("%s: encode_cred_authdata", __func__);
    643
    51
                    goto fail;
    644
    51
            }
    645
    646
    642
            if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
    647
    642
                fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
    648
    642
                fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) {
    649
    29
                    fido_log_debug("%s: fido_cred_set", __func__);
    650
    29
                    r = FIDO_ERR_INTERNAL;
    651
    29
                    goto fail;
    652
    29
            }
    653
    654
    613
            r = FIDO_OK;
    655
    2.08k
    fail:
    656
    2.08k
            freezero(kh, kh_len);
    657
    2.08k
            fido_blob_reset(&x5c);
    658
    2.08k
            fido_blob_reset(&sig);
    659
    2.08k
            fido_blob_reset(&ad);
    660
    2.08k
            fido_blob_reset(&stmt);
    661
    662
    2.08k
            return (r);
    663
    613
    }
    664
    665
    int
    666
    u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms)
    667
    3.08k
    {
    668
    3.08k
            iso7816_apdu_t  *apdu = NULL;
    669
    3.08k
            unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
    670
    3.08k
            unsigned char   *reply = NULL;
    671
    3.08k
            int              reply_len;
    672
    3.08k
            int              found;
    673
    3.08k
            int              r;
    674
    675
    3.08k
            if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
    676
    31
                    fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
    677
    31
                        cred->uv);
    678
    31
                    return (FIDO_ERR_UNSUPPORTED_OPTION);
    679
    31
            }
    680
    681
    3.05k
            if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL ||
    682
    3.05k
                cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) {
    683
    133
                    fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__,
    684
    133
                        cred->type, (void *)cred->cdh.ptr, cred->cdh.len);
    685
    133
                    return (FIDO_ERR_INVALID_ARGUMENT);
    686
    133
            }
    687
    688
    2.95k
            for (size_t i = 0; i < cred->excl.len; i++) {
    689
    725
                    if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i],
    690
    725
                        &found, ms)) != FIDO_OK) {
    691
    511
                            fido_log_debug("%s: key_lookup", __func__);
    692
    511
                            return (r);
    693
    511
                    }
    694
    214
                    if (found) {
    695
    180
                            if ((r = send_dummy_register(dev, ms)) != FIDO_OK) {
    696
    104
                                    fido_log_debug("%s: send_dummy_register",
    697
    104
                                        __func__);
    698
    104
                                    return (r);
    699
    104
                            }
    700
    76
                            return (FIDO_ERR_CREDENTIAL_EXCLUDED);
    701
    180
                    }
    702
    214
            }
    703
    704
    2.22k
            memset(&rp_id_hash, 0, sizeof(rp_id_hash));
    705
    706
    2.22k
            if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id),
    707
    2.22k
                rp_id_hash) != rp_id_hash) {
    708
    4
                    fido_log_debug("%s: sha256", __func__);
    709
    4
                    return (FIDO_ERR_INTERNAL);
    710
    4
            }
    711
    712
    2.22k
            if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
    713
    2.22k
                SHA256_DIGEST_LENGTH)) == NULL ||
    714
    2.22k
                iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 ||
    715
    2.22k
                iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
    716
    7
                    fido_log_debug("%s: iso7816", __func__);
    717
    7
                    r = FIDO_ERR_INTERNAL;
    718
    7
                    goto fail;
    719
    7
            }
    720
    721
    2.21k
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    722
    4
                    fido_log_debug("%s: malloc", __func__);
    723
    4
                    r = FIDO_ERR_INTERNAL;
    724
    4
                    goto fail;
    725
    4
            }
    726
    727
    4.06k
            do {
    728
    4.06k
                    if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
    729
    4.06k
                        iso7816_len(apdu), ms) < 0) {
    730
    22
                            fido_log_debug("%s: fido_tx", __func__);
    731
    22
                            r = FIDO_ERR_TX;
    732
    22
                            goto fail;
    733
    22
                    }
    734
    4.04k
                    if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply,
    735
    4.04k
                        FIDO_MAXMSG, ms)) < 2) {
    736
    104
                            fido_log_debug("%s: fido_rx", __func__);
    737
    104
                            r = FIDO_ERR_RX;
    738
    104
                            goto fail;
    739
    104
                    }
    740
    3.94k
                    if (delay_ms(U2F_PACE_MS, ms) != 0) {
    741
    4
                            fido_log_debug("%s: delay_ms", __func__);
    742
    4
                            r = FIDO_ERR_RX;
    743
    4
                            goto fail;
    744
    4
                    }
    745
    3.94k
            } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
    746
    747
    2.08k
            if ((r = parse_register_reply(cred, reply,
    748
    2.08k
                (size_t)reply_len)) != FIDO_OK) {
    749
    1.47k
                    fido_log_debug("%s: parse_register_reply", __func__);
    750
    1.47k
                    goto fail;
    751
    1.47k
            }
    752
    2.22k
    fail:
    753
    2.22k
            iso7816_free(&apdu);
    754
    2.22k
            freezero(reply, FIDO_MAXMSG);
    755
    756
    2.22k
            return (r);
    757
    2.08k
    }
    758
    759
    static int
    760
    u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
    761
        fido_assert_t *fa, size_t idx, int *ms)
    762
    4.91k
    {
    763
    4.91k
            fido_blob_t     sig;
    764
    4.91k
            fido_blob_t     ad;
    765
    4.91k
            int             found;
    766
    4.91k
            int             r;
    767
    768
    4.91k
            memset(&sig, 0, sizeof(sig));
    769
    4.91k
            memset(&ad, 0, sizeof(ad));
    770
    771
    4.91k
            if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) {
    772
    2.10k
                    fido_log_debug("%s: key_lookup", __func__);
    773
    2.10k
                    goto fail;
    774
    2.10k
            }
    775
    776
    2.81k
            if (!found) {
    777
    38
                    fido_log_debug("%s: not found", __func__);
    778
    38
                    r = FIDO_ERR_CREDENTIAL_EXCLUDED;
    779
    38
                    goto fail;
    780
    38
            }
    781
    782
    2.77k
            if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) {
    783
    4
                    fido_log_debug("%s: fido_blob_set", __func__);
    784
    4
                    r = FIDO_ERR_INTERNAL;
    785
    4
                    goto fail;
    786
    4
            }
    787
    788
    2.76k
            if (fa->up == FIDO_OPT_FALSE) {
    789
    424
                    fido_log_debug("%s: checking for key existence only", __func__);
    790
    424
                    r = FIDO_ERR_USER_PRESENCE_REQUIRED;
    791
    424
                    goto fail;
    792
    424
            }
    793
    794
    2.34k
            if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad,
    795
    2.34k
                ms)) != FIDO_OK) {
    796
    373
                    fido_log_debug("%s: do_auth", __func__);
    797
    373
                    goto fail;
    798
    373
            }
    799
    800
    1.97k
            if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK ||
    801
    1.97k
                fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) {
    802
    27
                    fido_log_debug("%s: fido_assert_set", __func__);
    803
    27
                    r = FIDO_ERR_INTERNAL;
    804
    27
                    goto fail;
    805
    27
            }
    806
    807
    1.94k
            r = FIDO_OK;
    808
    4.91k
    fail:
    809
    4.91k
            fido_blob_reset(&sig);
    810
    4.91k
            fido_blob_reset(&ad);
    811
    812
    4.91k
            return (r);
    813
    1.94k
    }
    814
    815
    int
    816
    u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms)
    817
    2.85k
    {
    818
    2.85k
            size_t  nfound = 0;
    819
    2.85k
            size_t  nauth_ok = 0;
    820
    2.85k
            int     r;
    821
    822
    2.85k
            if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
    823
    311
                    fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv,
    824
    311
                        (void *)fa->allow_list.ptr);
    825
    311
                    return (FIDO_ERR_UNSUPPORTED_OPTION);
    826
    311
            }
    827
    828
    2.54k
            if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) {
    829
    4
                    fido_log_debug("%s: fido_assert_set_count", __func__);
    830
    4
                    return (r);
    831
    4
            }
    832
    833
    4.94k
            for (size_t i = 0; i < fa->allow_list.len; i++) {
    834
    4.91k
                    switch ((r = u2f_authenticate_single(dev,
    835
    4.91k
                        &fa->allow_list.ptr[i], fa, nfound, ms))) {
    836
    1.94k
                    case FIDO_OK:
    837
    1.94k
                            nauth_ok++;
    838
    1.94k
                            FALLTHROUGH
    839
    2.36k
                    case FIDO_ERR_USER_PRESENCE_REQUIRED:
    840
    2.36k
                            nfound++;
    841
    2.36k
                            break;
    842
    2.54k
                    default:
    843
    2.54k
                            if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) {
    844
    2.50k
                                    fido_log_debug("%s: u2f_authenticate_single",
    845
    2.50k
                                        __func__);
    846
    2.50k
                                    return (r);
    847
    2.50k
                            }
    848
                            /* ignore credentials that don't exist */
    849
    4.91k
                    }
    850
    4.91k
            }
    851
    852
    37
            fa->stmt_len = nfound;
    853
    854
    37
            if (nfound == 0)
    855
    6
                    return (FIDO_ERR_NO_CREDENTIALS);
    856
    31
            if (nauth_ok == 0)
    857
    4
                    return (FIDO_ERR_USER_PRESENCE_REQUIRED);
    858
    859
    27
            return (FIDO_OK);
    860
    31
    }
    861
    862
    int
    863
    u2f_get_touch_begin(fido_dev_t *dev, int *ms)
    864
    10.7k
    {
    865
    10.7k
            iso7816_apdu_t  *apdu = NULL;
    866
    10.7k
            const char      *clientdata = FIDO_DUMMY_CLIENTDATA;
    867
    10.7k
            const char      *rp_id = FIDO_DUMMY_RP_ID;
    868
    10.7k
            unsigned char   *reply = NULL;
    869
    10.7k
            unsigned char    clientdata_hash[SHA256_DIGEST_LENGTH];
    870
    10.7k
            unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
    871
    10.7k
            int              r;
    872
    873
    10.7k
            memset(&clientdata_hash, 0, sizeof(clientdata_hash));
    874
    10.7k
            memset(&rp_id_hash, 0, sizeof(rp_id_hash));
    875
    876
    10.7k
            if (SHA256((const void *)clientdata, strlen(clientdata),
    877
    10.7k
                clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
    878
    10.6k
                strlen(rp_id), rp_id_hash) != rp_id_hash) {
    879
    72
                    fido_log_debug("%s: sha256", __func__);
    880
    72
                    return (FIDO_ERR_INTERNAL);
    881
    72
            }
    882
    883
    10.6k
            if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 *
    884
    10.6k
                SHA256_DIGEST_LENGTH)) == NULL ||
    885
    10.6k
                iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
    886
    10.6k
                iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
    887
    61
                    fido_log_debug("%s: iso7816", __func__);
    888
    61
                    r = FIDO_ERR_INTERNAL;
    889
    61
                    goto fail;
    890
    61
            }
    891
    892
    10.5k
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    893
    34
                    fido_log_debug("%s: malloc", __func__);
    894
    34
                    r =  FIDO_ERR_INTERNAL;
    895
    34
                    goto fail;
    896
    34
            }
    897
    898
    10.5k
            if (dev->attr.flags & FIDO_CAP_WINK) {
    899
    6.27k
                    fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms);
    900
    6.27k
                    fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms);
    901
    6.27k
            }
    902
    903
    10.5k
            if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
    904
    10.5k
                iso7816_len(apdu), ms) < 0) {
    905
    895
                    fido_log_debug("%s: fido_tx", __func__);
    906
    895
                    r = FIDO_ERR_TX;
    907
    895
                    goto fail;
    908
    895
            }
    909
    910
    9.66k
            r = FIDO_OK;
    911
    10.6k
    fail:
    912
    10.6k
            iso7816_free(&apdu);
    913
    10.6k
            freezero(reply, FIDO_MAXMSG);
    914
    915
    10.6k
            return (r);
    916
    9.66k
    }
    917
    918
    int
    919
    u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms)
    920
    10.6k
    {
    921
    10.6k
            unsigned char   *reply;
    922
    10.6k
            int              reply_len;
    923
    10.6k
            int              r;
    924
    925
    10.6k
            if ((reply = malloc(FIDO_MAXMSG)) == NULL) {
    926
    11
                    fido_log_debug("%s: malloc", __func__);
    927
    11
                    r =  FIDO_ERR_INTERNAL;
    928
    11
                    goto out;
    929
    11
            }
    930
    931
    10.6k
            if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG,
    932
    10.6k
                ms)) < 2) {
    933
    9.82k
                    fido_log_debug("%s: fido_rx", __func__);
    934
    9.82k
                    r = FIDO_OK; /* ignore */
    935
    9.82k
                    goto out;
    936
    9.82k
            }
    937
    938
    796
            switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
    939
    98
            case SW_CONDITIONS_NOT_SATISFIED:
    940
    98
                    if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) {
    941
    45
                            fido_log_debug("%s: u2f_get_touch_begin", __func__);
    942
    45
                            goto out;
    943
    45
                    }
    944
    53
                    *touched = 0;
    945
    53
                    break;
    946
    58
            case SW_NO_ERROR:
    947
    58
                    *touched = 1;
    948
    58
                    break;
    949
    640
            default:
    950
    640
                    fido_log_debug("%s: unexpected sw", __func__);
    951
    640
                    r = FIDO_ERR_RX;
    952
    640
                    goto out;
    953
    796
            }
    954
    955
    111
            r = FIDO_OK;
    956
    10.6k
    out:
    957
    10.6k
            freezero(reply, FIDO_MAXMSG);
    958
    959
    10.6k
            return (r);
    960
    111
    }