Coverage Report

Created: 2021-07-20 18:14

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