## Coverage Report

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

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

    /libfido2/src/ecdh.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 2018-2021 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/evp.h>
    9
    #include <openssl/sha.h>
    10
    #if defined(LIBRESSL_VERSION_NUMBER)
    11
    #include <openssl/hkdf.h>
    12
    #else
    13
    #include <openssl/kdf.h>
    14
    #endif
    15
    16
    #include "fido.h"
    17
    #include "fido/es256.h"
    18
    19
    #if defined(LIBRESSL_VERSION_NUMBER)
    20
    static int
    21
    hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret)
    22
    {
    23
            const EVP_MD *md;
    24
            uint8_t salt[32];
    25
    26
            memset(salt, 0, sizeof(salt));
    27
            if ((md = EVP_sha256()) == NULL ||
    28
                HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt,
    29
                sizeof(salt), (const uint8_t *)info, strlen(info)) != 1)
    30
                    return -1;
    31
    32
            return 0;
    33
    }
    34
    #else
    35
    static int
    36
    hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
    37
    7.13k
    {
    38
    7.13k
            const EVP_MD *const_md;
    39
    7.13k
            EVP_MD *md = NULL;
    40
    7.13k
            EVP_PKEY_CTX *ctx = NULL;
    41
    7.13k
            size_t keylen = SHA256_DIGEST_LENGTH;
    42
    7.13k
            uint8_t salt[32];
    43
    7.13k
            int ok = -1;
    44
    45
    7.13k
            memset(salt, 0, sizeof(salt));
    46
    7.13k
            if (secret->len > INT_MAX || strlen(info) > INT_MAX) {
    47
    0
                    fido_log_debug("%s: invalid param", __func__);
    48
    0
                    goto fail;
    49
    0
            }
    50
    7.13k
            if ((const_md = EVP_sha256()) == NULL ||
    51
    7.13k
                (md = EVP_MD_meth_dup(const_md)) == NULL ||
    52
    7.13k
                (ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) {
    53
    156
                    fido_log_debug("%s: init", __func__);
    54
    156
                    goto fail;
    55
    156
            }
    56
    6.97k
            if (EVP_PKEY_derive_init(ctx) < 1 ||
    57
    6.97k
                EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 ||
    58
    6.97k
                EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 ||
    59
    6.97k
                EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 ||
    60
    6.97k
                EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) {
    61
    94
                    fido_log_debug("%s: EVP_PKEY_CTX", __func__);
    62
    94
                    goto fail;
    63
    94
            }
    64
    6.88k
            if (EVP_PKEY_derive(ctx, key, &keylen) < 1) {
    65
    120
                    fido_log_debug("%s: EVP_PKEY_derive", __func__);
    66
    120
                    goto fail;
    67
    120
            }
    68
    69
    6.76k
            ok = 0;
    70
    7.13k
    fail:
    71
    7.13k
            if (md != NULL)
    72
    7.06k
                    EVP_MD_meth_free(md);
    73
    7.13k
            if (ctx != NULL)
    74
    6.97k
                    EVP_PKEY_CTX_free(ctx);
    75
    76
    7.13k
            return ok;
    77
    6.76k
    }
    78
    #endif /* defined(LIBRESSL_VERSION_NUMBER) */
    79
    80
    static int
    81
    kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret)
    82
    22.6k
    {
    83
    22.6k
            char hmac_info[] = "CTAP2 HMAC key"; /* const */
    84
    22.6k
            char aes_info[] = "CTAP2 AES key"; /* const */
    85
    86
    22.6k
            switch (prot) {
    87
    18.9k
            case CTAP_PIN_PROTOCOL1:
    88
                    /* use sha256 on the resulting secret */
    89
    18.9k
                    key->len = SHA256_DIGEST_LENGTH;
    90
    18.9k
                    if ((key->ptr = calloc(1, key->len)) == NULL ||
    91
    18.9k
                        SHA256(secret->ptr, secret->len, key->ptr) != key->ptr) {
    92
    98
                            fido_log_debug("%s: SHA256", __func__);
    93
    98
                            return -1;
    94
    98
                    }
    95
    18.8k
                    break;
    96
    18.8k
            case CTAP_PIN_PROTOCOL2:
    97
                    /* use two instances of hkdf-sha256 on the resulting secret */
    98
    3.71k
                    key->len = 2 * SHA256_DIGEST_LENGTH;
    99
    3.71k
                    if ((key->ptr = calloc(1, key->len)) == NULL ||
    100
    3.71k
                        hkdf_sha256(key->ptr, hmac_info, secret) < 0 ||
    101
    3.71k
                        hkdf_sha256(key->ptr + SHA256_DIGEST_LENGTH, aes_info,
    102
    3.48k
                        secret) < 0) {
    103
    432
                            fido_log_debug("%s: hkdf", __func__);
    104
    432
                            return -1;
    105
    432
                    }
    106
    3.28k
                    break;
    107
    3.28k
            default:
    108
    0
                    fido_log_debug("%s: unknown pin protocol %u", __func__, prot);
    109
    0
                    return -1;
    110
    22.6k
            }
    111
    112
    22.1k
            return 0;
    113
    22.6k
    }
    114
    115
    static int
    116
    do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk,
    117
        fido_blob_t **ecdh)
    118
    28.0k
    {
    119
    28.0k
            EVP_PKEY *pk_evp = NULL;
    120
    28.0k
            EVP_PKEY *sk_evp = NULL;
    121
    28.0k
            EVP_PKEY_CTX *ctx = NULL;
    122
    28.0k
            fido_blob_t *secret = NULL;
    123
    28.0k
            int ok = -1;
    124
    125
    28.0k
            *ecdh = NULL;
    126
    28.0k
            if ((secret = fido_blob_new()) == NULL ||
    127
    28.0k
                (*ecdh = fido_blob_new()) == NULL)
    128
    123
                    goto fail;
    129
    27.9k
            if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL ||
    130
    27.9k
                (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) {
    131
    4.63k
                    fido_log_debug("%s: es256_to_EVP_PKEY", __func__);
    132
    4.63k
                    goto fail;
    133
    4.63k
            }
    134
    23.3k
            if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL ||
    135
    23.3k
                EVP_PKEY_derive_init(ctx) <= 0 ||
    136
    23.3k
                EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) {
    137
    358
                    fido_log_debug("%s: EVP_PKEY_derive_init", __func__);
    138
    358
                    goto fail;
    139
    358
            }
    140
    22.9k
            if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 ||
    141
    22.9k
                (secret->ptr = calloc(1, secret->len)) == NULL ||
    142
    22.9k
                EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) {
    143
    281
                    fido_log_debug("%s: EVP_PKEY_derive", __func__);
    144
    281
                    goto fail;
    145
    281
            }
    146
    22.6k
            if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) {
    147
    530
                    fido_log_debug("%s: kdf", __func__);
    148
    530
                    goto fail;
    149
    530
            }
    150
    151
    22.1k
            ok = 0;
    152
    28.0k
    fail:
    153
    28.0k
            if (pk_evp != NULL)
    154
    23.7k
                    EVP_PKEY_free(pk_evp);
    155
    28.0k
            if (sk_evp != NULL)
    156
    23.3k
                    EVP_PKEY_free(sk_evp);
    157
    28.0k
            if (ctx != NULL)
    158
    23.2k
                    EVP_PKEY_CTX_free(ctx);
    159
    28.0k
            if (ok < 0)
    160
    5.92k
                    fido_blob_free(ecdh);
    161
    162
    28.0k
            fido_blob_free(&secret);
    163
    164
    28.0k
            return ok;
    165
    22.1k
    }
    166
    167
    int
    168
    fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms)
    169
    112k
    {
    170
    112k
            es256_sk_t *sk = NULL; /* our private key */
    171
    112k
            es256_pk_t *ak = NULL; /* authenticator's public key */
    172
    112k
            int r;
    173
    174
    112k
            *pk = NULL;
    175
    112k
            *ecdh = NULL;
    176
    112k
            if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
    177
    879
                    r = FIDO_ERR_INTERNAL;
    178
    879
                    goto fail;
    179
    879
            }
    180
    111k
            if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
    181
    8.67k
                    fido_log_debug("%s: es256_derive_pk", __func__);
    182
    8.67k
                    r = FIDO_ERR_INTERNAL;
    183
    8.67k
                    goto fail;
    184
    8.67k
            }
    185
    102k
            if ((ak = es256_pk_new()) == NULL ||
    186
    102k
                fido_dev_authkey(dev, ak, ms) != FIDO_OK) {
    187
    74.5k
                    fido_log_debug("%s: fido_dev_authkey", __func__);
    188
    74.5k
                    r = FIDO_ERR_INTERNAL;
    189
    74.5k
                    goto fail;
    190
    74.5k
            }
    191
    28.0k
            if (do_ecdh(dev, sk, ak, ecdh) < 0) {
    192
    5.92k
                    fido_log_debug("%s: do_ecdh", __func__);
    193
    5.92k
                    r = FIDO_ERR_INTERNAL;
    194
    5.92k
                    goto fail;
    195
    5.92k
            }
    196
    197
    22.1k
            r = FIDO_OK;
    198
    112k
    fail:
    199
    112k
            es256_sk_free(&sk);
    200
    112k
            es256_pk_free(&ak);
    201
    202
    112k
            if (r != FIDO_OK) {
    203
    90.0k
                    es256_pk_free(pk);
    204
    90.0k
                    fido_blob_free(ecdh);
    205
    90.0k
            }
    206
    207
    112k
            return r;
    208
    22.1k
    }