10afa8e06SEd Maste /*
20afa8e06SEd Maste * Copyright (c) 2021 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include "fido.h"
90afa8e06SEd Maste
100afa8e06SEd Maste static int
aes256_cbc(const fido_blob_t * key,const u_char * iv,const fido_blob_t * in,fido_blob_t * out,int encrypt)110afa8e06SEd Maste aes256_cbc(const fido_blob_t *key, const u_char *iv, const fido_blob_t *in,
120afa8e06SEd Maste fido_blob_t *out, int encrypt)
130afa8e06SEd Maste {
140afa8e06SEd Maste EVP_CIPHER_CTX *ctx = NULL;
150afa8e06SEd Maste const EVP_CIPHER *cipher;
160afa8e06SEd Maste int ok = -1;
170afa8e06SEd Maste
180afa8e06SEd Maste memset(out, 0, sizeof(*out));
190afa8e06SEd Maste
200afa8e06SEd Maste if (key->len != 32) {
210afa8e06SEd Maste fido_log_debug("%s: invalid key len %zu", __func__, key->len);
220afa8e06SEd Maste goto fail;
230afa8e06SEd Maste }
240afa8e06SEd Maste if (in->len > UINT_MAX || in->len % 16 || in->len == 0) {
250afa8e06SEd Maste fido_log_debug("%s: invalid input len %zu", __func__, in->len);
260afa8e06SEd Maste goto fail;
270afa8e06SEd Maste }
280afa8e06SEd Maste out->len = in->len;
290afa8e06SEd Maste if ((out->ptr = calloc(1, out->len)) == NULL) {
300afa8e06SEd Maste fido_log_debug("%s: calloc", __func__);
310afa8e06SEd Maste goto fail;
320afa8e06SEd Maste }
330afa8e06SEd Maste if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
340afa8e06SEd Maste (cipher = EVP_aes_256_cbc()) == NULL) {
350afa8e06SEd Maste fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
360afa8e06SEd Maste goto fail;
370afa8e06SEd Maste }
380afa8e06SEd Maste if (EVP_CipherInit(ctx, cipher, key->ptr, iv, encrypt) == 0 ||
390afa8e06SEd Maste EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)out->len) < 0) {
400afa8e06SEd Maste fido_log_debug("%s: EVP_Cipher", __func__);
410afa8e06SEd Maste goto fail;
420afa8e06SEd Maste }
430afa8e06SEd Maste
440afa8e06SEd Maste ok = 0;
450afa8e06SEd Maste fail:
460afa8e06SEd Maste if (ctx != NULL)
470afa8e06SEd Maste EVP_CIPHER_CTX_free(ctx);
480afa8e06SEd Maste if (ok < 0)
490afa8e06SEd Maste fido_blob_reset(out);
500afa8e06SEd Maste
510afa8e06SEd Maste return ok;
520afa8e06SEd Maste }
530afa8e06SEd Maste
540afa8e06SEd Maste static int
aes256_cbc_proto1(const fido_blob_t * key,const fido_blob_t * in,fido_blob_t * out,int encrypt)550afa8e06SEd Maste aes256_cbc_proto1(const fido_blob_t *key, const fido_blob_t *in,
560afa8e06SEd Maste fido_blob_t *out, int encrypt)
570afa8e06SEd Maste {
580afa8e06SEd Maste u_char iv[16];
590afa8e06SEd Maste
600afa8e06SEd Maste memset(&iv, 0, sizeof(iv));
610afa8e06SEd Maste
620afa8e06SEd Maste return aes256_cbc(key, iv, in, out, encrypt);
630afa8e06SEd Maste }
640afa8e06SEd Maste
650afa8e06SEd Maste static int
aes256_cbc_fips(const fido_blob_t * secret,const fido_blob_t * in,fido_blob_t * out,int encrypt)660afa8e06SEd Maste aes256_cbc_fips(const fido_blob_t *secret, const fido_blob_t *in,
670afa8e06SEd Maste fido_blob_t *out, int encrypt)
680afa8e06SEd Maste {
690afa8e06SEd Maste fido_blob_t key, cin, cout;
700afa8e06SEd Maste u_char iv[16];
710afa8e06SEd Maste
720afa8e06SEd Maste memset(out, 0, sizeof(*out));
730afa8e06SEd Maste
740afa8e06SEd Maste if (secret->len != 64) {
750afa8e06SEd Maste fido_log_debug("%s: invalid secret len %zu", __func__,
760afa8e06SEd Maste secret->len);
770afa8e06SEd Maste return -1;
780afa8e06SEd Maste }
790afa8e06SEd Maste if (in->len < sizeof(iv)) {
800afa8e06SEd Maste fido_log_debug("%s: invalid input len %zu", __func__, in->len);
810afa8e06SEd Maste return -1;
820afa8e06SEd Maste }
830afa8e06SEd Maste if (encrypt) {
840afa8e06SEd Maste if (fido_get_random(iv, sizeof(iv)) < 0) {
850afa8e06SEd Maste fido_log_debug("%s: fido_get_random", __func__);
860afa8e06SEd Maste return -1;
870afa8e06SEd Maste }
880afa8e06SEd Maste cin = *in;
890afa8e06SEd Maste } else {
900afa8e06SEd Maste memcpy(iv, in->ptr, sizeof(iv));
910afa8e06SEd Maste cin.ptr = in->ptr + sizeof(iv);
920afa8e06SEd Maste cin.len = in->len - sizeof(iv);
930afa8e06SEd Maste }
940afa8e06SEd Maste key.ptr = secret->ptr + 32;
950afa8e06SEd Maste key.len = secret->len - 32;
960afa8e06SEd Maste if (aes256_cbc(&key, iv, &cin, &cout, encrypt) < 0)
970afa8e06SEd Maste return -1;
980afa8e06SEd Maste if (encrypt) {
990afa8e06SEd Maste if (cout.len > SIZE_MAX - sizeof(iv) ||
1000afa8e06SEd Maste (out->ptr = calloc(1, sizeof(iv) + cout.len)) == NULL) {
1010afa8e06SEd Maste fido_blob_reset(&cout);
1020afa8e06SEd Maste return -1;
1030afa8e06SEd Maste }
1040afa8e06SEd Maste out->len = sizeof(iv) + cout.len;
1050afa8e06SEd Maste memcpy(out->ptr, iv, sizeof(iv));
1060afa8e06SEd Maste memcpy(out->ptr + sizeof(iv), cout.ptr, cout.len);
1070afa8e06SEd Maste fido_blob_reset(&cout);
1080afa8e06SEd Maste } else
1090afa8e06SEd Maste *out = cout;
1100afa8e06SEd Maste
1110afa8e06SEd Maste return 0;
1120afa8e06SEd Maste }
1130afa8e06SEd Maste
1140afa8e06SEd Maste static int
aes256_gcm(const fido_blob_t * key,const fido_blob_t * nonce,const fido_blob_t * aad,const fido_blob_t * in,fido_blob_t * out,int encrypt)1150afa8e06SEd Maste aes256_gcm(const fido_blob_t *key, const fido_blob_t *nonce,
1160afa8e06SEd Maste const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out,
1170afa8e06SEd Maste int encrypt)
1180afa8e06SEd Maste {
1190afa8e06SEd Maste EVP_CIPHER_CTX *ctx = NULL;
1200afa8e06SEd Maste const EVP_CIPHER *cipher;
1210afa8e06SEd Maste size_t textlen;
1220afa8e06SEd Maste int ok = -1;
1230afa8e06SEd Maste
1240afa8e06SEd Maste memset(out, 0, sizeof(*out));
1250afa8e06SEd Maste
1260afa8e06SEd Maste if (nonce->len != 12 || key->len != 32 || aad->len > UINT_MAX) {
1270afa8e06SEd Maste fido_log_debug("%s: invalid params %zu, %zu, %zu", __func__,
1280afa8e06SEd Maste nonce->len, key->len, aad->len);
1290afa8e06SEd Maste goto fail;
1300afa8e06SEd Maste }
1310afa8e06SEd Maste if (in->len > UINT_MAX || in->len > SIZE_MAX - 16 || in->len < 16) {
1320afa8e06SEd Maste fido_log_debug("%s: invalid input len %zu", __func__, in->len);
1330afa8e06SEd Maste goto fail;
1340afa8e06SEd Maste }
1350afa8e06SEd Maste /* add tag to (on encrypt) or trim tag from the output (on decrypt) */
1360afa8e06SEd Maste out->len = encrypt ? in->len + 16 : in->len - 16;
1370afa8e06SEd Maste if ((out->ptr = calloc(1, out->len)) == NULL) {
1380afa8e06SEd Maste fido_log_debug("%s: calloc", __func__);
1390afa8e06SEd Maste goto fail;
1400afa8e06SEd Maste }
1410afa8e06SEd Maste if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
1420afa8e06SEd Maste (cipher = EVP_aes_256_gcm()) == NULL) {
1430afa8e06SEd Maste fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
1440afa8e06SEd Maste goto fail;
1450afa8e06SEd Maste }
1460afa8e06SEd Maste if (EVP_CipherInit(ctx, cipher, key->ptr, nonce->ptr, encrypt) == 0) {
1470afa8e06SEd Maste fido_log_debug("%s: EVP_CipherInit", __func__);
1480afa8e06SEd Maste goto fail;
1490afa8e06SEd Maste }
1500afa8e06SEd Maste
1510afa8e06SEd Maste if (encrypt)
1520afa8e06SEd Maste textlen = in->len;
1530afa8e06SEd Maste else {
1540afa8e06SEd Maste textlen = in->len - 16;
1550afa8e06SEd Maste /* point openssl at the mac tag */
1560afa8e06SEd Maste if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16,
1570afa8e06SEd Maste in->ptr + in->len - 16) == 0) {
1580afa8e06SEd Maste fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
1590afa8e06SEd Maste goto fail;
1600afa8e06SEd Maste }
1610afa8e06SEd Maste }
1620afa8e06SEd Maste /* the last EVP_Cipher() will either compute or verify the mac tag */
1630afa8e06SEd Maste if (EVP_Cipher(ctx, NULL, aad->ptr, (u_int)aad->len) < 0 ||
1640afa8e06SEd Maste EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)textlen) < 0 ||
1650afa8e06SEd Maste EVP_Cipher(ctx, NULL, NULL, 0) < 0) {
1660afa8e06SEd Maste fido_log_debug("%s: EVP_Cipher", __func__);
1670afa8e06SEd Maste goto fail;
1680afa8e06SEd Maste }
1690afa8e06SEd Maste if (encrypt) {
1700afa8e06SEd Maste /* append the mac tag */
1710afa8e06SEd Maste if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16,
1720afa8e06SEd Maste out->ptr + out->len - 16) == 0) {
1730afa8e06SEd Maste fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
1740afa8e06SEd Maste goto fail;
1750afa8e06SEd Maste }
1760afa8e06SEd Maste }
1770afa8e06SEd Maste
1780afa8e06SEd Maste ok = 0;
1790afa8e06SEd Maste fail:
1800afa8e06SEd Maste if (ctx != NULL)
1810afa8e06SEd Maste EVP_CIPHER_CTX_free(ctx);
1820afa8e06SEd Maste if (ok < 0)
1830afa8e06SEd Maste fido_blob_reset(out);
1840afa8e06SEd Maste
1850afa8e06SEd Maste return ok;
1860afa8e06SEd Maste }
1870afa8e06SEd Maste
1880afa8e06SEd Maste int
aes256_cbc_enc(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * in,fido_blob_t * out)1890afa8e06SEd Maste aes256_cbc_enc(const fido_dev_t *dev, const fido_blob_t *secret,
1900afa8e06SEd Maste const fido_blob_t *in, fido_blob_t *out)
1910afa8e06SEd Maste {
1920afa8e06SEd Maste return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
1930afa8e06SEd Maste in, out, 1) : aes256_cbc_proto1(secret, in, out, 1);
1940afa8e06SEd Maste }
1950afa8e06SEd Maste
1960afa8e06SEd Maste int
aes256_cbc_dec(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * in,fido_blob_t * out)1970afa8e06SEd Maste aes256_cbc_dec(const fido_dev_t *dev, const fido_blob_t *secret,
1980afa8e06SEd Maste const fido_blob_t *in, fido_blob_t *out)
1990afa8e06SEd Maste {
2000afa8e06SEd Maste return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
2010afa8e06SEd Maste in, out, 0) : aes256_cbc_proto1(secret, in, out, 0);
2020afa8e06SEd Maste }
2030afa8e06SEd Maste
2040afa8e06SEd Maste int
aes256_gcm_enc(const fido_blob_t * key,const fido_blob_t * nonce,const fido_blob_t * aad,const fido_blob_t * in,fido_blob_t * out)2050afa8e06SEd Maste aes256_gcm_enc(const fido_blob_t *key, const fido_blob_t *nonce,
2060afa8e06SEd Maste const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
2070afa8e06SEd Maste {
2080afa8e06SEd Maste return aes256_gcm(key, nonce, aad, in, out, 1);
2090afa8e06SEd Maste }
2100afa8e06SEd Maste
2110afa8e06SEd Maste int
aes256_gcm_dec(const fido_blob_t * key,const fido_blob_t * nonce,const fido_blob_t * aad,const fido_blob_t * in,fido_blob_t * out)2120afa8e06SEd Maste aes256_gcm_dec(const fido_blob_t *key, const fido_blob_t *nonce,
2130afa8e06SEd Maste const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
2140afa8e06SEd Maste {
2150afa8e06SEd Maste return aes256_gcm(key, nonce, aad, in, out, 0);
2160afa8e06SEd Maste }
217