## Coverage Report

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

    /libfido2/src/u2f.c

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