summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-21 17:00:01 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-23 11:12:46 +0200
commit800c0f5769a98ebfe50d9deea4c7a1465cb4fc44 (patch)
tree98d3ae63f692b6aa152b2558fe04f57b15bf91d7
parent12c5a7e07cf222ab13a28b94e6bbaff0e99af251 (diff)
downloadgnutls-800c0f5769a98ebfe50d9deea4c7a1465cb4fc44.tar.gz
Added support for libnettle backend. This uses gmp for big number operations.
It is not currently completed. It lacks RSA blinding as well as optimizations.
-rw-r--r--configure.ac3
-rw-r--r--doc/examples/ex-serv-export.c5
-rw-r--r--doc/examples/ex-serv-psk.c5
-rw-r--r--doc/examples/ex-serv1.c5
-rw-r--r--lib/Makefile.am19
-rw-r--r--lib/auth_srp.c4
-rw-r--r--lib/configure.ac6
-rw-r--r--lib/gcrypt/Makefile.am33
-rw-r--r--lib/gcrypt/cipher.c (renamed from lib/cipher-libgcrypt.c)0
-rw-r--r--lib/gcrypt/mac.c (renamed from lib/mac-libgcrypt.c)0
-rw-r--r--lib/gcrypt/mpi.c (renamed from lib/mpi-libgcrypt.c)7
-rw-r--r--lib/gcrypt/pk.c (renamed from lib/pk-libgcrypt.c)0
-rw-r--r--lib/gcrypt/rnd.c (renamed from lib/rnd-libgcrypt.c)0
-rw-r--r--lib/gnutls_global.c5
-rw-r--r--lib/gnutls_mpi.c2
-rw-r--r--lib/gnutls_srp.c13
-rw-r--r--lib/m4/hooks.m431
-rw-r--r--lib/nettle/Makefile.am33
-rw-r--r--lib/nettle/cipher.c208
-rw-r--r--lib/nettle/mac.c290
-rw-r--r--lib/nettle/mpi.c551
-rw-r--r--lib/nettle/pk.c469
-rw-r--r--lib/nettle/rnd.c210
-rw-r--r--src/certtool.c19
-rw-r--r--src/cli.c19
-rw-r--r--src/serv.c16
-rw-r--r--tests/chainverify.c2
27 files changed, 1870 insertions, 85 deletions
diff --git a/configure.ac b/configure.ac
index 3695f83339..050c0a7365 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ AC_DEFINE([HAVE_CTYPE_H], 1, [Hard-code for src/cfg/.])
AC_DEFINE([HAVE_ERRNO_H], 1, [Hard-code for src/cfg/.])
# No fork on MinGW, disable some self-tests until we fix them.
-AC_CHECK_FUNCS(fork,,)
+AC_CHECK_FUNCS(fork getrusage,,)
AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no")
sj_VALGRIND
@@ -307,4 +307,5 @@ AC_MSG_NOTICE([summary of build options:
C++ library: $use_cxx
OpenSSL library: $enable_openssl
/dev/crypto: $enable_cryptodev
+ Crypto library: $cryptolib
])
diff --git a/doc/examples/ex-serv-export.c b/doc/examples/ex-serv-export.c
index 33b6d0ac68..b79ad55ed4 100644
--- a/doc/examples/ex-serv-export.c
+++ b/doc/examples/ex-serv-export.c
@@ -14,7 +14,6 @@
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
-#include <gcrypt.h> /* for gcry_control */
#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
@@ -132,10 +131,6 @@ main (void)
strcpy (name, "Echo Server");
- /* to disallow usage of the blocking /dev/random
- */
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
/* this must be called once in the program
*/
gnutls_global_init ();
diff --git a/doc/examples/ex-serv-psk.c b/doc/examples/ex-serv-psk.c
index b5768b443a..2cb3b98aa2 100644
--- a/doc/examples/ex-serv-psk.c
+++ b/doc/examples/ex-serv-psk.c
@@ -14,7 +14,6 @@
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
-#include <gcrypt.h> /* for gcry_control */
#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
@@ -101,10 +100,6 @@ main (void)
char buffer[MAX_BUF + 1];
int optval = 1;
- /* to disallow usage of the blocking /dev/random
- */
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
/* this must be called once in the program
*/
gnutls_global_init ();
diff --git a/doc/examples/ex-serv1.c b/doc/examples/ex-serv1.c
index 9d436105fc..f8b91b07d7 100644
--- a/doc/examples/ex-serv1.c
+++ b/doc/examples/ex-serv1.c
@@ -14,7 +14,6 @@
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
-#include <gcrypt.h> /* for gcry_control */
#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
@@ -90,10 +89,6 @@ main (void)
char buffer[MAX_BUF + 1];
int optval = 1;
- /* to disallow usage of the blocking /dev/random
- */
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
/* this must be called once in the program
*/
gnutls_global_init ();
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0deda0e7bc..8bfa067b42 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -80,11 +80,16 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \
gnutls_str.c gnutls_state.c gnutls_x509.c ext_cert_type.c \
gnutls_rsa_export.c auth_rsa_export.c ext_server_name.c \
auth_dh_common.c gnutls_helper.c gnutls_supplemental.c \
- crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c \
- rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
+ crypto.c random.c ext_signature.c cryptodev.c \
crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
pkcs11.c pkcs11_privkey.c
+if ENABLE_NETTLE
+SUBDIRS += nettle
+else
+SUBDIRS += gcrypt
+endif
+
if ENABLE_OPRFI
COBJECTS += $(OPRFI_COBJECTS)
endif
@@ -116,7 +121,7 @@ libgnutls_la_LDFLAGS = -no-undefined \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libgnutls_la_LIBADD = gl/liblgnu.la x509/libgnutls_x509.la \
- $(LTLIBZ) $(LTLIBGCRYPT) $(LTLIBINTL) $(LIBSOCKET)
+ $(LTLIBZ) $(LTLIBINTL) $(LIBSOCKET)
if ENABLE_OPENPGP
libgnutls_la_LIBADD += openpgp/libgnutls_openpgp.la
@@ -139,6 +144,14 @@ if ENABLE_PAKCHOIS
libgnutls_la_LDFLAGS += $(LTLIBPAKCHOIS)
endif
+if ENABLE_NETTLE
+libgnutls_la_LDFLAGS += $(LTLIBNETTLE) -lgmp -lpthread -lhogweed
+libgnutls_la_LIBADD += nettle/libcrypto.la
+else
+libgnutls_la_LDFLAGS += $(LTLIBGCRYPT)
+libgnutls_la_LIBADD += gcrypt/libcrypto.la
+endif
+
if HAVE_LD_OUTPUT_DEF
libgnutls_la_LDFLAGS += -Wl,--output-def,libgnutls-$(DLL_VERSION).def
defexecdir = $(bindir)
diff --git a/lib/auth_srp.c b/lib/auth_srp.c
index 26f6cb9492..8ab237c21a 100644
--- a/lib/auth_srp.c
+++ b/lib/auth_srp.c
@@ -196,7 +196,7 @@ _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque ** data)
return GNUTLS_E_MEMORY_ERROR;
}
- if (_gnutls_mpi_print (B, NULL, &n_b) != 0)
+ if (_gnutls_mpi_print (B, NULL, &n_b) != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
gnutls_assert ();
return GNUTLS_E_MPI_PRINT_FAILED;
@@ -344,7 +344,7 @@ _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data)
return ret;
}
- if (_gnutls_mpi_print (A, NULL, &n_a) != 0)
+ if (_gnutls_mpi_print (A, NULL, &n_a) != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
gnutls_assert ();
return GNUTLS_E_MPI_PRINT_FAILED;
diff --git a/lib/configure.ac b/lib/configure.ac
index fd849559ed..a372b89a14 100644
--- a/lib/configure.ac
+++ b/lib/configure.ac
@@ -87,9 +87,9 @@ if test x$ac_pakchois != xno; then
AC_MSG_RESULT(yes)
AC_LIB_HAVE_LINKFLAGS(pakchois,, [#include <pakchois/pakchois.h>], [pakchois_module_load(0,0);])
if test "$ac_cv_libpakchois" != yes; then
- AC_MSG_WARN(
+ AC_MSG_ERROR(
***
-*** Pakchois was not found. You will not be able to use PKCS11 support.)
+*** Pakchois was not found. This is required for PKCS11 support.)
fi
else
AC_MSG_RESULT(no)
@@ -124,5 +124,7 @@ AC_CONFIG_FILES([
openpgp/Makefile
po/Makefile.in
x509/Makefile
+ gcrypt/Makefile
+ nettle/Makefile
])
AC_OUTPUT
diff --git a/lib/gcrypt/Makefile.am b/lib/gcrypt/Makefile.am
new file mode 100644
index 0000000000..e55459cb8c
--- /dev/null
+++ b/lib/gcrypt/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# Author: Nikos Mavroyanopoulos
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library 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.
+#
+# The GNUTLS 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 the GNUTLS library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../gl \
+ -I$(builddir)/../gl \
+ -I$(srcdir)/../includes \
+ -I$(builddir)/../includes \
+ -I$(srcdir)/..
+
+noinst_LTLIBRARIES = libcrypto.la
+
+libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c
diff --git a/lib/cipher-libgcrypt.c b/lib/gcrypt/cipher.c
index 8412f0a8ee..8412f0a8ee 100644
--- a/lib/cipher-libgcrypt.c
+++ b/lib/gcrypt/cipher.c
diff --git a/lib/mac-libgcrypt.c b/lib/gcrypt/mac.c
index 184b421f76..184b421f76 100644
--- a/lib/mac-libgcrypt.c
+++ b/lib/gcrypt/mac.c
diff --git a/lib/mpi-libgcrypt.c b/lib/gcrypt/mpi.c
index eec739f36d..d45f023514 100644
--- a/lib/mpi-libgcrypt.c
+++ b/lib/gcrypt/mpi.c
@@ -68,6 +68,7 @@ wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes,
gnutls_bigint_format_t format)
{
int ret;
+ size_t init_bytes = *nbytes;
format = _format_conv (format);
@@ -75,8 +76,12 @@ wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes,
return GNUTLS_E_INVALID_REQUEST;
ret = gcry_mpi_print (format, buffer, *nbytes, nbytes, a);
- if (!ret)
+ if (!ret) {
+ if (buffer==NULL || init_bytes < *nbytes) {
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
return 0;
+ }
return GNUTLS_E_MPI_PRINT_FAILED;
}
diff --git a/lib/pk-libgcrypt.c b/lib/gcrypt/pk.c
index 5e0b159be6..5e0b159be6 100644
--- a/lib/pk-libgcrypt.c
+++ b/lib/gcrypt/pk.c
diff --git a/lib/rnd-libgcrypt.c b/lib/gcrypt/rnd.c
index 059011cb6d..059011cb6d 100644
--- a/lib/rnd-libgcrypt.c
+++ b/lib/gcrypt/rnd.c
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index 360bf1c54f..539debf6c2 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -28,7 +28,9 @@
#include <libtasn1.h>
#include <gnutls_dh.h>
#include <random.h>
+#ifndef HAVE_LIBNETTLE
#include <gcrypt.h>
+#endif
#include <gnutls/pkcs11.h>
#include <gnutls_extensions.h> /* for _gnutls_ext_init */
@@ -184,6 +186,7 @@ gnutls_global_init (void)
bindtextdomain (PACKAGE, LOCALEDIR);
+#ifndef HAVE_LIBNETTLE
/* Initialize libgcrypt if it hasn't already been initialized. */
if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
{
@@ -205,7 +208,7 @@ gnutls_global_init (void)
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
}
-
+#endif
/* initialize ASN.1 parser
* This should not deal with files in the final
* version.
diff --git a/lib/gnutls_mpi.c b/lib/gnutls_mpi.c
index 5279014ac6..9850108720 100644
--- a/lib/gnutls_mpi.c
+++ b/lib/gnutls_mpi.c
@@ -343,7 +343,7 @@ _gnutls_x509_write_int (ASN1_TYPE node, const char *value, bigint_t mpi,
else
result = _gnutls_mpi_print (mpi, NULL, &s_len);
- if (result != 0)
+ if (result != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
gnutls_assert ();
return result;
diff --git a/lib/gnutls_srp.c b/lib/gnutls_srp.c
index 927ea83ac1..8a8a844b9a 100644
--- a/lib/gnutls_srp.c
+++ b/lib/gnutls_srp.c
@@ -48,6 +48,7 @@ _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** result,
{
bigint_t x, e;
size_t result_size;
+ int ret;
if (_gnutls_mpi_scan_nz (&x, text, textsize))
{
@@ -67,19 +68,25 @@ _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** result,
_gnutls_mpi_powm (e, g, x, prime);
_gnutls_mpi_release (&x);
- _gnutls_mpi_print (e, NULL, &result_size);
- if (result != NULL)
+ ret = _gnutls_mpi_print (e, NULL, &result_size);
+ if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
*result = galloc_func (result_size);
if ((*result) == NULL)
return GNUTLS_E_MEMORY_ERROR;
_gnutls_mpi_print (e, *result, &result_size);
+ ret = result_size;
+ }
+ else
+ {
+ gnutls_assert();
+ ret = GNUTLS_E_MPI_PRINT_FAILED;
}
_gnutls_mpi_release (&e);
- return result_size;
+ return ret;
}
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index c90bd16e8b..3b06384078 100644
--- a/lib/m4/hooks.m4
+++ b/lib/m4/hooks.m4
@@ -34,7 +34,30 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
DLL_VERSION=`expr ${LT_CURRENT} - ${LT_AGE}`
AC_SUBST(DLL_VERSION)
- AC_LIB_HAVE_LINKFLAGS([gcrypt], [gpg-error], [#include <gcrypt.h>],
+ cryptolib="nettle (unsupported)"
+ AC_ARG_WITH(nettle,
+ AS_HELP_STRING([--with-nettle], [use libnettle 2.x as crypto library]),
+ nettle=$withval,
+ nettle=no)
+ if test "$nettle" = "yes"; then
+ AC_LIB_HAVE_LINKFLAGS([nettle],, [#include <nettle/aes.h>],
+ [aes_set_key (0, 0, 0)])
+ if test "$ac_cv_libnettle" != yes; then
+ nettle=yes
+ AC_MSG_WARN([[
+ ***
+ *** Libnettle was not found.
+ ]])
+ fi
+ fi
+
+ AC_MSG_CHECKING([whether to use nettle])
+ AC_MSG_RESULT($nettle)
+ AM_CONDITIONAL(ENABLE_NETTLE, test "$nettle" = "yes")
+
+ if test "$nettle" != "yes";then
+ cryptolib=libgcrypt
+ AC_LIB_HAVE_LINKFLAGS([gcrypt], [gpg-error], [#include <gcrypt.h>],
[enum gcry_cipher_algos i = GCRY_CIPHER_CAMELLIA128])
if test "$ac_cv_libgcrypt" != yes; then
AC_MSG_ERROR([[
@@ -44,6 +67,7 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
***
]])
fi
+ fi
AC_ARG_WITH(included-libtasn1,
AS_HELP_STRING([--with-included-libtasn1], [use the included libtasn1]),
@@ -174,9 +198,14 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
AM_CONDITIONAL(ENABLE_ANON, test "$ac_enable_anon" != "no")
# Allow disabling Camellia
+ if test "$nettle" != "yes";then
AC_ARG_ENABLE(camellia,
AS_HELP_STRING([--disable-camellia], [disable Camellia cipher]),
enable_camellia=$enableval, enable_camellia=yes)
+ else
+ enable_camellia=no
+ fi
+
AC_MSG_CHECKING([whether to disable Camellia cipher])
if test "$enable_camellia" != "no"; then
AC_MSG_RESULT([no])
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
new file mode 100644
index 0000000000..e55459cb8c
--- /dev/null
+++ b/lib/nettle/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# Author: Nikos Mavroyanopoulos
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library 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.
+#
+# The GNUTLS 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 the GNUTLS library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../gl \
+ -I$(builddir)/../gl \
+ -I$(srcdir)/../includes \
+ -I$(builddir)/../includes \
+ -I$(srcdir)/..
+
+noinst_LTLIBRARIES = libcrypto.la
+
+libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
new file mode 100644
index 0000000000..1c56a39d40
--- /dev/null
+++ b/lib/nettle/cipher.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here lie nettle's wrappers for cipher support.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_cipher_int.h>
+#include <nettle/aes.h>
+#include <nettle/arcfour.h>
+#include <nettle/arctwo.h>
+#include <nettle/des.h>
+#include <nettle/nettle-meta.h>
+#include <nettle/cbc.h>
+
+/* Functions that refer to the libgcrypt library.
+ */
+
+#define MAX_BLOCK_SIZE 32
+
+typedef void (*encrypt_func)(void*, nettle_crypt_func, unsigned, uint8_t*, unsigned, uint8_t *, const uint8_t *);
+typedef void (*decrypt_func)(void*, nettle_crypt_func, unsigned, uint8_t*, unsigned, uint8_t *, const uint8_t *);
+typedef void (*setkey_func)(void*, unsigned, const uint8_t*);
+
+static void stream_encrypt (void* ctx, nettle_crypt_func func, unsigned block_size, uint8_t* iv, unsigned length, uint8_t * dst, const uint8_t * src)
+{
+ func(ctx, length, dst, src);
+}
+
+struct nettle_cipher_ctx {
+ union {
+ struct aes_ctx aes;
+ struct arcfour_ctx arcfour;
+ struct arctwo_ctx arctwo;
+ struct des3_ctx des3;
+ struct des_ctx des;
+ } ctx;
+ void *ctx_ptr;
+ uint8_t iv[MAX_BLOCK_SIZE];
+ gnutls_cipher_algorithm_t algo;
+ size_t block_size;
+ nettle_crypt_func* i_encrypt;
+ nettle_crypt_func* i_decrypt;
+ encrypt_func encrypt;
+ decrypt_func decrypt;
+ setkey_func setkey;
+};
+
+
+
+static int
+wrap_nettle_cipher_init (gnutls_cipher_algorithm_t algo, void **_ctx)
+{
+ struct nettle_cipher_ctx* ctx;
+
+ ctx = gnutls_calloc(1, sizeof(struct nettle_cipher_ctx));
+ if (ctx == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ctx->algo = algo;
+
+ switch (algo) {
+ case GNUTLS_CIPHER_AES_128_CBC:
+ case GNUTLS_CIPHER_AES_192_CBC:
+ case GNUTLS_CIPHER_AES_256_CBC:
+ ctx->encrypt = cbc_encrypt;
+ ctx->decrypt = cbc_decrypt;
+ ctx->i_encrypt = (nettle_crypt_func*)aes_encrypt;
+ ctx->i_decrypt = (nettle_crypt_func*)aes_decrypt;
+ ctx->setkey = (setkey_func)aes_set_key;
+ ctx->ctx_ptr = &ctx->ctx.aes;
+ ctx->block_size = AES_BLOCK_SIZE;
+ break;
+ case GNUTLS_CIPHER_3DES_CBC:
+ ctx->encrypt = cbc_encrypt;
+ ctx->decrypt = cbc_decrypt;
+ ctx->i_encrypt = (nettle_crypt_func*)des3_encrypt;
+ ctx->i_decrypt = (nettle_crypt_func*)des3_decrypt;
+ ctx->setkey = (setkey_func)des3_set_key2;
+ ctx->ctx_ptr = &ctx->ctx.des3;
+ ctx->block_size = DES3_BLOCK_SIZE;
+ break;
+ case GNUTLS_CIPHER_DES_CBC:
+ ctx->encrypt = cbc_encrypt;
+ ctx->decrypt = cbc_decrypt;
+ ctx->i_encrypt = (nettle_crypt_func*)des_encrypt;
+ ctx->i_decrypt = (nettle_crypt_func*)des_decrypt;
+ ctx->setkey = (setkey_func)des_set_key2;
+ ctx->ctx_ptr = &ctx->ctx.des;
+ ctx->block_size = DES_BLOCK_SIZE;
+ break;
+ case GNUTLS_CIPHER_ARCFOUR_128:
+ case GNUTLS_CIPHER_ARCFOUR_40:
+ ctx->encrypt = stream_encrypt;
+ ctx->decrypt = stream_encrypt;
+ ctx->i_encrypt = (nettle_crypt_func*)arcfour_crypt;
+ ctx->i_decrypt = (nettle_crypt_func*)arcfour_crypt;
+ ctx->setkey = (setkey_func)arcfour_set_key;
+ ctx->ctx_ptr = &ctx->ctx.arcfour;
+ ctx->block_size = 1;
+ break;
+ case GNUTLS_CIPHER_RC2_40_CBC:
+ ctx->encrypt = cbc_encrypt;
+ ctx->decrypt = cbc_decrypt;
+ ctx->i_encrypt = (nettle_crypt_func*)arctwo_encrypt;
+ ctx->i_decrypt = (nettle_crypt_func*)arctwo_decrypt;
+ ctx->setkey = (setkey_func)arctwo_set_key;
+ ctx->ctx_ptr = &ctx->ctx.arctwo;
+ ctx->block_size = ARCTWO_BLOCK_SIZE;
+ break;
+ /* FIXME: Camellia? */
+ default:
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ *_ctx = ctx;
+
+ return 0;
+}
+
+static int
+wrap_nettle_cipher_setkey (void *_ctx, const void *key, size_t keysize)
+{
+ struct nettle_cipher_ctx* ctx = _ctx;
+
+ ctx->setkey(ctx->ctx_ptr, keysize, key);
+
+ return 0;
+}
+
+static int
+wrap_nettle_cipher_setiv (void *_ctx, const void *iv, size_t ivsize)
+{
+ struct nettle_cipher_ctx* ctx = _ctx;
+
+ if (ivsize > ctx->block_size) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+ memcpy(ctx->iv, iv, ivsize);
+
+ return 0;
+}
+
+static int
+wrap_nettle_cipher_decrypt (void *_ctx, const void *encr, size_t encrsize,
+ void *plain, size_t plainsize)
+{
+ struct nettle_cipher_ctx* ctx = _ctx;
+
+ ctx->decrypt(ctx->ctx_ptr, ctx->i_decrypt, ctx->block_size, ctx->iv, encrsize, plain, encr);
+
+ return 0;
+}
+
+static int
+wrap_nettle_cipher_encrypt (void *_ctx, const void *plain, size_t plainsize,
+ void *encr, size_t encrsize)
+{
+ struct nettle_cipher_ctx* ctx = _ctx;
+
+ ctx->encrypt(ctx->ctx_ptr, ctx->i_encrypt, ctx->block_size, ctx->iv, plainsize, encr, plain);
+
+ return 0;
+}
+
+static void
+wrap_nettle_cipher_close (void *h)
+{
+ gnutls_free(h);
+}
+
+
+int crypto_cipher_prio = INT_MAX;
+
+gnutls_crypto_cipher_st _gnutls_cipher_ops = {
+ .init = wrap_nettle_cipher_init,
+ .setkey = wrap_nettle_cipher_setkey,
+ .setiv = wrap_nettle_cipher_setiv,
+ .encrypt = wrap_nettle_cipher_encrypt,
+ .decrypt = wrap_nettle_cipher_decrypt,
+ .deinit = wrap_nettle_cipher_close,
+};
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
new file mode 100644
index 0000000000..5821843504
--- /dev/null
+++ b/lib/nettle/mac.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file provides is the backend hash/mac API for libgcrypt.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_hash_int.h>
+#include <gnutls_errors.h>
+#include <nettle/md5.h>
+#include <nettle/md2.h>
+#include <nettle/sha.h>
+#include <nettle/hmac.h>
+
+typedef void (*update_func) (void *, unsigned, const uint8_t *);
+typedef void (*digest_func) (void *, unsigned, uint8_t *);
+typedef void (*set_key_func) (void *, unsigned, const uint8_t *);
+
+static int wrap_nettle_hash_init(gnutls_mac_algorithm_t algo, void **_ctx);
+
+struct nettle_hash_ctx {
+ union {
+ struct md5_ctx md5;
+ struct md2_ctx md2;
+ struct sha256_ctx sha256;
+ struct sha1_ctx sha1;
+ } ctx;
+ void *ctx_ptr;
+ gnutls_mac_algorithm_t algo;
+ size_t length;
+ update_func update;
+ digest_func digest;
+};
+
+struct nettle_hmac_ctx {
+ union {
+ struct hmac_md5_ctx md5;
+ struct hmac_sha256_ctx sha256;
+ struct hmac_sha1_ctx sha1;
+ } ctx;
+ void *ctx_ptr;
+ gnutls_mac_algorithm_t algo;
+ size_t length;
+ update_func update;
+ digest_func digest;
+ set_key_func setkey;
+};
+
+static int wrap_nettle_hmac_init(gnutls_mac_algorithm_t algo, void **_ctx)
+{
+ struct nettle_hmac_ctx* ctx;
+
+ ctx = gnutls_malloc(sizeof(struct nettle_hmac_ctx));
+ if (ctx == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ctx->algo = algo;
+
+ switch (algo) {
+ case GNUTLS_MAC_MD5:
+ ctx->update = (update_func)hmac_md5_update;
+ ctx->digest = (digest_func)hmac_md5_digest;
+ ctx->setkey = (set_key_func)hmac_md5_set_key;
+ ctx->ctx_ptr = &ctx->ctx.md5;
+ ctx->length = MD5_DIGEST_SIZE;
+ break;
+ case GNUTLS_MAC_SHA1:
+ ctx->update = (update_func)hmac_sha1_update;
+ ctx->digest = (digest_func)hmac_sha1_digest;
+ ctx->setkey = (set_key_func)hmac_sha1_set_key;
+ ctx->ctx_ptr = &ctx->ctx.sha1;
+ ctx->length = SHA1_DIGEST_SIZE;
+ break;
+ case GNUTLS_MAC_SHA256:
+ ctx->update = (update_func)hmac_sha256_update;
+ ctx->digest = (digest_func)hmac_sha256_digest;
+ ctx->setkey = (set_key_func)hmac_sha256_set_key;
+ ctx->ctx_ptr = &ctx->ctx.sha256;
+ ctx->length = SHA256_DIGEST_SIZE;
+ break;
+ /* FIXME: SHA512/384/224? */
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ *_ctx = ctx;
+
+ return 0;
+}
+
+static int wrap_nettle_hmac_setkey(void *_ctx, const void *key, size_t keylen)
+{
+ struct nettle_hmac_ctx *ctx = _ctx;
+
+ ctx->setkey(ctx->ctx_ptr, keylen, key);
+
+ return GNUTLS_E_SUCCESS;
+}
+
+static int
+wrap_nettle_hmac_update(void *_ctx, const void *text, size_t textsize)
+{
+ struct nettle_hmac_ctx *ctx = _ctx;
+
+ ctx->update(ctx->ctx_ptr, textsize, text);
+
+ return GNUTLS_E_SUCCESS;
+}
+
+static int
+wrap_nettle_hash_update(void *_ctx, const void *text, size_t textsize)
+{
+ struct nettle_hash_ctx *ctx = _ctx;
+
+ ctx->update(ctx->ctx_ptr, textsize, text);
+
+ return GNUTLS_E_SUCCESS;
+}
+
+static int wrap_nettle_hash_copy(void **bhd, void *ahd)
+{
+ struct nettle_hash_ctx *ctx = ahd;
+ struct nettle_hash_ctx *dst_ctx;
+ int ret;
+
+ ret = wrap_nettle_hash_init(ctx->algo, bhd);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ dst_ctx = *bhd;
+
+ memcpy(&dst_ctx->ctx, &ctx->ctx, sizeof(ctx->ctx));
+
+ return 0;
+}
+
+static int wrap_nettle_hmac_copy(void **bhd, void *ahd)
+{
+ struct nettle_hmac_ctx *ctx = ahd;
+ struct nettle_hmac_ctx *dst_ctx;
+ int ret;
+
+ ret = wrap_nettle_hmac_init(ctx->algo, bhd);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ dst_ctx = *bhd;
+
+ memcpy(&dst_ctx->ctx, &ctx->ctx, sizeof(ctx->ctx));
+
+ return 0;
+}
+
+static void wrap_nettle_md_close(void *hd)
+{
+ gnutls_free(hd);
+}
+
+static int wrap_nettle_hash_init(gnutls_mac_algorithm_t algo, void **_ctx)
+{
+ struct nettle_hash_ctx* ctx;
+
+ ctx = gnutls_malloc(sizeof(struct nettle_hash_ctx));
+ if (ctx == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ctx->algo = algo;
+
+ switch (algo) {
+ case GNUTLS_DIG_MD5:
+ md5_init(&ctx->ctx.md5);
+ ctx->update = (update_func)md5_update;
+ ctx->digest = (digest_func)md5_digest;
+ ctx->ctx_ptr = &ctx->ctx.md5;
+ ctx->length = MD5_DIGEST_SIZE;
+ break;
+ case GNUTLS_DIG_SHA1:
+ sha1_init(&ctx->ctx.sha1);
+ ctx->update = (update_func)sha1_update;
+ ctx->digest = (digest_func)sha1_digest;
+ ctx->ctx_ptr = &ctx->ctx.sha1;
+ ctx->length = SHA1_DIGEST_SIZE;
+ break;
+ case GNUTLS_DIG_MD2:
+ md2_init(&ctx->ctx.md2);
+ ctx->update = (update_func)md2_update;
+ ctx->digest = (digest_func)md2_digest;
+ ctx->ctx_ptr = &ctx->ctx.md2;
+ ctx->length = MD2_DIGEST_SIZE;
+ break;
+ case GNUTLS_DIG_SHA256:
+ sha256_init(&ctx->ctx.sha256);
+ ctx->update = (update_func)sha256_update;
+ ctx->digest = (digest_func)sha256_digest;
+ ctx->ctx_ptr = &ctx->ctx.sha256;
+ ctx->length = SHA256_DIGEST_SIZE;
+ break;
+ /* FIXME: SHA512/384/224? */
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ *_ctx = ctx;
+
+ return 0;
+}
+
+static int
+wrap_nettle_hash_output(void *src_ctx, void *digest, size_t digestsize)
+{
+ struct nettle_hash_ctx *ctx;
+ ctx = src_ctx;
+
+ if (digestsize < ctx->length) {
+ gnutls_assert();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ ctx->digest(ctx->ctx_ptr, digestsize, digest);
+
+ return 0;
+}
+
+static int
+wrap_nettle_hmac_output(void *src_ctx, void *digest, size_t digestsize)
+{
+ struct nettle_hmac_ctx *ctx;
+ ctx = src_ctx;
+
+ if (digestsize < ctx->length) {
+ gnutls_assert();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ ctx->digest(ctx->ctx_ptr, digestsize, digest);
+
+ return 0;
+}
+
+int crypto_mac_prio = INT_MAX;
+
+gnutls_crypto_mac_st _gnutls_mac_ops = {
+ .init = wrap_nettle_hmac_init,
+ .setkey = wrap_nettle_hmac_setkey,
+ .hash = wrap_nettle_hmac_update,
+ .copy = wrap_nettle_hmac_copy,
+ .output = wrap_nettle_hmac_output,
+ .deinit = wrap_nettle_md_close,
+};
+
+int crypto_digest_prio = INT_MAX;
+
+gnutls_crypto_digest_st _gnutls_digest_ops = {
+ .init = wrap_nettle_hash_init,
+ .hash = wrap_nettle_hash_update,
+ .copy = wrap_nettle_hash_copy,
+ .output = wrap_nettle_hash_output,
+ .deinit = wrap_nettle_md_close,
+};
diff --git a/lib/nettle/mpi.c b/lib/nettle/mpi.c
new file mode 100644
index 0000000000..2bac5b731b
--- /dev/null
+++ b/lib/nettle/mpi.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2010 Free
+ * Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here lie everything that has to do with large numbers, gmp.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <gnutls_mpi.h>
+#include <gmp.h>
+#include <nettle/bignum.h>
+#include <random.h>
+
+static int
+wrap_nettle_mpi_print(const bigint_t a, void *buffer, size_t * nbytes,
+ gnutls_bigint_format_t format)
+{
+ unsigned int size;
+ mpz_t *p = (void*)a;
+
+ if (format == GNUTLS_MPI_FORMAT_USG) {
+ size = nettle_mpz_sizeinbase_256_u(*p);
+ } else {
+ size = nettle_mpz_sizeinbase_256_s(*p);
+ }
+
+ if (buffer==NULL || size > *nbytes) {
+ *nbytes=size;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ nettle_mpz_get_str_256(size, buffer, *p);
+ *nbytes=size;
+
+ return 0;
+}
+
+static bigint_t wrap_nettle_mpi_new(int nbits)
+{
+ mpz_t *p;
+
+ p = gnutls_malloc(sizeof(*p));
+ if (p == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+ mpz_init2(*p, nbits);
+
+ return p;
+}
+
+static bigint_t
+wrap_nettle_mpi_scan(const void *buffer, size_t nbytes,
+ gnutls_bigint_format_t format)
+{
+ bigint_t r = wrap_nettle_mpi_new(nbytes*8);
+
+ if (r==NULL) {
+ gnutls_assert();
+ return r;
+ }
+
+ if (format == GNUTLS_MPI_FORMAT_USG) {
+ nettle_mpz_set_str_256_u(*((mpz_t*)r), nbytes, buffer);
+ } else {
+ nettle_mpz_set_str_256_s(*((mpz_t*)r), nbytes, buffer);
+ }
+
+ return r;
+}
+
+static int wrap_nettle_mpi_cmp(const bigint_t u, const bigint_t v)
+{
+ mpz_t *i1 = u, *i2 = v;
+
+ return mpz_cmp(*i1, *i2);
+}
+
+static int wrap_nettle_mpi_cmp_ui(const bigint_t u, unsigned long v)
+{
+ mpz_t *i1 = u;
+
+ return mpz_cmp_ui(*i1, v);
+}
+
+static bigint_t wrap_nettle_mpi_set(bigint_t w, const bigint_t u)
+{
+ mpz_t *i1, *i2 = u;
+
+ if (w == NULL)
+ w = _gnutls_mpi_alloc_like(u);
+ i1 = w;
+
+ mpz_set(*i1, *i2);
+
+ return i1;
+}
+
+static bigint_t wrap_nettle_mpi_set_ui(bigint_t w, unsigned long u)
+{
+ mpz_t *i1;
+
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(32);
+
+ i1 = w;
+
+ mpz_set_ui(*i1, u);
+
+ return i1;
+}
+
+static unsigned int wrap_nettle_mpi_get_nbits(bigint_t a)
+{
+ return mpz_sizeinbase(*((mpz_t *) a), 2);
+}
+
+static void wrap_nettle_mpi_release(bigint_t a)
+{
+ mpz_clear(*((mpz_t *) a));
+ gnutls_free(a);
+}
+
+static bigint_t wrap_nettle_mpi_mod(const bigint_t a, const bigint_t b)
+{
+ bigint_t r = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(b));
+
+ if (r == NULL)
+ return NULL;
+
+ mpz_mod(*((mpz_t *) r), *((mpz_t *) a), *((mpz_t *) b));
+
+ return r;
+}
+
+static bigint_t
+wrap_nettle_mpi_powm(bigint_t w, const bigint_t b, const bigint_t e,
+ const bigint_t m)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(m));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_powm(*((mpz_t *) w), *((mpz_t *) b), *((mpz_t *) e),
+ *((mpz_t *) m));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_addm(bigint_t w, const bigint_t a, const bigint_t b,
+ const bigint_t m)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_add(*((mpz_t *) w), *((mpz_t *) b), *((mpz_t *) a));
+ mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_subm(bigint_t w, const bigint_t a, const bigint_t b,
+ const bigint_t m)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_sub(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+ mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_mulm(bigint_t w, const bigint_t a, const bigint_t b,
+ const bigint_t m)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(m));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_mul(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+ mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_add(bigint_t w, const bigint_t a, const bigint_t b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(b));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_add(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_sub(bigint_t w, const bigint_t a, const bigint_t b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_sub(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_mul(bigint_t w, const bigint_t a, const bigint_t b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_mul(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+ return w;
+}
+
+/* q = a / b */
+static bigint_t
+wrap_nettle_mpi_div(bigint_t q, const bigint_t a, const bigint_t b)
+{
+ if (q == NULL)
+ q = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (q == NULL)
+ return NULL;
+
+ mpz_cdiv_q(*((mpz_t *) q), *((mpz_t *) a), *((mpz_t *) b));
+
+ return q;
+}
+
+static bigint_t
+wrap_nettle_mpi_add_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_add_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+ return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_sub_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_sub_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+ return w;
+
+}
+
+static bigint_t
+wrap_nettle_mpi_mul_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+ if (w == NULL)
+ w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+ if (w == NULL)
+ return NULL;
+
+ mpz_mul_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+ return w;
+
+}
+
+#define PRIME_CHECK_PARAM 18
+static int wrap_nettle_prime_check(bigint_t pp)
+{
+ int ret;
+ ret = mpz_probab_prime_p(*((mpz_t *) pp), PRIME_CHECK_PARAM);
+
+ if (ret > 0) {
+ return 0;
+ }
+
+ return GNUTLS_E_INTERNAL_ERROR; /* ignored */
+}
+
+
+/* generate a prime of the form p=2qw+1
+ * The algorithm is simple but probably it has to be modified to gcrypt's
+ * since it is really really slow. Nature did not want 2qw+1 to be prime.
+ */
+inline static int gen_group (mpz_t *prime, mpz_t* generator, unsigned int nbits)
+{
+ mpz_t q, w;
+ unsigned int p_bytes = nbits/8;
+ opaque *buffer= NULL;
+ unsigned int q_bytes, w_bytes, r_bytes, w_bits;
+ int ret;
+
+ mpz_init(*prime);
+ mpz_init(*generator);
+
+ /* security level enforcement. "Check Fine-tuned implementation of an
+ * efficient secure proļ¬le matching protocol", p.61, El-gamal key generation.
+ */
+ if (nbits <= 1024) {
+ q_bytes = 160/8;
+ } else if (nbits <=2644) {
+ q_bytes = 256/8;
+ } else if (nbits <= 6897) {
+ q_bytes = 384/8;
+ } else {
+ q_bytes = 512/8;
+ }
+
+ if (nbits%8 != 0)
+ p_bytes++;
+
+ _gnutls_debug_log("Generating group of prime of %u bits and format of 2wq+1. q_size=%u bits\n", nbits, q_bytes*8);
+ buffer = gnutls_malloc(p_bytes); /* p_bytes > q_bytes */
+ if (buffer == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ mpz_init2(*prime, nbits);
+ mpz_init(*generator);
+ mpz_init(q);
+ mpz_init(w);
+
+ /* search for a prime. We are not that unlucky so search
+ * forever.
+ */
+ for (;;) {
+ ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, q_bytes);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ nettle_mpz_set_str_256_u(q, q_bytes, buffer);
+ /* always odd */
+ mpz_setbit(q, 0);
+
+ ret = mpz_probab_prime_p(q, PRIME_CHECK_PARAM);
+ if (ret > 0) {
+ break;
+ }
+ }
+
+ /* now generate w of size p_bytes - q_bytes */
+
+ w_bits = nbits - wrap_nettle_mpi_get_nbits(&q);
+
+ _gnutls_debug_log("Found prime q of %u bits. Will look for w of %u bits...\n", wrap_nettle_mpi_get_nbits(&q), w_bits);
+
+ w_bytes = w_bits/8;
+ if (w_bits % 8 != 0)
+ w_bytes++;
+
+ for (;;) {
+ ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, w_bytes);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ nettle_mpz_set_str_256_u(w, w_bytes, buffer);
+ /* always odd */
+ mpz_setbit(w, 0);
+
+ ret = mpz_probab_prime_p(w, PRIME_CHECK_PARAM);
+ if (ret == 0) {
+ continue;
+ }
+
+ /* check if 2wq+1 is prime */
+ mpz_mul_ui(*prime, w, 2);
+ mpz_mul(*prime, *prime, q);
+ mpz_add_ui(*prime, *prime, 1);
+
+ ret = mpz_probab_prime_p(*prime, PRIME_CHECK_PARAM);
+ if (ret > 0) {
+ break;
+ }
+ }
+
+ _gnutls_debug_log("Found prime w of %u bits. Looking for generator...\n", wrap_nettle_mpi_get_nbits(&w));
+
+ /* finally a prime! Let calculate generator
+ */
+
+ /* c = r^((p-1)/q), r == random
+ * c = r^(2w)
+ * if c!=1 c is the generator for the group of the prime
+ *
+ * (here we reuse q as r)
+ */
+ r_bytes = p_bytes;
+
+ mpz_mul_ui(w, w, 2); /* w = w*2 */
+ mpz_fdiv_r(w, w, *prime);
+
+ for (;;) {
+ ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, r_bytes);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ nettle_mpz_set_str_256_u(q, r_bytes, buffer);
+ mpz_fdiv_r(q, q, *prime);
+
+ /* check if r^w mod n != 1 mod n */
+ mpz_powm(*generator, q, w, *prime);
+
+ if (mpz_cmp_ui(*generator,1)==0)
+ continue;
+ else break;
+ }
+
+ _gnutls_debug_log("Found generator g of %u bits\n", wrap_nettle_mpi_get_nbits(generator));
+ _gnutls_debug_log("Prime n is of %u bits\n", wrap_nettle_mpi_get_nbits(prime));
+
+ mpz_clear(q);
+ mpz_clear(w);
+ gnutls_free(buffer);
+
+ return 0;
+
+fail:
+ mpz_clear(q);
+ mpz_clear(w);
+ mpz_clear(*prime);
+ mpz_clear(*generator);
+ gnutls_free(buffer);
+
+ return ret;
+}
+
+static int
+wrap_nettle_generate_group(gnutls_group_st * group, unsigned int bits)
+{
+int ret;
+bigint_t p = wrap_nettle_mpi_new(bits);
+bigint_t g;
+
+ if (p == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ g = wrap_nettle_mpi_new(bits);
+ if (g == NULL) {
+ gnutls_assert();
+ _gnutls_mpi_release(&p);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ret = gen_group(p, g, bits);
+ if (ret < 0) {
+ _gnutls_mpi_release(&g);
+ _gnutls_mpi_release(&p);
+ gnutls_assert();
+ return ret;
+ }
+
+ group->p = p;
+ group->g = g;
+
+ return 0;
+}
+
+
+int crypto_bigint_prio = INT_MAX;
+
+gnutls_crypto_bigint_st _gnutls_mpi_ops = {
+ .bigint_new = wrap_nettle_mpi_new,
+ .bigint_cmp = wrap_nettle_mpi_cmp,
+ .bigint_cmp_ui = wrap_nettle_mpi_cmp_ui,
+ .bigint_mod = wrap_nettle_mpi_mod,
+ .bigint_set = wrap_nettle_mpi_set,
+ .bigint_set_ui = wrap_nettle_mpi_set_ui,
+ .bigint_get_nbits = wrap_nettle_mpi_get_nbits,
+ .bigint_powm = wrap_nettle_mpi_powm,
+ .bigint_addm = wrap_nettle_mpi_addm,
+ .bigint_subm = wrap_nettle_mpi_subm,
+ .bigint_add = wrap_nettle_mpi_add,
+ .bigint_sub = wrap_nettle_mpi_sub,
+ .bigint_add_ui = wrap_nettle_mpi_add_ui,
+ .bigint_sub_ui = wrap_nettle_mpi_sub_ui,
+ .bigint_mul = wrap_nettle_mpi_mul,
+ .bigint_mulm = wrap_nettle_mpi_mulm,
+ .bigint_mul_ui = wrap_nettle_mpi_mul_ui,
+ .bigint_div = wrap_nettle_mpi_div,
+ .bigint_prime_check = wrap_nettle_prime_check,
+ .bigint_release = wrap_nettle_mpi_release,
+ .bigint_print = wrap_nettle_mpi_print,
+ .bigint_scan = wrap_nettle_mpi_scan,
+ .bigint_generate_group = wrap_nettle_generate_group
+};
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
new file mode 100644
index 0000000000..081c08c34c
--- /dev/null
+++ b/lib/nettle/pk.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2010
+ * Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file contains the functions needed for RSA/DSA public key
+ * encryption and signatures.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_mpi.h>
+#include <gnutls_pk.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_num.h>
+#include <x509/x509_int.h>
+#include <x509/common.h>
+#include <random.h>
+#include <gnutls_pk.h>
+#include <nettle/dsa.h>
+#include <nettle/rsa.h>
+#include <random.h>
+#include <gnutls/crypto.h>
+
+#define TOMPZ(x) (*((mpz_t*)(x)))
+
+static void rnd_func(void *_ctx, unsigned length, uint8_t * data)
+{
+ _gnutls_rnd(GNUTLS_RND_RANDOM, data, length);
+}
+
+static void _dsa_params_to_pubkey(const gnutls_pk_params_st * pk_params, struct dsa_public_key *pub)
+{
+ memcpy(&pub->p, pk_params->params[0], sizeof(mpz_t));
+ memcpy(&pub->q, pk_params->params[1], sizeof(mpz_t));
+ memcpy(&pub->g, pk_params->params[2], sizeof(mpz_t));
+ memcpy(&pub->y, pk_params->params[3], sizeof(mpz_t));
+}
+
+static void _dsa_params_to_privkey(const gnutls_pk_params_st * pk_params, struct dsa_private_key *pub)
+{
+ memcpy(&pub->x, pk_params->params[4], sizeof(mpz_t));
+}
+
+static void _rsa_params_to_privkey(const gnutls_pk_params_st * pk_params, struct rsa_private_key *priv)
+{
+mpz_t q_1;
+
+ memcpy(&priv->d, pk_params->params[2], sizeof(mpz_t));
+ memcpy(&priv->p, pk_params->params[3], sizeof(mpz_t));
+ memcpy(&priv->q, pk_params->params[4], sizeof(mpz_t));
+ memcpy(&priv->c, pk_params->params[5], sizeof(mpz_t));
+
+ /* FIXME: possibly move it to fixup to avoid those calculations here */
+
+ /* b = d % q-1 */
+ mpz_init(q_1);
+ mpz_sub_ui(q_1, priv->q, 1);
+
+ mpz_fdiv_r(priv->b, priv->d, q_1);
+
+ /* a = d % p-1 */
+ mpz_sub_ui(q_1, priv->p, 1);
+ mpz_fdiv_r(priv->a, priv->d, q_1);
+}
+
+static int
+_wrap_nettle_pk_encrypt(gnutls_pk_algorithm_t algo,
+ gnutls_datum_t * ciphertext,
+ const gnutls_datum_t * plaintext,
+ const gnutls_pk_params_st * pk_params)
+{
+ int ret;
+
+ /* make a sexp from pkey */
+ switch (algo) {
+ case GNUTLS_PK_RSA: {
+ bigint_t p;
+
+ if (_gnutls_mpi_scan_nz(&p, plaintext->data, plaintext->size) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ mpz_powm(p, p, TOMPZ(pk_params->params[1]), TOMPZ(pk_params->params[0]));
+
+ ret = _gnutls_mpi_dprint(p, ciphertext);
+ _gnutls_mpi_release(&p);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ break;
+ }
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+
+ return ret;
+}
+
+static int
+_wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
+ gnutls_datum_t * plaintext,
+ const gnutls_datum_t * ciphertext,
+ const gnutls_pk_params_st * pk_params)
+{
+ int ret;
+
+ /* make a sexp from pkey */
+ switch (algo) {
+ case GNUTLS_PK_RSA: {
+ struct rsa_private_key priv;
+ bigint_t c;
+
+ if (_gnutls_mpi_scan_nz(&c, ciphertext->data, ciphertext->size) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ /* FIXME: implement blinding */
+
+ rsa_private_key_init(&priv);
+ _rsa_params_to_privkey(pk_params, &priv);
+
+ rsa_compute_root(&priv, TOMPZ(c), TOMPZ(c));
+
+ ret = _gnutls_mpi_dprint(c, plaintext);
+ _gnutls_mpi_release(&c);
+ mpz_clear(priv.a);
+ mpz_clear(priv.b);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ break;
+ }
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+
+ return ret;
+}
+
+/* in case of DSA puts into data, r,s
+ */
+static int
+_wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
+ gnutls_datum_t * signature,
+ const gnutls_datum_t * vdata,
+ const gnutls_pk_params_st * pk_params)
+{
+ int ret;
+
+ switch (algo) {
+
+ case GNUTLS_PK_DSA: {
+ struct dsa_public_key pub;
+ struct dsa_private_key priv;
+ struct dsa_signature sig;
+
+ dsa_public_key_init(&pub);
+ dsa_private_key_init(&priv);
+ _dsa_params_to_pubkey(pk_params, &pub);
+ _dsa_params_to_privkey(pk_params, &priv);
+
+ dsa_signature_init(&sig);
+
+ dsa_sign_digest(&pub, &priv, NULL, rnd_func, vdata->data, &sig);
+
+ ret =
+ _gnutls_encode_ber_rs(signature, &sig.r,
+ &sig.s);
+
+ dsa_signature_clear(&sig);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ break;
+ }
+ case GNUTLS_PK_RSA: {
+ struct rsa_private_key priv;
+ bigint_t hash;
+
+ if (_gnutls_mpi_scan_nz(&hash, vdata->data, vdata->size) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ rsa_private_key_init(&priv);
+ _rsa_params_to_privkey(pk_params, &priv);
+
+ rsa_compute_root(&priv, TOMPZ(hash), TOMPZ(hash));
+
+ ret = _gnutls_mpi_dprint(hash, signature);
+ _gnutls_mpi_release(&hash);
+ mpz_clear(priv.a);
+ mpz_clear(priv.b);
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ break;
+ }
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+
+ return ret;
+}
+
+static int
+_int_rsa_verify(const gnutls_pk_params_st * pk_params,
+ bigint_t m,
+ bigint_t s)
+{
+ int res;
+
+ mpz_t m1;
+
+ if ( (mpz_sgn(TOMPZ(s)) <= 0)
+ || (mpz_cmp(TOMPZ(s), TOMPZ(pk_params->params[0])) >= 0) )
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+
+ mpz_init(m1);
+
+ mpz_powm(m1, TOMPZ(s), TOMPZ(pk_params->params[1]), TOMPZ(pk_params->params[0]));
+
+ res = !mpz_cmp(TOMPZ(m), m1);
+
+ mpz_clear(m1);
+
+ if (res == 0)
+ res = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ else res = 0;
+
+ return res;
+}
+
+static int
+_wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
+ const gnutls_datum_t * vdata,
+ const gnutls_datum_t * signature,
+ const gnutls_pk_params_st * pk_params)
+{
+ int ret;
+ bigint_t tmp[2] = { NULL, NULL };
+
+ switch (algo) {
+ case GNUTLS_PK_DSA: {
+ struct dsa_public_key pub;
+ struct dsa_signature sig;
+
+ ret = _gnutls_decode_ber_rs(signature, &tmp[0], &tmp[1]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ dsa_public_key_init(&pub);
+ _dsa_params_to_pubkey(pk_params, &pub);
+ memcpy(&sig.r, tmp[0], sizeof(sig.r));
+ memcpy(&sig.s, tmp[1], sizeof(sig.s));
+
+ ret = dsa_verify_digest(&pub, vdata->data, &sig);
+ if (ret == 0)
+ ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ else
+ ret = 0;
+
+ _gnutls_mpi_release(&tmp[0]);
+ _gnutls_mpi_release(&tmp[1]);
+ break;
+ }
+ case GNUTLS_PK_RSA: {
+ bigint_t hash;
+
+ if (_gnutls_mpi_scan_nz(&hash, vdata->data, vdata->size) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ ret =
+ _gnutls_mpi_scan_nz(&tmp[0], signature->data,
+ signature->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _int_rsa_verify(pk_params, hash, tmp[0]);
+ _gnutls_mpi_release(&tmp[0]);
+ _gnutls_mpi_release(&hash);
+ break;
+ }
+ default:
+ gnutls_assert();
+ ret = GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
+ }
+
+cleanup:
+
+ return ret;
+}
+
+static int
+wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
+ unsigned int level /*bits */ ,
+ gnutls_pk_params_st * params)
+{
+int ret, i;
+
+ switch (algo) {
+
+ case GNUTLS_PK_DSA: {
+ struct dsa_public_key pub;
+ struct dsa_private_key priv;
+
+ dsa_public_key_init(&pub);
+ dsa_private_key_init(&priv);
+
+ ret = dsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, NULL, level);
+ if (ret != 1) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ params->params_nr = 0;
+ for (i=0;i<DSA_PRIVATE_PARAMS;i++) {
+ params->params[i] = _gnutls_mpi_alloc_like(&pub.p);
+ if (params->params[i] == NULL) {
+ ret = GNUTLS_E_MEMORY_ERROR;
+ dsa_private_key_clear(&priv);
+ dsa_public_key_clear(&pub);
+ goto fail;
+ }
+ params->params_nr++;
+ }
+ _gnutls_mpi_set(params->params[0], pub.p);
+ _gnutls_mpi_set(params->params[1], pub.q);
+ _gnutls_mpi_set(params->params[2], pub.g);
+ _gnutls_mpi_set(params->params[3], pub.y);
+ _gnutls_mpi_set(params->params[4], priv.x);
+
+ dsa_private_key_clear(&priv);
+ dsa_public_key_clear(&pub);
+
+ break;
+ }
+ case GNUTLS_PK_RSA: {
+ struct rsa_public_key pub;
+ struct rsa_private_key priv;
+
+ rsa_public_key_init(&pub);
+ rsa_private_key_init(&priv);
+
+ ret = rsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, NULL, level, 64);
+ if (ret != 1) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ params->params_nr = 0;
+ for (i=0;i<RSA_PRIVATE_PARAMS;i++) {
+ params->params[i] = _gnutls_mpi_alloc_like(&pub.n);
+ if (params->params[i] == NULL) {
+ ret = GNUTLS_E_MEMORY_ERROR;
+ rsa_private_key_clear(&priv);
+ rsa_public_key_clear(&pub);
+ goto fail;
+ }
+ params->params_nr++;
+
+ }
+ _gnutls_mpi_set(params->params[0], pub.n);
+ _gnutls_mpi_set(params->params[1], pub.e);
+ _gnutls_mpi_set(params->params[2], priv.d);
+ _gnutls_mpi_set(params->params[3], priv.p);
+ _gnutls_mpi_set(params->params[4], priv.q);
+ _gnutls_mpi_set(params->params[5], priv.c);
+
+ rsa_private_key_clear(&priv);
+ rsa_public_key_clear(&pub);
+
+ break;
+ }
+ default:
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return 0;
+
+fail:
+
+ for (i=0;i<params->params_nr;i++) {
+ _gnutls_mpi_release(&params->params[i]);
+ }
+ params->params_nr=0;
+
+ return ret;
+}
+
+
+static int
+wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
+ gnutls_direction_t direction,
+ gnutls_pk_params_st * params)
+{
+ return 0;
+}
+
+int crypto_pk_prio = INT_MAX;
+
+gnutls_crypto_pk_st _gnutls_pk_ops = {
+ .encrypt = _wrap_nettle_pk_encrypt,
+ .decrypt = _wrap_nettle_pk_decrypt,
+ .sign = _wrap_nettle_pk_sign,
+ .verify = _wrap_nettle_pk_verify,
+ .generate = wrap_nettle_pk_generate_params,
+ .pk_fixup_private_params = wrap_nettle_pk_fixup,
+};
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
new file mode 100644
index 0000000000..0a1066fe7d
--- /dev/null
+++ b/lib/nettle/rnd.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here is the libgcrypt random generator layer.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <nettle/yarrow.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+
+#define SOURCES 2
+
+static pthread_mutex_t rnd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define RND_LOCK_INIT
+#define RND_LOCK if (pthread_mutex_lock(&rnd_mutex)!=0) abort()
+#define RND_UNLOCK if (pthread_mutex_unlock(&rnd_mutex)!=0) abort()
+
+enum {
+ RANDOM_SOURCE_TRIVIA=0,
+ RANDOM_SOURCE_DEVICE,
+};
+
+static struct yarrow256_ctx yctx;
+static struct yarrow_source ysources[SOURCES];
+static time_t device_last_read = 0;
+static int device_fd;
+
+static time_t trivia_previous_time = 0;
+static time_t trivia_time_count = 0;
+
+static int do_trivia_source(int init)
+{
+ struct {
+ struct timeval now;
+#ifdef HAVE_GETRUSAGE
+ struct rusage rusage;
+#endif
+ unsigned count;
+ pid_t pid;
+ } event;
+
+ unsigned entropy = 0;
+
+ if (gettimeofday(&event.now, NULL) < 0) {
+ _gnutls_debug_log("gettimeofday failed: %s\n", strerror(errno));
+ abort();
+ }
+#ifdef HAVE_GETRUSAGE
+ if (getrusage(RUSAGE_SELF, &event.rusage) < 0) {
+ _gnutls_debug_log("getrusage failed: %s\n", strerror(errno));
+ abort();
+ }
+#endif
+
+ event.count = 0;
+ if (init) {
+ trivia_time_count = 0;
+ } else {
+ event.count = trivia_time_count++;
+
+ if (event.now.tv_sec != trivia_previous_time) {
+ /* Count one bit of entropy if we either have more than two
+ * invocations in one second, or more than two seconds
+ * between invocations. */
+ if ((trivia_time_count > 2)
+ || ((event.now.tv_sec - trivia_previous_time) > 2))
+ entropy++;
+
+ trivia_time_count = 0;
+ }
+ }
+ trivia_previous_time = event.now.tv_sec;
+ event.pid = getpid();
+
+ return yarrow256_update(&yctx, RANDOM_SOURCE_TRIVIA, entropy,
+ sizeof(event), (const uint8_t *) &event);
+}
+
+#define DEVICE_READ_SIZE 16
+#define DEVICE_READ_SIZE_MAX 32
+#define DEVICE_READ_INTERVAL 360
+static int do_device_source(int init)
+{
+ time_t now = time(NULL);
+ int read_size = DEVICE_READ_SIZE;
+
+ if (init) {
+ int old;
+
+ device_fd = open("/dev/urandom", O_RDONLY);
+ if (device_fd < 0) {
+ _gnutls_debug_log("Cannot open urandom!\n");
+ abort();
+ }
+
+ old = fcntl(device_fd, F_GETFD);
+ fcntl(device_fd, F_SETFD, old | 1);
+ device_last_read = now;
+
+ read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
+ }
+
+ if ((device_fd > 0)
+ && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) {
+
+ /* More than a minute since we last read the device */
+ uint8_t buf[DEVICE_READ_SIZE_MAX];
+ uint32_t done;
+
+ for (done = 0; done < read_size;) {
+ int res;
+ do
+ res =
+ read(device_fd, buf + done, sizeof(buf) - done);
+ while (res < 0 && errno == EINTR);
+
+ if (res <= 0) {
+ if (res < 0) {
+ _gnutls_debug_log("Failed to read /dev/urandom: %s\n",
+ strerror(errno));
+ } else {
+ _gnutls_debug_log
+ ("Failed to read /dev/urandom: end of file\n");
+ }
+
+ return 0;
+ }
+
+ done += res;
+ }
+
+ device_last_read = now;
+ return yarrow256_update(&yctx, RANDOM_SOURCE_DEVICE, read_size*8/3 /* be more conservative */,
+ read_size, buf);
+ }
+ return 0;
+}
+
+static void wrap_nettle_rnd_deinit(void* ctx)
+{
+ RND_LOCK;
+ close(device_fd);
+ RND_UNLOCK;
+}
+
+static int wrap_nettle_rnd_init(void **ctx)
+{
+ RND_LOCK_INIT;
+
+ yarrow256_init(&yctx, SOURCES, ysources);
+ do_device_source(1);
+ do_trivia_source(1);
+
+ yarrow256_slow_reseed(&yctx);
+
+ return 0;
+}
+
+
+
+static int
+wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
+{
+ RND_LOCK;
+ do_trivia_source( 0);
+ do_device_source( 0);
+
+ yarrow256_random(&yctx, datasize, data);
+ RND_UNLOCK;
+ return 0;
+}
+
+int crypto_rnd_prio = INT_MAX;
+
+gnutls_crypto_rnd_st _gnutls_rnd_ops = {
+ .init = wrap_nettle_rnd_init,
+ .deinit = wrap_nettle_rnd_deinit,
+ .rnd = wrap_nettle_rnd,
+};
diff --git a/src/certtool.c b/src/certtool.c
index 2b5cdcaaee..bdc8b0c652 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -172,9 +172,6 @@ generate_private_key_int (void)
if (info.dsa)
{
key_type = GNUTLS_PK_DSA;
- /* FIXME: Remove me once we depend on 1.3.x */
- if (info.bits > 1024 && gcry_check_version ("1.3.1") == NULL)
- info.bits = 1024;
}
else
key_type = GNUTLS_PK_RSA;
@@ -921,19 +918,6 @@ gaa_parser (int argc, char **argv)
template_parse (info.template);
}
-#ifdef gcry_fips_mode_active
- /* Libgcrypt manual says that gcry_version_check must be called
- before calling gcry_fips_mode_active. */
- gcry_check_version (NULL);
- if (gcry_fips_mode_active ())
- {
- ret = gnutls_register_md5_handler ();
- if (ret)
- fprintf (stderr, "gnutls_register_md5_handler: %s\n",
- gnutls_strerror (ret));
- }
-#endif
-
gnutls_global_set_log_function (tls_log_func);
gnutls_global_set_log_level (info.debug);
if (info.debug > 1)
@@ -964,9 +948,6 @@ gaa_parser (int argc, char **argv)
if ((ret = gnutls_global_init_extra ()) < 0)
error (EXIT_FAILURE, 0, "global_init_extra: %s", gnutls_strerror (ret));
- if (info.quick_random != 0)
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
switch (info.action)
{
case ACTION_SELF_SIGNED:
diff --git a/src/cli.c b/src/cli.c
index 52666863f5..4400843613 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -38,7 +38,6 @@
#include <gnutls/x509.h>
#include <gnutls/openpgp.h>
#include <gnutls/pkcs11.h>
-#include <gcrypt.h>
/* Gnulib portability files. */
#include <progname.h>
@@ -700,21 +699,6 @@ main (int argc, char **argv)
set_program_name (argv[0]);
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
-#ifdef gcry_fips_mode_active
- /* Libgcrypt manual says that gcry_version_check must be called
- before calling gcry_fips_mode_active. */
- gcry_check_version (NULL);
- if (gcry_fips_mode_active ())
- {
- ret = gnutls_register_md5_handler ();
- if (ret)
- fprintf (stderr, "gnutls_register_md5_handler: %s\n",
- gnutls_strerror (ret));
- }
-#endif
-
if ((ret = gnutls_global_init ()) < 0)
{
fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
@@ -958,9 +942,6 @@ after_handshake:
}
}
- if (info.debug)
- gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
-
if (user_term != 0)
socket_bye (&hd);
else
diff --git a/src/serv.c b/src/serv.c
index 8b270df64a..a2457ea781 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -34,7 +34,6 @@
#include <sys/types.h>
#include <string.h>
#include <gnutls/gnutls.h>
-#include <gcrypt.h>
#include <gnutls/extra.h>
#include <gnutls/openpgp.h>
#include <sys/time.h>
@@ -865,19 +864,6 @@ main (int argc, char **argv)
set_program_name (argv[0]);
-#ifdef gcry_fips_mode_active
- /* Libgcrypt manual says that gcry_version_check must be called
- before calling gcry_fips_mode_active. */
- gcry_check_version (NULL);
- if (gcry_fips_mode_active ())
- {
- ret = gnutls_register_md5_handler ();
- if (ret)
- fprintf (stderr, "gnutls_register_md5_handler: %s\n",
- gnutls_strerror (ret));
- }
-#endif
-
#ifndef _WIN32
signal (SIGPIPE, SIG_IGN);
signal (SIGHUP, SIG_IGN);
@@ -902,8 +888,6 @@ main (int argc, char **argv)
strcpy (name, "Echo Server");
}
- gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
if ((ret = gnutls_global_init ()) < 0)
{
fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
diff --git a/tests/chainverify.c b/tests/chainverify.c
index 5aa4b88df1..1ddc20937a 100644
--- a/tests/chainverify.c
+++ b/tests/chainverify.c
@@ -848,7 +848,7 @@ doit (void)
if (verify_status != chains[i].expected_verify_result)
{
- fail ("verify_status: %d expected: %d",
+ fail ("verify_status: %d expected: %d\n",
verify_status, chains[i].expected_verify_result);
if (debug)