summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2012-12-03 20:41:28 +0100
committerWerner Koch <wk@gnupg.org>2012-12-03 20:47:38 +0100
commit7607ab81504ce44060ed0b331d309606f5da1e75 (patch)
tree67d02c0a5e7f2de47c0d6a5fd7b9f5437e1e49b0 /tests
parentf17e4d920c8a18007a98830dd13163ff19616202 (diff)
downloadlibgcrypt-7607ab81504ce44060ed0b331d309606f5da1e75.tar.gz
random: Add a RNG selection interface and system RNG wrapper.
* random/random-system.c: New. * random/Makefile.am (librandom_la_SOURCES): Add new module. * random/random.c (struct rng_types): New. (_gcry_set_preferred_rng_type, _gcry_get_rng_type): New. (_gcry_random_initialize, gcry_random_add_bytes, do_randomize) (_gcry_set_random_seed_file, _gcry_update_random_seed_file) (_gcry_fast_random_poll): Dispatch to the actual RNG. * src/gcrypt.h.in (GCRYCTL_SET_PREFERRED_RNG_TYPE): New. GCRYCTL_GET_CURRENT_RNG_TYPE): New. (gcry_rng_types): New. * src/global.c (print_config): Print the TNG type. (global_init, _gcry_vcontrol): Implement the new control codes. * doc/gcrypt.texi (Controlling the library): Document the new control codes. * tests/benchmark.c (main): Add options to test the RNG types. * tests/random.c (main): Add new options. (print_hex): Print to stderr. (progress_cb, rng_type): New. (check_rng_type_switching, check_early_rng_type_switching): New. (run_all_rng_tests): New. -- The purpose of this change is to allow applications with moderate random requirements to use the system's RNG (e.g. /dev/urandom). The type switching logic makes sure that existing applications won't be affected by this change. A library is in almost all cases not able to degrade the quality of the RNG. The definition of "degrade" comes from our own assertion of the quality/trustworthiness of the RNGs: The most trustworthy RNG is the CSPRNG which dates back to the early GnuPG days. It is quite conservative and often requires more seeding than might be justified. GCRY_RNG_TYPE_STANDARD is the default unless the process is in FIPS mode. The second trustworthy RNG is the FIPS recommended X9.81 AES based implementation. It is seeded by the system's RNG. GCRY_RNG_TYPE_FIPS is the only available RNG if running in FIPS mode. The third trustworthy RNG is a mere wrapper around the system's native RNG. Thus there is no extra step on top of what, for example, /dev/random provides. GCRY_RNG_TYPE_SYSTEM may be used by applications which would use /dev/random or /dev/urandom instead.
Diffstat (limited to 'tests')
-rw-r--r--tests/benchmark.c17
-rw-r--r--tests/random.c275
2 files changed, 282 insertions, 10 deletions
diff --git a/tests/benchmark.c b/tests/benchmark.c
index 106e01b3..61badd5d 100644
--- a/tests/benchmark.c
+++ b/tests/benchmark.c
@@ -1151,6 +1151,23 @@ main( int argc, char **argv )
use_random_daemon = 1;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--prefer-standard-rng"))
+ {
+ /* This is anyway the default, but we may want to use it for
+ debugging. */
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--prefer-fips-rng"))
+ {
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--prefer-system-rng"))
+ {
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--no-blinding"))
{
no_blinding = 1;
diff --git a/tests/random.c b/tests/random.c
index 3e253631..a46d754d 100644
--- a/tests/random.c
+++ b/tests/random.c
@@ -32,7 +32,12 @@
#include "../src/gcrypt.h"
+#define PGM "random"
+
+
static int verbose;
+static int debug;
+static int with_progress;
static void
die (const char *format, ...)
@@ -40,6 +45,7 @@ die (const char *format, ...)
va_list arg_ptr;
va_start (arg_ptr, format);
+ fputs ( PGM ": ", stderr);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
exit (1);
@@ -52,6 +58,7 @@ inf (const char *format, ...)
va_list arg_ptr;
va_start (arg_ptr, format);
+ fputs ( PGM ": ", stderr);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
}
@@ -62,13 +69,25 @@ print_hex (const char *text, const void *buf, size_t n)
{
const unsigned char *p = buf;
- fputs (text, stdout);
+ inf ("%s", text);
for (; n; n--, p++)
- printf ("%02X", *p);
- putchar ('\n');
+ fprintf (stderr, "%02X", *p);
+ putc ('\n', stderr);
+}
+
+
+static void
+progress_cb (void *cb_data, const char *what, int printchar,
+ int current, int total)
+{
+ (void)cb_data;
+
+ inf ("progress (%s %c %d %d)\n", what, printchar, current, total);
+ fflush (stderr);
}
+
static int
writen (int fd, const void *buf, size_t nbytes)
{
@@ -251,34 +270,270 @@ check_nonce_forking (void)
}
+static int
+rng_type (void)
+{
+ int rngtype;
+ if (gcry_control (GCRYCTL_GET_CURRENT_RNG_TYPE, &rngtype))
+ die ("retrieving RNG type failed\n");
+ return rngtype;
+}
+
+
+static void
+check_rng_type_switching (void)
+{
+ int rngtype, initial;
+ char tmp1[4];
+
+ if (verbose)
+ inf ("checking whether RNG type switching works\n");
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ initial = rngtype;
+ gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+ if (debug)
+ print_hex (" sample: ", tmp1, sizeof tmp1);
+ if (rngtype != rng_type ())
+ die ("RNG type unexpectedly changed\n");
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (rngtype != initial)
+ die ("switching to System RNG unexpectedly succeeded\n");
+ gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+ if (debug)
+ print_hex (" sample: ", tmp1, sizeof tmp1);
+ if (rngtype != rng_type ())
+ die ("RNG type unexpectedly changed\n");
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (rngtype != initial)
+ die ("switching to FIPS RNG unexpectedly succeeded\n");
+ gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+ if (debug)
+ print_hex (" sample: ", tmp1, sizeof tmp1);
+ if (rngtype != rng_type ())
+ die ("RNG type unexpectedly changed\n");
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (rngtype != GCRY_RNG_TYPE_STANDARD)
+ die ("switching to standard RNG failed\n");
+ gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+ if (debug)
+ print_hex (" sample: ", tmp1, sizeof tmp1);
+ if (rngtype != rng_type ())
+ die ("RNG type unexpectedly changed\n");
+}
+
+
+static void
+check_early_rng_type_switching (void)
+{
+ int rngtype, initial;
+
+ if (verbose)
+ inf ("checking whether RNG type switching works in the early stage\n");
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ initial = rngtype;
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (initial >= GCRY_RNG_TYPE_SYSTEM && rngtype != GCRY_RNG_TYPE_SYSTEM)
+ die ("switching to System RNG failed\n");
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (initial >= GCRY_RNG_TYPE_FIPS && rngtype != GCRY_RNG_TYPE_FIPS)
+ die ("switching to FIPS RNG failed\n");
+
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+
+ rngtype = rng_type ();
+ if (debug)
+ inf ("rng type: %d\n", rngtype);
+ if (rngtype != GCRY_RNG_TYPE_STANDARD)
+ die ("switching to standard RNG failed\n");
+}
+/* Because we want to check initialization behaviour, we need to
+ fork/exec this program with several command line arguments. We use
+ system, so that these tests work also on Windows. */
+static void
+run_all_rng_tests (const char *program)
+{
+ static const char *options[] = {
+ "--early-rng-check",
+ "--early-rng-check --prefer-standard-rng",
+ "--early-rng-check --prefer-fips-rng",
+ "--early-rng-check --prefer-system-rng",
+ "--prefer-standard-rng",
+ "--prefer-fips-rng",
+ "--prefer-system-rng",
+ NULL
+ };
+ int idx;
+ size_t len, maxlen;
+ char *cmdline;
+
+ maxlen = 0;
+ for (idx=0; options[idx]; idx++)
+ {
+ len = strlen (options[idx]);
+ if (len > maxlen)
+ maxlen = len;
+ }
+ maxlen += strlen (program);
+ maxlen += strlen (" --in-recursion --verbose --debug --progress");
+ maxlen++;
+ cmdline = malloc (maxlen + 1);
+ if (!cmdline)
+ die ("out of core\n");
+
+ for (idx=0; options[idx]; idx++)
+ {
+ if (verbose)
+ inf ("now running with options '%s'\n", options[idx]);
+ strcpy (cmdline, program);
+ strcat (cmdline, " --in-recursion");
+ if (verbose)
+ strcat (cmdline, " --verbose");
+ if (debug)
+ strcat (cmdline, " --debug");
+ if (with_progress)
+ strcat (cmdline, " --progress");
+ strcat (cmdline, " ");
+ strcat (cmdline, options[idx]);
+ if (system (cmdline))
+ die ("running '%s' failed\n", cmdline);
+ }
+ free (cmdline);
+}
int
main (int argc, char **argv)
{
- int debug = 0;
+ int last_argc = -1;
+ int early_rng = 0;
+ int in_recursion = 0;
+ const char *program = NULL;
+
+ if (argc)
+ {
+ program = *argv;
+ argc--; argv++;
+ }
+ else
+ die ("argv[0] missing\n");
- if ((argc > 1) && (! strcmp (argv[1], "--verbose")))
- verbose = 1;
- else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
- verbose = debug = 1;
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ fputs ("usage: random [options]\n", stdout);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ debug = verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--progress"))
+ {
+ argc--; argv++;
+ with_progress = 1;
+ }
+ else if (!strcmp (*argv, "--in-recursion"))
+ {
+ in_recursion = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--early-rng-check"))
+ {
+ early_rng = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--prefer-standard-rng"))
+ {
+ /* This is anyway the default, but we may want to use it for
+ debugging. */
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--prefer-fips-rng"))
+ {
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_FIPS);
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--prefer-system-rng"))
+ {
+ gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
+ argc--; argv++;
+ }
+ }
#ifndef HAVE_W32_SYSTEM
signal (SIGPIPE, SIG_IGN);
#endif
+ if (early_rng)
+ check_early_rng_type_switching ();
+
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch\n");
+ if (with_progress)
+ gcry_set_progress_handler (progress_cb, NULL);
+
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
if (debug)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
- check_forking ();
- check_nonce_forking ();
+ if (!in_recursion)
+ {
+ check_forking ();
+ check_nonce_forking ();
+ }
+ check_rng_type_switching ();
+
+ if (!in_recursion)
+ run_all_rng_tests (program);
return 0;
}