## Coverage Report

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

    /libfido2/src/pin.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 "fido.h"
    10
    #include "fido/es256.h"
    11
    12
    9
    #define CTAP21_UV_TOKEN_PERM_MAKECRED   0x01
    13
    10
    #define CTAP21_UV_TOKEN_PERM_ASSERT     0x02
    14
    15
    #define CTAP21_UV_TOKEN_PERM_CRED_MGMT  0x04
    15
    5
    #define CTAP21_UV_TOKEN_PERM_BIO        0x08
    16
    6
    #define CTAP21_UV_TOKEN_PERM_LARGEBLOB  0x10
    17
    28
    #define CTAP21_UV_TOKEN_PERM_CONFIG     0x20
    18
    19
    int
    20
    fido_sha256(fido_blob_t *digest, const u_char *data, size_t data_len)
    21
    3.06k
    {
    22
    3.06k
            if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
    23
    16
                    return (-1);
    24
    25
    3.04k
            digest->len = SHA256_DIGEST_LENGTH;
    26
    27
    3.04k
            if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
    28
    13
                    fido_blob_reset(digest);
    29
    13
                    return (-1);
    30
    13
            }
    31
    32
    3.03k
            return (0);
    33
    3.04k
    }
    34
    35
    static int
    36
    pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared,
    37
        const fido_blob_t *pin, fido_blob_t **out)
    38
    3.08k
    {
    39
    3.08k
            fido_blob_t     *ph = NULL;
    40
    3.08k
            int              r;
    41
    42
    3.08k
            if ((*out = fido_blob_new()) == NULL ||
    43
    3.08k
                (ph = fido_blob_new()) == NULL) {
    44
    19
                    r = FIDO_ERR_INTERNAL;
    45
    19
                    goto fail;
    46
    19
            }
    47
    48
    3.06k
            if (fido_sha256(ph, pin->ptr, pin->len) < 0 || ph->len < 16) {
    49
    29
                    fido_log_debug("%s: SHA256", __func__);
    50
    29
                    r = FIDO_ERR_INTERNAL;
    51
    29
                    goto fail;
    52
    29
            }
    53
    54
    3.03k
            ph->len = 16; /* first 16 bytes */
    55
    56
    3.03k
            if (aes256_cbc_enc(dev, shared, ph, *out) < 0) {
    57
    93
                    fido_log_debug("%s: aes256_cbc_enc", __func__);
    58
    93
                    r = FIDO_ERR_INTERNAL;
    59
    93
                    goto fail;
    60
    93
            }
    61
    62
    2.94k
            r = FIDO_OK;
    63
    3.08k
    fail:
    64
    3.08k
            fido_blob_free(&ph);
    65
    66
    3.08k
            return (r);
    67
    2.94k
    }
    68
    69
    static int
    70
    pad64(const char *pin, fido_blob_t **ppin)
    71
    103
    {
    72
    103
            size_t  pin_len;
    73
    103
            size_t  ppin_len;
    74
    75
    103
            pin_len = strlen(pin);
    76
    103
            if (pin_len < 4 || pin_len > 63) {
    77
    18
                    fido_log_debug("%s: invalid pin length", __func__);
    78
    18
                    return (FIDO_ERR_PIN_POLICY_VIOLATION);
    79
    18
            }
    80
    81
    85
            if ((*ppin = fido_blob_new()) == NULL)
    82
    1
                    return (FIDO_ERR_INTERNAL);
    83
    84
    84
            ppin_len = (pin_len + 63U) & ~63U;
    85
    84
            if (ppin_len < pin_len ||
    86
    84
                ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
    87
    1
                    fido_blob_free(ppin);
    88
    1
                    return (FIDO_ERR_INTERNAL);
    89
    1
            }
    90
    91
    83
            memcpy((*ppin)->ptr, pin, pin_len);
    92
    83
            (*ppin)->len = ppin_len;
    93
    94
    83
            return (FIDO_OK);
    95
    84
    }
    96
    97
    static int
    98
    pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared,
    99
        const char *pin, fido_blob_t **out)
    100
    103
    {
    101
    103
            fido_blob_t *ppin = NULL;
    102
    103
            int          r;
    103
    104
    103
            if ((r = pad64(pin, &ppin)) != FIDO_OK) {
    105
    20
                    fido_log_debug("%s: pad64", __func__);
    106
    20
                        goto fail;
    107
    20
            }
    108
    109
    83
            if ((*out = fido_blob_new()) == NULL) {
    110
    1
                    r = FIDO_ERR_INTERNAL;
    111
    1
                    goto fail;
    112
    1
            }
    113
    114
    82
            if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) {
    115
    6
                    fido_log_debug("%s: aes256_cbc_enc", __func__);
    116
    6
                    r = FIDO_ERR_INTERNAL;
    117
    6
                    goto fail;
    118
    6
            }
    119
    120
    76
            r = FIDO_OK;
    121
    103
    fail:
    122
    103
            fido_blob_free(&ppin);
    123
    124
    103
            return (r);
    125
    76
    }
    126
    127
    static cbor_item_t *
    128
    encode_uv_permission(uint8_t cmd)
    129
    73
    {
    130
    73
            switch (cmd) {
    131
    10
            case CTAP_CBOR_ASSERT:
    132
    10
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT));
    133
    5
            case CTAP_CBOR_BIO_ENROLL_PRE:
    134
    5
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO));
    135
    28
            case CTAP_CBOR_CONFIG:
    136
    28
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG));
    137
    9
            case CTAP_CBOR_MAKECRED:
    138
    9
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED));
    139
    15
            case CTAP_CBOR_CRED_MGMT_PRE:
    140
    15
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT));
    141
    6
            case CTAP_CBOR_LARGEBLOB:
    142
    6
                    return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB));
    143
    0
            default:
    144
    0
                    fido_log_debug("%s: cmd 0x%02x", __func__, cmd);
    145
    0
                    return (NULL);
    146
    73
            }
    147
    73
    }
    148
    149
    static int
    150
    ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
    151
        const es256_pk_t *pk, int *ms)
    152
    3.02k
    {
    153
    3.02k
            fido_blob_t      f;
    154
    3.02k
            fido_blob_t     *p = NULL;
    155
    3.02k
            fido_blob_t     *phe = NULL;
    156
    3.02k
            cbor_item_t     *argv[6];
    157
    3.02k
            int              r;
    158
    159
    3.02k
            memset(&f, 0, sizeof(f));
    160
    3.02k
            memset(argv, 0, sizeof(argv));
    161
    162
    3.02k
            if (pin == NULL) {
    163
    14
                    fido_log_debug("%s: NULL pin", __func__);
    164
    14
                    r = FIDO_ERR_PIN_REQUIRED;
    165
    14
                    goto fail;
    166
    14
            }
    167
    168
    3.01k
            if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
    169
    2.99k
                (const unsigned char *)pin, strlen(pin)) < 0) {
    170
    60
                    fido_log_debug("%s: fido_blob_set", __func__);
    171
    60
                    r = FIDO_ERR_INVALID_ARGUMENT;
    172
    60
                    goto fail;
    173
    60
            }
    174
    175
    2.95k
            if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
    176
    116
                    fido_log_debug("%s: pin_sha256_enc", __func__);
    177
    116
                    goto fail;
    178
    116
            }
    179
    180
    2.83k
            if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
    181
    2.83k
                (argv[1] = cbor_build_uint8(5)) == NULL ||
    182
    2.83k
                (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
    183
    2.83k
                (argv[5] = fido_blob_encode(phe)) == NULL) {
    184
    248
                    fido_log_debug("%s: cbor encode", __func__);
    185
    248
                    r = FIDO_ERR_INTERNAL;
    186
    248
                    goto fail;
    187
    248
            }
    188
    189
    2.58k
            if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
    190
    2.58k
                &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    191
    72
                    fido_log_debug("%s: fido_tx", __func__);
    192
    72
                    r = FIDO_ERR_TX;
    193
    72
                    goto fail;
    194
    72
            }
    195
    196
    2.51k
            r = FIDO_OK;
    197
    3.02k
    fail:
    198
    3.02k
            cbor_vector_free(argv, nitems(argv));
    199
    3.02k
            fido_blob_free(&p);
    200
    3.02k
            fido_blob_free(&phe);
    201
    3.02k
            free(f.ptr);
    202
    203
    3.02k
            return (r);
    204
    2.51k
    }
    205
    206
    static int
    207
    ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
    208
        const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms)
    209
    160
    {
    210
    160
            fido_blob_t      f;
    211
    160
            fido_blob_t     *p = NULL;
    212
    160
            fido_blob_t     *phe = NULL;
    213
    160
            cbor_item_t     *argv[10];
    214
    160
            uint8_t          subcmd;
    215
    160
            int              r;
    216
    217
    160
            memset(&f, 0, sizeof(f));
    218
    160
            memset(argv, 0, sizeof(argv));
    219
    220
    160
            if (pin != NULL) {
    221
    106
                    if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
    222
    97
                        (const unsigned char *)pin, strlen(pin)) < 0) {
    223
    18
                            fido_log_debug("%s: fido_blob_set", __func__);
    224
    18
                            r = FIDO_ERR_INVALID_ARGUMENT;
    225
    18
                            goto fail;
    226
    18
                    }
    227
    88
                    if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
    228
    23
                            fido_log_debug("%s: pin_sha256_enc", __func__);
    229
    23
                            goto fail;
    230
    23
                    }
    231
    65
                    subcmd = 9; /* getPinUvAuthTokenUsingPinWithPermissions */
    232
    65
            } else {
    233
    54
                    if (fido_dev_has_uv(dev) == false) {
    234
    4
                            fido_log_debug("%s: fido_dev_has_uv", __func__);
    235
    4
                            r = FIDO_ERR_PIN_REQUIRED;
    236
    4
                            goto fail;
    237
    4
                    }
    238
    50
                    subcmd = 6; /* getPinUvAuthTokenUsingUvWithPermissions */
    239
    50
            }
    240
    241
    115
            if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
    242
    115
                (argv[1] = cbor_build_uint8(subcmd)) == NULL ||
    243
    115
                (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
    244
    115
                (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) ||
    245
    115
                (argv[8] = encode_uv_permission(cmd)) == NULL ||
    246
    115
                (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) {
    247
    54
                    fido_log_debug("%s: cbor encode", __func__);
    248
    54
                    r = FIDO_ERR_INTERNAL;
    249
    54
                    goto fail;
    250
    54
            }
    251
    252
    61
            if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
    253
    61
                &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    254
    30
                    fido_log_debug("%s:  fido_tx", __func__);
    255
    30
                    r = FIDO_ERR_TX;
    256
    30
                    goto fail;
    257
    30
            }
    258
    259
    31
            r = FIDO_OK;
    260
    160
    fail:
    261
    160
            cbor_vector_free(argv, nitems(argv));
    262
    160
            fido_blob_free(&p);
    263
    160
            fido_blob_free(&phe);
    264
    160
            free(f.ptr);
    265
    266
    160
            return (r);
    267
    31
    }
    268
    269
    static int
    270
    parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    271
    2.45k
    {
    272
    2.45k
            fido_blob_t *token = arg;
    273
    274
    2.45k
            if (cbor_isa_uint(key) == false ||
    275
    2.45k
                cbor_int_get_width(key) != CBOR_INT_8 ||
    276
    2.45k
                cbor_get_uint8(key) != 2) {
    277
    336
                    fido_log_debug("%s: cbor type", __func__);
    278
    336
                    return (0); /* ignore */
    279
    336
            }
    280
    281
    2.12k
            return (fido_blob_decode(val, token));
    282
    2.45k
    }
    283
    284
    static int
    285
    uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
    286
        int *ms)
    287
    2.54k
    {
    288
    2.54k
            fido_blob_t     *aes_token = NULL;
    289
    2.54k
            unsigned char   *msg = NULL;
    290
    2.54k
            int              msglen;
    291
    2.54k
            int              r;
    292
    293
    2.54k
            if ((aes_token = fido_blob_new()) == NULL) {
    294
    7
                    r = FIDO_ERR_INTERNAL;
    295
    7
                    goto fail;
    296
    7
            }
    297
    298
    2.54k
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    299
    6
                    r = FIDO_ERR_INTERNAL;
    300
    6
                    goto fail;
    301
    6
            }
    302
    303
    2.53k
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    304
    155
                    fido_log_debug("%s: fido_rx", __func__);
    305
    155
                    r = FIDO_ERR_RX;
    306
    155
                    goto fail;
    307
    155
            }
    308
    309
    2.37k
            if ((r = cbor_parse_reply(msg, (size_t)msglen, aes_token,
    310
    2.37k
                parse_uv_token)) != FIDO_OK) {
    311
    209
                    fido_log_debug("%s: parse_uv_token", __func__);
    312
    209
                    goto fail;
    313
    209
            }
    314
    315
    2.17k
            if  (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) {
    316
    168
                    fido_log_debug("%s: aes256_cbc_dec", __func__);
    317
    168
                    r = FIDO_ERR_RX;
    318
    168
                    goto fail;
    319
    168
            }
    320
    321
    2.00k
            r = FIDO_OK;
    322
    2.54k
    fail:
    323
    2.54k
            fido_blob_free(&aes_token);
    324
    2.54k
            freezero(msg, FIDO_MAXMSG);
    325
    326
    2.54k
            return (r);
    327
    2.00k
    }
    328
    329
    static int
    330
    uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
    331
        const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
    332
        fido_blob_t *token, int *ms)
    333
    3.18k
    {
    334
    3.18k
            int r;
    335
    336
    3.18k
            if (ecdh == NULL || pk == NULL)
    337
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    338
    3.18k
            if (fido_dev_supports_permissions(dev))
    339
    160
                    r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms);
    340
    3.02k
            else
    341
    3.02k
                    r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms);
    342
    3.18k
            if (r != FIDO_OK)
    343
    639
                    return (r);
    344
    345
    2.54k
            return (uv_token_rx(dev, ecdh, token, ms));
    346
    3.18k
    }
    347
    348
    int
    349
    fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin,
    350
        const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
    351
        fido_blob_t *token, int *ms)
    352
    3.18k
    {
    353
    3.18k
            return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms));
    354
    3.18k
    }
    355
    356
    static int
    357
    fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin,
    358
        int *ms)
    359
    215
    {
    360
    215
            fido_blob_t      f;
    361
    215
            fido_blob_t     *ppine = NULL;
    362
    215
            fido_blob_t     *ecdh = NULL;
    363
    215
            fido_blob_t     *opin = NULL;
    364
    215
            fido_blob_t     *opinhe = NULL;
    365
    215
            cbor_item_t     *argv[6];
    366
    215
            es256_pk_t      *pk = NULL;
    367
    215
            int r;
    368
    369
    215
            memset(&f, 0, sizeof(f));
    370
    215
            memset(argv, 0, sizeof(argv));
    371
    372
    215
            if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin,
    373
    214
                (const unsigned char *)oldpin, strlen(oldpin)) < 0) {
    374
    74
                    fido_log_debug("%s: fido_blob_set", __func__);
    375
    74
                    r = FIDO_ERR_INVALID_ARGUMENT;
    376
    74
                    goto fail;
    377
    74
            }
    378
    379
    141
            if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
    380
    89
                    fido_log_debug("%s: fido_do_ecdh", __func__);
    381
    89
                    goto fail;
    382
    89
            }
    383
    384
            /* pad and encrypt new pin */
    385
    52
            if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
    386
    10
                    fido_log_debug("%s: pin_pad64_enc", __func__);
    387
    10
                    goto fail;
    388
    10
            }
    389
    390
            /* hash and encrypt old pin */
    391
    42
            if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) {
    392
    2
                    fido_log_debug("%s: pin_sha256_enc", __func__);
    393
    2
                    goto fail;
    394
    2
            }
    395
    396
    40
            if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
    397
    40
                (argv[1] = cbor_build_uint8(4)) == NULL ||
    398
    40
                (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
    399
    40
                (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL ||
    400
    40
                (argv[4] = fido_blob_encode(ppine)) == NULL ||
    401
    40
                (argv[5] = fido_blob_encode(opinhe)) == NULL) {
    402
    17
                    fido_log_debug("%s: cbor encode", __func__);
    403
    17
                    r = FIDO_ERR_INTERNAL;
    404
    17
                    goto fail;
    405
    17
            }
    406
    407
    23
            if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
    408
    23
                &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    409
    3
                    fido_log_debug("%s: fido_tx", __func__);
    410
    3
                    r = FIDO_ERR_TX;
    411
    3
                    goto fail;
    412
    3
            }
    413
    414
    20
            r = FIDO_OK;
    415
    215
    fail:
    416
    215
            cbor_vector_free(argv, nitems(argv));
    417
    215
            es256_pk_free(&pk);
    418
    215
            fido_blob_free(&ppine);
    419
    215
            fido_blob_free(&ecdh);
    420
    215
            fido_blob_free(&opin);
    421
    215
            fido_blob_free(&opinhe);
    422
    215
            free(f.ptr);
    423
    424
    215
            return (r);
    425
    426
    20
    }
    427
    428
    static int
    429
    fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms)
    430
    234
    {
    431
    234
            fido_blob_t      f;
    432
    234
            fido_blob_t     *ppine = NULL;
    433
    234
            fido_blob_t     *ecdh = NULL;
    434
    234
            cbor_item_t     *argv[5];
    435
    234
            es256_pk_t      *pk = NULL;
    436
    234
            int              r;
    437
    438
    234
            memset(&f, 0, sizeof(f));
    439
    234
            memset(argv, 0, sizeof(argv));
    440
    441
    234
            if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
    442
    183
                    fido_log_debug("%s: fido_do_ecdh", __func__);
    443
    183
                    goto fail;
    444
    183
            }
    445
    446
    51
            if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
    447
    17
                    fido_log_debug("%s: pin_pad64_enc", __func__);
    448
    17
                    goto fail;
    449
    17
            }
    450
    451
    34
            if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
    452
    34
                (argv[1] = cbor_build_uint8(3)) == NULL ||
    453
    34
                (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
    454
    34
                (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL ||
    455
    34
                (argv[4] = fido_blob_encode(ppine)) == NULL) {
    456
    11
                    fido_log_debug("%s: cbor encode", __func__);
    457
    11
                    r = FIDO_ERR_INTERNAL;
    458
    11
                    goto fail;
    459
    11
            }
    460
    461
    23
            if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
    462
    23
                &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    463
    3
                    fido_log_debug("%s: fido_tx", __func__);
    464
    3
                    r = FIDO_ERR_TX;
    465
    3
                    goto fail;
    466
    3
            }
    467
    468
    20
            r = FIDO_OK;
    469
    234
    fail:
    470
    234
            cbor_vector_free(argv, nitems(argv));
    471
    234
            es256_pk_free(&pk);
    472
    234
            fido_blob_free(&ppine);
    473
    234
            fido_blob_free(&ecdh);
    474
    234
            free(f.ptr);
    475
    476
    234
            return (r);
    477
    20
    }
    478
    479
    static int
    480
    fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
    481
        int *ms)
    482
    449
    {
    483
    449
            int r;
    484
    485
    449
            if (oldpin != NULL) {
    486
    215
                    if ((r = fido_dev_change_pin_tx(dev, pin, oldpin,
    487
    215
                        ms)) != FIDO_OK) {
    488
    195
                            fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
    489
    195
                            return (r);
    490
    195
                    }
    491
    234
            } else {
    492
    234
                    if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) {
    493
    214
                            fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
    494
    214
                            return (r);
    495
    214
                    }
    496
    234
            }
    497
    498
    40
            if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
    499
    33
                    fido_log_debug("%s: fido_rx_cbor_status", __func__);
    500
    33
                    return (r);
    501
    33
            }
    502
    503
    7
            if (dev->flags & FIDO_DEV_PIN_UNSET) {
    504
    4
                    dev->flags &= ~FIDO_DEV_PIN_UNSET;
    505
    4
                    dev->flags |= FIDO_DEV_PIN_SET;
    506
    4
            }
    507
    508
    7
            return (FIDO_OK);
    509
    40
    }
    510
    511
    int
    512
    fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
    513
    449
    {
    514
    449
            int ms = dev->timeout_ms;
    515
    516
    449
            return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms));
    517
    449
    }
    518
    519
    static int
    520
    parse_retry_count(const uint8_t keyval, const cbor_item_t *key,
    521
        const cbor_item_t *val, void *arg)
    522
    645
    {
    523
    645
            int             *retries = arg;
    524
    645
            uint64_t         n;
    525
    526
    645
            if (cbor_isa_uint(key) == false ||
    527
    645
                cbor_int_get_width(key) != CBOR_INT_8 ||
    528
    645
                cbor_get_uint8(key) != keyval) {
    529
    542
                    fido_log_debug("%s: cbor type", __func__);
    530
    542
                    return (0); /* ignore */
    531
    542
            }
    532
    533
    103
            if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) {
    534
    59
                    fido_log_debug("%s: cbor_decode_uint64", __func__);
    535
    59
                    return (-1);
    536
    59
            }
    537
    538
    44
            *retries = (int)n;
    539
    540
    44
            return (0);
    541
    103
    }
    542
    543
    static int
    544
    parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    545
    325
    {
    546
    325
            return (parse_retry_count(3, key, val, arg));
    547
    325
    }
    548
    549
    static int
    550
    parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    551
    320
    {
    552
    320
            return (parse_retry_count(5, key, val, arg));
    553
    320
    }
    554
    555
    static int
    556
    fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms)
    557
    1.29k
    {
    558
    1.29k
            fido_blob_t      f;
    559
    1.29k
            cbor_item_t     *argv[2];
    560
    1.29k
            int              r;
    561
    562
    1.29k
            memset(&f, 0, sizeof(f));
    563
    1.29k
            memset(argv, 0, sizeof(argv));
    564
    565
    1.29k
            if ((argv[0] = cbor_build_uint8(1)) == NULL ||
    566
    1.29k
                (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
    567
    19
                    r = FIDO_ERR_INTERNAL;
    568
    19
                    goto fail;
    569
    19
            }
    570
    571
    1.27k
            if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
    572
    1.27k
                &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
    573
    48
                    fido_log_debug("%s: fido_tx", __func__);
    574
    48
                    r = FIDO_ERR_TX;
    575
    48
                    goto fail;
    576
    48
            }
    577
    578
    1.22k
            r = FIDO_OK;
    579
    1.29k
    fail:
    580
    1.29k
            cbor_vector_free(argv, nitems(argv));
    581
    1.29k
            free(f.ptr);
    582
    583
    1.29k
            return (r);
    584
    1.22k
    }
    585
    586
    static int
    587
    fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
    588
    640
    {
    589
    640
            unsigned char   *msg;
    590
    640
            int              msglen;
    591
    640
            int              r;
    592
    593
    640
            *retries = 0;
    594
    595
    640
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    596
    2
                    r = FIDO_ERR_INTERNAL;
    597
    2
                    goto fail;
    598
    2
            }
    599
    600
    638
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    601
    417
                    fido_log_debug("%s: fido_rx", __func__);
    602
    417
                    r = FIDO_ERR_RX;
    603
    417
                    goto fail;
    604
    417
            }
    605
    606
    221
            if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
    607
    221
                parse_pin_retry_count)) != FIDO_OK) {
    608
    179
                    fido_log_debug("%s: parse_pin_retry_count", __func__);
    609
    179
                    goto fail;
    610
    179
            }
    611
    612
    42
            r = FIDO_OK;
    613
    640
    fail:
    614
    640
            freezero(msg, FIDO_MAXMSG);
    615
    616
    640
            return (r);
    617
    42
    }
    618
    619
    static int
    620
    fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
    621
    671
    {
    622
    671
            int r;
    623
    624
    671
            if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK ||
    625
    671
                (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK)
    626
    629
                    return (r);
    627
    628
    42
            return (FIDO_OK);
    629
    671
    }
    630
    631
    int
    632
    fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
    633
    671
    {
    634
    671
            int ms = dev->timeout_ms;
    635
    636
    671
            return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms));
    637
    671
    }
    638
    639
    static int
    640
    fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
    641
    587
    {
    642
    587
            unsigned char   *msg;
    643
    587
            int              msglen;
    644
    587
            int              r;
    645
    646
    587
            *retries = 0;
    647
    648
    587
            if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
    649
    1
                    r = FIDO_ERR_INTERNAL;
    650
    1
                    goto fail;
    651
    1
            }
    652
    653
    586
            if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
    654
    448
                    fido_log_debug("%s: fido_rx", __func__);
    655
    448
                    r = FIDO_ERR_RX;
    656
    448
                    goto fail;
    657
    448
            }
    658
    659
    138
            if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
    660
    138
                parse_uv_retry_count)) != FIDO_OK) {
    661
    126
                    fido_log_debug("%s: parse_uv_retry_count", __func__);
    662
    126
                    goto fail;
    663
    126
            }
    664
    665
    12
            r = FIDO_OK;
    666
    587
    fail:
    667
    587
            freezero(msg, FIDO_MAXMSG);
    668
    669
    587
            return (r);
    670
    12
    }
    671
    672
    static int
    673
    fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
    674
    623
    {
    675
    623
            int r;
    676
    677
    623
            if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK ||
    678
    623
                (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK)
    679
    611
                    return (r);
    680
    681
    12
            return (FIDO_OK);
    682
    623
    }
    683
    684
    int
    685
    fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries)
    686
    623
    {
    687
    623
            int ms = dev->timeout_ms;
    688
    689
    623
            return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms));
    690
    623
    }
    691
    692
    int
    693
    cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
    694
        const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
    695
        const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms)
    696
    2.48k
    {
    697
    2.48k
            fido_blob_t     *token = NULL;
    698
    2.48k
            int              r;
    699
    700
    2.48k
            if ((token = fido_blob_new()) == NULL) {
    701
    13
                    r = FIDO_ERR_INTERNAL;
    702
    13
                    goto fail;
    703
    13
            }
    704
    705
    2.47k
            if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid,
    706
    2.47k
                token, ms)) != FIDO_OK) {
    707
    859
                    fido_log_debug("%s: fido_dev_get_uv_token", __func__);
    708
    859
                    goto fail;
    709
    859
            }
    710
    711
    1.61k
            if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL ||
    712
    1.61k
                (*opt = cbor_encode_pin_opt(dev)) == NULL) {
    713
    20
                    fido_log_debug("%s: cbor encode", __func__);
    714
    20
                    r = FIDO_ERR_INTERNAL;
    715
    20
                    goto fail;
    716
    20
            }
    717
    718
    1.59k
            r = FIDO_OK;
    719
    2.48k
    fail:
    720
    2.48k
            fido_blob_free(&token);
    721
    722
    2.48k
            return (r);
    723
    1.59k
    }