summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--README6
-rw-r--r--configure.ac31
-rw-r--r--doc/gcrypt.texi4
-rw-r--r--random/ChangeLog8
-rw-r--r--random/rand-internal.h3
-rw-r--r--random/random-fips.c22
-rw-r--r--random/random.c74
-rw-r--r--random/random.h2
-rw-r--r--src/ChangeLog11
-rw-r--r--src/Makefile.am9
-rw-r--r--src/cipher-proto.h1
-rw-r--r--src/fips.c90
-rw-r--r--src/global.c7
-rw-r--r--src/hmac256.c117
-rw-r--r--src/hmac256.h3
-rw-r--r--tests/Makefile.am2
17 files changed, 341 insertions, 54 deletions
diff --git a/ChangeLog b/ChangeLog
index 24ae36c2..f78a85c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2008-08-22 Werner Koch <wk@g10code.com>
+
+ * configure.ac: Add option --enable-hmac-binary-check.
+ (DL_LIBS): Check whether -ldl is required.
+
2008-08-19 Werner Koch <wk@g10code.com>
Release 1.4.2rc1.
diff --git a/README b/README
index 714bc42d..ff5bebb2 100644
--- a/README
+++ b/README
@@ -158,12 +158,18 @@
auto - Compile linux, egd and unix in and
automagically select at runtime.
+ --enable-hmac-binary-check
+ Include support to check the binary at runtime
+ against a HMAC checksum. This works only in FIPS
+ mode and on systems providing the dladdr function.
+
--disable-padlock-support
Disable support for the PadLock engine of VIA
processors. The default is to use PadLock if
available. Try this if you get problems with
assembler code.
+
License
diff --git a/configure.ac b/configure.ac
index e332ce2b..82823f13 100644
--- a/configure.ac
+++ b/configure.ac
@@ -449,6 +449,19 @@ AC_ARG_WITH(capabilities,
[use_capabilities="$withval"],[use_capabilities=no])
AC_MSG_RESULT($use_capabilities)
+# Implementation of the --enable-hmac-binary-check.
+AC_MSG_CHECKING([whether a HMAC binary check is requested])
+AC_ARG_ENABLE(hmac-binary-check,
+ AC_HELP_STRING([--enable-hmac-binary-check],
+ [Enable library integrity check]),
+ [use_hmac_binary_check=$enableval],
+ [use_hmac_binary_check=no])
+AC_MSG_RESULT($use_hmac_binary_check)
+if test "$use_hmac_binary_check" = yes ; then
+ AC_DEFINE(ENABLE_HMAC_BINARY_CHECK,1,
+ [Define to support an HMAC based integrity check])
+fi
+
# Implementation of the --disable-padlock-support switch.
AC_MSG_CHECKING([whether padlock support is requested])
@@ -692,7 +705,25 @@ AC_CHECK_FUNCS(fcntl ftruncate)
GNUPG_CHECK_MLOCK
+
+#
+# Check wether it is necessary to link against libdl.
+#
+DL_LIBS=""
+if test "$use_hmac_binary_check" = yes ; then
+ _gcry_save_libs="$LIBS"
+ LIBS=""
+ AC_SEARCH_LIBS(dlopen, c dl,,,)
+ DL_LIBS=$LIBS
+ LIBS="$_gcry_save_libs"
+ LIBGCRYPT_CONFIG_LIBS="${LIBGCRYPT_CONFIG_LIBS} ${DL_LIBS}"
+fi
+AC_SUBST(DL_LIBS)
+
+
+#
# Check whether we can use Linux capabilities as requested.
+#
if test "$use_capabilities" = "yes" ; then
use_capabilities=no
AC_CHECK_HEADERS(sys/capability.h)
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 7d2adee5..b13464c9 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -4607,7 +4607,9 @@ If Libgcrypt is used FIPS mode these restrictions are effective:
@itemize
-@item TBD
+@item
+It may only be used on systesm with a /dev/random device. Swicthing
+into FIPS mode on other systems will fail at runtime.
diff --git a/random/ChangeLog b/random/ChangeLog
index 9f874534..73bfc6fa 100644
--- a/random/ChangeLog
+++ b/random/ChangeLog
@@ -1,3 +1,11 @@
+2008-08-22 Werner Koch <wk@g10code.com>
+
+ * random.c (_gcry_update_random_seed_file): Move operational check
+ to _gcry_vcontrol.
+ (_gcry_fast_random_poll): Ditto.
+ (_gcry_random_selftest): New.
+ * random-fips.c (_gcry_rngfips_selftest): New.
+
2008-08-21 Werner Koch <wk@g10code.com>
* random-fips.c: Finish implementation.
diff --git a/random/rand-internal.h b/random/rand-internal.h
index 7a2edf5b..e3c01920 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -20,6 +20,7 @@
#ifndef G10_RAND_INTERNAL_H
#define G10_RAND_INTERNAL_H
+#include "../src/cipher-proto.h"
/* Constants used to define the origin of random added to the pool.
The code is sensitive to the order of the values. */
@@ -76,6 +77,8 @@ void _gcry_rngfips_randomize (void *buffer, size_t length,
enum gcry_random_level level);
void _gcry_rngfips_create_nonce (void *buffer, size_t length);
+gcry_error_t _gcry_rngfips_selftest (selftest_report_func_t report);
+
diff --git a/random/random-fips.c b/random/random-fips.c
index 077679d1..cbecefcb 100644
--- a/random/random-fips.c
+++ b/random/random-fips.c
@@ -602,6 +602,7 @@ get_random (void *buffer, size_t length, rng_context_t rng_ctx)
}
+
/* Initialize this random subsystem. If FULL is false, this function
merely calls the basic initialization of the module and does not do
anything more. Doing this is not really required but when running
@@ -639,9 +640,11 @@ _gcry_rngfips_initialize (int full)
}
+/* Print some statistics about the RNG. */
void
_gcry_rngfips_dump_stats (void)
{
+ /* Not yet implemented. */
}
@@ -656,11 +659,11 @@ _gcry_rngfips_is_faked (void)
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
should be in the range of 0..100 to indicate the goodness of the
- entropy added, or -1 for goodness not known. */
+ entropy added, or -1 for goodness not known. */
gcry_error_t
_gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality)
{
- return 0;
+ return 0; /* Not implemented. */
}
@@ -691,3 +694,18 @@ _gcry_rngfips_create_nonce (void *buffer, size_t length)
get_random (buffer, length, nonce_context);
}
+
+/* Run the self-tests. */
+gcry_error_t
+_gcry_rngfips_selftest (selftest_report_func_t report)
+{
+ gcry_err_code_t ec = 0;
+ char buffer[8];
+
+ /* Do a simple test using the public interface. */
+ gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM);
+
+
+ return gpg_error (ec);
+}
+
diff --git a/random/random.c b/random/random.c
index ff7c280e..3e71195d 100644
--- a/random/random.c
+++ b/random/random.c
@@ -75,7 +75,7 @@ _gcry_random_progress (const char *what, int printchar, int current, int total)
void
_gcry_random_initialize (int full)
{
- if ( fips_mode() )
+ if (fips_mode ())
_gcry_rngfips_initialize (full);
else
_gcry_rngcsprng_initialize (full);
@@ -85,7 +85,7 @@ _gcry_random_initialize (int full)
void
_gcry_random_dump_stats (void)
{
- if ( fips_mode() )
+ if (fips_mode ())
_gcry_rngfips_dump_stats ();
else
_gcry_rngcsprng_dump_stats ();
@@ -98,9 +98,10 @@ _gcry_random_dump_stats (void)
void
_gcry_secure_random_alloc (void)
{
- if ( fips_mode() )
- return; /* Not used; the fips rng is allows in secure mode. */
- _gcry_rngcsprng_secure_alloc ();
+ if (fips_mode ())
+ ; /* Not used; the fips rng is allows in secure mode. */
+ else
+ _gcry_rngcsprng_secure_alloc ();
}
@@ -109,18 +110,20 @@ _gcry_secure_random_alloc (void)
void
_gcry_enable_quick_random_gen (void)
{
- if ( fips_mode() )
- return; /* Not used. */
- _gcry_rngcsprng_enable_quick_gen ();
+ if (fips_mode ())
+ ; /* Not used. */
+ else
+ _gcry_rngcsprng_enable_quick_gen ();
}
void
_gcry_set_random_daemon_socket (const char *socketname)
{
- if ( fips_mode() )
- return; /* Not used. */
- _gcry_rngcsprng_set_daemon_socket (socketname);
+ if (fips_mode ())
+ ; /* Not used. */
+ else
+ _gcry_rngcsprng_set_daemon_socket (socketname);
}
/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set
@@ -131,7 +134,8 @@ _gcry_use_random_daemon (int onoff)
{
if (fips_mode ())
return 0; /* Never enabled in fips mode. */
- return _gcry_rngcsprng_use_daemon (onoff);
+ else
+ return _gcry_rngcsprng_use_daemon (onoff);
}
@@ -141,8 +145,9 @@ int
_gcry_random_is_faked (void)
{
if (fips_mode ())
- return 0; /* Never faked in fips mode. */
- return _gcry_rngcsprng_is_faked ();
+ return _gcry_rngfips_is_faked ();
+ else
+ return _gcry_rngcsprng_is_faked ();
}
@@ -154,7 +159,8 @@ gcry_random_add_bytes (const void *buf, size_t buflen, int quality)
{
if (fips_mode ())
return 0; /* No need for this in fips mode. */
- return _gcry_rngcsprng_add_bytes (buf, buflen, quality);
+ else
+ return _gcry_rngcsprng_add_bytes (buf, buflen, quality);
}
@@ -217,7 +223,10 @@ gcry_randomize (void *buffer, size_t length, enum gcry_random_level level)
void
_gcry_set_random_seed_file (const char *name)
{
- _gcry_rngcsprng_set_seed_file (name);
+ if (fips_mode ())
+ ; /* No need for this in fips mode. */
+ else
+ _gcry_rngcsprng_set_seed_file (name);
}
@@ -226,10 +235,10 @@ _gcry_set_random_seed_file (const char *name)
void
_gcry_update_random_seed_file (void)
{
- if (!fips_is_operational ()) /* FIXME: This does no look correct. */
- return;
-
- _gcry_rngcsprng_update_seed_file ();
+ if (fips_mode ())
+ ; /* No need for this in fips mode. */
+ else
+ _gcry_rngcsprng_update_seed_file ();
}
@@ -244,10 +253,10 @@ _gcry_update_random_seed_file (void)
void
_gcry_fast_random_poll (void)
{
- if (!fips_is_operational ())
- return;
-
- _gcry_rngcsprng_fast_poll ();
+ if (fips_mode ())
+ ; /* No need for this in fips mode. */
+ else
+ _gcry_rngcsprng_fast_poll ();
}
@@ -256,6 +265,21 @@ _gcry_fast_random_poll (void)
void
gcry_create_nonce (void *buffer, size_t length)
{
- _gcry_rngcsprng_create_nonce (buffer, length);
+ if (fips_mode ())
+ _gcry_rngfips_create_nonce (buffer, length);
+ else
+ _gcry_rngcsprng_create_nonce (buffer, length);
+}
+
+
+/* Run the self-tests for the RNG. This is currently only implemented
+ for the FIPS generator. */
+gpg_error_t
+_gcry_random_selftest (selftest_report_func_t report)
+{
+ if (fips_mode ())
+ return _gcry_rngfips_selftest (report);
+ else
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
}
diff --git a/random/random.h b/random/random.h
index 1db189ea..eda44d36 100644
--- a/random/random.h
+++ b/random/random.h
@@ -22,6 +22,7 @@
#include "types.h"
+/*-- random.c --*/
void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
void *cb_data );
@@ -38,6 +39,7 @@ void _gcry_update_random_seed_file (void);
byte *_gcry_get_random_bits( size_t nbits, int level, int secure );
void _gcry_fast_random_poll( void );
+
/*-- rndegd.c --*/
gpg_error_t _gcry_rndegd_set_socket_name (const char *name);
diff --git a/src/ChangeLog b/src/ChangeLog
index b811b6ed..7f54e745 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
+2008-08-22 Werner Koch <wk@g10code.com>
+
+ * hmac256.c (_gcry_hmac256_file): New.
+ (main): New option --binary.
+ * fips.c (check_binary_integrity): New.
+ (_gcry_fips_run_selftests): Run it.
+
+ * global.c (_gcry_vcontrol) <GCRYCTL_UPDATE_RANDOM_SEED_FILE>:
+ Check for fips operational state.
+ (_gcry_vcontrol) <GCRYCTL_FAST_POLL>: Ditt.
+
2008-08-21 Werner Koch <wk@g10code.com>
* misc.c (_gcry_log_printhex): New.
diff --git a/src/Makefile.am b/src/Makefile.am
index d9a58457..bb88520d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -121,3 +121,12 @@ endif USE_RANDOM_DAEMON
install-data-local: install-def-file
uninstall-local: uninstall-def-file
+
+# FIXME: We ned to figure out how to gte the actual name (parsing
+# libgcrypt.la?) and how to create the hmac file already at link time
+# so that it can be used without first installing.
+#install-exec-hook:
+# ./hmac256 --binary "What am I, a doctor or a moonshuttle conductor?" \
+# $(DESTDIR)$(libdir)/libgcrypt.so.11.5.0 \
+# >$(DESTDIR)$(libdir)/libgcrypt.so.11.5.0.hmac
+
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index 4b826c1d..ae5492b4 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -79,5 +79,6 @@ gcry_error_t _gcry_md_selftest (int algo, selftest_report_func_t report);
gcry_error_t _gcry_pk_selftest (int algo, selftest_report_func_t report);
gcry_error_t _gcry_hmac_selftest (int algo, selftest_report_func_t report);
+gcry_error_t _gcry_random_selftest (selftest_report_func_t report);
#endif /*G10_CIPHER_PROTO_H*/
diff --git a/src/fips.c b/src/fips.c
index ed4b9fd5..8f367977 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -22,12 +22,14 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
-
-/* #include <dlfcn.h> /\* FIXME: GNU only *\/ */
+#ifdef ENABLE_HMAC_BINARY_CHECK
+# include <dlfcn.h>
+#endif
#include "g10lib.h"
#include "ath.h"
#include "cipher-proto.h"
+#include "hmac256.h"
/* The states of the finite state machine used in fips mode. */
enum module_states
@@ -417,17 +419,79 @@ run_pubkey_selftests (void)
}
-/* Run self-tests for the random number generator. Return 0 on
+/* Run self-tests for the random number generator. Returns 0 on
success. */
static int
run_random_selftests (void)
{
- char buffer[8];
+ gpg_error_t err;
- /* FIXME: For now we just try to get a few bytes. */
- gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM);
+ err = _gcry_random_selftest (reporter);
+ reporter ("random", 0, NULL, err? gpg_strerror (err):NULL);
+
+ return !!err;
+}
+/* Run an integrity check on the binary. Returns 0 on success. */
+static int
+check_binary_integrity (void)
+{
+#ifdef ENABLE_HMAC_BINARY_CHECK
+ gpg_error_t err;
+ Dl_info info;
+ unsigned char digest[32];
+ int dlen;
+ char *fname = NULL;
+ const char key[] = "What am I, a doctor or a moonshuttle conductor?";
+
+ if (!dladdr ("gcry_check_version", &info))
+ err = gpg_error_from_syserror ();
+ else
+ {
+ dlen = _gcry_hmac256_file (digest, sizeof digest, info.dli_fname,
+ key, strlen (key));
+ if (dlen < 0)
+ err = gpg_error_from_syserror ();
+ else if (dlen != 32)
+ err = gpg_error (GPG_ERR_INTERNAL);
+ else
+ {
+ FILE *fp;
+
+ fname = gcry_malloc (strlen (info.dli_fname) + 5 + 1 );
+ if (!fname)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ strcpy (stpcpy (fname, info.dli_fname), ".hmac");
+ fp = fopen (fname, "rb");
+ if (!fp)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ char buffer[33];
+ int n;
+
+ /* We expect a file of exactly 32 bytes. Consider
+ the self-test failed if this is not the case or
+ if it does not match the just computed HMAC. */
+ if ((n=fread (buffer, 1, 33, fp)) != 32
+ || memcmp (digest, buffer, 32) )
+ err = gpg_error (GPG_ERR_SELFTEST_FAILED);
+ else
+ err = 0;
+
+ fclose (fp);
+ }
+ }
+ }
+ }
+ reporter ("binary", 0, fname, err? gpg_strerror (err):NULL);
+ gcry_free (fname);
+ return !!err;
+#else
return 0;
+#endif
}
@@ -439,15 +503,6 @@ _gcry_fips_run_selftests (void)
fips_new_state (STATE_SELFTEST);
-/* { */
-/* Dl_info info; */
-
-/* if (dladdr ("gcry_check_version", &info)) */
-/* log_info ("DL_info: fname=`%s'\n", */
-/* info.dli_fname); */
-/* } */
-
-
if (run_cipher_selftests ())
goto leave;
@@ -463,6 +518,11 @@ _gcry_fips_run_selftests (void)
if (run_random_selftests ())
goto leave;
+ /* Now check the integrity of the binary. We do this this after
+ having checked the HMAC code. */
+ if (check_binary_integrity ())
+ goto leave;
+
/* All selftests passed. */
result = STATE_OPERATIONAL;
diff --git a/src/global.c b/src/global.c
index ed4e4807..2b7f0bcc 100644
--- a/src/global.c
+++ b/src/global.c
@@ -349,7 +349,8 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
break;
case GCRYCTL_UPDATE_RANDOM_SEED_FILE:
- _gcry_update_random_seed_file ();
+ if ( fips_is_operational () )
+ _gcry_update_random_seed_file ();
break;
case GCRYCTL_SET_VERBOSITY:
@@ -405,7 +406,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
/* We need to do make sure that the random pool is really
initialized so that the poll function is not a NOP. */
_gcry_random_initialize (1);
- _gcry_fast_random_poll ();
+
+ if ( fips_is_operational () )
+ _gcry_fast_random_poll ();
break;
case GCRYCTL_SET_RNDEGD_SOCKET:
diff --git a/src/hmac256.c b/src/hmac256.c
index 9cfffa27..8a318af9 100644
--- a/src/hmac256.c
+++ b/src/hmac256.c
@@ -52,6 +52,9 @@
#include <string.h>
#include <assert.h>
#include <errno.h>
+#if defined(__WIN32) && defined(STANDALONE)
+# include <fcntl.h> /* We need setmode(). */
+#endif
#include "hmac256.h"
@@ -361,6 +364,7 @@ _gcry_hmac256_release (hmac256_context_t ctx)
{
if (ctx)
{
+ /* Note: We need to take care not to modify errno. */
if (ctx->use_hmac)
my_wipememory (ctx->opad, 64);
free (ctx);
@@ -441,6 +445,78 @@ _gcry_hmac256_finalize (hmac256_context_t hd, size_t *r_dlen)
}
+/* Convenience function to compute the HMAC-SHA256 of one file. The
+ user needs to provide a buffer RESULT of at least 32 bytes, he
+ needs to put the size of the buffer into RESULTSIZE and the
+ FILENAME. KEY and KEYLEN are as described for _gcry_hmac256_new.
+ On success the function returns the valid length of the result
+ buffer (which will be 32) or -1 on error. On error ERRNO is set
+ appropriate. */
+int
+_gcry_hmac256_file (void *result, size_t resultsize, const char *filename,
+ const void *key, size_t keylen)
+{
+ FILE *fp;
+ hmac256_context_t hd;
+ size_t buffer_size, nread, digestlen;
+ char *buffer;
+ const unsigned char *digest;
+
+ fp = fopen (filename, "rb");
+ if (!fp)
+ return -1;
+
+ hd = _gcry_hmac256_new (key, keylen);
+ if (!hd)
+ {
+ fclose (fp);
+ return -1;
+ }
+
+ buffer_size = 32768;
+ buffer = malloc (buffer_size);
+ if (!buffer)
+ {
+ fclose (fp);
+ _gcry_hmac256_release (hd);
+ return -1;
+ }
+
+ while ( (nread = fread (buffer, 1, buffer_size, fp)))
+ _gcry_hmac256_update (hd, buffer, nread);
+
+ free (buffer);
+
+ if (ferror (fp))
+ {
+ fclose (fp);
+ _gcry_hmac256_release (hd);
+ return -1;
+ }
+
+ fclose (fp);
+
+ digest = _gcry_hmac256_finalize (hd, &digestlen);
+ if (!digest)
+ {
+ _gcry_hmac256_release (hd);
+ return -1;
+ }
+
+ if (digestlen > resultsize)
+ {
+ _gcry_hmac256_release (hd);
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy (result, digest, digestlen);
+ _gcry_hmac256_release (hd);
+
+ return digestlen;
+}
+
+
+
#ifdef STANDALONE
static int
selftest (void)
@@ -574,8 +650,12 @@ main (int argc, char **argv)
char buffer[4096];
size_t n, dlen, idx;
int use_stdin = 0;
+ int use_binary = 0;
assert (sizeof (u32) == 4);
+#ifdef __WIN32
+ setmode (fileno (stdin), O_BINARY);
+#endif
if (argc)
{
@@ -609,14 +689,23 @@ main (int argc, char **argv)
stdout);
exit (0);
}
+ else if (!strcmp (*argv, "--binary"))
+ {
+ argc--; argv++;
+ use_binary = 1;
+ }
}
if (argc < 1)
{
- fprintf (stderr, "usage: %s key [filename]\n", pgm);
+ fprintf (stderr, "usage: %s [--binary] key [filename]\n", pgm);
exit (1);
}
+#ifdef __WIN32
+ if (use_binary)
+ setmode (fileno (stdout), O_BINARY);
+#endif
key = *argv;
argc--, argv++;
@@ -664,15 +753,27 @@ main (int argc, char **argv)
pgm, strerror (errno));
exit (1);
}
- for (idx=0; idx < dlen; idx++)
- printf ("%02x", digest[idx]);
- _gcry_hmac256_release (hd);
- if (use_stdin)
+ if (use_binary)
{
- putchar ('\n');
- break;
+ if (fwrite (digest, dlen, 1, stdout) != 1)
+ {
+ fprintf (stderr, "%s: error writing output: %s\n",
+ pgm, strerror (errno));
+ exit (1);
+ }
+ }
+ else
+ {
+ for (idx=0; idx < dlen; idx++)
+ printf ("%02x", digest[idx]);
+ _gcry_hmac256_release (hd);
+ if (use_stdin)
+ {
+ putchar ('\n');
+ break;
+ }
+ printf (" %s\n", fname);
}
- printf (" %s\n", fname);
}
return 0;
diff --git a/src/hmac256.h b/src/hmac256.h
index 2f4d1ea4..df28e727 100644
--- a/src/hmac256.h
+++ b/src/hmac256.h
@@ -29,5 +29,8 @@ void _gcry_hmac256_update (hmac256_context_t hd, const void *buf, size_t len);
const void *_gcry_hmac256_finalize (hmac256_context_t hd, size_t *r_dlen);
void _gcry_hmac256_release (hmac256_context_t hd);
+int _gcry_hmac256_file (void *result, size_t resultsize, const char *filename,
+ const void *key, size_t keylen);
+
#endif /*HMAC256_H*/
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2af4dbdc..4f6ab42a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -36,7 +36,7 @@ TESTS += benchmark
AM_CPPFLAGS = -I../src -I$(top_srcdir)/src
AM_CFLAGS = $(GPG_ERROR_CFLAGS)
-LDADD = ../src/libgcrypt.la
+LDADD = ../src/libgcrypt.la $(DL_LIBS)
EXTRA_PROGRAMS = testapi
noinst_PROGRAMS = $(TESTS)