--- /dev/null
+#include <config.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <utils.h>
+#include <stdlib.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/self-test.h>
+
+#ifndef HAVE_LIBNETTLE
+int main(int argc, char **argv)
+{
+ exit(77);
+}
+#else
+
+# include <nettle/aes.h>
+# include <nettle/cbc.h>
+# include <nettle/gcm.h>
+
+/* this tests whether the API to override ciphers works sanely.
+ */
+static int used = 0;
+static int aead_used = 0;
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "<%d>| %s", level, str);
+}
+
+#ifndef ENABLE_SELF_CHECKS
+# define AVOID_INTERNALS
+# include "../../lib/crypto-selftests.c"
+#endif
+
+struct myaes_ctx {
+ struct aes_ctx aes;
+ unsigned char iv[16];
+ int enc;
+};
+
+static int
+myaes_init(gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc)
+{
+ /* we use key size to distinguish */
+ if (algorithm != GNUTLS_CIPHER_AES_128_CBC
+ && algorithm != GNUTLS_CIPHER_AES_192_CBC
+ && algorithm != GNUTLS_CIPHER_AES_256_CBC)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ *_ctx = calloc(1, sizeof(struct myaes_ctx));
+ if (*_ctx == NULL) {
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ((struct myaes_ctx *) (*_ctx))->enc = enc;
+
+ return 0;
+}
+
+static int
+myaes_setkey(void *_ctx, const void *userkey, size_t keysize)
+{
+ struct myaes_ctx *ctx = _ctx;
+
+ if (ctx->enc)
+ aes_set_encrypt_key(&ctx->aes, keysize, userkey);
+ else
+ aes_set_decrypt_key(&ctx->aes, keysize, userkey);
+
+ return 0;
+}
+
+static int myaes_setiv(void *_ctx, const void *iv, size_t iv_size)
+{
+ struct myaes_ctx *ctx = _ctx;
+
+ memcpy(ctx->iv, iv, 16);
+ return 0;
+}
+
+static int
+myaes_encrypt(void *_ctx, const void *src, size_t src_size,
+ void *dst, size_t dst_size)
+{
+ struct myaes_ctx *ctx = _ctx;
+
+ used++;
+ cbc_encrypt(&ctx->aes, (nettle_cipher_func*)aes_encrypt, 16, ctx->iv, src_size, dst, src);
+ return 0;
+}
+
+static int
+myaes_decrypt(void *_ctx, const void *src, size_t src_size,
+ void *dst, size_t dst_size)
+{
+ struct myaes_ctx *ctx = _ctx;
+
+ used++;
+ cbc_decrypt(&ctx->aes, (nettle_cipher_func*)aes_decrypt, 16, ctx->iv, src_size, dst, src);
+
+ return 0;
+}
+
+static void myaes_deinit(void *_ctx)
+{
+ free(_ctx);
+}
+
+/* AES-GCM */
+struct myaes_gcm_ctx {
+ struct gcm_aes128_ctx aes;
+};
+
+static int
+myaes_gcm_init(gnutls_cipher_algorithm_t algorithm, void **_ctx, int enc)
+{
+ /* we use key size to distinguish */
+ if (algorithm != GNUTLS_CIPHER_AES_128_GCM
+ && algorithm != GNUTLS_CIPHER_AES_256_GCM)
+ return GNUTLS_E_INVALID_REQUEST;
+
+ *_ctx = calloc(1, sizeof(struct myaes_gcm_ctx));
+ if (*_ctx == NULL) {
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+static int
+myaes_gcm_setkey(void *_ctx, const void *userkey, size_t keysize)
+{
+ struct myaes_gcm_ctx *ctx = _ctx;
+
+ gcm_aes128_set_key(&ctx->aes, userkey);
+
+ return 0;
+}
+
+static void myaes_gcm_deinit(void *_ctx)
+{
+ free(_ctx);
+}
+
+static int
+myaes_gcm_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)
+{
+ /* proper AEAD cipher */
+ struct myaes_gcm_ctx *ctx = _ctx;
+ if (encr_size < plain_size + tag_size)
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+
+ aead_used++;
+ gcm_aes128_set_iv(&ctx->aes, nonce_size, nonce);
+ gcm_aes128_update(&ctx->aes, auth_size, auth);
+
+ gcm_aes128_encrypt(&ctx->aes, plain_size, encr, plain);
+
+ gcm_aes128_digest(&ctx->aes, tag_size, ((uint8_t*)encr) + plain_size);
+ return 0;
+}
+
+static int
+myaes_gcm_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)
+{
+ uint8_t tag[16];
+ struct myaes_gcm_ctx *ctx = _ctx;
+
+ if (encr_size < tag_size)
+ return GNUTLS_E_DECRYPTION_FAILED;
+
+ aead_used++;
+ gcm_aes128_set_iv(&ctx->aes, nonce_size, nonce);
+ gcm_aes128_update(&ctx->aes, auth_size, auth);
+
+ encr_size -= tag_size;
+ gcm_aes128_decrypt(&ctx->aes, encr_size, plain, encr);
+
+ gcm_aes128_digest(&ctx->aes, tag_size, tag);
+
+ if (gnutls_memcmp(((uint8_t*)encr)+encr_size, tag, tag_size) != 0)
+ return GNUTLS_E_DECRYPTION_FAILED;
+
+ return 0;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ gnutls_global_set_log_function(tls_log_func);
+ if (argc > 1)
+ gnutls_global_set_log_level(4711);
+
+ ret = gnutls_crypto_register_cipher(GNUTLS_CIPHER_AES_128_CBC, 1,
+ myaes_init,
+ myaes_setkey,
+ myaes_setiv,
+ myaes_encrypt,
+ myaes_decrypt,
+ myaes_deinit);
+ if (ret < 0) {
+ fprintf(stderr, "%d: cannot register cipher\n", __LINE__);
+ exit(1);
+ }
+
+ ret = gnutls_crypto_register_aead_cipher(GNUTLS_CIPHER_AES_128_GCM, 1,
+ myaes_gcm_init,
+ myaes_gcm_setkey,
+ myaes_gcm_encrypt,
+ myaes_gcm_decrypt,
+ myaes_gcm_deinit);
+ if (ret < 0) {
+ fprintf(stderr, "%d: cannot register cipher\n", __LINE__);
+ exit(1);
+ }
+
+ global_init();
+
+ if (gnutls_cipher_self_test(1, 0) < 0)
+ return 1;
+
+ if (used == 0) {
+ fprintf(stderr, "The CBC cipher was not used\n");
+ exit(1);
+ }
+
+ if (aead_used == 0) {
+ fprintf(stderr, "The AEAD cipher was not used\n");
+ exit(1);
+ }
+
+ gnutls_global_deinit();
+ return 0;
+}
+
+#endif
--- /dev/null
+#!/bin/sh
+
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# Author: Nikos Mavrogiannopoulos
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+srcdir="${srcdir:-.}"
+CLI="${CLI:-../../src/gnutls-cli$EXEEXT}"
+unset RETCODE
+if ! test -z "${VALGRIND}";then
+VALGRIND="${LIBTOOL:-libtool} --mode=execute ${VALGRIND}"
+fi
+
+GNUTLS_NO_EXPLICIT_INIT=1 $VALGRIND ./cipher-override
+if test $? != 0;then
+ echo "overriden cipher tests failed"
+ exit 1
+fi
+
+$VALGRIND ./cipher-override
+if test $? != 0;then
+ echo "overriden cipher tests 2 failed"
+ exit 1
+fi
+
+exit 0