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
}