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