]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Add AF_ALG acceleration
authorStephan Mueller <smueller@chronox.de>
Sat, 14 Oct 2017 18:46:09 +0000 (20:46 +0200)
committerHedgehog5040 <krenzelok.frantisek@gmail.com>
Tue, 20 Apr 2021 13:38:16 +0000 (15:38 +0200)
The patch set adds the backend implementation to use the Linux kernel
crypto API via the AF_ALG interface. The GnuTLS AF_ALG extension uses
libkcapi [1] as the backend library which implements the actual kernel
communication.

[1] http://www.chronox.de/libkcapi.html

The symmetric cipher support, the hashing and the MAC support are
validated to work correctly using NIST CAVS test vectors.

The AEAD cipher support was tested by connecting to a remote host using
gnutls-cli (the following log strips out unrelated information):

Processed 143 CA certificate(s).
...
- Certificate type: X.509
- Got a certificate list of 1 certificates.
- Certificate[0] info:
...
- Description: (TLS1.2)-(ECDHE-SECP384R1)-(RSA-SHA512)-(AES-256-GCM)
- Session ID: 9E:5E:FC:09:2A:4E:2A:3D:22:44:68:42:C3:F6:2D:AB:F9:67:08:CE:6D:EE:E4:A2:EF:80:43:FE:3B:D9:1E:FE
- Ephemeral EC Diffie-Hellman parameters
 - Using curve: SECP384R1
 - Curve size: 384 bits
- Version: TLS1.2
- Key Exchange: ECDHE-RSA
- Server Signature: RSA-SHA512
- Cipher: AES-256-GCM
- MAC: AEAD
- Options: extended master secret, safe renegotiation,
- Handshake was completed

- Simple Client Mode:

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Co-authored-by: Daiki Ueno <ueno@gnu.org>
Co-authored-by: Hedgehog5040 <krenzelok.frantisek@gmail.com>
configure.ac
lib/accelerated/Makefile.am
lib/accelerated/afalg.c [new file with mode: 0644]
lib/accelerated/afalg.h [new file with mode: 0644]
lib/global.c
m4/hooks.m4
src/benchmark-cipher.c

index 126f95ee2e0344eb455fc9d211944fd3df62d9ec..a6f1c1c8457c9b197ef991ce28c1de68d2e10e6c 100644 (file)
@@ -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
index d44920def41d230a4db47952672a51bfc97a0648..69d05960e9efec1c053ce9736c7be96d80ff29c4 100644 (file)
@@ -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 (file)
index 0000000..fe72f8f
--- /dev/null
@@ -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 (file)
index 0000000..51de67e
--- /dev/null
@@ -0,0 +1,2 @@
+int _gnutls_afalg_init(void);
+void _gnutls_afalg_deinit(void);
index b41e20a9a09979588591939439a21bea8856750c..d1bd668269bd534bf5c7caea029fa9531d52281e 100644 (file)
@@ -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
index 09190102cc53a7776689e67b2f3193da6c857dd5..c90a2c9209a74721c63efc14af0294e0a24d74cc 100644 (file)
@@ -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],
index 03e1d45fef55556f0f3e21bb530d35a933441ebf..76a3cdc50a0403ed33bdcdee8cc08f1384c75c77 100644 (file)
@@ -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;