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