| 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 | } |