]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support for libnettle backend. This uses gmp for big number operations.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 21 May 2010 15:00:01 +0000 (17:00 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:42:47 +0000 (19:42 +0200)
It is not currently completed. It lacks RSA blinding as well as optimizations.

27 files changed:
configure.ac
doc/examples/ex-serv-export.c
doc/examples/ex-serv-psk.c
doc/examples/ex-serv1.c
lib/Makefile.am
lib/auth_srp.c
lib/configure.ac
lib/gcrypt/Makefile.am [new file with mode: 0644]
lib/gcrypt/cipher.c [moved from lib/cipher-libgcrypt.c with 100% similarity]
lib/gcrypt/mac.c [moved from lib/mac-libgcrypt.c with 100% similarity]
lib/gcrypt/mpi.c [moved from lib/mpi-libgcrypt.c with 98% similarity]
lib/gcrypt/pk.c [moved from lib/pk-libgcrypt.c with 100% similarity]
lib/gcrypt/rnd.c [moved from lib/rnd-libgcrypt.c with 100% similarity]
lib/gnutls_global.c
lib/gnutls_mpi.c
lib/gnutls_srp.c
lib/m4/hooks.m4
lib/nettle/Makefile.am [new file with mode: 0644]
lib/nettle/cipher.c [new file with mode: 0644]
lib/nettle/mac.c [new file with mode: 0644]
lib/nettle/mpi.c [new file with mode: 0644]
lib/nettle/pk.c [new file with mode: 0644]
lib/nettle/rnd.c [new file with mode: 0644]
src/certtool.c
src/cli.c
src/serv.c
tests/chainverify.c

index ed6e69d9ea02ab83ef6c596c25c2934f03b814c7..e3af9f23d7d09d17a086b5a374c4f02d1af0579c 100644 (file)
@@ -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")
 
 AC_CHECK_TYPES(uint,,, [
@@ -305,4 +305,5 @@ AC_MSG_NOTICE([summary of build options:
   C++ library:      $use_cxx
   OpenSSL library:  $enable_openssl
   /dev/crypto:      $enable_cryptodev
+  Crypto library:   $cryptolib
 ])
index 33b6d0ac686fdfdad2013f08759339d0cdd8aba6..b79ad55ed4d7a09b5fcab6da59e448ed1349f38f 100644 (file)
@@ -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 ();
index b5768b443afc285a74df0403ceb5da24e8e86aee..2cb3b98aa2e949e1d0d76caf91038ee25710ed6d 100644 (file)
@@ -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 ();
index 9d436105fce55ce61eb55a8023a7eecccd5e2051..f8b91b07d77ca02fe1a96c392f36c438613e94d5 100644 (file)
@@ -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 ();
index ca5ea994f30fc220d0b3d24d25973b171dbed624..e0291c00c0aba20660efe7f4bfcb5dcfecc3aa9d 100644 (file)
@@ -81,7 +81,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.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 \
+       rnd-libgcrypt.c cipher-libgcrypt.c ext_signature.c \
        crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c \
        gnutls_privkey.c pkcs11.c pkcs11_privkey.c
 
@@ -89,6 +89,12 @@ if ENABLE_PKCS11
 COBJECTS += pkcs11.c pkcs11_privkey.c
 endif
 
+if ENABLE_NETTLE
+SUBDIRS += nettle
+else
+SUBDIRS += gcrypt
+endif
+
 if ENABLE_OPRFI
 COBJECTS += $(OPRFI_COBJECTS)
 endif
@@ -120,7 +126,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
@@ -143,6 +149,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)
index 26f6cb94928fec6186c650aac4308ff4a0783368..8ab237c21a54a2d5b75d4a180265ceb6e798f548 100644 (file)
@@ -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;
index fd849559ed070c969c35154214812efd4eb05087..a372b89a145cf10aaac1fc2ea58dbfbc0dbf56e6 100644 (file)
@@ -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 (file)
index 0000000..e55459c
--- /dev/null
@@ -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
similarity index 100%
rename from lib/cipher-libgcrypt.c
rename to lib/gcrypt/cipher.c
similarity index 100%
rename from lib/mac-libgcrypt.c
rename to lib/gcrypt/mac.c
similarity index 98%
rename from lib/mpi-libgcrypt.c
rename to lib/gcrypt/mpi.c
index eec739f36d61c2fccdb9d3bfe0b10b6e277cbeae..d45f023514fb07ce21485e14d19ee1088e71c3fb 100644 (file)
@@ -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;
 }
similarity index 100%
rename from lib/pk-libgcrypt.c
rename to lib/gcrypt/pk.c
similarity index 100%
rename from lib/rnd-libgcrypt.c
rename to lib/gcrypt/rnd.c
index 360bf1c54f740b0a0601b21b37ecbbeed083645b..539debf6c21f9170fd1c278ab85e3858de0d58e0 100644 (file)
@@ -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.
index 5279014ac6a40c5518cb55c52fe557c11c65fb77..98501087204e89f74286958fad98dad05abc9f60 100644 (file)
@@ -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;
index 927ea83ac15751fe50025be8365044ee52961071..8a8a844b9a198f92d88d8417dce0da1fbd200c66 100644 (file)
@@ -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;
 
 }
 
index c90bd16e8bd9176b2e73c80cfbc74453b2f532d0..3b06384078c9841feacdb7bf6785865a3a232ddf 100644 (file)
@@ -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 (file)
index 0000000..e55459c
--- /dev/null
@@ -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 (file)
index 0000000..1c56a39
--- /dev/null
@@ -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 (file)
index 0000000..5821843
--- /dev/null
@@ -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 (file)
index 0000000..2bac5b7
--- /dev/null
@@ -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 profile 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 (file)
index 0000000..081c08c
--- /dev/null
@@ -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 (file)
index 0000000..0a1066f
--- /dev/null
@@ -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,
+};
index 2b5cdcaaee6a6da4bf7d79829edaf374ab2f3986..bdc8b0c652f8fb1246398af6c1fb0c84a1aa9c95 100644 (file)
@@ -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:
index 52666863f55e7e89bede16228507860cfb48471e..44008436136d83312a7e40b98117deffb97e5d40 100644 (file)
--- 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
index 8b270df64a69506b4419a739c72b0d0d8f978a32..a2457ea78124fe375d8f65b156dd6e7228372497 100644 (file)
@@ -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));
index 5aa4b88df16d253869b60116b2a27cdc4ebe4ad0..1ddc20937a9277aa76787c96e482f4077b1026e3 100644 (file)
@@ -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)