## Coverage Report

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

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

    /libfido2/src/aes256.c

    Line
    Count
    Source
    1
    /*
    2
     * Copyright (c) 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 "fido.h"
    9
    10
    static int
    11
    aes256_cbc(const fido_blob_t *key, const u_char *iv, const fido_blob_t *in,
    12
        fido_blob_t *out, int encrypt)
    13
    35.9k
    {
    14
    35.9k
            EVP_CIPHER_CTX *ctx = NULL;
    15
    35.9k
            const EVP_CIPHER *cipher;
    16
    35.9k
            int ok = -1;
    17
    18
    35.9k
            memset(out, 0, sizeof(*out));
    19
    20
    35.9k
            if (key->len != 32) {
    21
    0
                    fido_log_debug("%s: invalid key len %zu", __func__, key->len);
    22
    0
                    goto fail;
    23
    0
            }
    24
    35.9k
            if (in->len > UINT_MAX || in->len % 16 || in->len == 0) {
    25
    1.01k
                    fido_log_debug("%s: invalid input len %zu", __func__, in->len);
    26
    1.01k
                    goto fail;
    27
    1.01k
            }
    28
    34.9k
            out->len = in->len;
    29
    34.9k
            if ((out->ptr = calloc(1, out->len)) == NULL) {
    30
    63
                    fido_log_debug("%s: calloc", __func__);
    31
    63
                    goto fail;
    32
    63
            }
    33
    34.8k
            if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
    34
    34.8k
                (cipher = EVP_aes_256_cbc()) == NULL) {
    35
    176
                    fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
    36
    176
                    goto fail;
    37
    176
            }
    38
    34.7k
            if (EVP_CipherInit(ctx, cipher, key->ptr, iv, encrypt) == 0 ||
    39
    34.7k
                EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)out->len) < 0) {
    40
    218
                    fido_log_debug("%s: EVP_Cipher", __func__);
    41
    218
                    goto fail;
    42
    218
            }
    43
    44
    34.5k
            ok = 0;
    45
    35.9k
    fail:
    46
    35.9k
            if (ctx != NULL)
    47
    34.8k
                    EVP_CIPHER_CTX_free(ctx);
    48
    35.9k
            if (ok < 0)
    49
    1.47k
                    fido_blob_reset(out);
    50
    51
    35.9k
            return ok;
    52
    34.5k
    }
    53
    54
    static int
    55
    aes256_cbc_proto1(const fido_blob_t *key, const fido_blob_t *in,
    56
        fido_blob_t *out, int encrypt)
    57
    32.3k
    {
    58
    32.3k
            u_char iv[16];
    59
    60
    32.3k
            memset(&iv, 0, sizeof(iv));
    61
    62
    32.3k
            return aes256_cbc(key, iv, in, out, encrypt);
    63
    32.3k
    }
    64
    65
    static int
    66
    aes256_cbc_fips(const fido_blob_t *secret, const fido_blob_t *in,
    67
        fido_blob_t *out, int encrypt)
    68
    4.18k
    {
    69
    4.18k
            fido_blob_t key, cin, cout;
    70
    4.18k
            u_char iv[16];
    71
    72
    4.18k
            memset(out, 0, sizeof(*out));
    73
    74
    4.18k
            if (secret->len != 64) {
    75
    0
                    fido_log_debug("%s: invalid secret len %zu", __func__,
    76
    0
                        secret->len);
    77
    0
                    return -1;
    78
    0
            }
    79
    4.18k
            if (in->len < sizeof(iv)) {
    80
    523
                    fido_log_debug("%s: invalid input len %zu", __func__, in->len);
    81
    523
                    return -1;
    82
    523
            }
    83
    3.66k
            if (encrypt) {
    84
    2.90k
                    if (fido_get_random(iv, sizeof(iv)) < 0) {
    85
    72
                            fido_log_debug("%s: fido_get_random", __func__);
    86
    72
                            return -1;
    87
    72
                    }
    88
    2.83k
                    cin = *in;
    89
    2.83k
            } else {
    90
    761
                    memcpy(iv, in->ptr, sizeof(iv));
    91
    761
                    cin.ptr = in->ptr + sizeof(iv);
    92
    761
                    cin.len = in->len - sizeof(iv);
    93
    761
            }
    94
    3.59k
            key.ptr = secret->ptr + 32;
    95
    3.59k
            key.len = secret->len - 32;
    96
    3.59k
            if (aes256_cbc(&key, iv, &cin, &cout, encrypt) < 0)
    97
    706
                    return -1;
    98
    2.88k
            if (encrypt) {
    99
    2.69k
                    if (cout.len > SIZE_MAX - sizeof(iv) ||
    100
    2.69k
                        (out->ptr = calloc(1, sizeof(iv) + cout.len)) == NULL) {
    101
    50
                            fido_blob_reset(&cout);
    102
    50
                            return -1;
    103
    50
                    }
    104
    2.64k
                    out->len = sizeof(iv) + cout.len;
    105
    2.64k
                    memcpy(out->ptr, iv, sizeof(iv));
    106
    2.64k
                    memcpy(out->ptr + sizeof(iv), cout.ptr, cout.len);
    107
    2.64k
                    fido_blob_reset(&cout);
    108
    2.64k
            } else
    109
    192
                    *out = cout;
    110
    111
    2.83k
            return 0;
    112
    2.88k
    }
    113
    114
    static int
    115
    aes256_gcm(const fido_blob_t *key, const fido_blob_t *nonce,
    116
        const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out,
    117
        int encrypt)
    118
    13.8k
    {
    119
    13.8k
            EVP_CIPHER_CTX *ctx = NULL;
    120
    13.8k
            const EVP_CIPHER *cipher;
    121
    13.8k
            size_t textlen;
    122
    13.8k
            int ok = -1;
    123
    124
    13.8k
            memset(out, 0, sizeof(*out));
    125
    126
    13.8k
            if (nonce->len != 12 || key->len != 32 || aad->len > UINT_MAX) {
    127
    0
                    fido_log_debug("%s: invalid params %zu, %zu, %zu", __func__,
    128
    0
                        nonce->len, key->len, aad->len);
    129
    0
                    goto fail;
    130
    0
            }
    131
    13.8k
            if (in->len > UINT_MAX || in->len > SIZE_MAX - 16) {
    132
    0
                    fido_log_debug("%s: invalid input len %zu", __func__, in->len);
    133
    0
                    goto fail;
    134
    0
            }
    135
    13.8k
            if (!encrypt && in->len < 16) {
    136
    0
                    fido_log_debug("%s: invalid input len %zu", __func__, in->len);
    137
    0
                    goto fail;
    138
    0
            }
    139
            /* add tag to (on encrypt) or trim tag from the output (on decrypt) */
    140
    13.8k
            out->len = encrypt ? in->len + 16 : in->len - 16;
    141
    13.8k
            if ((out->ptr = calloc(1, out->len)) == NULL) {
    142
    62
                    fido_log_debug("%s: calloc", __func__);
    143
    62
                    goto fail;
    144
    62
            }
    145
    13.7k
            if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
    146
    13.7k
                (cipher = EVP_aes_256_gcm()) == NULL) {
    147
    106
                    fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
    148
    106
                    goto fail;
    149
    106
            }
    150
    13.6k
            if (EVP_CipherInit(ctx, cipher, key->ptr, nonce->ptr, encrypt) == 0) {
    151
    49
                    fido_log_debug("%s: EVP_CipherInit", __func__);
    152
    49
                    goto fail;
    153
    49
            }
    154
    155
    13.6k
            if (encrypt)
    156
    10.6k
                    textlen = in->len;
    157
    2.98k
            else {
    158
    2.98k
                    textlen = in->len - 16;
    159
                    /* point openssl at the mac tag */
    160
    2.98k
                    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16,
    161
    2.98k
                        in->ptr + in->len - 16) == 0) {
    162
    27
                            fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
    163
    27
                            goto fail;
    164
    27
                    }
    165
    2.98k
            }
    166
            /* the last EVP_Cipher() will either compute or verify the mac tag */
    167
    13.6k
            if (EVP_Cipher(ctx, NULL, aad->ptr, (u_int)aad->len) < 0 ||
    168
    13.6k
                EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)textlen) < 0 ||
    169
    13.6k
                EVP_Cipher(ctx, NULL, NULL, 0) < 0) {
    170
    1.36k
                    fido_log_debug("%s: EVP_Cipher", __func__);
    171
    1.36k
                    goto fail;
    172
    1.36k
            }
    173
    12.2k
            if (encrypt) {
    174
                    /* append the mac tag */
    175
    10.5k
                    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16,
    176
    10.5k
                        out->ptr + out->len - 16) == 0) {
    177
    23
                            fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
    178
    23
                            goto fail;
    179
    23
                    }
    180
    10.5k
            }
    181
    182
    12.2k
            ok = 0;
    183
    13.8k
    fail:
    184
    13.8k
            if (ctx != NULL)
    185
    13.7k
                    EVP_CIPHER_CTX_free(ctx);
    186
    13.8k
            if (ok < 0)
    187
    1.63k
                    fido_blob_reset(out);
    188
    189
    13.8k
            return ok;
    190
    12.2k
    }
    191
    192
    int
    193
    aes256_cbc_enc(const fido_dev_t *dev, const fido_blob_t *secret,
    194
        const fido_blob_t *in, fido_blob_t *out)
    195
    20.8k
    {
    196
    20.8k
            return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
    197
    17.9k
                in, out, 1) : aes256_cbc_proto1(secret, in, out, 1);
    198
    20.8k
    }
    199
    200
    int
    201
    aes256_cbc_dec(const fido_dev_t *dev, const fido_blob_t *secret,
    202
        const fido_blob_t *in, fido_blob_t *out)
    203
    15.6k
    {
    204
    15.6k
            return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
    205
    14.4k
                in, out, 0) : aes256_cbc_proto1(secret, in, out, 0);
    206
    15.6k
    }
    207
    208
    int
    209
    aes256_gcm_enc(const fido_blob_t *key, const fido_blob_t *nonce,
    210
        const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
    211
    10.7k
    {
    212
    10.7k
            return aes256_gcm(key, nonce, aad, in, out, 1);
    213
    10.7k
    }
    214
    215
    int
    216
    aes256_gcm_dec(const fido_blob_t *key, const fido_blob_t *nonce,
    217
        const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
    218
    3.08k
    {
    219
    3.08k
            return aes256_gcm(key, nonce, aad, in, out, 0);
    220
    3.08k
    }