summaryrefslogtreecommitdiff
path: root/src/fips.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fips.c')
-rw-r--r--src/fips.c90
1 files changed, 75 insertions, 15 deletions
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;