diff options
author | Daiki Ueno <ueno@gnu.org> | 2021-04-20 15:15:52 +0000 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2021-04-20 15:15:52 +0000 |
commit | 6805b30455680d5cf212030aa59c76bcdfa6b225 (patch) | |
tree | a6430df5309c777ad545871dc78af2800f5971eb | |
parent | 0610ae666df2b359cd80a1fe7813a264b22ce7bb (diff) | |
parent | 733bba1c47c545e5a2a40436ac839961e929e364 (diff) | |
download | gnutls-6805b30455680d5cf212030aa59c76bcdfa6b225.tar.gz |
Merge branch 'af_alg' into 'master'
Add Linux kernel AF_ALG backend
See merge request gnutls/gnutls!1404
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | lib/accelerated/Makefile.am | 8 | ||||
-rw-r--r-- | lib/accelerated/afalg.c | 855 | ||||
-rw-r--r-- | lib/accelerated/afalg.h | 2 | ||||
-rw-r--r-- | lib/cipher_int.c | 9 | ||||
-rw-r--r-- | lib/global.c | 2 | ||||
-rw-r--r-- | m4/hooks.m4 | 12 | ||||
-rw-r--r-- | src/benchmark-cipher.c | 2 |
8 files changed, 887 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 126f95ee2e..a6f1c1c845 100644 --- a/configure.ac +++ b/configure.ac @@ -1208,6 +1208,7 @@ AC_MSG_NOTICE([summary of build options: AC_MSG_NOTICE([External hardware support: /dev/crypto: $enable_cryptodev + AF_ALG support: $enable_afalg Hardware accel: $hw_accel Padlock accel: $use_padlock Random gen. variant: $rnd_variant diff --git a/lib/accelerated/Makefile.am b/lib/accelerated/Makefile.am index d44920def4..69d05960e9 100644 --- a/lib/accelerated/Makefile.am +++ b/lib/accelerated/Makefile.am @@ -35,8 +35,8 @@ endif noinst_LTLIBRARIES = libaccelerated.la -EXTRA_DIST = accelerated.h cryptodev.h -libaccelerated_la_SOURCES = accelerated.c cryptodev.c cryptodev-gcm.c +EXTRA_DIST = accelerated.h cryptodev.h afalg.h +libaccelerated_la_SOURCES = accelerated.c cryptodev.c cryptodev-gcm.c afalg.c libaccelerated_la_LIBADD = if ENABLE_NETTLE @@ -60,3 +60,7 @@ endif if ASM_X86_64 AM_CFLAGS += -DASM_X86_64 endif + +if ENABLE_AFALG +libaccelerated_la_LDFLAGS = -lkcapi +endif diff --git a/lib/accelerated/afalg.c b/lib/accelerated/afalg.c new file mode 100644 index 0000000000..fe72f8f344 --- /dev/null +++ b/lib/accelerated/afalg.c @@ -0,0 +1,855 @@ +/* + * Copyright (C) 2017 Stephan Mueller <smueller@chronox.de> + * + * Author: Stephan Mueller + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "errors.h" +#include "gnutls_int.h" +#include <gnutls/crypto.h> +#include "errors.h" +#include <accelerated/afalg.h> +#include "malloca.h" + +#include <sys/uio.h> + +#ifdef ENABLE_AFALG + +#include <kcapi.h> +#include <limits.h> + +/************************ Symmetric cipher algorithms ************************/ + +struct kcapi_ctx { + struct kcapi_handle *handle; + int enc; + uint8_t iv[MAX_CIPHER_IV_SIZE]; +}; + + +static const char *gnutls_cipher_map[] = { + [GNUTLS_CIPHER_AES_128_CBC] = "cbc(aes)", + [GNUTLS_CIPHER_AES_192_CBC] = "cbc(aes)", + [GNUTLS_CIPHER_AES_256_CBC] = "cbc(aes)", + [GNUTLS_CIPHER_3DES_CBC] = "cbc(des3_ede)", + [GNUTLS_CIPHER_CAMELLIA_128_CBC] = "cbc(camellia)", + [GNUTLS_CIPHER_CAMELLIA_192_CBC] = "cbc(camellia)", + [GNUTLS_CIPHER_CAMELLIA_256_CBC] = "cbc(camellia)", + [GNUTLS_CIPHER_SALSA20_256] = "salsa20", +}; + +static int +afalg_cipher_init(gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc) +{ + struct kcapi_handle *handle = NULL; + struct kcapi_ctx *ctx; + + if (kcapi_cipher_init(&handle, gnutls_cipher_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx = (struct kcapi_ctx *)gnutls_calloc(1, sizeof(struct kcapi_ctx) + + kcapi_cipher_ivsize(handle)); + if (ctx == NULL) { + gnutls_assert(); + kcapi_cipher_destroy(handle); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx->handle = handle; + ctx->enc = enc; + *_ctx = ctx; + return 0; +} + +static int afalg_cipher_setkey(void *_ctx, const void *key, size_t keysize) +{ + struct kcapi_ctx *ctx = _ctx; + + if (kcapi_cipher_setkey(ctx->handle, key, keysize) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + +static int afalg_cipher_setiv(void *_ctx, const void *iv, size_t iv_size) +{ + struct kcapi_ctx *ctx = _ctx; + + if (iv_size > kcapi_cipher_ivsize(ctx->handle)) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + memcpy(ctx->iv, iv, iv_size); + if (ctx->enc) { + if (kcapi_cipher_stream_init_enc(ctx->handle, ctx->iv, NULL, 0) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + } else { + if (kcapi_cipher_stream_init_dec(ctx->handle, ctx->iv, NULL, 0) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + } + + return 0; +} + +static int afalg_cipher_encrypt(void *_ctx, const void *src, size_t src_size, + void *dst, size_t dst_size) +{ + struct kcapi_ctx *ctx = _ctx; + struct iovec iov; + + iov.iov_base = (void *)src; + iov.iov_len = src_size; + + if (unlikely(src_size % kcapi_cipher_blocksize(ctx->handle))) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + if (kcapi_cipher_stream_update(ctx->handle, &iov, 1) < 0) { + return gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + } + + iov.iov_base = (void *)dst; + iov.iov_len = (src_size > dst_size) ? dst_size : src_size; + + if (kcapi_cipher_stream_op(ctx->handle, &iov, 1) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + +static int afalg_cipher_decrypt(void *_ctx, const void *src, size_t src_size, + void *dst, size_t dst_size) +{ + struct kcapi_ctx *ctx = _ctx; + struct iovec iov; + + iov.iov_base = (void *)src; + iov.iov_len = src_size; + + if (unlikely(src_size % kcapi_cipher_blocksize(ctx->handle))) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + if (kcapi_cipher_stream_update(ctx->handle, &iov, 1) < 0) { + return gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + } + + iov.iov_base = (void *)dst; + iov.iov_len = (src_size > dst_size) ? dst_size : src_size; + + if (kcapi_cipher_stream_op(ctx->handle, &iov, 1) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + +static void afalg_cipher_deinit(void *_ctx) +{ + struct kcapi_ctx *ctx = _ctx; + + kcapi_cipher_destroy(ctx->handle); + gnutls_free(ctx); +} + +static const gnutls_crypto_cipher_st afalg_cipher_struct = { + .init = afalg_cipher_init, + .setkey = afalg_cipher_setkey, + .setiv = afalg_cipher_setiv, + .encrypt = afalg_cipher_encrypt, + .decrypt = afalg_cipher_decrypt, + .deinit = afalg_cipher_deinit, +}; + +static int afalg_cipher_register(void) +{ + unsigned int i; + int ret = 0; + + for (i = 0; + i < sizeof(gnutls_cipher_map) / sizeof(gnutls_cipher_map[0]); + i++) { + struct kcapi_handle *handle = NULL; + + if (gnutls_cipher_map[i] == 0) + continue; + + /* Check whether cipher is available. */ + if (kcapi_cipher_init(&handle, gnutls_cipher_map[i], 0)) + continue; + + kcapi_cipher_destroy(handle); + + _gnutls_debug_log("afalg: registering: %s\n", + gnutls_cipher_get_name(i)); + ret = gnutls_crypto_single_cipher_register(i, 90, + &afalg_cipher_struct, + 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + + return ret; +} + +/************************ Symmetric cipher algorithms ************************/ + +struct kcapi_aead_ctx { + struct kcapi_handle *handle; + int taglen_set; + int ccm; +}; + +static const char *gnutls_aead_map[] = { + [GNUTLS_CIPHER_CAMELLIA_128_GCM] = "gcm(camellia)", + [GNUTLS_CIPHER_CAMELLIA_256_GCM] = "gcm(camellia)", + [GNUTLS_CIPHER_AES_128_CCM] = "ccm(aes)", + [GNUTLS_CIPHER_AES_256_CCM] = "ccm(aes)", + [GNUTLS_CIPHER_AES_128_GCM] = "gcm(aes)", + [GNUTLS_CIPHER_AES_256_GCM] = "gcm(aes)", +}; + +static void afalg_aead_deinit(void *_ctx) +{ + struct kcapi_aead_ctx *ctx = _ctx; + + kcapi_aead_destroy(ctx->handle); + gnutls_free(ctx); +} + +static int +afalg_aead_init(gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc) +{ + struct kcapi_handle *handle = NULL; + struct kcapi_aead_ctx *ctx; + + if (kcapi_aead_init(&handle, gnutls_aead_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + ctx = (struct kcapi_aead_ctx *)gnutls_calloc(1, + sizeof(struct kcapi_aead_ctx)); + if (ctx == NULL) { + gnutls_assert(); + kcapi_aead_destroy(handle); + return GNUTLS_E_MEMORY_ERROR; + } + + switch(algorithm) { + case GNUTLS_CIPHER_AES_128_CCM: + case GNUTLS_CIPHER_AES_256_CCM: + ctx->ccm = 1; + break; + default: + ctx->ccm = 0; + } + ctx->handle = handle; + *_ctx = ctx; + + return 0; +} + +static int afalg_aead_setkey(void *_ctx, const void *key, size_t keysize) +{ + struct kcapi_aead_ctx *ctx = _ctx; + + if (kcapi_aead_setkey(ctx->handle, key, keysize) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + +static int afalg_aead_decrypt(void *_ctx, + const void *nonce, size_t nonce_size, + const void *auth, size_t auth_size, + size_t tag_size, + const void *encr, size_t encr_size, + void *plain, size_t plain_size) +{ + int ret = 0; + struct kcapi_aead_ctx *ctx = _ctx; + struct iovec iov[2]; + uint8_t *authtmp = malloca(auth_size); + if (authtmp == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + if (encr_size < tag_size) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + + /* Init stream once. */ + if (!ctx->taglen_set) { + ctx->taglen_set = 1; + if (kcapi_aead_settaglen(ctx->handle, tag_size) < 0) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + } + + kcapi_aead_setassoclen(ctx->handle, auth_size); + + /* CCM nonce to IV conversion */ + if (ctx->ccm) { + uint8_t *ccm_iv = NULL; + uint32_t ccm_iv_len; + + if (kcapi_aead_ccm_nonce_to_iv(nonce, nonce_size, &ccm_iv, + &ccm_iv_len)) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + if (kcapi_aead_stream_init_dec(ctx->handle, ccm_iv, NULL, 0) + < 0) { + free(ccm_iv); + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + free(ccm_iv); + } else { + if (kcapi_aead_stream_init_dec(ctx->handle, nonce, NULL, 0) + < 0) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + } + + /* + * Set AAD: IOVECs do not support const, this buffer is guaranteed to be + * read-only + */ + iov[0].iov_base = (void*)auth; + iov[0].iov_len = auth_size; + + /* + * Set CT: IOVECs do not support const, this buffer is guaranteed to be + * read-only + */ + iov[1].iov_base = (void *)encr; + iov[1].iov_len = encr_size; + + if (kcapi_aead_stream_update_last(ctx->handle, iov, 2) < 0) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + + iov[0].iov_base = authtmp; + iov[0].iov_len = auth_size; + + /* Set PT buffer to be filled by kernel */ + uint32_t outbuflen = kcapi_aead_outbuflen_dec(ctx->handle, + encr_size - tag_size, + auth_size, tag_size)-auth_size; + iov[1].iov_base = (void *)plain; + iov[1].iov_len = (plain_size > outbuflen) ? outbuflen : plain_size; + + if (kcapi_aead_stream_op(ctx->handle, iov, 2) < 0) { + gnutls_assert(); + ret = GNUTLS_E_DECRYPTION_FAILED; + goto end; + } + +end: + freea(authtmp); + return ret; +} +static int afalg_aead_encrypt(void *_ctx, const void *nonce, size_t nonce_size, + const void *auth, size_t auth_size, + size_t tag_size, + const void *plain, size_t plain_size, + void *encr, size_t encr_size) +{ + int ret = 0; + struct kcapi_aead_ctx *ctx = _ctx; + struct iovec iov[3]; + uint32_t iovlen = 2; + uint8_t *authtmp = malloca(auth_size); + if (authtmp == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + if (encr_size < plain_size + tag_size) { + ret = GNUTLS_E_SHORT_MEMORY_BUFFER; + gnutls_assert(); + goto end; + } + + if (nonce_size > kcapi_aead_ivsize(ctx->handle)) { + ret = GNUTLS_E_INVALID_REQUEST; + gnutls_assert(); + goto end; + } + + /* Init taglen once. */ + if (!ctx->taglen_set) { + ctx->taglen_set = 1; + + if (kcapi_aead_settaglen(ctx->handle, tag_size) < 0) { + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + } + + kcapi_aead_setassoclen(ctx->handle, auth_size); + + /* CCM nonce to IV conversion */ + if (ctx->ccm) { + uint8_t *ccm_iv = NULL; + uint32_t ccm_iv_len; + + if (kcapi_aead_ccm_nonce_to_iv(nonce, nonce_size, &ccm_iv, + &ccm_iv_len)) { + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + if (kcapi_aead_stream_init_enc(ctx->handle, ccm_iv, NULL, 0) + < 0) { + free(ccm_iv); + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + free(ccm_iv); + } else { + if (kcapi_aead_stream_init_enc(ctx->handle, nonce, NULL, 0) + < 0) { + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + } + + /* + * Set AAD: IOVECs do not support const, this buffer is guaranteed to be + * read-only + */ + iov[0].iov_base = (void*)auth; + iov[0].iov_len = auth_size; + + /* + * Set PT: IOVECs do not support const, this buffer is guaranteed to be + * read-only + */ + iov[1].iov_base = (void *)plain; + iov[1].iov_len = plain_size; + + /* + * Older kernels require tag as input. This buffer data is unused + * which implies the encr buffer can serve as tmp space. + */ + uint32_t inbuflen = kcapi_aead_inbuflen_enc(ctx->handle, plain_size, + auth_size, tag_size); + if ((auth_size + plain_size) < inbuflen) { + iov[2].iov_base = encr; + iov[2].iov_len = tag_size; + iovlen = 3; + } + + if (kcapi_aead_stream_update_last(ctx->handle, iov, iovlen) < 0) { + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + + iov[0].iov_base = authtmp; + iov[0].iov_len = auth_size; + + /* Set CT buffer to be filled by kernel */ + uint32_t outbuflen = kcapi_aead_outbuflen_enc(ctx->handle, + plain_size, auth_size, + tag_size) - auth_size; + + iov[1].iov_base = encr; + iov[1].iov_len = (encr_size > outbuflen) ? outbuflen : encr_size; + + if (kcapi_aead_stream_op(ctx->handle, iov, 2) < 0) { + gnutls_assert(); + ret = GNUTLS_E_ENCRYPTION_FAILED; + goto end; + } + +end: + freea(authtmp); + return ret; +} + +static const gnutls_crypto_cipher_st afalg_aead_struct = { + .init = afalg_aead_init, + .setkey = afalg_aead_setkey, + .aead_encrypt = afalg_aead_encrypt, + .aead_decrypt = afalg_aead_decrypt, + .deinit = afalg_aead_deinit, +}; + +static int afalg_aead_register(void) +{ + unsigned int i; + int ret = 0; + + for (i = 0; + i < sizeof(gnutls_aead_map) / sizeof(gnutls_aead_map[0]); + i++) { + struct kcapi_handle *handle = NULL; + + if (gnutls_aead_map[i] == 0) + continue; + + /* Check whether cipher is available. */ + if (kcapi_aead_init(&handle, gnutls_aead_map[i], 0)) + continue; + + kcapi_aead_destroy(handle); + + _gnutls_debug_log("afalg: registering: %s\n", + gnutls_cipher_get_name(i)); + ret = gnutls_crypto_single_cipher_register(i, 90, + &afalg_aead_struct, + 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + + return ret; +} + +/********************** Keyed message digest algorithms **********************/ + +static const char *gnutls_mac_map[] = { + [GNUTLS_MAC_SHA1] = "hmac(sha1)", + [GNUTLS_MAC_SHA256] = "hmac(sha256)", + [GNUTLS_MAC_SHA384] = "hmac(sha384)", + [GNUTLS_MAC_SHA512] = "hmac(sha512)", +}; + +static int afalg_mac_init(gnutls_mac_algorithm_t algorithm, void **ctx) +{ + struct kcapi_handle *handle = NULL; + + if (kcapi_md_init(&handle, gnutls_mac_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + *ctx = handle; + + return 0; +} + +static int afalg_mac_setkey(void *ctx, const void *key, size_t keysize) +{ + struct kcapi_handle *handle = ctx; + + if (kcapi_md_setkey(handle, key, keysize) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + +static int afalg_mac_hash(void *ctx, const void *_text, size_t textsize) +{ + struct kcapi_handle *handle = ctx; + const uint8_t *text = _text; + size_t offset; + + for (offset = 0; offset < textsize - textsize % INT_MAX; offset += INT_MAX) { + if (kcapi_md_update(handle, text + offset, INT_MAX) < 0) { + return gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + } + } + + if (offset < textsize) { + if (kcapi_md_update(handle, text + offset, textsize - offset) < 0) { + return gnutls_assert_val(GNUTLS_E_ENCRYPTION_FAILED); + } + } + + return 0; +} + +static int afalg_mac_output(void *ctx, void *digest, size_t digestsize) +{ + struct kcapi_handle *handle = ctx; + + if (kcapi_md_final(handle, digest, digestsize) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; + +} + +static void afalg_mac_deinit(void *ctx) +{ + struct kcapi_handle *handle = ctx; + + kcapi_md_destroy(handle); +} + +static int afalg_mac_fast(gnutls_mac_algorithm_t algorithm, const void *nonce, + size_t nonce_size, const void *key, size_t keysize, + const void *text, size_t textsize, void *digest) +{ + struct kcapi_handle *handle = NULL; + int ret = GNUTLS_E_ENCRYPTION_FAILED; + + if (kcapi_md_init(&handle, gnutls_mac_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + if (kcapi_md_setkey(handle, key, keysize) < 0) { + gnutls_assert(); + goto out; + } + + if (textsize <= INT_MAX) { + if (kcapi_md_digest(handle, text, textsize, digest, + kcapi_md_digestsize(handle)) < 0) { + gnutls_assert(); + goto out; + } + } else { + ret = afalg_mac_hash(handle, text, textsize); + if (ret < 0) { + goto out; + } + if (kcapi_md_final(handle, digest, + kcapi_md_digestsize(handle)) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + } + + ret = 0; + +out: + kcapi_md_destroy(handle); + + return ret; +} + +static const gnutls_crypto_mac_st afalg_mac_struct = { + .init = afalg_mac_init, + .setkey = afalg_mac_setkey, + .setnonce = NULL, + .hash = afalg_mac_hash, + .output = afalg_mac_output, + .deinit = afalg_mac_deinit, + .fast = afalg_mac_fast, +}; + +static int afalg_mac_register(void) +{ + unsigned int i; + int ret = 0; + + for (i = 0; + i < sizeof(gnutls_mac_map) / sizeof(gnutls_mac_map[0]); + i++) { + struct kcapi_handle *handle = NULL; + + if (gnutls_mac_map[i] == 0) + continue; + + /* Check whether cipher is available. */ + if (kcapi_md_init(&handle, gnutls_mac_map[i], 0)) + continue; + + kcapi_md_destroy(handle); + + _gnutls_debug_log("afalg: registering: %s\n", + gnutls_mac_get_name(i)); + ret = gnutls_crypto_single_mac_register(i, 90, + &afalg_mac_struct, 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + + return ret; +} + + +/***************************** Digest algorithms *****************************/ + +static const char *gnutls_digest_map[] = { + [GNUTLS_DIG_SHA1] = "sha1", + [GNUTLS_DIG_SHA256] = "sha256", + [GNUTLS_DIG_SHA384] = "sha384", + [GNUTLS_DIG_SHA512] = "sha512", +}; + +static int afalg_digest_init(gnutls_digest_algorithm_t algorithm, void **ctx) +{ + struct kcapi_handle *handle = NULL; + + if (kcapi_md_init(&handle, gnutls_digest_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + *ctx = handle; + + return 0; +} + +static int afalg_digest_fast(gnutls_digest_algorithm_t algorithm, + const void *text, size_t textsize, void *digest) +{ + struct kcapi_handle *handle = NULL; + int ret = GNUTLS_E_ENCRYPTION_FAILED; + + if (kcapi_md_init(&handle, gnutls_digest_map[algorithm], 0) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + if (textsize <= INT_MAX) { + if (kcapi_md_digest(handle, text, textsize, digest, + kcapi_md_digestsize(handle)) < 0) { + gnutls_assert(); + goto out; + } + } else { + ret = afalg_mac_hash(handle, text, textsize); + if (ret < 0) { + goto out; + } + + if (kcapi_md_final(handle, digest, + kcapi_md_digestsize(handle)) < 0) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + } + + ret = 0; + +out: + kcapi_md_destroy(handle); + + return ret; +} + +static const gnutls_crypto_digest_st afalg_digest_struct = { + .init = afalg_digest_init, + .hash = afalg_mac_hash, + .output = afalg_mac_output, + .deinit = afalg_mac_deinit, + .fast = afalg_digest_fast +}; + +static int afalg_digest_register(void) +{ + unsigned int i; + int ret = 0; + + for (i = 0; + i < sizeof(gnutls_digest_map) / sizeof(gnutls_digest_map[0]); + i++) { + struct kcapi_handle *handle = NULL; + + if (gnutls_digest_map[i] == 0) + continue; + + /* Check whether cipher is available. */ + if (kcapi_md_init(&handle, gnutls_digest_map[i], 0)) + continue; + + kcapi_md_destroy(handle); + + _gnutls_debug_log("afalg: registering: %s\n", + gnutls_digest_get_name(i)); + ret = gnutls_crypto_single_digest_register(i, 90, + &afalg_digest_struct, + 0); + if (ret < 0) { + gnutls_assert(); + return ret; + } + } + + return ret; +} + +int _gnutls_afalg_init(void) +{ + int ret; + + ret = afalg_cipher_register(); + if (ret) + return ret; + + ret = afalg_aead_register(); + if (ret) + return ret; + + ret = afalg_mac_register(); + if (ret) + return ret; + + return afalg_digest_register(); +} + +void _gnutls_afalg_deinit(void) +{ + return; +} + +#else /* ENABLE_AFALG */ + +int _gnutls_afalg_init(void) +{ + return 0; +} + +void _gnutls_afalg_deinit(void) +{ + return; +} + +#endif /* ENABLE_AFALG */ diff --git a/lib/accelerated/afalg.h b/lib/accelerated/afalg.h new file mode 100644 index 0000000000..51de67e412 --- /dev/null +++ b/lib/accelerated/afalg.h @@ -0,0 +1,2 @@ +int _gnutls_afalg_init(void); +void _gnutls_afalg_deinit(void); diff --git a/lib/cipher_int.c b/lib/cipher_int.c index 058fe7a6f8..e01157cde1 100644 --- a/lib/cipher_int.c +++ b/lib/cipher_int.c @@ -110,8 +110,15 @@ _gnutls_cipher_init(cipher_hd_st *handle, const cipher_entry_st *e, SR_FB(cc->setkey(handle->handle, key->data, key->size), cc_cleanup); if (iv) { - if (unlikely(cc->setiv == NULL)) /* the API doesn't accept IV */ + /* the API doesn't accept IV */ + if (unlikely(cc->setiv == NULL)) { + if (cc->aead_encrypt) { + if (handle->handle) + handle->deinit(handle->handle); + goto fallback; + } return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } SR(cc->setiv(handle->handle, iv->data, iv->size), cc_cleanup); } diff --git a/lib/global.c b/lib/global.c index b41e20a9a0..d1bd668269 100644 --- a/lib/global.c +++ b/lib/global.c @@ -33,6 +33,7 @@ #include <locks.h> #include <system.h> #include <accelerated/cryptodev.h> +#include <accelerated/afalg.h> #include <accelerated/accelerated.h> #include <fips.h> #include <atfork.h> @@ -358,6 +359,7 @@ static int _gnutls_global_init(unsigned constructor) _gnutls_register_accel_crypto(); _gnutls_cryptodev_init(); + _gnutls_afalg_init(); #ifdef ENABLE_FIPS140 /* These self tests are performed on the overridden algorithms diff --git a/m4/hooks.m4 b/m4/hooks.m4 index 09190102cc..c90a2c9209 100644 --- a/m4/hooks.m4 +++ b/m4/hooks.m4 @@ -344,6 +344,18 @@ LIBTASN1_MINIMUM=4.9 AC_DEFINE([ENABLE_CRYPTODEV], 1, [Enable cryptodev support]) fi + # For AF_ALG + AC_MSG_CHECKING([whether to add AF_ALG support]) + AC_ARG_ENABLE(afalg, + AS_HELP_STRING([--enable-afalg], [enable AF_ALG support]), + enable_afalg=$enableval,enable_afalg=no) + AC_MSG_RESULT($enable_afalg) + + if test "$enable_afalg" = "yes"; then + AC_DEFINE([ENABLE_AFALG], 1, [Enable AF_ALG support]) + fi + AM_CONDITIONAL(ENABLE_AFALG, test "$enable_afalg" != "no") + AC_MSG_CHECKING([whether to disable OCSP support]) AC_ARG_ENABLE(ocsp, AS_HELP_STRING([--disable-ocsp], diff --git a/src/benchmark-cipher.c b/src/benchmark-cipher.c index 03e1d45fef..76a3cdc50a 100644 --- a/src/benchmark-cipher.c +++ b/src/benchmark-cipher.c @@ -200,7 +200,7 @@ static void cipher_bench(int algo, int size, int aead) } do { - out_size = step+64; + out_size = step+tag_size; assert(gnutls_aead_cipher_encrypt(actx, iv.data, iv.size, NULL, 0, tag_size, i, step, output, &out_size) >= 0); st.size += step; |