From: Nikos Mavrogiannopoulos Date: Fri, 21 May 2010 15:00:01 +0000 (+0200) Subject: Added support for libnettle backend. This uses gmp for big number operations. X-Git-Tag: gnutls_2_11_3~287 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eb24bfa808ee029e9b3b198d66d29256eea3fd08;p=thirdparty%2Fgnutls.git 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. --- diff --git a/configure.ac b/configure.ac index ed6e69d9ea..e3af9f23d7 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") 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 ]) 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 #include #include -#include /* 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 #include #include -#include /* 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 #include #include -#include /* 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 ca5ea994f3..e0291c00c0 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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) 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_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 similarity index 100% rename from lib/cipher-libgcrypt.c rename to lib/gcrypt/cipher.c diff --git a/lib/mac-libgcrypt.c b/lib/gcrypt/mac.c similarity index 100% rename from lib/mac-libgcrypt.c rename to lib/gcrypt/mac.c diff --git a/lib/mpi-libgcrypt.c b/lib/gcrypt/mpi.c similarity index 98% rename from lib/mpi-libgcrypt.c rename to 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 similarity index 100% rename from lib/pk-libgcrypt.c rename to lib/gcrypt/pk.c diff --git a/lib/rnd-libgcrypt.c b/lib/gcrypt/rnd.c similarity index 100% rename from lib/rnd-libgcrypt.c rename to 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 #include #include +#ifndef HAVE_LIBNETTLE #include +#endif #include #include /* 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 ], + 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 ], + [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 ], [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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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;iparams[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;iparams[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;iparams_nr;i++) { + _gnutls_mpi_release(¶ms->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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 #include #include -#include /* Gnulib portability files. */ #include @@ -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 #include #include -#include #include #include #include @@ -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)