## Coverage Report

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

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

    /libfido2/src/eddsa.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 2019-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/bn.h>
    9
    #include <openssl/obj_mac.h>
    10
    11
    #include "fido.h"
    12
    #include "fido/eddsa.h"
    13
    14
    #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f
    15
    EVP_PKEY *
    16
    EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
    17
        size_t keylen)
    18
    {
    19
            (void)type;
    20
            (void)e;
    21
            (void)key;
    22
            (void)keylen;
    23
    24
            fido_log_debug("%s: unimplemented", __func__);
    25
    26
            return (NULL);
    27
    }
    28
    29
    int
    30
    EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
    31
        size_t *len)
    32
    {
    33
            (void)pkey;
    34
            (void)pub;
    35
            (void)len;
    36
    37
            fido_log_debug("%s: unimplemented", __func__);
    38
    39
            return (0);
    40
    }
    41
    #endif /* LIBRESSL_VERSION_NUMBER */
    42
    43
    #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f
    44
    int
    45
    EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
    46
        const unsigned char *tbs, size_t tbslen)
    47
    {
    48
            (void)ctx;
    49
            (void)sigret;
    50
            (void)siglen;
    51
            (void)tbs;
    52
            (void)tbslen;
    53
    54
            fido_log_debug("%s: unimplemented", __func__);
    55
    56
            return (0);
    57
    }
    58
    #endif /* LIBRESSL_VERSION_NUMBER < 0x3040000f */
    59
    60
    static int
    61
    decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
    62
    1.86k
    {
    63
    1.86k
            if (cbor_isa_bytestring(item) == false ||
    64
    1.86k
                cbor_bytestring_is_definite(item) == false ||
    65
    1.86k
                cbor_bytestring_length(item) != xy_len) {
    66
    153
                    fido_log_debug("%s: cbor type", __func__);
    67
    153
                    return (-1);
    68
    153
            }
    69
    70
    1.70k
            memcpy(xy, cbor_bytestring_handle(item), xy_len);
    71
    72
    1.70k
            return (0);
    73
    1.86k
    }
    74
    75
    static int
    76
    decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    77
    8.27k
    {
    78
    8.27k
            eddsa_pk_t *k = arg;
    79
    80
    8.27k
            if (cbor_isa_negint(key) == false ||
    81
    8.27k
                cbor_int_get_width(key) != CBOR_INT_8)
    82
    4.28k
                    return (0); /* ignore */
    83
    84
    3.98k
            switch (cbor_get_uint8(key)) {
    85
    1.86k
            case 1: /* x coordinate */
    86
    1.86k
                    return (decode_coord(val, &k->x, sizeof(k->x)));
    87
    3.98k
            }
    88
    89
    2.12k
            return (0); /* ignore */
    90
    3.98k
    }
    91
    92
    int
    93
    eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k)
    94
    2.07k
    {
    95
    2.07k
            if (cbor_isa_map(item) == false ||
    96
    2.07k
                cbor_map_is_definite(item) == false ||
    97
    2.07k
                cbor_map_iter(item, k, decode_pubkey_point) < 0) {
    98
    155
                    fido_log_debug("%s: cbor type", __func__);
    99
    155
                    return (-1);
    100
    155
            }
    101
    102
    1.91k
            return (0);
    103
    2.07k
    }
    104
    105
    eddsa_pk_t *
    106
    eddsa_pk_new(void)
    107
    6.49k
    {
    108
    6.49k
            return (calloc(1, sizeof(eddsa_pk_t)));
    109
    6.49k
    }
    110
    111
    void
    112
    eddsa_pk_free(eddsa_pk_t **pkp)
    113
    14.3k
    {
    114
    14.3k
            eddsa_pk_t *pk;
    115
    116
    14.3k
            if (pkp == NULL || (pk = *pkp) == NULL)
    117
    7.87k
                    return;
    118
    119
    6.46k
            freezero(pk, sizeof(*pk));
    120
    6.46k
            *pkp = NULL;
    121
    6.46k
    }
    122
    123
    int
    124
    eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
    125
    3.27k
    {
    126
    3.27k
            EVP_PKEY *pkey;
    127
    128
    3.27k
            if (len < sizeof(*pk))
    129
    2.83k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    130
    131
    438
            memcpy(pk, ptr, sizeof(*pk));
    132
    133
    438
            if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
    134
    3
                    fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__);
    135
    3
                    return (FIDO_ERR_INVALID_ARGUMENT);
    136
    3
            }
    137
    138
    435
            EVP_PKEY_free(pkey);
    139
    140
    435
            return (FIDO_OK);
    141
    438
    }
    142
    143
    EVP_PKEY *
    144
    eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k)
    145
    4.31k
    {
    146
    4.31k
            EVP_PKEY *pkey = NULL;
    147
    148
    4.31k
            if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x,
    149
    4.31k
                sizeof(k->x))) == NULL)
    150
    88
                    fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__);
    151
    152
    4.31k
            return (pkey);
    153
    4.31k
    }
    154
    155
    int
    156
    eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
    157
    3.19k
    {
    158
    3.19k
            size_t len = 0;
    159
    160
    3.19k
            if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519)
    161
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    162
    3.19k
            if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
    163
    3.19k
                len != sizeof(pk->x))
    164
    4
                    return (FIDO_ERR_INTERNAL);
    165
    3.18k
            if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 ||
    166
    3.18k
                len != sizeof(pk->x))
    167
    35
                    return (FIDO_ERR_INTERNAL);
    168
    169
    3.15k
            return (FIDO_OK);
    170
    3.18k
    }
    171
    172
    int
    173
    eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
    174
        const fido_blob_t *sig)
    175
    600
    {
    176
    600
            EVP_MD_CTX      *mdctx = NULL;
    177
    600
            int              ok = -1;
    178
    179
    600
            if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) {
    180
    13
                    fido_log_debug("%s: EVP_PKEY_base_id", __func__);
    181
    13
                    goto fail;
    182
    13
            }
    183
    184
            /* EVP_DigestVerify needs ints */
    185
    587
            if (dgst->len > INT_MAX || sig->len > INT_MAX) {
    186
    0
                    fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
    187
    0
                        dgst->len, sig->len);
    188
    0
                    return (-1);
    189
    0
            }
    190
    191
    587
            if ((mdctx = EVP_MD_CTX_new()) == NULL) {
    192
    18
                    fido_log_debug("%s: EVP_MD_CTX_new", __func__);
    193
    18
                    goto fail;
    194
    18
            }
    195
    196
    569
            if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
    197
    14
                    fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
    198
    14
                    goto fail;
    199
    14
            }
    200
    201
    555
            if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
    202
    555
                dgst->len) != 1) {
    203
    555
                    fido_log_debug("%s: EVP_DigestVerify", __func__);
    204
    555
                    goto fail;
    205
    555
            }
    206
    207
    0
            ok = 0;
    208
    600
    fail:
    209
    600
            EVP_MD_CTX_free(mdctx);
    210
    211
    600
            return (ok);
    212
    0
    }
    213
    214
    int
    215
    eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk,
    216
        const fido_blob_t *sig)
    217
    603
    {
    218
    603
            EVP_PKEY        *pkey;
    219
    603
            int              ok = -1;
    220
    221
    603
            if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL ||
    222
    603
                eddsa_verify_sig(dgst, pkey, sig) < 0) {
    223
    603
                    fido_log_debug("%s: eddsa_verify_sig", __func__);
    224
    603
                    goto fail;
    225
    603
            }
    226
    227
    0
            ok = 0;
    228
    603
    fail:
    229
    603
            EVP_PKEY_free(pkey);
    230
    231
    603
            return (ok);
    232
    0
    }