## Coverage Report

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

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

    /libfido2/src/rs256.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
    3
     * Use of this source code is governed by a BSD-style
    4
     * license that can be found in the LICENSE file.
    5
     * SPDX-License-Identifier: BSD-2-Clause
    6
     */
    7
    8
    #include <openssl/bn.h>
    9
    #include <openssl/rsa.h>
    10
    #include <openssl/obj_mac.h>
    11
    12
    #include "fido.h"
    13
    #include "fido/rs256.h"
    14
    15
    #if OPENSSL_VERSION_NUMBER >= 0x30000000
    16
    288
    #define get0_RSA(x)     EVP_PKEY_get0_RSA((x))
    17
    #else
    18
    #define get0_RSA(x)     EVP_PKEY_get0((x))
    19
    #endif
    20
    21
    #if defined(__GNUC__)
    22
    #define PRAGMA(s) _Pragma(s)
    23
    #else
    24
    #define PRAGMA(s)
    25
    #endif
    26
    27
    static EVP_MD *
    28
    rs256_get_EVP_MD(void)
    29
    177
    {
    30
    177
    PRAGMA("GCC diagnostic push")
    31
    177
    PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
    32
    177
            return ((EVP_MD *)EVP_sha256());
    33
    177
    PRAGMA("GCC diagnostic pop")
    34
    177
    }
    35
    36
    static int
    37
    decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
    38
    692
    {
    39
    692
            if (cbor_isa_bytestring(item) == false ||
    40
    692
                cbor_bytestring_is_definite(item) == false ||
    41
    692
                cbor_bytestring_length(item) != len) {
    42
    36
                    fido_log_debug("%s: cbor type", __func__);
    43
    36
                    return (-1);
    44
    36
            }
    45
    46
    656
            memcpy(ptr, cbor_bytestring_handle(item), len);
    47
    48
    656
            return (0);
    49
    692
    }
    50
    51
    static int
    52
    decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
    53
    2.11k
    {
    54
    2.11k
            rs256_pk_t *k = arg;
    55
    56
    2.11k
            if (cbor_isa_negint(key) == false ||
    57
    2.11k
                cbor_int_get_width(key) != CBOR_INT_8)
    58
    1.29k
                    return (0); /* ignore */
    59
    60
    819
            switch (cbor_get_uint8(key)) {
    61
    360
            case 0: /* modulus */
    62
    360
                    return (decode_bignum(val, &k->n, sizeof(k->n)));
    63
    332
            case 1: /* public exponent */
    64
    332
                    return (decode_bignum(val, &k->e, sizeof(k->e)));
    65
    819
            }
    66
    67
    127
            return (0); /* ignore */
    68
    819
    }
    69
    70
    int
    71
    rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
    72
    560
    {
    73
    560
            if (cbor_isa_map(item) == false ||
    74
    560
                cbor_map_is_definite(item) == false ||
    75
    560
                cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
    76
    56
                    fido_log_debug("%s: cbor type", __func__);
    77
    56
                    return (-1);
    78
    56
            }
    79
    80
    504
            return (0);
    81
    560
    }
    82
    83
    rs256_pk_t *
    84
    rs256_pk_new(void)
    85
    3.09k
    {
    86
    3.09k
            return (calloc(1, sizeof(rs256_pk_t)));
    87
    3.09k
    }
    88
    89
    void
    90
    rs256_pk_free(rs256_pk_t **pkp)
    91
    13.9k
    {
    92
    13.9k
            rs256_pk_t *pk;
    93
    94
    13.9k
            if (pkp == NULL || (pk = *pkp) == NULL)
    95
    10.8k
                    return;
    96
    97
    3.07k
            freezero(pk, sizeof(*pk));
    98
    3.07k
            *pkp = NULL;
    99
    3.07k
    }
    100
    101
    int
    102
    rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
    103
    2.78k
    {
    104
    2.78k
            EVP_PKEY *pkey;
    105
    106
    2.78k
            if (len < sizeof(*pk))
    107
    2.24k
                    return (FIDO_ERR_INVALID_ARGUMENT);
    108
    109
    541
            memcpy(pk, ptr, sizeof(*pk));
    110
    111
    541
            if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
    112
    246
                    fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
    113
    246
                    return (FIDO_ERR_INVALID_ARGUMENT);
    114
    246
            }
    115
    116
    295
            EVP_PKEY_free(pkey);
    117
    118
    295
            return (FIDO_OK);
    119
    541
    }
    120
    121
    EVP_PKEY *
    122
    rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
    123
    3.65k
    {
    124
    3.65k
            RSA             *rsa = NULL;
    125
    3.65k
            EVP_PKEY        *pkey = NULL;
    126
    3.65k
            BIGNUM          *n = NULL;
    127
    3.65k
            BIGNUM          *e = NULL;
    128
    3.65k
            int              ok = -1;
    129
    130
    3.65k
            if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
    131
    82
                    goto fail;
    132
    133
    3.57k
            if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
    134
    3.57k
                BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
    135
    147
                    fido_log_debug("%s: BN_bin2bn", __func__);
    136
    147
                    goto fail;
    137
    147
            }
    138
    139
    3.42k
            if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
    140
    78
                    fido_log_debug("%s: RSA_set0_key", __func__);
    141
    78
                    goto fail;
    142
    78
            }
    143
    144
            /* at this point, n and e belong to rsa */
    145
    3.35k
            n = NULL;
    146
    3.35k
            e = NULL;
    147
    148
    3.35k
            if (RSA_bits(rsa) != 2048) {
    149
    2.55k
                    fido_log_debug("%s: invalid key length", __func__);
    150
    2.55k
                    goto fail;
    151
    2.55k
            }
    152
    153
    799
            if ((pkey = EVP_PKEY_new()) == NULL ||
    154
    799
                EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
    155
    35
                    fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
    156
    35
                    goto fail;
    157
    35
            }
    158
    159
    764
            rsa = NULL; /* at this point, rsa belongs to evp */
    160
    161
    764
            ok = 0;
    162
    3.65k
    fail:
    163
    3.65k
            if (n != NULL)
    164
    277
                    BN_free(n);
    165
    3.65k
            if (e != NULL)
    166
    225
                    BN_free(e);
    167
    3.65k
            if (rsa != NULL)
    168
    2.63k
                    RSA_free(rsa);
    169
    3.65k
            if (ok < 0 && pkey != NULL) {
    170
    21
                    EVP_PKEY_free(pkey);
    171
    21
                    pkey = NULL;
    172
    21
            }
    173
    174
    3.65k
            return (pkey);
    175
    764
    }
    176
    177
    int
    178
    rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
    179
    283
    {
    180
    283
            const BIGNUM    *n = NULL;
    181
    283
            const BIGNUM    *e = NULL;
    182
    283
            const BIGNUM    *d = NULL;
    183
    283
            int              k;
    184
    185
    283
            if (RSA_bits(rsa) != 2048) {
    186
    0
                    fido_log_debug("%s: invalid key length", __func__);
    187
    0
                    return (FIDO_ERR_INVALID_ARGUMENT);
    188
    0
            }
    189
    190
    283
            RSA_get0_key(rsa, &n, &e, &d);
    191
    192
    283
            if (n == NULL || e == NULL) {
    193
    0
                    fido_log_debug("%s: RSA_get0_key", __func__);
    194
    0
                    return (FIDO_ERR_INTERNAL);
    195
    0
            }
    196
    197
    283
            if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
    198
    283
                (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
    199
    0
                    fido_log_debug("%s: invalid key", __func__);
    200
    0
                    return (FIDO_ERR_INTERNAL);
    201
    0
            }
    202
    203
    283
            if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
    204
    283
                (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
    205
    10
                    fido_log_debug("%s: BN_bn2bin", __func__);
    206
    10
                    return (FIDO_ERR_INTERNAL);
    207
    10
            }
    208
    209
    273
            return (FIDO_OK);
    210
    283
    }
    211
    212
    int
    213
    rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
    214
    288
    {
    215
    288
            const RSA *rsa;
    216
    217
    288
            if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
    218
    288
                (rsa = get0_RSA(pkey)) == NULL)
    219
    5
                    return (FIDO_ERR_INVALID_ARGUMENT);
    220
    221
    283
            return (rs256_pk_from_RSA(pk, rsa));
    222
    288
    }
    223
    224
    int
    225
    rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
    226
        const fido_blob_t *sig)
    227
    181
    {
    228
    181
            EVP_PKEY_CTX    *pctx = NULL;
    229
    181
            EVP_MD          *md = NULL;
    230
    181
            int              ok = -1;
    231
    232
    181
            if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
    233
    4
                    fido_log_debug("%s: EVP_PKEY_base_id", __func__);
    234
    4
                    goto fail;
    235
    4
            }
    236
    237
    177
            if ((md = rs256_get_EVP_MD()) == NULL) {
    238
    6
                    fido_log_debug("%s: rs256_get_EVP_MD", __func__);
    239
    6
                    goto fail;
    240
    6
            }
    241
    242
    171
            if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
    243
    171
                EVP_PKEY_verify_init(pctx) != 1 ||
    244
    171
                EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
    245
    171
                EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
    246
    25
                    fido_log_debug("%s: EVP_PKEY_CTX", __func__);
    247
    25
                    goto fail;
    248
    25
            }
    249
    250
    146
            if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
    251
    146
                dgst->len) != 1) {
    252
    146
                    fido_log_debug("%s: EVP_PKEY_verify", __func__);
    253
    146
                    goto fail;
    254
    146
            }
    255
    256
    0
            ok = 0;
    257
    181
    fail:
    258
    181
            EVP_PKEY_CTX_free(pctx);
    259
    260
    181
            return (ok);
    261
    0
    }
    262
    263
    int
    264
    rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
    265
        const fido_blob_t *sig)
    266
    327
    {
    267
    327
            EVP_PKEY        *pkey;
    268
    327
            int              ok = -1;
    269
    270
    327
            if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
    271
    327
                rs256_verify_sig(dgst, pkey, sig) < 0) {
    272
    327
                    fido_log_debug("%s: rs256_verify_sig", __func__);
    273
    327
                    goto fail;
    274
    327
            }
    275
    276
    0
            ok = 0;
    277
    327
    fail:
    278
    327
            EVP_PKEY_free(pkey);
    279
    280
    327
            return (ok);
    281
    0
    }